diff --git a/app/app.go b/app/app.go
index a2b66870abf09cda1637ad60f0e2349794e851fa..55665cf147f6ea41ba0b37574c415c3dc13915ed 100644
--- a/app/app.go
+++ b/app/app.go
@@ -339,6 +339,9 @@ func NewOsmosisApp(
 			distrParams.BaseProposerReward = sdk.ZeroDec()
 			distrParams.BonusProposerReward = sdk.ZeroDec()
 			app.DistrKeeper.SetParams(ctx, distrParams)
+
+			// configure upgrade for gamm module's pool creation fee param add
+			app.GAMMKeeper.SetParams(ctx, gammtypes.NewParams(sdk.Coins{sdk.NewInt64Coin("uosmo", 1000000000)})) // 1000 OSMO
 		})
 
 	// Create IBC Keeper
@@ -373,7 +376,7 @@ func NewOsmosisApp(
 	app.StakingKeeper = *stakingKeeper.SetHooks(
 		stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks(), app.ClaimKeeper.Hooks()),
 	)
-	gammKeeper := gammkeeper.NewKeeper(appCodec, keys[gammtypes.StoreKey], app.AccountKeeper, app.BankKeeper)
+	gammKeeper := gammkeeper.NewKeeper(appCodec, keys[gammtypes.StoreKey], app.GetSubspace(gammtypes.ModuleName), app.AccountKeeper, app.BankKeeper, app.DistrKeeper)
 	lockupKeeper := lockupkeeper.NewKeeper(appCodec, keys[lockuptypes.StoreKey], app.AccountKeeper, app.BankKeeper)
 	epochsKeeper := epochskeeper.NewKeeper(appCodec, keys[epochstypes.StoreKey])
 	incentivesKeeper := incentiveskeeper.NewKeeper(appCodec, keys[incentivestypes.StoreKey], app.GetSubspace(incentivestypes.ModuleName), app.AccountKeeper, app.BankKeeper, *lockupKeeper, epochsKeeper, app.StakingKeeper)
@@ -517,6 +520,7 @@ func NewOsmosisApp(
 		claimtypes.ModuleName,
 		incentivestypes.ModuleName,
 		epochstypes.ModuleName,
+		gammtypes.ModuleName,
 	)
 
 	app.mm.RegisterInvariants(&app.CrisisKeeper)
@@ -770,6 +774,7 @@ func initParamsKeeper(appCodec codec.BinaryMarshaler, legacyAmino *codec.LegacyA
 	paramsKeeper.Subspace(ibchost.ModuleName)
 	paramsKeeper.Subspace(incentivestypes.ModuleName)
 	paramsKeeper.Subspace(poolincentivestypes.ModuleName)
+	paramsKeeper.Subspace(gammtypes.ModuleName)
 
 	return paramsKeeper
 }
diff --git a/osmomath/math.go b/osmomath/math.go
new file mode 100644
index 0000000000000000000000000000000000000000..1889531af8116a442288eaeddeb522dadda9a513
--- /dev/null
+++ b/osmomath/math.go
@@ -0,0 +1,156 @@
+package osmomath
+
+import (
+	"fmt"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+// Don't EVER change after initializing
+// TODO: Analyze choice here
+var powPrecision, _ = sdk.NewDecFromStr("0.00000001")
+
+// Singletons
+var zero sdk.Dec = sdk.ZeroDec()
+var one_half sdk.Dec = sdk.MustNewDecFromStr("0.5")
+var one sdk.Dec = sdk.OneDec()
+var two sdk.Dec = sdk.MustNewDecFromStr("2")
+
+
+/*********************************************************/
+
+// AbsDifferenceWithSign returns | a - b |, (a - b).sign()
+// a is mutated and returned
+func AbsDifferenceWithSign(a, b sdk.Dec) (sdk.Dec, bool) {
+	if a.GTE(b) {
+		return a.SubMut(b), false
+	} else {
+		return a.NegMut().AddMut(b), true
+	}
+}
+
+// func largeBasePow(base sdk.Dec, exp sdk.Dec) sdk.Dec {
+// 	// pow requires the base to be <= 2
+// }
+
+// Pow computes base^(exp)
+// However since the exponent is not an integer, we must do an approximation algorithm.
+// TODO: In the future, lets add some optimized routines for common exponents, e.g. for common wIn / wOut ratios
+// Many simple exponents like 2:1 pools
+func Pow(base sdk.Dec, exp sdk.Dec) sdk.Dec {
+	// Exponentiation of a negative base with an arbitrary real exponent is not closed within the reals.
+	// You can see this by recalling that `i = (-1)^(.5)`. We have to go to complex numbers to define this.
+	// (And would have to implement complex logarithms)
+	// We don't have a need for negative bases, so we don't include any such logic.
+	if !base.IsPositive() {
+		panic(fmt.Errorf("base must be greater than 0"))
+	}
+	// TODO: Remove this if we want to generalize the function,
+	// we can adjust the algorithm in this setting.
+	if base.GTE(two) {
+		panic(fmt.Errorf("base must be lesser than two"))
+	}
+
+	// We will use an approximation algorithm to compute the power.
+	// Since computing an integer power is easy, we split up the exponent into
+	// an integer component and a fractional component.
+	integer := exp.TruncateDec()
+	fractional := exp.Sub(integer)
+
+	integerPow := base.Power(uint64(integer.TruncateInt64()))
+
+	if fractional.IsZero() {
+		return integerPow
+	}
+
+	fractionalPow := PowApprox(base, fractional, powPrecision)
+
+	return integerPow.Mul(fractionalPow)
+}
+
+// Contract: 0 < base <= 2
+// 0 < exp < 1
+func PowApprox(base sdk.Dec, exp sdk.Dec, precision sdk.Dec) sdk.Dec {
+	if exp.IsZero() {
+		return sdk.ZeroDec()
+	}
+
+	// Common case optimization
+	// Optimize for it being equal to one-half
+	if exp.Equal(one_half) {
+		output, err := base.ApproxSqrt()
+		if err != nil {
+			panic(err)
+		}
+		return output
+	}
+	// TODO: Make an approx-equal function, and then check if exp * 3 = 1, and do a check accordingly
+
+	// We compute this via taking the maclaurin series of (1 + x)^a
+	// where x = base - 1.
+	// The maclaurin series of (1 + x)^a = sum_{k=0}^{infty} binom(a, k) x^k
+	// Binom(a, k) takes the natural continuation on the first parameter, namely that
+	// Binom(a, k) = N/D, where D = k!, and N = a(a-1)(a-2)...(a-k+1)
+	// Next we show that the absolute value of each term is less than the last term.
+	// Note that the change in term n's value vs term n + 1 is a multiplicative factor of
+	// v_n = x(a - n) / (n+1)
+	// So if |v_n| < 1, we know that each term has a lesser impact on the result than the last.
+	// For our bounds on |x| < 1, |a| < 1,
+	// it suffices to see for what n is |v_n| < 1,
+	// in the worst parameterization of x = 1, a = -1.
+	// v_n = |(-1 + epsilon - n) / (n+1)|
+	// So |v_n| is always less than 1, as n ranges over the integers.
+	//
+	// Note that term_n of the expansion is 1 * prod_{i=0}^{n-1} v_i
+	// The error if we stop the expansion at term_n is:
+	// error_n = sum_{k=n+1}^{infty} term_k
+	// At this point we further restrict a >= 0, so 0 <= a < 1.
+	// Now we take the _INCORRECT_ assumption that if term_n < p, then
+	// error_n < p.
+	// This assumption is obviously wrong.
+	// However our usages of this function don't use the full domain.
+	// With a > 0, |x| << 1, and p sufficiently low, perhaps this actually is true.
+
+	// TODO: Check with our parameterization
+	// TODO: If theres a bug, balancer is also wrong here :thonk:
+
+	base = base.Clone()
+	x, xneg := AbsDifferenceWithSign(base, one)
+	term := sdk.OneDec()
+	sum := sdk.OneDec()
+	negative := false
+
+	a := exp.Clone()
+	bigK := sdk.NewDec(0)
+	// TODO: Document this computation via taylor expansion
+	for i := int64(1); term.GTE(precision); i++ {
+		// At each iteration, we need two values, i and i-1.
+		// To avoid expensive big.Int allocation, we reuse bigK variable.
+		// On this line, bigK == i-1.
+		c, cneg := AbsDifferenceWithSign(a, bigK)
+		// On this line, bigK == i.
+		bigK.Set(sdk.NewDec(i)) // TODO: O(n) bigint allocation happens
+		term.MulMut(c).MulMut(x).QuoMut(bigK)
+
+		// a is mutated on absDifferenceWithSign, reset
+		a.Set(exp)
+
+		if term.IsZero() {
+			break
+		}
+		if xneg {
+			negative = !negative
+		}
+
+		if cneg {
+			negative = !negative
+		}
+
+		if negative {
+			sum.SubMut(term)
+		} else {
+			sum.AddMut(term)
+		}
+	}
+	return sum
+}
diff --git a/osmomath/math_test.go b/osmomath/math_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..096a685a20464f0f454a93e5f97a3d4b7b9c5a9b
--- /dev/null
+++ b/osmomath/math_test.go
@@ -0,0 +1,59 @@
+package osmomath
+
+import (
+	"testing"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestAbsDifferenceWithSign(t *testing.T) {
+	decA, err := sdk.NewDecFromStr("3.2")
+	require.NoError(t, err)
+	decB, err := sdk.NewDecFromStr("4.3432389")
+	require.NoError(t, err)
+
+	s, b := AbsDifferenceWithSign(decA, decB)
+	require.True(t, b)
+
+	expectedDec, err := sdk.NewDecFromStr("1.1432389")
+	require.NoError(t, err)
+	require.Equal(t, expectedDec, s)
+}
+
+func TestPowApprox(t *testing.T) {
+	base, err := sdk.NewDecFromStr("0.8")
+	require.NoError(t, err)
+	exp, err := sdk.NewDecFromStr("0.32")
+	require.NoError(t, err)
+
+	s := PowApprox(base, exp, powPrecision)
+	expectedDec, err := sdk.NewDecFromStr("0.93108385")
+	require.NoError(t, err)
+
+	require.True(
+		t,
+		expectedDec.Sub(s).Abs().LTE(powPrecision),
+		"expected value & actual value's difference should less than precision",
+	)
+}
+
+func TestPow(t *testing.T) {
+	base, err := sdk.NewDecFromStr("1.68")
+	require.NoError(t, err)
+	exp, err := sdk.NewDecFromStr("0.32")
+	require.NoError(t, err)
+
+	s := Pow(base, exp)
+	expectedDec, err := sdk.NewDecFromStr("1.18058965")
+	require.NoError(t, err)
+
+	require.True(
+		t,
+		expectedDec.Sub(s).Abs().LTE(powPrecision),
+		"expected value & actual value's difference should less than precision",
+	)
+}
+
+
diff --git a/x/gamm/keeper/pow_bench_test.go b/osmomath/pow_bench_test.go
similarity index 95%
rename from x/gamm/keeper/pow_bench_test.go
rename to osmomath/pow_bench_test.go
index 0af73bb365c1a5d8a47cdc04d1b03904ea50bca9..51c4095ccda9e15c4fac116b4dc31208bdb17bfc 100644
--- a/x/gamm/keeper/pow_bench_test.go
+++ b/osmomath/pow_bench_test.go
@@ -1,4 +1,4 @@
-package keeper
+package osmomath
 
 import (
 	"testing"
@@ -56,7 +56,7 @@ func BenchmarkPow(b *testing.B) {
 
 	for i := 0; i < b.N; i++ {
 		for _, test := range tests {
-			pow(test.base, test.exp)
+			Pow(test.base, test.exp)
 		}
 	}
 }
@@ -80,7 +80,7 @@ func BenchmarkSqrtPow(b *testing.B) {
 
 	for i := 0; i < b.N; i++ {
 		for _, test := range tests {
-			pow(test.base, one_half)
+			Pow(test.base, one_half)
 		}
 	}
 }
diff --git a/proto/osmosis/gamm/v1beta1/genesis.proto b/proto/osmosis/gamm/v1beta1/genesis.proto
index 8f682fa187ea4d20e99fe7764e2dcacec856e259..1e815bcd64c5bca5d1ee6974c04a32c81a32a64b 100644
--- a/proto/osmosis/gamm/v1beta1/genesis.proto
+++ b/proto/osmosis/gamm/v1beta1/genesis.proto
@@ -4,6 +4,17 @@ package osmosis.gamm;
 import "gogoproto/gogo.proto";
 import "google/protobuf/any.proto";
 import "cosmos_proto/cosmos.proto";
+import "cosmos/base/v1beta1/coin.proto";
+
+// Params holds parameters for the incentives module
+message Params {
+    repeated cosmos.base.v1beta1.Coin pool_creation_fee = 1 [
+        (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
+        (gogoproto.moretags) = "yaml:\"pool_creation_fee\"",
+        (gogoproto.nullable) = false
+    ];
+}
+
 
 option go_package = "github.com/osmosis-labs/osmosis/x/gamm/types";
 
@@ -12,4 +23,5 @@ message GenesisState {
     repeated google.protobuf.Any pools = 1
         [ (cosmos_proto.accepts_interface) = "PoolI" ];
     uint64 next_pool_number = 2;
+    Params params = 3 [ (gogoproto.nullable) = false ];
 }
diff --git a/x/epochs/genesis_test.go b/x/epochs/genesis_test.go
index 050b6ec21d0d247ff7bd2e8bc3e85bd57de43e0d..60673004cd2e9149ddc37d300bb93aa388915f02 100644
--- a/x/epochs/genesis_test.go
+++ b/x/epochs/genesis_test.go
@@ -51,7 +51,8 @@ func TestEpochsInitGenesis(t *testing.T) {
 	ctx = ctx.WithBlockHeight(1)
 	ctx = ctx.WithBlockTime(now)
 
-	epochs.InitGenesis(ctx, app.EpochsKeeper, types.GenesisState{
+	//test genesisState validation
+	genesisState := types.GenesisState{
 		Epochs: []types.EpochInfo{
 			{
 				Identifier:            "monthly",
@@ -62,9 +63,34 @@ func TestEpochsInitGenesis(t *testing.T) {
 				EpochCountingStarted:  true,
 				CurrentEpochEnded:     true,
 			},
+			{
+				Identifier:            "monthly",
+				StartTime:             time.Time{},
+				Duration:              time.Hour * 24,
+				CurrentEpoch:          0,
+				CurrentEpochStartTime: time.Time{},
+				EpochCountingStarted:  true,
+				CurrentEpochEnded:     true,
+			},
 		},
-	})
+	}
+	require.EqualError(t, genesisState.Validate(), "epoch identifier should be unique")
+
+	genesisState = types.GenesisState{
+		Epochs: []types.EpochInfo{
+			{
+				Identifier:            "monthly",
+				StartTime:             time.Time{},
+				Duration:              time.Hour * 24,
+				CurrentEpoch:          0,
+				CurrentEpochStartTime: time.Time{},
+				EpochCountingStarted:  true,
+				CurrentEpochEnded:     true,
+			},
+		},
+	}
 
+	epochs.InitGenesis(ctx, app.EpochsKeeper, genesisState)
 	epochInfo := app.EpochsKeeper.GetEpochInfo(ctx, "monthly")
 	require.Equal(t, epochInfo.Identifier, "monthly")
 	require.Equal(t, epochInfo.StartTime.UTC().String(), now.UTC().String())
diff --git a/x/epochs/types/genesis.go b/x/epochs/types/genesis.go
index f0a9bfdbbd490276dd2672bc2d8094beda9a4bdf..3387ecac3c5e88c4418afc900496cd9c55aeb37d 100644
--- a/x/epochs/types/genesis.go
+++ b/x/epochs/types/genesis.go
@@ -41,13 +41,18 @@ func DefaultGenesis() *GenesisState {
 // failure.
 func (gs GenesisState) Validate() error {
 	// TODO: Epochs identifiers should be unique
+	epochIdentifiers := map[string]bool{}
 	for _, epoch := range gs.Epochs {
 		if epoch.Identifier == "" {
 			return errors.New("epoch identifier should NOT be empty")
 		}
+		if epochIdentifiers[epoch.Identifier] {
+			return errors.New("epoch identifier should be unique")
+		}
 		if epoch.Duration == 0 {
 			return errors.New("epoch duration should NOT be 0")
 		}
+		epochIdentifiers[epoch.Identifier] = true
 	}
 	return nil
 }
diff --git a/x/epochs/types/identifier.go b/x/epochs/types/identifier.go
new file mode 100644
index 0000000000000000000000000000000000000000..9e6a15d85861a35469428f63042cd76f9c755631
--- /dev/null
+++ b/x/epochs/types/identifier.go
@@ -0,0 +1,22 @@
+package types
+
+import (
+	"fmt"
+)
+
+func ValidateEpochIdentifierInterface(i interface{}) error {
+	v, ok := i.(string)
+	if !ok {
+		return fmt.Errorf("invalid parameter type: %T", i)
+	}
+	ValidateEpochIdentifierString(v)
+
+	return nil
+}
+
+func ValidateEpochIdentifierString(s string) error {
+	if s == "" {
+		return fmt.Errorf("empty distribution epoch identifier: %+v", s)
+	}
+	return nil
+}
diff --git a/x/gamm/client/cli/cli_test.go b/x/gamm/client/cli/cli_test.go
index 974532e24b338ff94ea2a766420f2bf8c6f74a2f..7011ea0f270678692c73b4abf6b9f1833425faee 100644
--- a/x/gamm/client/cli/cli_test.go
+++ b/x/gamm/client/cli/cli_test.go
@@ -19,7 +19,7 @@ import (
 	"github.com/osmosis-labs/osmosis/x/gamm/client/cli"
 	gammtestutil "github.com/osmosis-labs/osmosis/x/gamm/client/testutil"
 	"github.com/osmosis-labs/osmosis/x/gamm/types"
-
+	gammtypes "github.com/osmosis-labs/osmosis/x/gamm/types"
 	tmcli "github.com/tendermint/tendermint/libs/cli"
 )
 
@@ -35,6 +35,16 @@ func (s *IntegrationTestSuite) SetupSuite() {
 
 	s.cfg = app.DefaultConfig()
 
+	encCfg := app.MakeEncodingConfig()
+
+	// modification to pay fee with test bond denom "stake"
+	genesisState := app.ModuleBasics.DefaultGenesis(encCfg.Marshaler)
+	gammGen := gammtypes.DefaultGenesis()
+	gammGen.Params.PoolCreationFee = sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 1000000)}
+	gammGenJson := encCfg.Marshaler.MustMarshalJSON(gammGen)
+	genesisState[gammtypes.ModuleName] = gammGenJson
+	s.cfg.GenesisState = genesisState
+
 	s.network = network.New(s.T(), s.cfg)
 
 	_, err := s.network.WaitForHeight(1)
@@ -67,7 +77,7 @@ func (s *IntegrationTestSuite) TestNewCreatePoolCmd() {
 		val.ClientCtx,
 		val.Address,
 		newAddr,
-		sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 20000), sdk.NewInt64Coin("node0token", 20000)), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
+		sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 200000000), sdk.NewInt64Coin("node0token", 20000)), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
 		fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
 		fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
 	)
diff --git a/x/gamm/client/cli/query.go b/x/gamm/client/cli/query.go
index 6a35870766d6e1c5378d762238067813da35010b..15a2e899892e0022423c9d2ce0325e4c649fcf9b 100644
--- a/x/gamm/client/cli/query.go
+++ b/x/gamm/client/cli/query.go
@@ -119,8 +119,13 @@ $ %s query gamm pools
 			}
 			queryClient := types.NewQueryClient(clientCtx)
 
+			pageReq, err := client.ReadPageRequest(cmd.Flags())
+			if err != nil {
+				return err
+			}
+
 			res, err := queryClient.Pools(cmd.Context(), &types.QueryPoolsRequest{
-				Pagination: nil,
+				Pagination: pageReq,
 			})
 			if err != nil {
 				return err
@@ -131,6 +136,7 @@ $ %s query gamm pools
 	}
 
 	flags.AddQueryFlagsToCmd(cmd)
+	flags.AddPaginationFlagsToCmd(cmd, "pools")
 
 	return cmd
 }
diff --git a/x/gamm/genesis.go b/x/gamm/genesis.go
index 37dcea8d5e31d293f0d098b997fe5ff38e1a9931..9345a372af4477ba2a2da1056c7e4c48c6636da1 100644
--- a/x/gamm/genesis.go
+++ b/x/gamm/genesis.go
@@ -12,6 +12,7 @@ import (
 // InitGenesis initializes the capability module's state from a provided genesis
 // state.
 func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState, unpacker codectypes.AnyUnpacker) {
+	k.SetParams(ctx, genState.Params)
 	k.SetNextPoolNumber(ctx, genState.NextPoolNumber)
 
 	liquidity := sdk.Coins{}
@@ -56,5 +57,6 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
 	return &types.GenesisState{
 		NextPoolNumber: k.GetNextPoolNumber(ctx),
 		Pools:          poolAnys,
+		Params:         k.GetParams(ctx),
 	}
 }
diff --git a/x/gamm/genesis_test.go b/x/gamm/genesis_test.go
index eac860593ee442f9ee83924a6f6fcf31f598de4b..e394b1991d2b508c04b1f2fe96b7cf3feb7c6011 100644
--- a/x/gamm/genesis_test.go
+++ b/x/gamm/genesis_test.go
@@ -6,6 +6,7 @@ import (
 	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	simapp "github.com/osmosis-labs/osmosis/app"
+	appparams "github.com/osmosis-labs/osmosis/app/params"
 	"github.com/osmosis-labs/osmosis/x/gamm"
 	"github.com/osmosis-labs/osmosis/x/gamm/types"
 	"github.com/stretchr/testify/assert"
@@ -42,6 +43,9 @@ func TestGammInitGenesis(t *testing.T) {
 	gamm.InitGenesis(ctx, app.GAMMKeeper, types.GenesisState{
 		Pools:          []*codectypes.Any{any},
 		NextPoolNumber: 2,
+		Params: types.Params{
+			PoolCreationFee: sdk.Coins{sdk.NewInt64Coin(appparams.BaseCoinUnit, 1000_000_000)},
+		},
 	}, app.AppCodec())
 
 	require.Equal(t, app.GAMMKeeper.GetNextPoolNumber(ctx), uint64(2))
@@ -68,6 +72,7 @@ func TestGammExportGenesis(t *testing.T) {
 
 	acc1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address().Bytes())
 	app.BankKeeper.SetBalances(ctx, acc1, sdk.Coins{
+		sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 		sdk.NewInt64Coin("foo", 100000),
 		sdk.NewInt64Coin("bar", 100000),
 	})
@@ -110,6 +115,7 @@ func TestMarshalUnmarshalGenesis(t *testing.T) {
 	am := gamm.NewAppModule(appCodec, app.GAMMKeeper, app.AccountKeeper, app.BankKeeper)
 	acc1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address().Bytes())
 	app.BankKeeper.SetBalances(ctx, acc1, sdk.Coins{
+		sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 		sdk.NewInt64Coin("foo", 100000),
 		sdk.NewInt64Coin("bar", 100000),
 	})
diff --git a/x/gamm/keeper/invariants.go b/x/gamm/keeper/invariants.go
index 012d58b8c666fad806474fc3553ba5935d60de22..e8168964da4b752187125bf6c3aef4e79b4f685c 100644
--- a/x/gamm/keeper/invariants.go
+++ b/x/gamm/keeper/invariants.go
@@ -6,6 +6,8 @@ import (
 	"fmt"
 
 	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	"github.com/osmosis-labs/osmosis/osmomath"
 	"github.com/osmosis-labs/osmosis/x/gamm/types"
 )
 
@@ -88,9 +90,9 @@ func PoolTotalWeightInvariant(keeper Keeper, bk types.BankKeeper) sdk.Invariant
 
 func genericPow(base, exp sdk.Dec) sdk.Dec {
 	if !base.GTE(sdk.NewDec(2)) {
-		return pow(base, exp)
+		return osmomath.Pow(base, exp)
 	}
-	return powApprox(sdk.OneDec().Quo(base), exp.Neg(), powPrecision)
+	return osmomath.PowApprox(sdk.OneDec().Quo(base), exp.Neg(), powPrecision)
 }
 
 // constantChange returns the multiplicative factor difference in the pool constant, between two different pools.
diff --git a/x/gamm/keeper/keeper.go b/x/gamm/keeper/keeper.go
index fef062d463ccfc45ab337e0952a52347c6201ecd..dfc5d2b6b8fc8164f0cd8a9a86f681a2013211dd 100644
--- a/x/gamm/keeper/keeper.go
+++ b/x/gamm/keeper/keeper.go
@@ -7,6 +7,7 @@ import (
 	"github.com/cosmos/cosmos-sdk/codec"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
+	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
 	"github.com/osmosis-labs/osmosis/x/gamm/types"
 )
 
@@ -24,14 +25,16 @@ type Keeper struct {
 	storeKey sdk.StoreKey
 	cdc      codec.BinaryMarshaler
 
-	hooks types.GammHooks
+	paramSpace paramtypes.Subspace
+	hooks      types.GammHooks
 
 	// keepers
 	accountKeeper types.AccountKeeper
 	bankKeeper    types.BankKeeper
+	distrKeeper   types.DistrKeeper
 }
 
-func NewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper) Keeper {
+func NewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, distrKeeper types.DistrKeeper) Keeper {
 	// Ensure that the module account are set.
 	moduleAddr, perms := accountKeeper.GetModuleAddressAndPermissions(types.ModuleName)
 	if moduleAddr == nil {
@@ -43,12 +46,17 @@ func NewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, accountKeeper t
 	if !permContains(perms, authtypes.Burner) {
 		panic(fmt.Sprintf("%s module account should have the burner permission", types.ModuleName))
 	}
+	if !paramSpace.HasKeyTable() {
+		paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
+	}
 	return Keeper{
-		storeKey: storeKey,
-		cdc:      cdc,
+		storeKey:   storeKey,
+		cdc:        cdc,
+		paramSpace: paramSpace,
 		// keepers
 		accountKeeper: accountKeeper,
 		bankKeeper:    bankKeeper,
+		distrKeeper:   distrKeeper,
 	}
 }
 
diff --git a/x/gamm/keeper/keeper_test.go b/x/gamm/keeper/keeper_test.go
index 087382cda4bb6851903386ba9728d38c56e8604d..3fcd6c46fea1d2d81c24b613b06b3ffb9ea6c87b 100644
--- a/x/gamm/keeper/keeper_test.go
+++ b/x/gamm/keeper/keeper_test.go
@@ -50,6 +50,7 @@ func (suite *KeeperTestSuite) preparePoolWithPoolParams(poolParams types.PoolPar
 			suite.ctx,
 			acc,
 			sdk.NewCoins(
+				sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 				sdk.NewCoin("foo", sdk.NewInt(10000000)),
 				sdk.NewCoin("bar", sdk.NewInt(10000000)),
 				sdk.NewCoin("baz", sdk.NewInt(10000000)),
diff --git a/x/gamm/keeper/math.go b/x/gamm/keeper/math.go
index 83e1afa74ec23f4b43105b6ca54959f0901f5efc..2132eca29ac67b65061ac308c832ef77fdee401e 100644
--- a/x/gamm/keeper/math.go
+++ b/x/gamm/keeper/math.go
@@ -1,7 +1,7 @@
 package keeper
 
 import (
-	"fmt"
+	"github.com/osmosis-labs/osmosis/osmomath"
 
 	sdk "github.com/cosmos/cosmos-sdk/types"
 )
@@ -67,7 +67,7 @@ func calcOutGivenIn(
 	adjustedIn := sdk.OneDec().Sub(swapFee)
 	adjustedIn = tokenAmountIn.Mul(adjustedIn)
 	y := tokenBalanceIn.Quo(tokenBalanceIn.Add(adjustedIn))
-	foo := pow(y, weightRatio)
+	foo := osmomath.Pow(y, weightRatio)
 	bar := sdk.OneDec().Sub(foo)
 	return tokenBalanceOut.Mul(bar)
 }
@@ -84,7 +84,7 @@ func calcInGivenOut(
 	weightRatio := tokenWeightOut.Quo(tokenWeightIn)
 	diff := tokenBalanceOut.Sub(tokenAmountOut)
 	y := tokenBalanceOut.Quo(diff)
-	foo := pow(y, weightRatio)
+	foo := osmomath.Pow(y, weightRatio)
 	foo = foo.Sub(one)
 	tokenAmountIn := sdk.OneDec().Sub(swapFee)
 	return (tokenBalanceIn.Mul(foo)).Quo(tokenAmountIn)
@@ -108,7 +108,7 @@ func calcPoolOutGivenSingleIn(
 	tokenInRatio := newTokenBalanceIn.Quo(tokenBalanceIn)
 
 	// uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;
-	poolRatio := pow(tokenInRatio, normalizedWeight)
+	poolRatio := osmomath.Pow(tokenInRatio, normalizedWeight)
 	newPoolSupply := poolRatio.Mul(poolSupply)
 	return newPoolSupply.Sub(poolSupply)
 }
@@ -128,7 +128,7 @@ func calcSingleInGivenPoolOut(
 
 	//uint newBalTi = poolRatio^(1/weightTi) * balTi;
 	boo := sdk.OneDec().Quo(normalizedWeight)
-	tokenInRatio := pow(poolRatio, boo)
+	tokenInRatio := osmomath.Pow(poolRatio, boo)
 	newTokenBalanceIn := tokenInRatio.Mul(tokenBalanceIn)
 	tokenAmountInAfterFee := newTokenBalanceIn.Sub(tokenBalanceIn)
 	// Do reverse order of fees charged in joinswap_ExternAmountIn, this way
@@ -157,7 +157,7 @@ func calcSingleOutGivenPoolIn(
 
 	// newBalTo = poolRatio^(1/weightTo) * balTo;
 
-	tokenOutRatio := pow(poolRatio, sdk.OneDec().Quo(normalizedWeight))
+	tokenOutRatio := osmomath.Pow(poolRatio, sdk.OneDec().Quo(normalizedWeight))
 	newTokenBalanceOut := tokenOutRatio.Mul(tokenBalanceOut)
 
 	tokenAmountOutBeforeSwapFee := tokenBalanceOut.Sub(newTokenBalanceOut)
@@ -190,7 +190,7 @@ func calcPoolInGivenSingleOut(
 	tokenOutRatio := newTokenBalanceOut.Quo(tokenBalanceOut)
 
 	//uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;
-	poolRatio := pow(tokenOutRatio, normalizedWeight)
+	poolRatio := osmomath.Pow(tokenOutRatio, normalizedWeight)
 	newPoolSupply := poolRatio.Mul(poolSupply)
 	poolAmountInAfterExitFee := poolSupply.Sub(newPoolSupply)
 
@@ -198,141 +198,3 @@ func calcPoolInGivenSingleOut(
 	// pAi = pAiAfterExitFee/(1-exitFee)
 	return poolAmountInAfterExitFee.Quo(sdk.OneDec().Sub(exitFee))
 }
-
-/*********************************************************/
-
-// absDifferenceWithSign returns | a - b |, (a - b).sign()
-// a is mutated and returned
-func absDifferenceWithSign(a, b sdk.Dec) (sdk.Dec, bool) {
-	if a.GTE(b) {
-		return a.SubMut(b), false
-	} else {
-		return a.NegMut().AddMut(b), true
-	}
-}
-
-// func largeBasePow(base sdk.Dec, exp sdk.Dec) sdk.Dec {
-// 	// pow requires the base to be <= 2
-// }
-
-// pow computes base^(exp)
-// However since the exponent is not an integer, we must do an approximation algorithm.
-// TODO: In the future, lets add some optimized routines for common exponents, e.g. for common wIn / wOut ratios
-// Many simple exponents like 2:1 pools
-func pow(base sdk.Dec, exp sdk.Dec) sdk.Dec {
-	// Exponentiation of a negative base with an arbitrary real exponent is not closed within the reals.
-	// You can see this by recalling that `i = (-1)^(.5)`. We have to go to complex numbers to define this.
-	// (And would have to implement complex logarithms)
-	// We don't have a need for negative bases, so we don't include any such logic.
-	if !base.IsPositive() {
-		panic(fmt.Errorf("base must be greater than 0"))
-	}
-	// TODO: Remove this if we want to generalize the function,
-	// we can adjust the algorithm in this setting.
-	if base.GTE(two) {
-		panic(fmt.Errorf("base must be lesser than two"))
-	}
-
-	// We will use an approximation algorithm to compute the power.
-	// Since computing an integer power is easy, we split up the exponent into
-	// an integer component and a fractional component.
-	integer := exp.TruncateDec()
-	fractional := exp.Sub(integer)
-
-	integerPow := base.Power(uint64(integer.TruncateInt64()))
-
-	if fractional.IsZero() {
-		return integerPow
-	}
-
-	fractionalPow := powApprox(base, fractional, powPrecision)
-
-	return integerPow.Mul(fractionalPow)
-}
-
-// Contract: 0 < base <= 2
-// 0 < exp < 1
-func powApprox(base sdk.Dec, exp sdk.Dec, precision sdk.Dec) sdk.Dec {
-	if exp.IsZero() {
-		return sdk.ZeroDec()
-	}
-
-	// Common case optimization
-	// Optimize for it being equal to one-half
-	if exp.Equal(one_half) {
-		output, err := base.ApproxSqrt()
-		if err != nil {
-			panic(err)
-		}
-		return output
-	}
-	// TODO: Make an approx-equal function, and then check if exp * 3 = 1, and do a check accordingly
-
-	// We compute this via taking the maclaurin series of (1 + x)^a
-	// where x = base - 1.
-	// The maclaurin series of (1 + x)^a = sum_{k=0}^{infty} binom(a, k) x^k
-	// Binom(a, k) takes the natural continuation on the first parameter, namely that
-	// Binom(a, k) = N/D, where D = k!, and N = a(a-1)(a-2)...(a-k+1)
-	// Next we show that the absolute value of each term is less than the last term.
-	// Note that the change in term n's value vs term n + 1 is a multiplicative factor of
-	// v_n = x(a - n) / (n+1)
-	// So if |v_n| < 1, we know that each term has a lesser impact on the result than the last.
-	// For our bounds on |x| < 1, |a| < 1,
-	// it suffices to see for what n is |v_n| < 1,
-	// in the worst parameterization of x = 1, a = -1.
-	// v_n = |(-1 + epsilon - n) / (n+1)|
-	// So |v_n| is always less than 1, as n ranges over the integers.
-	//
-	// Note that term_n of the expansion is 1 * prod_{i=0}^{n-1} v_i
-	// The error if we stop the expansion at term_n is:
-	// error_n = sum_{k=n+1}^{infty} term_k
-	// At this point we further restrict a >= 0, so 0 <= a < 1.
-	// Now we take the _INCORRECT_ assumption that if term_n < p, then
-	// error_n < p.
-	// This assumption is obviously wrong.
-	// However our usages of this function don't use the full domain.
-	// With a > 0, |x| << 1, and p sufficiently low, perhaps this actually is true.
-
-	// TODO: Check with our parameterization
-	// TODO: If theres a bug, balancer is also wrong here :thonk:
-
-	base = base.Clone()
-	x, xneg := absDifferenceWithSign(base, one)
-	term := sdk.OneDec()
-	sum := sdk.OneDec()
-	negative := false
-
-	a := exp.Clone()
-	bigK := sdk.NewDec(0)
-	// TODO: Document this computation via taylor expansion
-	for i := int64(1); term.GTE(precision); i++ {
-		// At each iteration, we need two values, i and i-1.
-		// To avoid expensive big.Int allocation, we reuse bigK variable.
-		// On this line, bigK == i-1.
-		c, cneg := absDifferenceWithSign(a, bigK)
-		// On this line, bigK == i.
-		bigK.Set(sdk.NewDec(i)) // TODO: O(n) bigint allocation happens
-		term.MulMut(c).MulMut(x).QuoMut(bigK)
-
-		// a is mutated on absDifferenceWithSign, reset
-		a.Set(exp)
-
-		if term.IsZero() {
-			break
-		}
-		if xneg {
-			negative = !negative
-		}
-
-		if cneg {
-			negative = !negative
-		}
-
-		if negative {
-			sum.SubMut(term)
-		} else {
-			sum.AddMut(term)
-		}
-	}
-	return sum
-}
diff --git a/x/gamm/keeper/math_test.go b/x/gamm/keeper/math_test.go
index 7660beb69f3078294178155e240d45dab7c91541..0c400c05351f2fac0cb7daf3fb6db3e1199c7ee1 100644
--- a/x/gamm/keeper/math_test.go
+++ b/x/gamm/keeper/math_test.go
@@ -8,54 +8,6 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func TestAbsDifferenceWithSign(t *testing.T) {
-	decA, err := sdk.NewDecFromStr("3.2")
-	require.NoError(t, err)
-	decB, err := sdk.NewDecFromStr("4.3432389")
-	require.NoError(t, err)
-
-	s, b := absDifferenceWithSign(decA, decB)
-	require.True(t, b)
-
-	expectedDec, err := sdk.NewDecFromStr("1.1432389")
-	require.NoError(t, err)
-	require.Equal(t, expectedDec, s)
-}
-
-func TestPowApprox(t *testing.T) {
-	base, err := sdk.NewDecFromStr("0.8")
-	require.NoError(t, err)
-	exp, err := sdk.NewDecFromStr("0.32")
-	require.NoError(t, err)
-
-	s := powApprox(base, exp, powPrecision)
-	expectedDec, err := sdk.NewDecFromStr("0.93108385")
-	require.NoError(t, err)
-
-	require.True(
-		t,
-		expectedDec.Sub(s).Abs().LTE(powPrecision),
-		"expected value & actual value's difference should less than precision",
-	)
-}
-
-func TestPow(t *testing.T) {
-	base, err := sdk.NewDecFromStr("1.68")
-	require.NoError(t, err)
-	exp, err := sdk.NewDecFromStr("0.32")
-	require.NoError(t, err)
-
-	s := pow(base, exp)
-	expectedDec, err := sdk.NewDecFromStr("1.18058965")
-	require.NoError(t, err)
-
-	require.True(
-		t,
-		expectedDec.Sub(s).Abs().LTE(powPrecision),
-		"expected value & actual value's difference should less than precision",
-	)
-}
-
 func TestCalcSpotPrice(t *testing.T) {
 	// TODO: Change test to be table driven
 	tokenBalanceIn, err := sdk.NewDecFromStr("100")
diff --git a/x/gamm/keeper/params.go b/x/gamm/keeper/params.go
new file mode 100644
index 0000000000000000000000000000000000000000..0c633bbc056f0f556cb4367959d0159303f72a9d
--- /dev/null
+++ b/x/gamm/keeper/params.go
@@ -0,0 +1,17 @@
+package keeper
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	"github.com/osmosis-labs/osmosis/x/gamm/types"
+)
+
+// GetParams returns the total set params
+func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
+	k.paramSpace.GetParamSet(ctx, &params)
+	return params
+}
+
+// SetParams sets the total set of params
+func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
+	k.paramSpace.SetParamSet(ctx, &params)
+}
diff --git a/x/gamm/keeper/pool_service.go b/x/gamm/keeper/pool_service.go
index 0eff1a8664fd2d235d38074b3378dcca13f87a6d..70f7f1a36330179591c766d485b3e3537224726e 100644
--- a/x/gamm/keeper/pool_service.go
+++ b/x/gamm/keeper/pool_service.go
@@ -28,6 +28,13 @@ func (k Keeper) CreatePool(
 		)
 	}
 
+	// send pool creation fee to community pool
+	params := k.GetParams(ctx)
+	err := k.distrKeeper.FundCommunityPool(ctx, params.PoolCreationFee, sender)
+	if err != nil {
+		return 0, err
+	}
+
 	pool, err := k.newPool(ctx, poolParams, poolAssets, futurePoolGovernor)
 	if err != nil {
 		return 0, err
diff --git a/x/gamm/keeper/pool_service_test.go b/x/gamm/keeper/pool_service_test.go
index c5a523fa89be13a39a084d8e441bd689ea89d6fd..10447922dfb36736b25d337dbe73b3ec0cf7a089 100644
--- a/x/gamm/keeper/pool_service_test.go
+++ b/x/gamm/keeper/pool_service_test.go
@@ -19,6 +19,13 @@ var (
 )
 
 func (suite *KeeperTestSuite) TestCreatePool() {
+	params := suite.app.GAMMKeeper.GetParams(suite.ctx)
+
+	poolCreationFeeDecCoins := sdk.DecCoins{}
+	for _, coin := range params.PoolCreationFee {
+		poolCreationFeeDecCoins = poolCreationFeeDecCoins.Add(sdk.NewDecCoin(coin.Denom, coin.Amount))
+	}
+
 	func() {
 		keeper := suite.app.GAMMKeeper
 
@@ -41,6 +48,8 @@ func (suite *KeeperTestSuite) TestCreatePool() {
 	}{{
 		fn: func() {
 			keeper := suite.app.GAMMKeeper
+			prevFeePool := suite.app.DistrKeeper.GetFeePoolCommunityCoins(suite.ctx)
+			prevAcc1Bal := suite.app.BankKeeper.GetAllBalances(suite.ctx, acc1)
 			poolId, err := keeper.CreatePool(suite.ctx, acc1, types.PoolParams{
 				SwapFee: sdk.NewDecWithPrec(1, 2),
 				ExitFee: sdk.NewDecWithPrec(1, 2),
@@ -59,6 +68,20 @@ func (suite *KeeperTestSuite) TestCreatePool() {
 				fmt.Sprintf("share token should be minted as %s initially", types.InitPoolSharesSupply.String()),
 			)
 
+			// check fee is correctly sent to community pool
+			feePool := suite.app.DistrKeeper.GetFeePoolCommunityCoins(suite.ctx)
+			suite.Require().Equal(feePool, prevFeePool.Add(poolCreationFeeDecCoins...))
+
+			// check account's balance is correctly reduced
+			acc1Bal := suite.app.BankKeeper.GetAllBalances(suite.ctx, acc1)
+			suite.Require().Equal(acc1Bal.String(),
+				prevAcc1Bal.Sub(params.PoolCreationFee).
+					Sub(sdk.Coins{
+						sdk.NewCoin("bar", sdk.NewInt(10000)),
+						sdk.NewCoin("foo", sdk.NewInt(10000)),
+					}).Add(sdk.NewCoin(types.GetPoolShareDenom(pool.GetId()), types.InitPoolSharesSupply)).String(),
+			)
+
 			liquidity := suite.app.GAMMKeeper.GetTotalLiquidity(suite.ctx)
 			suite.Require().Equal("10000bar,10000foo", liquidity.String())
 		},
@@ -183,6 +206,48 @@ func (suite *KeeperTestSuite) TestCreatePool() {
 			}}, defaultFutureGovernor)
 			suite.Require().Error(err, "can't create the pool with duplicated PoolAssets")
 		},
+	}, {
+		fn: func() {
+			keeper := suite.app.GAMMKeeper
+			keeper.SetParams(suite.ctx, types.Params{
+				PoolCreationFee: sdk.Coins{},
+			})
+			_, err := keeper.CreatePool(suite.ctx, acc1, types.PoolParams{
+				SwapFee: sdk.NewDecWithPrec(1, 2),
+				ExitFee: sdk.NewDecWithPrec(1, 2),
+			}, []types.PoolAsset{{
+				Weight: sdk.NewInt(100),
+				Token:  sdk.NewCoin("foo", sdk.NewInt(10000)),
+			}, {
+				Weight: sdk.NewInt(100),
+				Token:  sdk.NewCoin("bar", sdk.NewInt(10000)),
+			}}, defaultFutureGovernor)
+			suite.Require().NoError(err)
+			pools, err := keeper.GetPools(suite.ctx)
+			suite.Require().Len(pools, 1)
+			suite.Require().NoError(err)
+		},
+	}, {
+		fn: func() {
+			keeper := suite.app.GAMMKeeper
+			keeper.SetParams(suite.ctx, types.Params{
+				PoolCreationFee: nil,
+			})
+			_, err := keeper.CreatePool(suite.ctx, acc1, types.PoolParams{
+				SwapFee: sdk.NewDecWithPrec(1, 2),
+				ExitFee: sdk.NewDecWithPrec(1, 2),
+			}, []types.PoolAsset{{
+				Weight: sdk.NewInt(100),
+				Token:  sdk.NewCoin("foo", sdk.NewInt(10000)),
+			}, {
+				Weight: sdk.NewInt(100),
+				Token:  sdk.NewCoin("bar", sdk.NewInt(10000)),
+			}}, defaultFutureGovernor)
+			suite.Require().NoError(err)
+			pools, err := keeper.GetPools(suite.ctx)
+			suite.Require().Len(pools, 1)
+			suite.Require().NoError(err)
+		},
 	}}
 
 	for _, test := range tests {
@@ -194,6 +259,7 @@ func (suite *KeeperTestSuite) TestCreatePool() {
 				suite.ctx,
 				acc,
 				sdk.NewCoins(
+					sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 					sdk.NewCoin("foo", sdk.NewInt(10000000)),
 					sdk.NewCoin("bar", sdk.NewInt(10000000)),
 					sdk.NewCoin("baz", sdk.NewInt(10000000)),
@@ -281,6 +347,7 @@ func (suite *KeeperTestSuite) TestJoinPool() {
 				suite.ctx,
 				acc,
 				sdk.NewCoins(
+					sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 					sdk.NewCoin("foo", sdk.NewInt(10000000)),
 					sdk.NewCoin("bar", sdk.NewInt(10000000)),
 					sdk.NewCoin("baz", sdk.NewInt(10000000)),
@@ -389,6 +456,7 @@ func (suite *KeeperTestSuite) TestExitPool() {
 				suite.ctx,
 				acc,
 				sdk.NewCoins(
+					sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 					sdk.NewCoin("foo", sdk.NewInt(10000000)),
 					sdk.NewCoin("bar", sdk.NewInt(10000000)),
 					sdk.NewCoin("baz", sdk.NewInt(10000000)),
@@ -436,6 +504,7 @@ func (suite *KeeperTestSuite) TestActivePool() {
 				suite.ctx,
 				acc,
 				sdk.NewCoins(
+					sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 					sdk.NewCoin("foo", sdk.NewInt(10000000)),
 					sdk.NewCoin("bar", sdk.NewInt(10000000)),
 					sdk.NewCoin("baz", sdk.NewInt(10000000)),
diff --git a/x/gamm/keeper/swap_test.go b/x/gamm/keeper/swap_test.go
index aa3a4423d3609024f0bb2ec56d53f45fdc6bdc23..8fa6e880dc987b230184239b135fb6f6696ce00d 100644
--- a/x/gamm/keeper/swap_test.go
+++ b/x/gamm/keeper/swap_test.go
@@ -218,6 +218,7 @@ func (suite *KeeperTestSuite) TestActivePoolSwap() {
 				suite.ctx,
 				acc,
 				sdk.NewCoins(
+					sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 					sdk.NewCoin("foo", sdk.NewInt(10000000)),
 					sdk.NewCoin("bar", sdk.NewInt(10000000)),
 					sdk.NewCoin("baz", sdk.NewInt(10000000)),
diff --git a/x/gamm/module.go b/x/gamm/module.go
index f3cfb208d434a349642e3f5793ec81c7f841a87f..ff134856c868a558a48cc4539cd39c19bf3c5065 100644
--- a/x/gamm/module.go
+++ b/x/gamm/module.go
@@ -3,6 +3,7 @@ package gamm
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"math/rand"
 
 	"github.com/cosmos/cosmos-sdk/client"
@@ -45,12 +46,16 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
 // DefaultGenesis returns default genesis state as raw bytes for the gamm
 // module.
 func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage {
-	return nil
+	return cdc.MustMarshalJSON(types.DefaultGenesis())
 }
 
 // ValidateGenesis performs genesis state validation for the gamm module.
 func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error {
-	return nil
+	var genState types.GenesisState
+	if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
+		return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
+	}
+	return genState.Validate()
 }
 
 //---------------------------------------
diff --git a/x/gamm/simulation/operations.go b/x/gamm/simulation/operations.go
index 63c34f5deb80d4b7365b2506f48e0ddc6c7cb24f..3745a606e2d7bfd75cf8223d82e963093696afd3 100644
--- a/x/gamm/simulation/operations.go
+++ b/x/gamm/simulation/operations.go
@@ -154,6 +154,12 @@ func SimulateMsgCreatePool(ak stakingTypes.AccountKeeper, bk stakingTypes.BankKe
 		for i := range balances {
 			denoms[i] = balances[i].Denom
 		}
+
+		// set the pool params to set the pool creation fee to dust amount of denom
+		k.SetParams(ctx, types.Params{
+			PoolCreationFee: sdk.Coins{sdk.NewInt64Coin(denoms[0], 1)},
+		})
+
 		// futurePoolGovernor := genFuturePoolGovernor(r, simAccount.Address, denoms)
 		msg := types.MsgCreatePool{
 			Sender:             simAccount.Address.String(),
@@ -184,7 +190,7 @@ func SimulateMsgSwapExactAmountIn(ak stakingTypes.AccountKeeper, bk stakingTypes
 
 		coin := simCoins[r.Intn(len(simCoins))]
 		// Use under 0.5% of the account balance
-              // TODO: Make like a 33% probability of using a ton of balance 
+		// TODO: Make like a 33% probability of using a ton of balance
 		amt, _ := simtypes.RandPositiveInt(r, coin.Amount.QuoRaw(200))
 
 		tokenIn := sdk.Coin{
diff --git a/x/gamm/spec/04_params.md b/x/gamm/spec/04_params.md
new file mode 100644
index 0000000000000000000000000000000000000000..4bde2ebb07bdfb936154beeffdbff0db2742bab7
--- /dev/null
+++ b/x/gamm/spec/04_params.md
@@ -0,0 +1,14 @@
+<!--
+order: 4
+-->
+
+# Parameters
+
+The gamm module contains the following parameters:
+
+| Key             | Type      | Example           |
+| --------------- | --------- | ----------------- |
+| PoolCreationFee | sdk.Coins | "1000000000uosmo" |
+
+Note:
+PoolCreationFee is the amount of coins paid to community pool at the time of pool creation which is introduced to prevent spam pool creation.
diff --git a/x/gamm/types/expected_keepers.go b/x/gamm/types/expected_keepers.go
index e9d8238cb38825b655cbfdfa0049f2b181a8e205..f07b8da1222637b14bcc51d77a8a3c1bbded4bbe 100644
--- a/x/gamm/types/expected_keepers.go
+++ b/x/gamm/types/expected_keepers.go
@@ -56,3 +56,8 @@ type BankKeeper interface {
 	UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
 	DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
 }
+
+// DistrKeeper defines the contract needed to be fulfilled for distribution keeper
+type DistrKeeper interface {
+	FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error
+}
diff --git a/x/gamm/types/genesis.go b/x/gamm/types/genesis.go
new file mode 100644
index 0000000000000000000000000000000000000000..47b2102730e6fb9f35d9aadc94ccb10ad7d022fe
--- /dev/null
+++ b/x/gamm/types/genesis.go
@@ -0,0 +1,23 @@
+package types
+
+import (
+	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
+)
+
+// DefaultGenesis creates a default GenesisState object
+func DefaultGenesis() *GenesisState {
+	return &GenesisState{
+		Pools:          []*codectypes.Any{},
+		NextPoolNumber: 1,
+		Params:         DefaultParams(),
+	}
+}
+
+// Validate performs basic genesis state validation returning an error upon any
+// failure.
+func (gs GenesisState) Validate() error {
+	if err := gs.Params.Validate(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/x/gamm/types/genesis.pb.go b/x/gamm/types/genesis.pb.go
index 4022360b6bf763be9dcade0429458a82f3ee5529..66dd5a3348d943804fd7c90bcce1d77aef1d06c0 100644
--- a/x/gamm/types/genesis.pb.go
+++ b/x/gamm/types/genesis.pb.go
@@ -5,7 +5,9 @@ package types
 
 import (
 	fmt "fmt"
-	types "github.com/cosmos/cosmos-sdk/codec/types"
+	types1 "github.com/cosmos/cosmos-sdk/codec/types"
+	github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
+	types "github.com/cosmos/cosmos-sdk/types"
 	_ "github.com/gogo/protobuf/gogoproto"
 	proto "github.com/gogo/protobuf/proto"
 	_ "github.com/regen-network/cosmos-proto"
@@ -25,17 +27,63 @@ var _ = math.Inf
 // proto package needs to be updated.
 const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
+// Params holds parameters for the incentives module
+type Params struct {
+	PoolCreationFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=pool_creation_fee,json=poolCreationFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"pool_creation_fee" yaml:"pool_creation_fee"`
+}
+
+func (m *Params) Reset()         { *m = Params{} }
+func (m *Params) String() string { return proto.CompactTextString(m) }
+func (*Params) ProtoMessage()    {}
+func (*Params) Descriptor() ([]byte, []int) {
+	return fileDescriptor_5a324eb7f1dd793e, []int{0}
+}
+func (m *Params) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Params.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *Params) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Params.Merge(m, src)
+}
+func (m *Params) XXX_Size() int {
+	return m.Size()
+}
+func (m *Params) XXX_DiscardUnknown() {
+	xxx_messageInfo_Params.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Params proto.InternalMessageInfo
+
+func (m *Params) GetPoolCreationFee() github_com_cosmos_cosmos_sdk_types.Coins {
+	if m != nil {
+		return m.PoolCreationFee
+	}
+	return nil
+}
+
 // GenesisState defines the gamm module's genesis state.
 type GenesisState struct {
-	Pools          []*types.Any `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
-	NextPoolNumber uint64       `protobuf:"varint,2,opt,name=next_pool_number,json=nextPoolNumber,proto3" json:"next_pool_number,omitempty"`
+	Pools          []*types1.Any `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
+	NextPoolNumber uint64        `protobuf:"varint,2,opt,name=next_pool_number,json=nextPoolNumber,proto3" json:"next_pool_number,omitempty"`
+	Params         Params        `protobuf:"bytes,3,opt,name=params,proto3" json:"params"`
 }
 
 func (m *GenesisState) Reset()         { *m = GenesisState{} }
 func (m *GenesisState) String() string { return proto.CompactTextString(m) }
 func (*GenesisState) ProtoMessage()    {}
 func (*GenesisState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_5a324eb7f1dd793e, []int{0}
+	return fileDescriptor_5a324eb7f1dd793e, []int{1}
 }
 func (m *GenesisState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -64,7 +112,7 @@ func (m *GenesisState) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_GenesisState proto.InternalMessageInfo
 
-func (m *GenesisState) GetPools() []*types.Any {
+func (m *GenesisState) GetPools() []*types1.Any {
 	if m != nil {
 		return m.Pools
 	}
@@ -78,7 +126,15 @@ func (m *GenesisState) GetNextPoolNumber() uint64 {
 	return 0
 }
 
+func (m *GenesisState) GetParams() Params {
+	if m != nil {
+		return m.Params
+	}
+	return Params{}
+}
+
 func init() {
+	proto.RegisterType((*Params)(nil), "osmosis.gamm.Params")
 	proto.RegisterType((*GenesisState)(nil), "osmosis.gamm.GenesisState")
 }
 
@@ -87,24 +143,69 @@ func init() {
 }
 
 var fileDescriptor_5a324eb7f1dd793e = []byte{
-	// 259 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xca, 0x2f, 0xce, 0xcd,
-	0x2f, 0xce, 0x2c, 0xd6, 0x4f, 0x4f, 0xcc, 0xcd, 0xd5, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34,
-	0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2,
-	0x81, 0xaa, 0xd1, 0x03, 0xa9, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xe8, 0x83, 0x58,
-	0x10, 0x35, 0x52, 0x92, 0xe9, 0xf9, 0xf9, 0xe9, 0x39, 0xa9, 0xfa, 0x60, 0x5e, 0x52, 0x69, 0x9a,
-	0x7e, 0x62, 0x5e, 0x25, 0x4c, 0x2a, 0x19, 0xac, 0x3f, 0x1e, 0xa2, 0x07, 0xc2, 0x81, 0x48, 0x29,
-	0xe5, 0x73, 0xf1, 0xb8, 0x43, 0xac, 0x0a, 0x2e, 0x49, 0x2c, 0x49, 0x15, 0x32, 0xe5, 0x62, 0x2d,
-	0xc8, 0xcf, 0xcf, 0x29, 0x96, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x12, 0xd1, 0x83, 0x98, 0xaa,
-	0x07, 0x33, 0x55, 0xcf, 0x31, 0xaf, 0xd2, 0x89, 0xf3, 0xd4, 0x16, 0x5d, 0xd6, 0x80, 0xfc, 0xfc,
-	0x1c, 0xcf, 0x20, 0x88, 0x6a, 0x21, 0x0d, 0x2e, 0x81, 0xbc, 0xd4, 0x8a, 0x92, 0x78, 0x10, 0x2f,
-	0x3e, 0xaf, 0x34, 0x37, 0x29, 0xb5, 0x48, 0x82, 0x49, 0x81, 0x51, 0x83, 0x25, 0x88, 0x0f, 0x24,
-	0x0e, 0x52, 0xeb, 0x07, 0x16, 0x75, 0x72, 0x3b, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6,
-	0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39,
-	0x86, 0x28, 0x9d, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xa8, 0x7f,
-	0x75, 0x73, 0x12, 0x93, 0x8a, 0x61, 0x1c, 0xfd, 0x0a, 0x48, 0x10, 0x95, 0x54, 0x16, 0xa4, 0x16,
-	0x27, 0xb1, 0x81, 0x5d, 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x16, 0xaa, 0x73, 0x98, 0x3f,
-	0x01, 0x00, 0x00,
+	// 390 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x3d, 0xeb, 0xd3, 0x40,
+	0x18, 0xcf, 0xf9, 0xff, 0xb7, 0x60, 0x2c, 0xbe, 0x84, 0x0e, 0x69, 0x87, 0xb4, 0x64, 0xca, 0x60,
+	0xef, 0x68, 0xc5, 0xc5, 0xcd, 0x14, 0x2a, 0x82, 0x48, 0x89, 0x9b, 0x4b, 0xb8, 0xc4, 0x6b, 0x0c,
+	0x26, 0xf7, 0x84, 0xdc, 0x55, 0x9a, 0x6f, 0x21, 0xb8, 0xbb, 0xb8, 0x39, 0xfb, 0x21, 0x8a, 0x53,
+	0x47, 0xa7, 0x2a, 0xed, 0x37, 0xf0, 0x13, 0xc8, 0xbd, 0x54, 0x0a, 0x4e, 0xc9, 0xef, 0x7e, 0x2f,
+	0xf7, 0x3c, 0xbf, 0xc4, 0x0d, 0x41, 0xd4, 0x20, 0x4a, 0x41, 0x0a, 0x5a, 0xd7, 0xe4, 0xe3, 0x3c,
+	0x63, 0x92, 0xce, 0x49, 0xc1, 0x38, 0x13, 0xa5, 0xc0, 0x4d, 0x0b, 0x12, 0xbc, 0x81, 0xd5, 0x60,
+	0xa5, 0x19, 0x0f, 0x0b, 0x28, 0x40, 0x13, 0x44, 0xbd, 0x19, 0xcd, 0x78, 0x54, 0x00, 0x14, 0x15,
+	0x23, 0x1a, 0x65, 0xdb, 0x0d, 0xa1, 0xbc, 0xbb, 0x50, 0xb9, 0xf6, 0xa7, 0xc6, 0x63, 0x80, 0xa5,
+	0x02, 0x83, 0x48, 0x46, 0x05, 0xfb, 0x77, 0x79, 0x0e, 0x25, 0x37, 0x7c, 0xf8, 0x05, 0xb9, 0xfd,
+	0x35, 0x6d, 0x69, 0x2d, 0xbc, 0xcf, 0xc8, 0x7d, 0xd4, 0x00, 0x54, 0x69, 0xde, 0x32, 0x2a, 0x4b,
+	0xe0, 0xe9, 0x86, 0x31, 0x1f, 0x4d, 0x6f, 0xa2, 0x7b, 0x8b, 0x11, 0xb6, 0xa9, 0x2a, 0x07, 0xdb,
+	0x1c, 0xbc, 0x84, 0x92, 0xc7, 0xaf, 0xf6, 0xc7, 0x89, 0xf3, 0xe7, 0x38, 0xf1, 0x3b, 0x5a, 0x57,
+	0xcf, 0xc2, 0xff, 0x12, 0xc2, 0x6f, 0xbf, 0x26, 0x51, 0x51, 0xca, 0xf7, 0xdb, 0x0c, 0xe7, 0x50,
+	0xdb, 0xf1, 0xec, 0x63, 0x26, 0xde, 0x7d, 0x20, 0xb2, 0x6b, 0x98, 0xd0, 0x61, 0x22, 0x79, 0xa0,
+	0xfc, 0x4b, 0x6b, 0x5f, 0x31, 0x16, 0x7e, 0x45, 0xee, 0xe0, 0x85, 0x29, 0xeb, 0x8d, 0xa4, 0x92,
+	0x79, 0x4f, 0xdd, 0x9e, 0xd2, 0x08, 0x3b, 0xd9, 0x10, 0x9b, 0x5e, 0xf0, 0xa5, 0x17, 0xfc, 0x9c,
+	0x77, 0xf1, 0xdd, 0x1f, 0xdf, 0x67, 0xbd, 0x35, 0x40, 0xf5, 0x32, 0x31, 0x6a, 0x2f, 0x72, 0x1f,
+	0x72, 0xb6, 0x93, 0xa9, 0x9e, 0x8f, 0x6f, 0xeb, 0x8c, 0xb5, 0xfe, 0x9d, 0x29, 0x8a, 0x6e, 0x93,
+	0xfb, 0xea, 0x5c, 0x69, 0x5f, 0xeb, 0x53, 0x6f, 0xe1, 0xf6, 0x1b, 0xdd, 0x88, 0x7f, 0x33, 0x45,
+	0xfa, 0x86, 0xeb, 0xaf, 0x83, 0x4d, 0x5b, 0xf1, 0xad, 0x5a, 0x3b, 0xb1, 0xca, 0x78, 0xb5, 0x3f,
+	0x05, 0xe8, 0x70, 0x0a, 0xd0, 0xef, 0x53, 0x80, 0x3e, 0x9d, 0x03, 0xe7, 0x70, 0x0e, 0x9c, 0x9f,
+	0xe7, 0xc0, 0x79, 0xfb, 0xf8, 0x6a, 0x75, 0x9b, 0x33, 0xab, 0x68, 0x26, 0x2e, 0x80, 0xec, 0xcc,
+	0x8f, 0xa1, 0x4b, 0xc8, 0xfa, 0x7a, 0x8b, 0x27, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x6a,
+	0x74, 0x74, 0x35, 0x02, 0x00, 0x00,
+}
+
+func (m *Params) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Params) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.PoolCreationFee) > 0 {
+		for iNdEx := len(m.PoolCreationFee) - 1; iNdEx >= 0; iNdEx-- {
+			{
+				size, err := m.PoolCreationFee[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+				if err != nil {
+					return 0, err
+				}
+				i -= size
+				i = encodeVarintGenesis(dAtA, i, uint64(size))
+			}
+			i--
+			dAtA[i] = 0xa
+		}
+	}
+	return len(dAtA) - i, nil
 }
 
 func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@@ -127,6 +228,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	{
+		size, err := m.Params.MarshalToSizedBuffer(dAtA[:i])
+		if err != nil {
+			return 0, err
+		}
+		i -= size
+		i = encodeVarintGenesis(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x1a
 	if m.NextPoolNumber != 0 {
 		i = encodeVarintGenesis(dAtA, i, uint64(m.NextPoolNumber))
 		i--
@@ -160,6 +271,21 @@ func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int {
 	dAtA[offset] = uint8(v)
 	return base
 }
+func (m *Params) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if len(m.PoolCreationFee) > 0 {
+		for _, e := range m.PoolCreationFee {
+			l = e.Size()
+			n += 1 + l + sovGenesis(uint64(l))
+		}
+	}
+	return n
+}
+
 func (m *GenesisState) Size() (n int) {
 	if m == nil {
 		return 0
@@ -175,6 +301,8 @@ func (m *GenesisState) Size() (n int) {
 	if m.NextPoolNumber != 0 {
 		n += 1 + sovGenesis(uint64(m.NextPoolNumber))
 	}
+	l = m.Params.Size()
+	n += 1 + l + sovGenesis(uint64(l))
 	return n
 }
 
@@ -184,6 +312,93 @@ func sovGenesis(x uint64) (n int) {
 func sozGenesis(x uint64) (n int) {
 	return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
 }
+func (m *Params) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowGenesis
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Params: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field PoolCreationFee", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGenesis
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.PoolCreationFee = append(m.PoolCreationFee, types.Coin{})
+			if err := m.PoolCreationFee[len(m.PoolCreationFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipGenesis(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			if (iNdEx + skippy) < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *GenesisState) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
@@ -242,7 +457,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Pools = append(m.Pools, &types.Any{})
+			m.Pools = append(m.Pools, &types1.Any{})
 			if err := m.Pools[len(m.Pools)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 				return err
 			}
@@ -266,6 +481,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error {
 					break
 				}
 			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGenesis
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthGenesis
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipGenesis(dAtA[iNdEx:])
diff --git a/x/gamm/types/params.go b/x/gamm/types/params.go
new file mode 100644
index 0000000000000000000000000000000000000000..59aeef798e320c53b66a31a1935b12446a5cc896
--- /dev/null
+++ b/x/gamm/types/params.go
@@ -0,0 +1,62 @@
+package types
+
+import (
+	"fmt"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
+	appparams "github.com/osmosis-labs/osmosis/app/params"
+)
+
+// Parameter store keys
+var (
+	KeyPoolCreationFee = []byte("PoolCreationFee")
+)
+
+// ParamTable for gamm module.
+func ParamKeyTable() paramtypes.KeyTable {
+	return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
+}
+
+func NewParams(poolCreationFee sdk.Coins) Params {
+	return Params{
+		PoolCreationFee: poolCreationFee,
+	}
+}
+
+// default gamm module parameters
+func DefaultParams() Params {
+	return Params{
+		PoolCreationFee: sdk.Coins{sdk.NewInt64Coin(appparams.BaseCoinUnit, 1000_000_000)}, // 1000 OSMO
+	}
+}
+
+// validate params
+func (p Params) Validate() error {
+	if err := validatePoolCreationFee(p.PoolCreationFee); err != nil {
+		return err
+	}
+
+	return nil
+
+}
+
+// Implements params.ParamSet
+func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
+	return paramtypes.ParamSetPairs{
+		paramtypes.NewParamSetPair(KeyPoolCreationFee, &p.PoolCreationFee, validatePoolCreationFee),
+	}
+}
+
+func validatePoolCreationFee(i interface{}) error {
+	v, ok := i.(sdk.Coins)
+	if !ok {
+		return fmt.Errorf("invalid parameter type: %T", i)
+	}
+
+	if v.Validate() != nil {
+		return fmt.Errorf("invalid pool creation fee: %+v", i)
+	}
+
+	return nil
+}
diff --git a/x/incentives/genesis_test.go b/x/incentives/genesis_test.go
index 96d4ad47235b44f244c93b6ebec4f971ef1c6c9d..6a92f10d0341934e5e7e64085e82e89133142055 100644
--- a/x/incentives/genesis_test.go
+++ b/x/incentives/genesis_test.go
@@ -53,6 +53,9 @@ func TestIncentivesInitGenesis(t *testing.T) {
 	app := simapp.Setup(false)
 	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
 
+	validateGenesis := types.DefaultGenesis().Params.Validate()
+	require.NoError(t, validateGenesis)
+
 	coins := sdk.Coins{sdk.NewInt64Coin("stake", 10000)}
 	startTime := time.Now()
 	distrTo := lockuptypes.QueryCondition{
@@ -87,4 +90,5 @@ func TestIncentivesInitGenesis(t *testing.T) {
 	gauges := app.IncentivesKeeper.GetGauges(ctx)
 	require.Len(t, gauges, 1)
 	require.Equal(t, gauges[0], gauge)
+
 }
diff --git a/x/incentives/types/params.go b/x/incentives/types/params.go
index e521860dd5e681b472a836cd1e45a103f1604544..bbbd4027b7129b508607b670266fafffc7d68e0a 100644
--- a/x/incentives/types/params.go
+++ b/x/incentives/types/params.go
@@ -5,6 +5,7 @@ import (
 
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
+	epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types"
 )
 
 // Parameter store keys
@@ -35,7 +36,7 @@ func DefaultParams() Params {
 
 // validate params
 func (p Params) Validate() error {
-	if err := validateDistrEpochIdentifier(p.DistrEpochIdentifier); err != nil {
+	if err := epochtypes.ValidateEpochIdentifierInterface(p.DistrEpochIdentifier); err != nil {
 		return err
 	}
 	if err := validateMinAutostakingRate(p.MinAutostakingRate); err != nil {
@@ -43,7 +44,6 @@ func (p Params) Validate() error {
 	}
 
 	return nil
-
 }
 
 // Implements params.ParamSet
@@ -63,7 +63,6 @@ func validateDistrEpochIdentifier(i interface{}) error {
 	if v == "" {
 		return fmt.Errorf("empty distribution epoch identifier: %+v", i)
 	}
-
 	return nil
 }
 
diff --git a/x/mint/genesis_test.go b/x/mint/genesis_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2b4bafe61f8c3aa9069cb34ad5594ba55f85cee1
--- /dev/null
+++ b/x/mint/genesis_test.go
@@ -0,0 +1,27 @@
+package mint_test
+
+import (
+	"testing"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	simapp "github.com/osmosis-labs/osmosis/app"
+	"github.com/osmosis-labs/osmosis/x/mint/types"
+	"github.com/stretchr/testify/require"
+	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
+)
+
+func TestMintInitGenesis(t *testing.T) {
+	app := simapp.Setup(false)
+	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
+
+	validateGenesis := types.ValidateGenesis(*types.DefaultGenesisState())
+	require.NoError(t, validateGenesis)
+
+	developerAccount := app.AccountKeeper.GetModuleAddress(types.DeveloperVestingModuleAcctName)
+	initialVestingCoins := app.BankKeeper.GetBalance(ctx, developerAccount, sdk.DefaultBondDenom)
+
+	expectedVestingCoins, ok := sdk.NewIntFromString("225000000000000")
+	require.True(t, ok)
+	require.Equal(t, expectedVestingCoins, initialVestingCoins.Amount)
+	require.Equal(t, int64(0), app.MintKeeper.GetLastHalvenEpochNum(ctx))
+}
diff --git a/x/mint/types/params.go b/x/mint/types/params.go
index 388945ada5862923631617519f5e5aca7a33e3f2..9abec74b04240af4cf7ab485bcd9f07b2f5e5a57 100644
--- a/x/mint/types/params.go
+++ b/x/mint/types/params.go
@@ -7,6 +7,7 @@ import (
 
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
+	epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types"
 	yaml "gopkg.in/yaml.v2"
 )
 
@@ -72,7 +73,7 @@ func (p Params) Validate() error {
 	if err := validateGenesisEpochProvisions(p.GenesisEpochProvisions); err != nil {
 		return err
 	}
-	if err := validateEpochIdentifier(p.EpochIdentifier); err != nil {
+	if err := epochtypes.ValidateEpochIdentifierInterface(p.EpochIdentifier); err != nil {
 		return err
 	}
 	if err := validateReductionPeriodInEpochs(p.ReductionPeriodInEpochs); err != nil {
@@ -105,7 +106,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
 	return paramtypes.ParamSetPairs{
 		paramtypes.NewParamSetPair(KeyMintDenom, &p.MintDenom, validateMintDenom),
 		paramtypes.NewParamSetPair(KeyGenesisEpochProvisions, &p.GenesisEpochProvisions, validateGenesisEpochProvisions),
-		paramtypes.NewParamSetPair(KeyEpochIdentifier, &p.EpochIdentifier, validateEpochIdentifier),
+		paramtypes.NewParamSetPair(KeyEpochIdentifier, &p.EpochIdentifier, epochtypes.ValidateEpochIdentifierInterface),
 		paramtypes.NewParamSetPair(KeyReductionPeriodInEpochs, &p.ReductionPeriodInEpochs, validateReductionPeriodInEpochs),
 		paramtypes.NewParamSetPair(KeyReductionFactor, &p.ReductionFactor, validateReductionFactor),
 		paramtypes.NewParamSetPair(KeyPoolAllocationRatio, &p.DistributionProportions, validateDistributionProportions),
@@ -143,19 +144,6 @@ func validateGenesisEpochProvisions(i interface{}) error {
 	return nil
 }
 
-func validateEpochIdentifier(i interface{}) error {
-	v, ok := i.(string)
-	if !ok {
-		return fmt.Errorf("invalid parameter type: %T", i)
-	}
-
-	if v == "" {
-		return fmt.Errorf("empty distribution epoch identifier: %+v", i)
-	}
-
-	return nil
-}
-
 func validateReductionPeriodInEpochs(i interface{}) error {
 	v, ok := i.(int64)
 	if !ok {
diff --git a/x/pool-incentives/client/cli/query.go b/x/pool-incentives/client/cli/query.go
index d91d16d784ea294fb777c7bd948bdde84c218996..a0cb6c049f7a0e7b2eaca2d8bee75e09d334ff4c 100644
--- a/x/pool-incentives/client/cli/query.go
+++ b/x/pool-incentives/client/cli/query.go
@@ -25,6 +25,10 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
 
 	cmd.AddCommand(
 		GetCmdGaugeIds(),
+		GetCmdDistrInfo(),
+		GetCmdParams(),
+		GetCmdLockableDurations(),
+		GetCmdIncentivizedPools(),
 	)
 
 	return cmd
@@ -73,7 +77,7 @@ $ %s query pool-incentives gauge-ids 1
 	return cmd
 }
 
-// GetCmdDistrInfo takes the pool id and returns the matching gauge ids and durations
+// GetCmdDistrInfo takes the pool id and returns the matching gauge ids and weights
 func GetCmdDistrInfo() *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "distr-info",
diff --git a/x/pool-incentives/keeper/keeper_test.go b/x/pool-incentives/keeper/keeper_test.go
index d32789e84120619f02de2aef9ec9b8634a1c988d..bdf3229aeb0e8739f07b64c270b29c84cb4722a8 100644
--- a/x/pool-incentives/keeper/keeper_test.go
+++ b/x/pool-incentives/keeper/keeper_test.go
@@ -52,6 +52,7 @@ func (suite *KeeperTestSuite) preparePoolWithPoolParams(poolParams gammtypes.Poo
 			suite.ctx,
 			acc,
 			sdk.NewCoins(
+				sdk.NewCoin("uosmo", sdk.NewInt(10000000000)),
 				sdk.NewCoin("foo", sdk.NewInt(10000000)),
 				sdk.NewCoin("bar", sdk.NewInt(10000000)),
 				sdk.NewCoin("baz", sdk.NewInt(10000000)),