Repository: osmosis-labs/osmosis
Pull request #5250 (2023-05-20 12:56:27)

Auto add changelog and backport labels to dependabot 
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v                               ✰  Thanks for creating a PR! ✰    
v    Before smashing the submit button please review the checkboxes.
v    If a checkbox is n/a - please still include it but + a little note why
v    If your PR doesn't close an issue, that's OK!  Just remove the Closes: #XXX line!
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  -->

Closes: #5227 

## What is the purpose of the change

Adds labels to dependabot to avoid adding them manually 

## Testing and Verifying

Minor 

## Documentation and Release Note

Changelog


Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index bb472acee..327de5f6a 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,10 +5,15 @@ updates:
   schedule:
     interval: daily
   open-pull-requests-limit: 10
+  labels:
+    - "A:no-changelog"
+    - "V:state/compatible/no_backport"
 - package-ecosystem: gomod
   directory: "/"
   schedule:
     interval: weekly
+  labels:
+    - "A:no-changelog"
   ignore:
     - dependency-name: "github.com/tendermint/tendermint"
       update-types: ["version-update:semver-major", "version-update:semver-minor"]
diff --git a/.github/workflows/check-broken-links.yml b/.github/workflows/check-broken-links.yml
index ecb5f74e7..9d91128ec 100644
--- a/.github/workflows/check-broken-links.yml
+++ b/.github/workflows/check-broken-links.yml
@@ -23,6 +23,6 @@ jobs:
         if: env.lychee_exit_code != 0
         uses: peter-evans/create-issue-from-file@v4
         with:
-          title: Link Checker Report
+          title: Broken Links Detected
           content-filepath: ./lychee/out.md
           labels: report, automated issue
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e605d96a..88c3c6c95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,8 +69,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   * [#5129](https://github.com/osmosis-labs/osmosis/pull/5129) Relax twap record validation in init genesis to allow one of the spot prices to be non-zero when twap error is observed.
   * [#5165](https://github.com/osmosis-labs/osmosis/pull/5165) Improve error message when fully exiting from a pool.
   * [#5187](https://github.com/osmosis-labs/osmosis/pull/5187) Expand `IncentivizedPools` query to include internally incentivized CL pools.
-  * [#5239](https://github.com/osmosis-labs/osmosis/pull/5239) Implement `GetTotalPoolShares` public keeper function for GAMM.
-  
+  * [#5239](https://github.com/osmosis-labs/osmosis/pull/5239) Implement `GetTotalPoolShares` public keeper function for GAMM. 
+
 ### API breaks
 
 * [#4336](https://github.com/osmosis-labs/osmosis/pull/4336) Move epochs module into its own go.mod
diff --git a/go.mod b/go.mod
index a7c88a282..85d0f29b8 100644
--- a/go.mod
+++ b/go.mod
@@ -25,13 +25,13 @@ require (
 	github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230331072320-5d6f6cfa2627
 	github.com/pkg/errors v0.9.1
 	github.com/rakyll/statik v0.1.7
-	github.com/spf13/cast v1.5.0
+	github.com/spf13/cast v1.5.1
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.15.0
 	github.com/strangelove-ventures/async-icq/v4 v4.0.0-rc0
 	github.com/strangelove-ventures/packet-forward-middleware/v4 v4.0.5
-	github.com/stretchr/testify v1.8.2
+	github.com/stretchr/testify v1.8.3
 	github.com/tendermint/tendermint v0.34.26
 	github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b
 	github.com/tidwall/btree v1.6.0
diff --git a/go.sum b/go.sum
index 85fb44ff8..f59f480a0 100644
--- a/go.sum
+++ b/go.sum
@@ -1114,8 +1114,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
 github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
 github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
+github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -1158,8 +1158,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
diff --git a/scripts/approximations/requirements.txt b/scripts/approximations/requirements.txt
index ce1140c3e..c8636777a 100644
--- a/scripts/approximations/requirements.txt
+++ b/scripts/approximations/requirements.txt
@@ -3,7 +3,7 @@ cycler==0.11.0
 fonttools==4.38.0
 kiwisolver==1.4.4
 matplotlib==3.6.2
-mpmath==1.2.1
+mpmath==1.3.0
 numpy==1.23.5
 packaging==22.0
 Pillow==9.3.0
diff --git a/x/concentrated-liquidity/README.md b/x/concentrated-liquidity/README.md
index bcf100fe0..51ef64f69 100644
--- a/x/concentrated-liquidity/README.md
+++ b/x/concentrated-liquidity/README.md
@@ -84,7 +84,7 @@ in a concentrated liquidity pool.
 
 The price [p] corresponding to a tick [t] is defined by the equation:
 
-$$ p(i) = 1.0001^t $$
+$$ p(t) = 1.0001^t $$
 
 This results in a .01% difference between adjacent tick prices. This does not,
 however, allow for control over the specific prices that the ticks correspond
diff --git a/x/poolmanager/client/cli/flags.go b/x/poolmanager/client/cli/flags.go
index e3275864c..1705eeee8 100644
--- a/x/poolmanager/client/cli/flags.go
+++ b/x/poolmanager/client/cli/flags.go
@@ -1,6 +1,10 @@
 package cli
 
-import flag "github.com/spf13/pflag"
+import (
+	flag "github.com/spf13/pflag"
+
+	"github.com/osmosis-labs/osmosis/v15/x/poolmanager/types"
+)
 
 const (
 	// Names of fields in pool json file.
@@ -21,6 +25,8 @@ const (
 	FlagSwapRoutePoolIds = "swap-route-pool-ids"
 	// Will be parsed to []string.
 	FlagSwapRouteDenoms = "swap-route-denoms"
+	// Will be parsed to string.
+	FlagRoutesFile = "routes-file"
 )
 
 type createBalancerPoolInputs struct {
@@ -47,6 +53,23 @@ type smoothWeightChangeParamsInputs struct {
 	TargetPoolWeights string `json:"target-pool-weights"`
 }
 
+type RoutesIn struct {
+	Route []SwapAmountInSplitRoute `json:"route"`
+}
+type RoutesOut struct {
+	Route []SwapAmountOutSplitRoute `json:"route"`
+}
+
+type SwapAmountInSplitRoute struct {
+	Pools         []types.SwapAmountInRoute `json:"swap_amount_in_route"`
+	TokenInAmount int64                     `json:"token_in_amount"`
+}
+
+type SwapAmountOutSplitRoute struct {
+	Pools          []types.SwapAmountOutRoute `json:"swap_amount_out_route"`
+	TokenOutAmount int64                      `json:"token_out_amount"`
+}
+
 func FlagSetMultihopSwapRoutes() *flag.FlagSet {
 	fs := flag.NewFlagSet("", flag.ContinueOnError)
 	fs.String(FlagSwapRoutePoolIds, "", "swap route pool id")
@@ -76,3 +99,10 @@ func FlagSetCreatePool() *flag.FlagSet {
 	fs.String(FlagPoolFile, "", "Pool json file path (if this path is given, other create pool flags should not be used)")
 	return fs
 }
+
+func FlagSetCreateRoutes() *flag.FlagSet {
+	fs := flag.NewFlagSet("", flag.ContinueOnError)
+
+	fs.String(FlagRoutesFile, "", "Routes json file path (if this path is given, other routes flags should not be used)")
+	return fs
+}
diff --git a/x/poolmanager/client/cli/tx.go b/x/poolmanager/client/cli/tx.go
index fd480976d..b1c9008ba 100644
--- a/x/poolmanager/client/cli/tx.go
+++ b/x/poolmanager/client/cli/tx.go
@@ -1,8 +1,10 @@
 package cli
 
 import (
+	"encoding/json"
 	"errors"
 	"fmt"
+	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -27,6 +29,8 @@ func NewTxCmd() *cobra.Command {
 
 	osmocli.AddTxCmd(txCmd, NewSwapExactAmountInCmd)
 	osmocli.AddTxCmd(txCmd, NewSwapExactAmountOutCmd)
+	osmocli.AddTxCmd(txCmd, NewSplitRouteSwapExactAmountIn)
+	osmocli.AddTxCmd(txCmd, NewSplitRouteSwapExactAmountOut)
 
 	txCmd.AddCommand(
 		NewCreatePoolCmd(),
@@ -57,29 +61,154 @@ func NewSwapExactAmountOutCmd() (*osmocli.TxCliDesc, *types.MsgSwapExactAmountOu
 	}, &types.MsgSwapExactAmountOut{}
 }
 
-func NewBuildSwapExactAmountInMsg(clientCtx client.Context, tokenInStr, tokenOutMinAmtStr string, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, sdk.Msg, error) {
-	routes, err := swapAmountInRoutes(fs)
+func NewSplitRouteSwapExactAmountIn() (*osmocli.TxCliDesc, *types.MsgSplitRouteSwapExactAmountIn) {
+	return &osmocli.TxCliDesc{
+		Use:   "split-route-swap-exact-amount-in [token-in-denom] [token-out-min-amount] [flags]",
+		Short: "split route swap exact amount in",
+		Example: `osmosisd tx poolmanager split-route-swap-exact-amount-in uosmo 1 --routes-file="./routes.json" --from val --keyring-backend test -b=block --chain-id=localosmosis --fees 10000uosmo
+		- routes.json
+		{
+			"Route": [
+			  {
+			  "swap_amount_in_route": [
+				{
+				"pool_id": 1,
+				"token_out_denom": "uion"
+				},
+				{
+				"pool_id": 2,
+				"token_out_denom": "uosmo"
+				}
+			  ],
+			  "token_in_amount": 1000
+			  },
+			  {
+			  "swap_amount_in_route": [
+				{
+				"pool_id": 3,
+				"token_out_denom": "bar"
+				},
+				{
+				"pool_id": 4,
+				"token_out_denom": "uosmo"
+				}
+			  ],
+			  "token_in_amount": 999
+			  }
+			]
+		}
+		`,
+		CustomFieldParsers: map[string]osmocli.CustomFieldParserFn{
+			"Routes": osmocli.FlagOnlyParser(NewMsgNewSplitRouteSwapExactAmountIn),
+		},
+		Flags: osmocli.FlagDesc{
+			RequiredFlags: []*flag.FlagSet{FlagSetCreateRoutes()},
+		},
+	}, &types.MsgSplitRouteSwapExactAmountIn{}
+}
+
+func NewSplitRouteSwapExactAmountOut() (*osmocli.TxCliDesc, *types.MsgSplitRouteSwapExactAmountOut) {
+	return &osmocli.TxCliDesc{
+		Use:   "split-route-swap-exact-amount-out [token-out-denom] [token-in-max-amount] [flags]",
+		Short: "split route swap exact amount out",
+		Example: `osmosisd tx poolmanager split-route-swap-exact-amount-out uosmo 1 --routes-file="./routes.json" --from val --keyring-backend test -b=block --chain-id=localosmosis --fees 10000uosmo
+		- routes.json
+		{
+			"route": [
+				{
+				"swap_amount_out_route": [
+					{
+					"pool_id": 1,
+					"token_in_denom": "uion"
+					},
+					{
+					"pool_id": 2,
+					"token_in_denom": "uosmo"
+					}
+				],
+				"token_out_amount": 1000
+				},
+				{
+				"swap_amount_out_route": [
+					{
+					"pool_id": 3,
+					"token_in_denom": "uion"
+					},
+					{
+					"pool_id": 4,
+					"token_in_denom": "uosmo"
+					}
+				],
+				"token_out_amount": 999
+				}
+			]
+			}
+		`,
+		CustomFieldParsers: map[string]osmocli.CustomFieldParserFn{
+			"Routes": osmocli.FlagOnlyParser(NewMsgNewSplitRouteSwapExactAmountOut),
+		},
+		Flags: osmocli.FlagDesc{
+			RequiredFlags: []*flag.FlagSet{FlagSetCreateRoutes()},
+		},
+	}, &types.MsgSplitRouteSwapExactAmountOut{}
+}
+
+func NewMsgNewSplitRouteSwapExactAmountOut(fs *flag.FlagSet) ([]types.SwapAmountOutSplitRoute, error) {
+	routesFile, _ := fs.GetString(FlagRoutesFile)
+	if routesFile == "" {
+		return nil, fmt.Errorf("must pass in a routes json using the --%s flag", FlagRoutesFile)
+	}
+
+	contents, err := os.ReadFile(routesFile)
 	if err != nil {
-		return txf, nil, err
+		return nil, err
 	}
 
-	tokenIn, err := sdk.ParseCoinNormalized(tokenInStr)
+	var splitRouteJSONdata RoutesOut
+	err = json.Unmarshal(contents, &splitRouteJSONdata)
 	if err != nil {
-		return txf, nil, err
+		return nil, err
 	}
 
-	tokenOutMinAmt, ok := sdk.NewIntFromString(tokenOutMinAmtStr)
-	if !ok {
-		return txf, nil, fmt.Errorf("invalid token out min amount, %s", tokenOutMinAmtStr)
+	var splitRouteProto []types.SwapAmountOutSplitRoute
+	for _, route := range splitRouteJSONdata.Route {
+		protoRoute := types.SwapAmountOutSplitRoute{
+			TokenOutAmount: sdk.NewInt(route.TokenOutAmount),
+		}
+		protoRoute.Pools = append(protoRoute.Pools, route.Pools...)
+		splitRouteProto = append(splitRouteProto, protoRoute)
 	}
-	msg := &types.MsgSwapExactAmountIn{
-		Sender:            clientCtx.GetFromAddress().String(),
-		Routes:            routes,
-		TokenIn:           tokenIn,
-		TokenOutMinAmount: tokenOutMinAmt,
+
+	return splitRouteProto, nil
+}
+
+func NewMsgNewSplitRouteSwapExactAmountIn(fs *flag.FlagSet) ([]types.SwapAmountInSplitRoute, error) {
+	routesFile, _ := fs.GetString(FlagRoutesFile)
+	if routesFile == "" {
+		return nil, fmt.Errorf("must pass in a routes json using the --%s flag", FlagRoutesFile)
 	}
 
-	return txf, msg, nil
+	contents, err := os.ReadFile(routesFile)
+	if err != nil {
+		return nil, err
+	}
+
+	var splitRouteJSONdata RoutesIn
+	err = json.Unmarshal(contents, &splitRouteJSONdata)
+	if err != nil {
+		return nil, err
+	}
+
+	var splitRouteProto []types.SwapAmountInSplitRoute
+	for _, route := range splitRouteJSONdata.Route {
+		protoRoute := types.SwapAmountInSplitRoute{
+			TokenInAmount: sdk.NewInt(route.TokenInAmount),
+		}
+		protoRoute.Pools = append(protoRoute.Pools, route.Pools...)
+		splitRouteProto = append(splitRouteProto, protoRoute)
+	}
+
+	return splitRouteProto, nil
 }
 
 func NewBuildSwapExactAmountOutMsg(clientCtx client.Context, args []string, fs *flag.FlagSet) (sdk.Msg, error) {
diff --git a/x/poolmanager/router.go b/x/poolmanager/router.go
index 008917c0b..d86fae920 100644
--- a/x/poolmanager/router.go
+++ b/x/poolmanager/router.go
@@ -103,7 +103,7 @@ func (k Keeper) RouteExactAmountIn(
 	return tokenOutAmount, nil
 }
 
-// SplitRouteExactAmountIn route the swap across multiple multihop paths
+// SplitRouteExactAmountIn routes the swap across multiple multihop paths
 // to get the desired token out. This is useful for achieving the most optimal execution. However, note that the responsibility
 // of determining the optimal split is left to the client. This method simply route the swap across the given route.
 // The route must end with the same token out and begin with the same token in.
@@ -121,11 +121,11 @@ func (k Keeper) RouteExactAmountIn(
 func (k Keeper) SplitRouteExactAmountIn(
 	ctx sdk.Context,
 	sender sdk.AccAddress,
-	route []types.SwapAmountInSplitRoute,
+	routes []types.SwapAmountInSplitRoute,
 	tokenInDenom string,
 	tokenOutMinAmount sdk.Int,
 ) (sdk.Int, error) {
-	if err := types.ValidateSwapAmountInSplitRoute(route); err != nil {
+	if err := types.ValidateSwapAmountInSplitRoute(routes); err != nil {
 		return sdk.Int{}, err
 	}
 
@@ -137,7 +137,7 @@ func (k Keeper) SplitRouteExactAmountIn(
 		totalOutAmount                 = sdk.ZeroInt()
 	)
 
-	for _, multihopRoute := range route {
+	for _, multihopRoute := range routes {
 		tokenOutAmount, err := k.RouteExactAmountIn(
 			ctx,
 			sender,
diff --git a/x/poolmanager/types/routes.go b/x/poolmanager/types/routes.go
index 3f80fc32d..ca29063db 100644
--- a/x/poolmanager/types/routes.go
+++ b/x/poolmanager/types/routes.go
@@ -185,7 +185,9 @@ func (routes SwapAmountOutRoutes) Length() int {
 	return len(routes)
 }
 
-// ValidateSwapAmountInSplitRoute validates a slice of SwapAmountInSplitRoute and returns an error if any of the following are true:
+// ValidateSwapAmountInSplitRoute validates a slice of SwapAmountInSplitRoute.
+//
+// returns an error if any of the following are true:
 // - the slice is empty
 // - any SwapAmountInRoute in the slice is invalid
 // - the last TokenOutDenom of any SwapAmountInRoute in the slice does not match the TokenOutDenom of the previous SwapAmountInRoute in the slice


Test patch:
diff --git a/x/concentrated-liquidity/keeper_test.go b/x/concentrated-liquidity/keeper_test.go
index f8b18c659..fce41f0c5 100644
--- a/x/concentrated-liquidity/keeper_test.go
+++ b/x/concentrated-liquidity/keeper_test.go
@@ -9,6 +9,7 @@ import (
 	"github.com/stretchr/testify/suite"
 
 	"github.com/osmosis-labs/osmosis/osmoutils/accum"
+	concentrated_liquidity "github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity"
 	"github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/clmocks"
 	"github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/math"
 	"github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/model"
@@ -58,6 +59,7 @@ var (
 
 type KeeperTestSuite struct {
 	apptesting.KeeperTestHelper
+	clk *concentrated_liquidity.Keeper
 }
 
 func TestKeeperTestSuite(t *testing.T) {
@@ -66,6 +68,7 @@ func TestKeeperTestSuite(t *testing.T) {
 
 func (s *KeeperTestSuite) SetupTest() {
 	s.Setup()
+	s.clk = s.App.ConcentratedLiquidityKeeper
 }
 
 func (s *KeeperTestSuite) SetupDefaultPosition(poolId uint64) {
diff --git a/x/concentrated-liquidity/swaps_test.go b/x/concentrated-liquidity/swaps_test.go
index 293e36c6a..a80abbf1e 100644
--- a/x/concentrated-liquidity/swaps_test.go
+++ b/x/concentrated-liquidity/swaps_test.go
@@ -55,6 +55,8 @@ type SwapTest struct {
 }
 
 var (
+	swapFundCoins = sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000)))
+
 	// Allow 0.01% margin of error.
 	multiplicativeTolerance = osmomath.ErrTolerance{
 		MultiplicativeTolerance: sdk.MustNewDecFromStr("0.0001"),
@@ -1442,47 +1444,122 @@ var (
 	}
 )
 
-func (s *KeeperTestSuite) TestComputeAndSwapOutAmtGivenIn() {
-	tests := make(map[string]SwapTest, len(swapOutGivenInCases)+len(swapOutGivenInFeeCases)+len(swapOutGivenInErrorCases))
-	for name, test := range swapOutGivenInCases {
-		tests[name] = test
+func (s *KeeperTestSuite) setupAndFundSwapTest() {
+	s.SetupTest()
+	s.FundAcc(s.TestAccs[0], swapFundCoins)
+	s.FundAcc(s.TestAccs[1], swapFundCoins)
+}
+
+func (s *KeeperTestSuite) preparePoolAndDefaultPosition() types.ConcentratedPoolExtension {
+	pool := s.PrepareConcentratedPool()
+	s.SetupDefaultPosition(pool.GetId())
+	return pool
+}
+
+func (s *KeeperTestSuite) preparePoolAndDefaultPositions(test SwapTest) types.ConcentratedPoolExtension {
+	pool := s.preparePoolAndDefaultPosition()
+	s.setupSecondPosition(test, pool)
+	pool, _ = s.clk.GetConcentratedPoolById(s.Ctx, pool.GetId())
+	return pool
+}
+
+func (s *KeeperTestSuite) preparePoolWithCustSpread(spread sdk.Dec) types.ConcentratedPoolExtension {
+	clParams := s.App.ConcentratedLiquidityKeeper.GetParams(s.Ctx)
+	clParams.AuthorizedSpreadFactors = append(clParams.AuthorizedSpreadFactors, spread)
+	s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, clParams)
+	return s.PrepareCustomConcentratedPool(s.TestAccs[0], "eth", "usdc", DefaultTickSpacing, spread)
+}
+
+func makeSwapTests(tests ...map[string]SwapTest) map[string]SwapTest {
+	length := 0
+	for i := range tests {
+		length += len(tests[i])
+	}
+	retTests := make(map[string]SwapTest, length)
+	for _, tt := range tests {
+		for name, test := range tt {
+			retTests[name] = test
+		}
 	}
+	return retTests
+}
 
-	for name, test := range swapOutGivenInFeeCases {
-		tests[name] = test
+func (s *KeeperTestSuite) assertPoolNotModified(poolBeforeCalc types.ConcentratedPoolExtension) {
+	poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(s.Ctx, poolBeforeCalc.GetId())
+	s.Require().NoError(err)
+	s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
+	s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
+	s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
+	s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
+}
+
+func (s *KeeperTestSuite) assertFeeAccum(test SwapTest, poolId uint64) {
+	feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, poolId)
+	s.Require().NoError(err)
+
+	feeAccumValue := feeAccum.GetValue()
+	if test.expectedFeeGrowthAccumulatorValue.IsNil() {
+		s.Require().Equal(0, feeAccumValue.Len())
+		return
+	}
+	amountOfDenom := test.tokenIn.Denom
+	if amountOfDenom == "" {
+		amountOfDenom = test.tokenInDenom
 	}
+	feeVal := feeAccumValue.AmountOf(amountOfDenom)
+	s.Require().Equal(1, feeAccumValue.Len(), "fee accumulator should only have one denom, was (%s)", feeAccumValue)
+	s.Require().Equal(0,
+		additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
+			osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
+			osmomath.BigDecFromSDKDec(feeVal),
+		),
+		fmt.Sprintf("expected %s, got %s", test.expectedFeeGrowthAccumulatorValue.String(), feeVal.String()),
+	)
+}
 
-	// add error cases as well
-	for name, test := range swapOutGivenInErrorCases {
-		tests[name] = test
+func (s *KeeperTestSuite) assertZeroFees(poolId uint64) {
+	feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, poolId)
+	s.Require().NoError(err)
+	s.Require().Equal(0, feeAccum.GetValue().Len())
+}
+
+func (s *KeeperTestSuite) getExpectedLiquidity(test SwapTest, pool types.ConcentratedPoolExtension) sdk.Dec {
+	if test.newLowerPrice.IsNil() && test.newUpperPrice.IsNil() {
+		test.newLowerPrice = DefaultLowerPrice
+		test.newUpperPrice = DefaultUpperPrice
+	}
+
+	newLowerTick, err := math.PriceToTickRoundDown(test.newLowerPrice, pool.GetTickSpacing())
+	s.Require().NoError(err)
+	newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
+	s.Require().NoError(err)
+
+	_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
+	s.Require().NoError(err)
+	_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
+	s.Require().NoError(err)
+
+	if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
+		test.poolLiqAmount0 = DefaultAmt0
+		test.poolLiqAmount1 = DefaultAmt1
 	}
 
+	expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1)
+	return expectedLiquidity
+}
+
+func (s *KeeperTestSuite) TestComputeAndSwapOutAmtGivenIn() {
+	// add error cases as well
+	tests := makeSwapTests(swapOutGivenInCases, swapOutGivenInCases, swapOutGivenInErrorCases)
+
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			clParams := s.App.ConcentratedLiquidityKeeper.GetParams(s.Ctx)
-			clParams.AuthorizedSpreadFactors = append(clParams.AuthorizedSpreadFactors, test.spreadFactor)
-			s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, clParams)
-			pool := s.PrepareCustomConcentratedPool(s.TestAccs[0], "eth", "usdc", DefaultTickSpacing, test.spreadFactor)
-
+			s.setupAndFundSwapTest()
+			pool := s.preparePoolWithCustSpread(test.spreadFactor)
 			// add default position
 			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
+			s.setupSecondPosition(test, pool)
 
 			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
 			s.Require().NoError(err)
@@ -1502,49 +1579,13 @@ func (s *KeeperTestSuite) TestComputeAndSwapOutAmtGivenIn() {
 			if test.expectErr {
 				s.Require().Error(err)
 			} else {
-				s.Require().NoError(err)
-
-				// check that tokenIn, tokenOut, tick, and sqrtPrice from CalcOut are all what we expected
-				s.Require().Equal(test.expectedTick, updatedTick)
-				s.Require().Equal(test.expectedTokenIn.String(), tokenIn.String())
-				s.Require().Equal(test.expectedTokenOut.String(), tokenOut.String())
-				s.Require().Equal(test.expectedSqrtPrice, sqrtPrice)
+				s.testSwapResult(test, pool, tokenIn, tokenOut, updatedTick, updatedLiquidity, sqrtPrice, err)
 
 				expectedFees := tokenIn.Amount.ToDec().Mul(pool.GetSpreadFactor(s.Ctx)).TruncateInt()
 				s.Require().Equal(expectedFees.String(), totalFees.TruncateInt().String())
 
-				if test.newLowerPrice.IsNil() && test.newUpperPrice.IsNil() {
-					test.newLowerPrice = DefaultLowerPrice
-					test.newUpperPrice = DefaultUpperPrice
-				}
-
-				newLowerTick, err := math.PriceToTickRoundDown(test.newLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
-				s.Require().NoError(err)
-				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
-				s.Require().NoError(err)
-
-				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
-					test.poolLiqAmount0 = DefaultAmt0
-					test.poolLiqAmount1 = DefaultAmt1
-				}
-
-				// check that liquidity is what we expected
-				expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1)
-				s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String())
-
 				// check that the pool has not been modified after performing calc
-				poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-				s.Require().NoError(err)
-
-				s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-				s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-				s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-				s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
+				s.assertPoolNotModified(poolBeforeCalc)
 			}
 
 			// perform swap
@@ -1557,80 +1598,26 @@ func (s *KeeperTestSuite) TestComputeAndSwapOutAmtGivenIn() {
 			if test.expectErr {
 				s.Require().Error(err)
 			} else {
-				s.Require().NoError(err)
-
-				s.Require().Equal(test.expectedTokenIn.String(), tokenIn.String())
-				s.Require().Equal(test.expectedTokenOut.String(), tokenOut.String())
-				s.Require().Equal(test.expectedTick, updatedTick)
-				s.Require().Equal(test.expectedSqrtPrice, sqrtPrice)
-
-				if test.newLowerPrice.IsNil() && test.newUpperPrice.IsNil() {
-					test.newLowerPrice = DefaultLowerPrice
-					test.newUpperPrice = DefaultUpperPrice
-				}
-
-				newLowerTick, err := math.PriceToTickRoundDown(test.newLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
-				s.Require().NoError(err)
-				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
-				s.Require().NoError(err)
-
-				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
-					test.poolLiqAmount0 = DefaultAmt0
-					test.poolLiqAmount1 = DefaultAmt1
-				}
-
-				expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1)
-				s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String())
-
-				feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
-				s.Require().NoError(err)
-
-				feeAccumValue := feeAccum.GetValue()
-				if test.expectedFeeGrowthAccumulatorValue.IsNil() {
-					s.Require().Equal(0, feeAccumValue.Len())
-					return
-				}
-				s.Require().Equal(1, feeAccumValue.Len())
-				s.Require().Equal(0,
-					additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-						osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-						osmomath.BigDecFromSDKDec(feeAccum.GetValue().AmountOf(test.tokenIn.Denom)),
-					),
-					fmt.Sprintf("expected %s, got %s", test.expectedFeeGrowthAccumulatorValue.String(), feeAccum.GetValue().AmountOf(test.tokenIn.Denom).String()),
-				)
+				s.testSwapResult(test, pool, tokenIn, tokenOut, updatedTick, updatedLiquidity, sqrtPrice, err)
+				s.assertFeeAccum(test, pool.GetId())
 			}
 		})
 	}
 }
 
-func (s *KeeperTestSuite) TestSwapOutAmtGivenIn_NoPositions() {
+func (s *KeeperTestSuite) TestSwap_NoPositions() {
 	s.SetupTest()
-
 	pool := s.PrepareConcentratedPool()
-
 	// perform swap
-	_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapOutAmtGivenIn(
+	_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapInAmtGivenOut(
 		s.Ctx, s.TestAccs[0], pool,
 		DefaultCoin0, DefaultCoin1.Denom,
 		sdk.ZeroDec(), sdk.ZeroDec(),
 	)
-
 	s.Require().Error(err)
 	s.Require().ErrorIs(err, types.NoSpotPriceWhenNoLiquidityError{PoolId: pool.GetId()})
-}
-
-func (s *KeeperTestSuite) TestSwapInAmtGivenOut_NoPositions() {
-	s.SetupTest()
-
-	pool := s.PrepareConcentratedPool()
 
-	// perform swap
-	_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapInAmtGivenOut(
+	_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.SwapOutAmtGivenIn(
 		s.Ctx, s.TestAccs[0], pool,
 		DefaultCoin0, DefaultCoin1.Denom,
 		sdk.ZeroDec(), sdk.ZeroDec(),
@@ -1641,17 +1628,11 @@ func (s *KeeperTestSuite) TestSwapInAmtGivenOut_NoPositions() {
 }
 
 func (s *KeeperTestSuite) TestSwapOutAmtGivenIn_TickUpdates() {
-	tests := make(map[string]SwapTest)
-	for name, test := range swapOutGivenInCases {
-		tests[name] = test
-	}
-
+	tests := makeSwapTests(swapOutGivenInCases)
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
+			s.setupAndFundSwapTest()
 
 			// Create default CL pool
 			pool := s.PrepareCustomConcentratedPool(s.TestAccs[0], ETH, USDC, DefaultTickSpacing, sdk.ZeroDec())
@@ -1663,17 +1644,7 @@ func (s *KeeperTestSuite) TestSwapOutAmtGivenIn_TickUpdates() {
 
 			// add default position
 			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
+			s.setupSecondPosition(test, pool)
 
 			// add 2*DefaultFeeAccumCoins to fee accumulator, now fee accumulator has 3*DefaultFeeAccumCoins as its value
 			feeAccum, err = s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
@@ -1718,50 +1689,30 @@ func (s *KeeperTestSuite) TestSwapOutAmtGivenIn_TickUpdates() {
 	}
 }
 
-func (s *KeeperTestSuite) TestComputeAndSwapInAmtGivenOut() {
-	tests := make(map[string]SwapTest, len(swapInGivenOutTestCases)+len(swapInGivenOutFeeTestCases)+len(swapInGivenOutErrorTestCases))
-	for name, test := range swapInGivenOutTestCases {
-		tests[name] = test
-	}
+func (s *KeeperTestSuite) testSwapResult(test SwapTest, pool types.ConcentratedPoolExtension, tokenIn, tokenOut sdk.Coin, updatedTick int64, updatedLiquidity sdk.Dec, sqrtPrice sdk.Dec, err error) {
+	s.Require().NoError(err)
 
-	for name, test := range swapInGivenOutFeeTestCases {
-		tests[name] = test
-	}
+	// check that tokenIn, tokenOut, tick, and sqrtPrice from CalcOut are all what we expected
+	s.Require().Equal(test.expectedSqrtPrice, sqrtPrice)
+	s.Require().Equal(test.expectedTokenOut.String(), tokenOut.String())
+	s.Require().Equal(test.expectedTokenIn.String(), tokenIn.String())
+	s.Require().Equal(test.expectedTick, updatedTick)
 
-	// add error cases as well
-	for name, test := range swapInGivenOutErrorTestCases {
-		tests[name] = test
-	}
+	expectedLiquidity := s.getExpectedLiquidity(test, pool)
+	s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String())
+}
 
+func (s *KeeperTestSuite) TestComputeAndSwapInAmtGivenOut() {
+	// add error cases as well
+	tests := makeSwapTests(swapInGivenOutTestCases, swapInGivenOutFeeTestCases, swapInGivenOutErrorTestCases)
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			clParams := s.App.ConcentratedLiquidityKeeper.GetParams(s.Ctx)
-			clParams.AuthorizedSpreadFactors = append(clParams.AuthorizedSpreadFactors, test.spreadFactor)
-			s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, clParams)
-			pool := s.PrepareCustomConcentratedPool(s.TestAccs[0], "eth", "usdc", DefaultTickSpacing, test.spreadFactor)
-
+			s.setupAndFundSwapTest()
+			pool := s.preparePoolWithCustSpread(test.spreadFactor)
 			// add default position
 			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupSecondPosition(test, pool)
 
 			// perform compute
 			cacheCtx, _ := s.Ctx.CacheContext()
@@ -1772,49 +1723,10 @@ func (s *KeeperTestSuite) TestComputeAndSwapInAmtGivenOut() {
 			if test.expectErr {
 				s.Require().Error(err)
 			} else {
-				s.Require().NoError(err)
-
-				// check that tokenIn, tokenOut, tick, and sqrtPrice from CalcOut are all what we expected
-				s.Require().Equal(test.expectedSqrtPrice, sqrtPrice)
-				s.Require().Equal(test.expectedTokenOut.String(), tokenOut.String())
-				s.Require().Equal(test.expectedTokenIn.String(), tokenIn.String())
-				s.Require().Equal(test.expectedTick, updatedTick)
+				s.testSwapResult(test, pool, tokenIn, tokenOut, updatedTick, updatedLiquidity, sqrtPrice, err)
 
 				expectedFees := tokenIn.Amount.ToDec().Mul(pool.GetSpreadFactor(s.Ctx)).TruncateInt()
 				s.Require().Equal(expectedFees.String(), totalFees.TruncateInt().String())
-
-				if test.newLowerPrice.IsNil() && test.newUpperPrice.IsNil() {
-					test.newLowerPrice = DefaultLowerPrice
-					test.newUpperPrice = DefaultUpperPrice
-				}
-
-				newLowerTick, err := math.PriceToTickRoundDown(test.newLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
-				s.Require().NoError(err)
-				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
-				s.Require().NoError(err)
-
-				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
-					test.poolLiqAmount0 = DefaultAmt0
-					test.poolLiqAmount1 = DefaultAmt1
-				}
-
-				// check that liquidity is what we expected
-				expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1)
-				s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String())
-
-				// check that the pool has not been modified after performing calc
-				poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-				s.Require().NoError(err)
-
-				s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-				s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-				s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-				s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
 			}
 
 			// perform swap
@@ -1824,86 +1736,37 @@ func (s *KeeperTestSuite) TestComputeAndSwapInAmtGivenOut() {
 				test.spreadFactor, test.priceLimit)
 			if test.expectErr {
 				s.Require().Error(err)
-			} else {
-				s.Require().NoError(err)
-
-				pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-				s.Require().NoError(err)
-
-				// check that tokenIn, tokenOut, tick, and sqrtPrice from SwapOut are all what we expected
-				s.Require().Equal(test.expectedTick, updatedTick)
-				s.Require().Equal(test.expectedTokenIn.String(), tokenIn.String())
-				s.Require().Equal(test.expectedTokenOut.String(), tokenOut.String())
-				s.Require().Equal(test.expectedSqrtPrice, sqrtPrice)
-				// also ensure the pool's currentTick and currentSqrtPrice was updated due to calling a mutative method
-				s.Require().Equal(test.expectedTick, pool.GetCurrentTick())
-
-				if test.newLowerPrice.IsNil() && test.newUpperPrice.IsNil() {
-					test.newLowerPrice = DefaultLowerPrice
-					test.newUpperPrice = DefaultUpperPrice
-				}
-
-				newLowerTick, err := math.PriceToTickRoundDown(test.newLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
-				s.Require().NoError(err)
-				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
-				s.Require().NoError(err)
+				return
+			}
+			s.Require().NoError(err)
 
-				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
-					test.poolLiqAmount0 = DefaultAmt0
-					test.poolLiqAmount1 = DefaultAmt1
-				}
+			pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
+			s.Require().NoError(err)
 
-				expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1)
-				// check that liquidity is what we expected
-				s.Require().Equal(expectedLiquidity.String(), pool.GetLiquidity().String())
-				// also ensure the pool's currentLiquidity was updated due to calling a mutative method
-				s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String())
+			// check that tokenIn, tokenOut, tick, and sqrtPrice from SwapOut are all what we expected
+			s.testSwapResult(test, pool, tokenIn, tokenOut, updatedTick, updatedLiquidity, sqrtPrice, err)
 
-				feeAcc, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
-				s.Require().NoError(err)
+			// Check variables on pool were set correctly
+			// - ensure the pool's currentTick and currentSqrtPrice was updated due to calling a mutative method
+			s.Require().Equal(test.expectedTick, pool.GetCurrentTick())
+			// check that liquidity is what we expected
+			expectedLiquidity := s.getExpectedLiquidity(test, pool)
+			s.Require().Equal(expectedLiquidity.String(), pool.GetLiquidity().String())
 
-				feeAccValue := feeAcc.GetValue()
-				actualValue := feeAccValue.AmountOf(test.tokenInDenom)
-
-				if test.spreadFactor.IsZero() {
-					s.Require().Equal(sdk.ZeroDec(), actualValue)
-					return
-				}
-
-				if test.expectedFeeGrowthAccumulatorValue.IsNil() {
-					s.Require().Equal(0, feeAccValue.Len())
-					return
-				}
-
-				s.Require().Equal(1, feeAccValue.Len(), fmt.Sprintf("fee accumulator should only have one denom, was (%s)", feeAccValue))
-				s.Require().Equal(0,
-					additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-						osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-						osmomath.BigDecFromSDKDec(actualValue),
-					),
-					fmt.Sprintf("expected fee growth accumulator value: %s, got: %s", test.expectedFeeGrowthAccumulatorValue, actualValue),
-				)
+			if test.spreadFactor.IsZero() {
+				s.assertZeroFees(pool.GetId())
+				return
 			}
+			s.assertFeeAccum(test, pool.GetId())
 		})
 	}
 }
 
 func (s *KeeperTestSuite) TestSwapInAmtGivenOut_TickUpdates() {
-	tests := make(map[string]SwapTest)
-	for name, test := range swapInGivenOutTestCases {
-		tests[name] = test
-	}
-
+	tests := makeSwapTests(swapInGivenOutTestCases)
 	for name, test := range tests {
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
+			s.setupAndFundSwapTest()
 
 			// Create default CL pool
 			pool := s.PrepareConcentratedPool()
@@ -1915,17 +1778,7 @@ func (s *KeeperTestSuite) TestSwapInAmtGivenOut_TickUpdates() {
 
 			// add default position
 			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
+			s.setupSecondPosition(test, pool)
 
 			// add 2*DefaultFeeAccumCoins to fee accumulator, now fee accumulator has 3*DefaultFeeAccumCoins as its value
 			feeAccum, err = s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
@@ -1978,6 +1831,9 @@ func (s *KeeperTestSuite) TestSwapExactAmountIn() {
 		expectedTokenOut  sdk.Int
 	}
 
+	// liquidity and sqrtPriceCurrent for all tests are:
+	// liquidity: 		 1517882343.751510418088349649
+	// sqrtPriceCurrent: 70.710678118654752440 which is sqrt(5000)
 	tests := []struct {
 		name        string
 		param       param
@@ -1986,9 +1842,7 @@ func (s *KeeperTestSuite) TestSwapExactAmountIn() {
 		{
 			name: "Proper swap usdc > eth",
 			// params
-			// liquidity: 		 1517882343.751510418088349649
 			// sqrtPriceNext:    70.738348247484497717 which is 5003.91391278239310954 https://www.wolframalpha.com/input?i=70.710678118654752440+%2B+42000000+%2F+1517882343.751510418088349649
-			// sqrtPriceCurrent: 70.710678118654752440 which is 5000
 			// expectedTokenIn:  41999999.999 rounded up https://www.wolframalpha.com/input?i=1517882343.751510418088349649+*+%2870.738348247484497717+-+70.710678118654752440%29
 			// expectedTokenOut: 8396.7142421 rounded down https://www.wolframalpha.com/input?i=%281517882343.751510418088349649+*+%2870.738348247484497717+-+70.710678118654752440+%29%29+%2F+%2870.710678118654752440+*+70.738348247484497717%29
 			param: param{
@@ -2001,9 +1855,7 @@ func (s *KeeperTestSuite) TestSwapExactAmountIn() {
 		{
 			name: "Proper swap eth > usdc",
 			// params
-			// liquidity: 		 1517882343.751510418088349649
 			// sqrtPriceNext:    70.66666391085714433 which is 4993.77738829003954884402 https://www.wolframalpha.com/input?i=%28%281517882343.751510418088349649%29%29+%2F+%28%28%281517882343.751510418088349649%29+%2F+%2870.710678118654752440%29%29+%2B+%2813370%29%29
-			// sqrtPriceCurrent: 70.710678118654752440 which is 5000
 			// expectedTokenIn:  13370.0000 rounded up https://www.wolframalpha.com/input?i=%281517882343.751510418088349649+*+%2870.710678118654752440+-+70.66666391085714433+%29%29+%2F+%2870.66666391085714433+*+70.710678118654752440%29
 			// expectedTokenOut: 66808388.890 rounded down https://www.wolframalpha.com/input?i=1517882343.751510418088349649+*+%2870.710678118654752440+-+70.66666391085714433%29
 			param: param{
@@ -2075,17 +1927,12 @@ func (s *KeeperTestSuite) TestSwapExactAmountIn() {
 		s.Run(test.name, func() {
 			// Init suite for each test.
 			s.SetupTest()
-
-			// Create a default CL pool
-			pool := s.PrepareConcentratedPool()
+			pool := s.preparePoolAndDefaultPosition()
 
 			// Check the test case to see if we are swapping asset0 for asset1 or vice versa
 			asset0 := pool.GetToken0()
 			zeroForOne := test.param.tokenIn.Denom == asset0
 
-			// Create a default position to the pool created earlier
-			s.SetupDefaultPosition(1)
-
 			// Set mock listener to make sure that is is called when desired.
 			s.setListenerMockOnConcentratedLiquidityKeeper()
 
@@ -2112,40 +1959,40 @@ func (s *KeeperTestSuite) TestSwapExactAmountIn() {
 			if test.expectedErr != nil {
 				s.Require().Error(err)
 				s.Require().ErrorAs(err, test.expectedErr)
-			} else {
-				s.Require().NoError(err)
-				s.Require().Equal(test.param.expectedTokenOut.String(), tokenOutAmount.String())
-
-				gasConsumedForSwap := s.Ctx.GasMeter().GasConsumed() - prevGasConsumed
+				return
+			}
+			s.Require().NoError(err)
+			s.Require().Equal(test.param.expectedTokenOut.String(), tokenOutAmount.String())
 
-				// Check that we consume enough gas that a CL pool swap warrants
-				// We consume `types.GasFeeForSwap` directly, so the extra I/O operation mean we end up consuming more.
-				s.Require().Greater(gasConsumedForSwap, uint64(types.ConcentratedGasFeeForSwap))
+			gasConsumedForSwap := s.Ctx.GasMeter().GasConsumed() - prevGasConsumed
 
-				// Assert events
-				s.AssertEventEmitted(s.Ctx, types.TypeEvtTokenSwapped, 1)
+			// Check that we consume enough gas that a CL pool swap warrants
+			// We consume `types.GasFeeForSwap` directly, so the extra I/O operation mean we end up consuming more.
+			s.Require().Greater(gasConsumedForSwap, uint64(types.ConcentratedGasFeeForSwap))
 
-				// Retrieve pool again post swap
-				pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-				s.Require().NoError(err)
+			// Assert events
+			s.AssertEventEmitted(s.Ctx, types.TypeEvtTokenSwapped, 1)
 
-				spotPriceAfter := pool.GetCurrentSqrtPrice().Power(2)
+			// Retrieve pool again post swap
+			pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
+			s.Require().NoError(err)
 
-				// Ratio of the token out should be between the before spot price and after spot price.
-				tradeAvgPrice := tokenOutAmount.ToDec().Quo(test.param.tokenIn.Amount.ToDec())
+			spotPriceAfter := pool.GetCurrentSqrtPrice().Power(2)
 
-				if zeroForOne {
-					s.Require().True(tradeAvgPrice.LT(spotPriceBefore))
-					s.Require().True(tradeAvgPrice.GT(spotPriceAfter))
-				} else {
-					tradeAvgPrice = sdk.OneDec().Quo(tradeAvgPrice)
-					s.Require().True(tradeAvgPrice.GT(spotPriceBefore))
-					s.Require().True(tradeAvgPrice.LT(spotPriceAfter))
-				}
+			// Ratio of the token out should be between the before spot price and after spot price.
+			tradeAvgPrice := tokenOutAmount.ToDec().Quo(test.param.tokenIn.Amount.ToDec())
 
-				// Validate that listeners were called the desired number of times
-				s.validateListenerCallCount(0, 0, 0, 1)
+			if zeroForOne {
+				s.Require().True(tradeAvgPrice.LT(spotPriceBefore))
+				s.Require().True(tradeAvgPrice.GT(spotPriceAfter))
+			} else {
+				tradeAvgPrice = sdk.OneDec().Quo(tradeAvgPrice)
+				s.Require().True(tradeAvgPrice.GT(spotPriceBefore))
+				s.Require().True(tradeAvgPrice.LT(spotPriceAfter))
 			}
+
+			// Validate that listeners were called the desired number of times
+			s.validateListenerCallCount(0, 0, 0, 1)
 		})
 	}
 }
@@ -2255,17 +2102,12 @@ func (s *KeeperTestSuite) TestSwapExactAmountOut() {
 		s.Run(test.name, func() {
 			// Init suite for each test.
 			s.SetupTest()
-
-			// Create a default CL pool
-			pool := s.PrepareConcentratedPool()
+			pool := s.preparePoolAndDefaultPosition()
 
 			// Check the test case to see if we are swapping asset0 for asset1 or vice versa
 			asset1 := pool.GetToken1()
 			zeroForOne := test.param.tokenOut.Denom == asset1
 
-			// Then create a default position to the pool created earlier
-			s.SetupDefaultPosition(1)
-
 			// Set mock listener to make sure that is is called when desired.
 			s.setListenerMockOnConcentratedLiquidityKeeper()
 
@@ -2289,41 +2131,41 @@ func (s *KeeperTestSuite) TestSwapExactAmountOut() {
 			if test.expectedErr != nil {
 				s.Require().Error(err)
 				s.Require().ErrorAs(err, test.expectedErr)
-			} else {
-				s.Require().NoError(err)
-				s.Require().Equal(test.param.expectedTokenIn.String(), tokenIn.String())
-
-				gasConsumedForSwap := s.Ctx.GasMeter().GasConsumed() - prevGasConsumed
-				// Check that we consume enough gas that a CL pool swap warrants
-				// We consume `types.GasFeeForSwap` directly, so the extra I/O operation mean we end up consuming more.
-				s.Require().Greater(gasConsumedForSwap, uint64(types.ConcentratedGasFeeForSwap))
+				return
+			}
+			s.Require().NoError(err)
+			s.Require().Equal(test.param.expectedTokenIn.String(), tokenIn.String())
 
-				// Assert events
-				s.AssertEventEmitted(s.Ctx, types.TypeEvtTokenSwapped, 1)
+			gasConsumedForSwap := s.Ctx.GasMeter().GasConsumed() - prevGasConsumed
+			// Check that we consume enough gas that a CL pool swap warrants
+			// We consume `types.GasFeeForSwap` directly, so the extra I/O operation mean we end up consuming more.
+			s.Require().Greater(gasConsumedForSwap, uint64(types.ConcentratedGasFeeForSwap))
 
-				// Retrieve pool again post swap
-				pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-				s.Require().NoError(err)
+			// Assert events
+			s.AssertEventEmitted(s.Ctx, types.TypeEvtTokenSwapped, 1)
 
-				spotPriceAfter := pool.GetCurrentSqrtPrice().Power(2)
+			// Retrieve pool again post swap
+			pool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
+			s.Require().NoError(err)
 
-				// Ratio of the token out should be between the before spot price and after spot price.
-				tradeAvgPrice := tokenIn.ToDec().Quo(test.param.tokenOut.Amount.ToDec())
+			spotPriceAfter := pool.GetCurrentSqrtPrice().Power(2)
 
-				if zeroForOne {
-					// token in is token zero, token out is token one
-					tradeAvgPrice = sdk.OneDec().Quo(tradeAvgPrice)
-					s.Require().True(tradeAvgPrice.LT(spotPriceBefore), fmt.Sprintf("tradeAvgPrice: %s, spotPriceBefore: %s", tradeAvgPrice, spotPriceBefore))
-					s.Require().True(tradeAvgPrice.GT(spotPriceAfter), fmt.Sprintf("tradeAvgPrice: %s, spotPriceAfter: %s", tradeAvgPrice, spotPriceAfter))
-				} else {
-					// token in is token one, token out is token zero
-					s.Require().True(tradeAvgPrice.GT(spotPriceBefore), fmt.Sprintf("tradeAvgPrice: %s, spotPriceBefore: %s", tradeAvgPrice, spotPriceBefore))
-					s.Require().True(tradeAvgPrice.LT(spotPriceAfter), fmt.Sprintf("tradeAvgPrice: %s, spotPriceAfter: %s", tradeAvgPrice, spotPriceAfter))
-				}
+			// Ratio of the token out should be between the before spot price and after spot price.
+			tradeAvgPrice := tokenIn.ToDec().Quo(test.param.tokenOut.Amount.ToDec())
 
-				// Validate that listeners were called the desired number of times
-				s.validateListenerCallCount(0, 0, 0, 1)
+			if zeroForOne {
+				// token in is token zero, token out is token one
+				tradeAvgPrice = sdk.OneDec().Quo(tradeAvgPrice)
+				s.Require().True(tradeAvgPrice.LT(spotPriceBefore), fmt.Sprintf("tradeAvgPrice: %s, spotPriceBefore: %s", tradeAvgPrice, spotPriceBefore))
+				s.Require().True(tradeAvgPrice.GT(spotPriceAfter), fmt.Sprintf("tradeAvgPrice: %s, spotPriceAfter: %s", tradeAvgPrice, spotPriceAfter))
+			} else {
+				// token in is token one, token out is token zero
+				s.Require().True(tradeAvgPrice.GT(spotPriceBefore), fmt.Sprintf("tradeAvgPrice: %s, spotPriceBefore: %s", tradeAvgPrice, spotPriceBefore))
+				s.Require().True(tradeAvgPrice.LT(spotPriceAfter), fmt.Sprintf("tradeAvgPrice: %s, spotPriceAfter: %s", tradeAvgPrice, spotPriceAfter))
 			}
+
+			// Validate that listeners were called the desired number of times
+			s.validateListenerCallCount(0, 0, 0, 1)
 		})
 	}
 }
@@ -2341,58 +2183,20 @@ func (s *KeeperTestSuite) TestComputeOutAmtGivenIn() {
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBeforeCalc := s.preparePoolAndDefaultPositions(test)
 
 			// perform calc
-			_, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.ComputeOutAmtGivenIn(
+			_, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.ComputeOutAmtGivenIn(
 				s.Ctx,
-				pool.GetId(),
+				poolBeforeCalc.GetId(),
 				test.tokenIn, test.tokenOutDenom,
 				test.spreadFactor, test.priceLimit)
-
-			// check that the pool has not been modified after performing calc
-			poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
-
-			s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-			s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-			s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-			s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
-
-			// check that fee accum has been correctly updated.
-			feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
 			s.Require().NoError(err)
 
-			feeAccumValue := feeAccum.GetValue()
-			s.Require().Equal(1, feeAccumValue.Len())
-			s.Require().Equal(0,
-				additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-					osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-					osmomath.BigDecFromSDKDec(feeAccum.GetValue().AmountOf(test.tokenIn.Denom)),
-				),
-			)
+			// check that the pool has not been modified after performing calc
+			s.assertPoolNotModified(poolBeforeCalc)
+			s.assertFeeAccum(test, poolBeforeCalc.GetId())
 		})
 	}
 }
@@ -2400,41 +2204,15 @@ func (s *KeeperTestSuite) TestComputeOutAmtGivenIn() {
 // TestCalcOutAmtGivenIn_NonMutative tests that CalcOutAmtGivenIn is non-mutative.
 func (s *KeeperTestSuite) TestCalcOutAmtGivenIn_NonMutative() {
 	// we only use fee cases here since write Ctx only takes effect in the fee accumulator
-	tests := make(map[string]SwapTest, len(swapOutGivenInFeeCases))
-
-	for name, test := range swapOutGivenInFeeCases {
-		tests[name] = test
-	}
-
+	tests := makeSwapTests(swapOutGivenInFeeCases)
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBeforeCalc := s.preparePoolAndDefaultPositions(test)
 
 			// perform calc
-			_, err = s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(
+			_, err := s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(
 				s.Ctx,
 				poolBeforeCalc,
 				test.tokenIn, test.tokenOutDenom,
@@ -2442,67 +2220,37 @@ func (s *KeeperTestSuite) TestCalcOutAmtGivenIn_NonMutative() {
 			s.Require().NoError(err)
 
 			// check that the pool has not been modified after performing calc
-			poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
-
-			s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-			s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-			s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-			s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
+			s.assertPoolNotModified(poolBeforeCalc)
+			s.assertZeroFees(poolBeforeCalc.GetId())
+		})
+	}
+}
 
-			feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
-			s.Require().NoError(err)
+func (s *KeeperTestSuite) setupSecondPosition(test SwapTest, pool types.ConcentratedPoolExtension) {
+	if !test.secondPositionLowerPrice.IsNil() {
+		newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
+		s.Require().NoError(err)
+		newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
+		s.Require().NoError(err)
 
-			feeAccumValue := feeAccum.GetValue()
-			s.Require().Equal(0, feeAccumValue.Len())
-			s.Require().Equal(1,
-				additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-					osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-					osmomath.BigDecFromSDKDec(feeAccum.GetValue().AmountOf(test.tokenIn.Denom)),
-				),
-			)
-		})
+		_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
+		s.Require().NoError(err)
 	}
 }
 
 // TestCalcInAmtGivenOut_NonMutative tests that CalcInAmtGivenOut is non-mutative.
 func (s *KeeperTestSuite) TestCalcInAmtGivenOut_NonMutative() {
 	// we only use fee cases here since write Ctx only takes effect in the fee accumulator
-	tests := make(map[string]SwapTest, len(swapOutGivenInFeeCases))
-
-	for name, test := range swapOutGivenInFeeCases {
-		tests[name] = test
-	}
+	tests := makeSwapTests(swapOutGivenInFeeCases)
 
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBeforeCalc := s.preparePoolAndDefaultPositions(test)
 
 			// perform calc
-			_, err = s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(
+			_, err := s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(
 				s.Ctx,
 				poolBeforeCalc,
 				test.tokenIn, test.tokenOutDenom,
@@ -2510,25 +2258,8 @@ func (s *KeeperTestSuite) TestCalcInAmtGivenOut_NonMutative() {
 			s.Require().NoError(err)
 
 			// check that the pool has not been modified after performing calc
-			poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
-
-			s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-			s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-			s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-			s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
-
-			feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
-			s.Require().NoError(err)
-
-			feeAccumValue := feeAccum.GetValue()
-			s.Require().Equal(0, feeAccumValue.Len())
-			s.Require().Equal(1,
-				additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-					osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-					osmomath.BigDecFromSDKDec(feeAccum.GetValue().AmountOf(test.tokenIn.Denom)),
-				),
-			)
+			s.assertPoolNotModified(poolBeforeCalc)
+			s.assertZeroFees(poolBeforeCalc.GetId())
 		})
 	}
 }
@@ -2536,67 +2267,24 @@ func (s *KeeperTestSuite) TestCalcInAmtGivenOut_NonMutative() {
 // TestComputeInAmtGivenOut tests that ComputeInAmtGivenOut successfully performs state changes as expected.
 func (s *KeeperTestSuite) TestComputeInAmtGivenOut() {
 	// we only use fee cases here since write Ctx only takes effect in the fee accumulator
-	tests := make(map[string]SwapTest, len(swapInGivenOutFeeTestCases))
-
-	for name, test := range swapInGivenOutFeeTestCases {
-		tests[name] = test
-	}
+	tests := makeSwapTests(swapInGivenOutFeeTestCases)
 
 	for name, test := range tests {
 		test := test
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin(ETH, sdk.NewInt(10000000000000)), sdk.NewCoin(USDC, sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin(ETH, sdk.NewInt(10000000000000)), sdk.NewCoin(USDC, sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBeforeCalc := s.preparePoolAndDefaultPositions(test)
 
 			// perform calc
-			_, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.ComputeInAmtGivenOut(
+			_, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.ComputeInAmtGivenOut(
 				s.Ctx,
 				test.tokenOut, test.tokenInDenom,
-				test.spreadFactor, test.priceLimit, pool.GetId())
+				test.spreadFactor, test.priceLimit, poolBeforeCalc.GetId())
 			s.Require().NoError(err)
 
 			// check that the pool has not been modified after performing calc
-			poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
-
-			s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice())
-			s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick())
-			s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity())
-			s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing())
-
-			// check that fee accum has been correctly updated.
-			feeAccum, err := s.App.ConcentratedLiquidityKeeper.GetFeeAccumulator(s.Ctx, 1)
-			s.Require().NoError(err)
-
-			feeAccumValue := feeAccum.GetValue()
-			s.Require().Equal(1, feeAccumValue.Len())
-			s.Require().Equal(0,
-				additiveFeeGrowthGlobalErrTolerance.CompareBigDec(
-					osmomath.BigDecFromSDKDec(test.expectedFeeGrowthAccumulatorValue),
-					osmomath.BigDecFromSDKDec(feeAccum.GetValue().AmountOf(test.tokenInDenom)),
-				),
-			)
+			s.assertPoolNotModified(poolBeforeCalc)
+			s.assertFeeAccum(test, poolBeforeCalc.GetId())
 		})
 	}
 }
@@ -2606,42 +2294,20 @@ func (s *KeeperTestSuite) TestInverseRelationshipSwapOutAmtGivenIn() {
 
 	for name, test := range tests {
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			// mark pool state and user balance before swap
-			poolBefore, err := s.App.ConcentratedLiquidityKeeper.GetPool(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBefore := s.preparePoolAndDefaultPositions(test)
 			userBalanceBeforeSwap := s.App.BankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
 			poolBalanceBeforeSwap := s.App.BankKeeper.GetAllBalances(s.Ctx, poolBefore.GetAddress())
 
 			// system under test
 			firstTokenIn, firstTokenOut, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapOutAmtGivenIn(
-				s.Ctx, s.TestAccs[0], pool,
+				s.Ctx, s.TestAccs[0], poolBefore,
 				test.tokenIn, test.tokenOutDenom,
 				DefaultZeroSpreadFactor, test.priceLimit)
 			s.Require().NoError(err)
 
 			secondTokenIn, secondTokenOut, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapOutAmtGivenIn(
-				s.Ctx, s.TestAccs[0], pool,
+				s.Ctx, s.TestAccs[0], poolBefore,
 				firstTokenOut, firstTokenIn.Denom,
 				DefaultZeroSpreadFactor, sdk.ZeroDec(),
 			)
@@ -2704,42 +2370,20 @@ func (s *KeeperTestSuite) TestInverseRelationshipSwapInAmtGivenOut() {
 
 	for name, test := range tests {
 		s.Run(name, func() {
-			s.SetupTest()
-			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(10000000000000)), sdk.NewCoin("usdc", sdk.NewInt(1000000000000))))
-
-			// Create default CL pool
-			pool := s.PrepareConcentratedPool()
-
-			// add default position
-			s.SetupDefaultPosition(pool.GetId())
-
-			// add second position depending on the test
-			if !test.secondPositionLowerPrice.IsNil() {
-				newLowerTick, err := math.PriceToTickRoundDown(test.secondPositionLowerPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
-				s.Require().NoError(err)
-
-				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick, newUpperTick)
-				s.Require().NoError(err)
-			}
-
-			// mark pool state and user balance before swap
-			poolBefore, err := s.App.ConcentratedLiquidityKeeper.GetPool(s.Ctx, pool.GetId())
-			s.Require().NoError(err)
+			s.setupAndFundSwapTest()
+			poolBefore := s.preparePoolAndDefaultPositions(test)
 			userBalanceBeforeSwap := s.App.BankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
 			poolBalanceBeforeSwap := s.App.BankKeeper.GetAllBalances(s.Ctx, poolBefore.GetAddress())
 
 			// system under test
 			firstTokenIn, firstTokenOut, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapInAmtGivenOut(
-				s.Ctx, s.TestAccs[0], pool,
+				s.Ctx, s.TestAccs[0], poolBefore,
 				test.tokenOut, test.tokenInDenom,
 				DefaultZeroSpreadFactor, test.priceLimit)
 			s.Require().NoError(err)
 
 			secondTokenIn, secondTokenOut, _, _, _, err := s.App.ConcentratedLiquidityKeeper.SwapInAmtGivenOut(
-				s.Ctx, s.TestAccs[0], pool,
+				s.Ctx, s.TestAccs[0], poolBefore,
 				firstTokenIn, firstTokenOut.Denom,
 				DefaultZeroSpreadFactor, sdk.ZeroDec(),
 			)
@@ -2818,12 +2462,7 @@ func (s *KeeperTestSuite) TestUpdatePoolForSwap() {
 		s.Run(name, func() {
 			s.SetupTest()
 			concentratedLiquidityKeeper := s.App.ConcentratedLiquidityKeeper
-
-			// Create pool with initial balance
-			clParams := s.App.ConcentratedLiquidityKeeper.GetParams(s.Ctx)
-			clParams.AuthorizedSpreadFactors = append(clParams.AuthorizedSpreadFactors, tc.spreadFactor)
-			s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, clParams)
-			pool := s.PrepareCustomConcentratedPool(s.TestAccs[0], "eth", "usdc", DefaultTickSpacing, tc.spreadFactor)
+			pool := s.preparePoolWithCustSpread(tc.spreadFactor)
 
 			s.FundAcc(pool.GetAddress(), tc.poolInitialBalance)
 			// Create account with empty balance and fund with initial balance
diff --git a/x/gamm/keeper/export_test.go b/x/gamm/keeper/export_test.go
index 2a15cdbaa..ff9e5bd1a 100644
--- a/x/gamm/keeper/export_test.go
+++ b/x/gamm/keeper/export_test.go
@@ -29,3 +29,7 @@ func (k Keeper) UnmarshalPoolLegacy(bz []byte) (poolmanagertypes.PoolI, error) {
 	var acc poolmanagertypes.PoolI
 	return acc, k.cdc.UnmarshalInterface(bz, &acc)
 }
+
+func GetMaximalNoSwapLPAmount(ctx sdk.Context, pool types.CFMMPoolI, shareOutAmount sdk.Int) (neededLpLiquidity sdk.Coins, err error) {
+	return getMaximalNoSwapLPAmount(ctx, pool, shareOutAmount)
+}
diff --git a/x/gamm/keeper/pool_test.go b/x/gamm/keeper/pool_test.go
index 37de1be79..e4eec2b7d 100644
--- a/x/gamm/keeper/pool_test.go
+++ b/x/gamm/keeper/pool_test.go
@@ -518,6 +518,227 @@ func (s *KeeperTestSuite) TestSetStableSwapScalingFactors() {
 	}
 }
 
+func (suite *KeeperTestSuite) TestGetMaximalNoSwapLPAmount() {
+	tests := map[string]struct {
+		poolId              uint64
+		shareOutAmount      sdk.Int
+		expectedLpLiquidity sdk.Coins
+		err				error
+	}{
+		"Balancer pool: Share ratio is zero": {
+			poolId: suite.prepareCustomBalancerPool(defaultAcctFunds, defaultPoolAssets, balancer.PoolParams{
+				SwapFee: defaultSpreadFactor,
+				ExitFee: defaultZeroExitFee,
+			}),
+			shareOutAmount: sdk.ZeroInt(),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Balancer pool: Share ratio is negative": {
+			poolId: suite.prepareCustomBalancerPool(defaultAcctFunds, defaultPoolAssets, balancer.PoolParams{
+				SwapFee: defaultSpreadFactor,
+				ExitFee: defaultZeroExitFee,
+			}),
+			shareOutAmount: sdk.NewInt(-1),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Balancer pool: Pass": {
+			poolId: suite.prepareCustomBalancerPool(defaultAcctFunds, defaultPoolAssets, balancer.PoolParams{
+				SwapFee: defaultSpreadFactor,
+				ExitFee: defaultZeroExitFee,
+			}),
+
+			// totalShare:   100_000_000_000_000_000_000
+			// shareOutAmount: 8_000_000_000_000_000_000
+			// shareRatio = shareOutAmount/totalShare = 0.08
+			// Amount of tokens in poolAssets:
+			// 		- defaultPoolAssets[1].Token.Amount: 10000
+			//  	- defaultPoolAssets[0].Token.Amount: 10000
+			shareOutAmount: sdk.NewInt(8_000_000_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultPoolAssets[1].Token.Denom, 800),
+				sdk.NewInt64Coin(defaultPoolAssets[0].Token.Denom, 800),
+			},
+		},
+
+		"Balancer pool: Pass with ceiling result": {
+			poolId: suite.prepareCustomBalancerPool(defaultAcctFunds, defaultPoolAssets, balancer.PoolParams{
+				SwapFee: defaultSpreadFactor,
+				ExitFee: defaultZeroExitFee,
+			}),
+
+			// totalShare:   100_000_000_000_000_000_000
+			// shareOutAmount: 8_888_000_000_000_000_000
+			// shareRatio = shareOutAmount/totalShare = 0.08888
+			// Amount of tokens in poolAssets:
+			// 		- defaultPoolAssets[1].Token.Amount: 10000
+			//  	- defaultPoolAssets[0].Token.Amount: 10000
+			shareOutAmount: sdk.NewInt(8_888_000_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultPoolAssets[1].Token.Denom, 889),
+				sdk.NewInt64Coin(defaultPoolAssets[0].Token.Denom, 889),
+			},
+		},
+
+		"Stableswap pool: Share ratio is zero with even two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.ZeroInt(),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Stableswap pool: Share ratio is zero with uneven two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount.QuoRaw(2)), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.ZeroInt(),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Stableswap pool: Share ratio is negative with even two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.NewInt(-1),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Stableswap pool: Share ratio is negative with uneven two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount.QuoRaw(2)), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.NewInt(-1),
+			err: types.ErrInvalidMathApprox,
+		},
+
+		"Stableswap pool: Pass with even two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.NewInt(8_000_000_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultAcctFunds[1].Denom, 800000),
+				sdk.NewInt64Coin(defaultAcctFunds[2].Denom, 800000),
+			},
+		},
+
+		"Stableswap pool: Pass with even two-asset, ceiling result": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			// totalShare:   100_000_000_000_000_000_000
+			// shareOutAmount: 8_888_888_000_000_000_000
+			// shareRatio = shareOutAmount/totalShare = 0.08888888
+			// Amount of tokens in liquidity:
+			// 		- defaultAcctFunds[1].Amount: 10000000
+			//  	- defaultAcctFunds[2].Amount: 10000000
+			shareOutAmount: sdk.NewInt(8_888_888_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultAcctFunds[1].Denom, 888889),
+				sdk.NewInt64Coin(defaultAcctFunds[2].Denom, 888889),
+			},
+		},
+
+		"Stableswap pool: Pass with uneven two-asset": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount.QuoRaw(2)), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			shareOutAmount: sdk.NewInt(8_000_000_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultAcctFunds[1].Denom, 400000),
+				sdk.NewInt64Coin(defaultAcctFunds[2].Denom, 800000),
+			},
+		},
+
+		"Stableswap pool: Pass with uneven two-asset, ceiling result": {
+			poolId: suite.prepareCustomStableswapPool(
+				defaultAcctFunds, 
+				stableswap.PoolParams{
+					SwapFee: defaultSpreadFactor,
+					ExitFee: defaultZeroExitFee,
+				}, 
+				sdk.NewCoins(sdk.NewCoin(defaultAcctFunds[1].Denom, defaultAcctFunds[1].Amount.QuoRaw(2)), sdk.NewCoin(defaultAcctFunds[2].Denom, defaultAcctFunds[2].Amount)),
+				[]uint64{1, 1},
+			),
+			// totalShare:   100_000_000_000_000_000_000
+			// shareOutAmount: 8_888_888_000_000_000_000
+			// shareRatio = shareOutAmount/totalShare = 0.08888888
+			// Amount of tokens in liquidity:
+			// 		- defaultAcctFunds[1].Amount: 10000000
+			//  	- defaultAcctFunds[2].Amount: 5000000
+			shareOutAmount: sdk.NewInt(8_888_888_000_000_000_000),
+			expectedLpLiquidity: sdk.Coins{
+				sdk.NewInt64Coin(defaultAcctFunds[1].Denom, 444445),
+				sdk.NewInt64Coin(defaultAcctFunds[2].Denom, 888889),
+			},
+		},
+	}
+	for name, tc := range tests {
+		suite.Run(name, func() {
+			k := suite.App.GAMMKeeper
+
+			pool, err := k.GetPoolAndPoke(suite.Ctx, tc.poolId)
+			suite.Require().NoError(err)
+			suite.Require().Equal(tc.poolId, pool.GetId())
+
+			neededLpLiquidity, err := keeper.GetMaximalNoSwapLPAmount(suite.Ctx, pool, tc.shareOutAmount)
+			if tc.err != nil {
+				suite.Require().Error(err)
+				msgError := fmt.Sprintf("Too few shares out wanted. (debug: getMaximalNoSwapLPAmount share ratio is zero or negative): %s", tc.err)
+				suite.Require().EqualError(err, msgError)
+			} else {
+				suite.Require().NoError(err)
+				suite.Require().Equal(neededLpLiquidity, tc.expectedLpLiquidity)
+			}
+
+		})
+	}
+}
+
 func (suite *KeeperTestSuite) TestGetTotalPoolShares() {
 	tests := map[string]struct {
 		sharesJoined   sdk.Int
diff --git a/x/poolmanager/msg_server_test.go b/x/poolmanager/msg_server_test.go
new file mode 100644
index 000000000..ad5eb0563
--- /dev/null
+++ b/x/poolmanager/msg_server_test.go
@@ -0,0 +1,198 @@
+package poolmanager_test
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	poolmanagerKeeper "github.com/osmosis-labs/osmosis/v15/x/poolmanager"
+	"github.com/osmosis-labs/osmosis/v15/x/poolmanager/types"
+)
+
+var (
+	amount     = sdk.NewInt(100)
+	min_amount = sdk.ZeroInt()
+	max_amount = sdk.NewInt(10000000)
+
+	pool1_in = types.SwapAmountInRoute{PoolId: 1, TokenOutDenom: "bar"}
+	pool2_in = types.SwapAmountInRoute{PoolId: 2, TokenOutDenom: "baz"}
+	pool3_in = types.SwapAmountInRoute{PoolId: 3, TokenOutDenom: "uosmo"}
+	pool4_in = types.SwapAmountInRoute{PoolId: 4, TokenOutDenom: "baz"}
+
+	pool1_out = types.SwapAmountOutRoute{PoolId: 1, TokenInDenom: "bar"}
+	pool2_out = types.SwapAmountOutRoute{PoolId: 2, TokenInDenom: "baz"}
+	pool3_out = types.SwapAmountOutRoute{PoolId: 3, TokenInDenom: "bar"}
+	pool4_out = types.SwapAmountOutRoute{PoolId: 4, TokenInDenom: "baz"}
+)
+
+func (s *KeeperTestSuite) TestSplitRouteSwapExactAmountIn() {
+	testcases := map[string]struct {
+		routes            []types.SwapAmountInSplitRoute
+		tokenInDenom      string
+		tokenoutMinAmount sdk.Int
+
+		expectedSplitRouteSwapEvent int
+		expectedMessageEvents       int
+		expectedError               bool
+	}{
+		"valid case: two routes": {
+			routes: []types.SwapAmountInSplitRoute{
+				{
+					Pools:         []types.SwapAmountInRoute{pool1_in, pool2_in},
+					TokenInAmount: amount,
+				},
+				{
+					Pools:         []types.SwapAmountInRoute{pool3_in, pool4_in},
+					TokenInAmount: amount,
+				},
+			},
+			tokenInDenom:      "baz",
+			tokenoutMinAmount: min_amount,
+
+			expectedSplitRouteSwapEvent: 1,
+			expectedMessageEvents:       9, // 4 pool creation + 5 events in SplitRouteExactAmountIn keeper methods
+		},
+		"error: empty route": {
+			routes:            []types.SwapAmountInSplitRoute{},
+			tokenInDenom:      "baz",
+			tokenoutMinAmount: min_amount,
+			expectedError:     true,
+		},
+		"error path: denom doesnot exist routes": {
+			routes: []types.SwapAmountInSplitRoute{
+				{
+					Pools:         []types.SwapAmountInRoute{pool1_in, pool2_in},
+					TokenInAmount: amount,
+				},
+				{
+					Pools:         []types.SwapAmountInRoute{pool1_in, pool2_in},
+					TokenInAmount: amount,
+				},
+			},
+			tokenInDenom:      "baz",
+			tokenoutMinAmount: min_amount,
+
+			expectedError: true,
+		},
+	}
+
+	for name, tc := range testcases {
+		s.Run(name, func() {
+			s.Setup()
+			ctx := s.Ctx
+
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+
+			msgServer := poolmanagerKeeper.NewMsgServerImpl(s.App.PoolManagerKeeper)
+
+			// Reset event counts to 0 by creating a new manager.
+			ctx = ctx.WithEventManager(sdk.NewEventManager())
+			s.Equal(0, len(ctx.EventManager().Events()))
+
+			response, err := msgServer.SplitRouteSwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSplitRouteSwapExactAmountIn{
+				Sender:            s.TestAccs[0].String(),
+				Routes:            tc.routes,
+				TokenInDenom:      tc.tokenInDenom,
+				TokenOutMinAmount: tc.tokenoutMinAmount,
+			})
+			if tc.expectedError {
+				s.Require().Error(err)
+				s.Require().Nil(response)
+			} else {
+				s.Require().NoError(err)
+				s.AssertEventEmitted(ctx, types.TypeMsgSplitRouteSwapExactAmountIn, tc.expectedSplitRouteSwapEvent)
+				s.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
+			}
+
+		})
+	}
+}
+
+func (s *KeeperTestSuite) TestSplitRouteSwapExactAmountOut() {
+	testcases := map[string]struct {
+		routes            []types.SwapAmountOutSplitRoute
+		tokenOutDenom     string
+		tokenoutMaxAmount sdk.Int
+
+		expectedSplitRouteSwapEvent int
+		expectedMessageEvents       int
+		expectedError               bool
+	}{
+		"valid case: two routes": {
+			routes: []types.SwapAmountOutSplitRoute{
+				{
+					Pools:          []types.SwapAmountOutRoute{pool1_out, pool2_out},
+					TokenOutAmount: amount,
+				},
+				{
+					Pools:          []types.SwapAmountOutRoute{pool3_out, pool4_out},
+					TokenOutAmount: amount,
+				},
+			},
+			tokenOutDenom:     "uosmo",
+			tokenoutMaxAmount: max_amount,
+
+			expectedSplitRouteSwapEvent: 1,
+			expectedMessageEvents:       9, // 4 pool creation + 5 events in SplitRouteExactAmountOut keeper methods
+		},
+		"error: empty route": {
+			routes:            []types.SwapAmountOutSplitRoute{},
+			tokenOutDenom:     "baz",
+			tokenoutMaxAmount: max_amount,
+
+			expectedError: true,
+		},
+		"error path: denom duplicate route": {
+			routes: []types.SwapAmountOutSplitRoute{
+				{
+					Pools:          []types.SwapAmountOutRoute{pool1_out, pool2_out},
+					TokenOutAmount: amount,
+				},
+				{
+					Pools:          []types.SwapAmountOutRoute{pool1_out, pool2_out},
+					TokenOutAmount: amount,
+				},
+			},
+			tokenOutDenom:     "baz",
+			tokenoutMaxAmount: max_amount,
+
+			expectedError: true,
+		},
+	}
+
+	for name, tc := range testcases {
+		s.Run(name, func() {
+			s.Setup()
+			ctx := s.Ctx
+
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+			s.PrepareBalancerPool()
+
+			msgServer := poolmanagerKeeper.NewMsgServerImpl(s.App.PoolManagerKeeper)
+
+			// Reset event counts to 0 by creating a new manager.
+			ctx = ctx.WithEventManager(sdk.NewEventManager())
+			s.Equal(0, len(ctx.EventManager().Events()))
+
+			response, err := msgServer.SplitRouteSwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSplitRouteSwapExactAmountOut{
+				Sender:           s.TestAccs[0].String(),
+				Routes:           tc.routes,
+				TokenOutDenom:    tc.tokenOutDenom,
+				TokenInMaxAmount: tc.tokenoutMaxAmount,
+			})
+			if tc.expectedError {
+				s.Require().Error(err)
+				s.Require().Nil(response)
+			} else {
+
+				s.Require().NoError(err)
+				s.AssertEventEmitted(ctx, types.TypeMsgSplitRouteSwapExactAmountOut, tc.expectedSplitRouteSwapEvent)
+				s.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
+			}
+
+		})
+	}
+}