Repository: osmosis-labs/osmosis
Pull request #393 (2021-08-02 13:59:32)

Add documentation for gamm module
This pull request adds the documentation for gamm module, specifically the concepts of following.

- Pool and share
- Swap
- Multihop


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..0cf505b37
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,40 @@
+# This is a basic workflow that is manually triggered
+
+name: compile osmosis
+
+# Controls when the action will run. Workflow runs when manually triggered using the UI
+# or API.
+on: [push, pull_request, workflow_dispatch]
+
+# This workflow makes x86_64 binaries for mac, windows, and linux.
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        arch: [amd64, arm64]
+        targetos: [darwin, linux]
+        include:
+          - targetos: windows
+            arch: amd64
+    name: osmosis ${{ matrix.arch }} for ${{ matrix.targetos }}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-go@v2.1.3
+        with: 
+          go-version: '^1.17'
+        env:
+          GOOS: ${{ matrix.targetos }}
+          GOARCH: ${{ matrix.arch }}
+
+      - name: Compile osmosis
+        run: |
+          go mod download
+          cd cmd/osmosisd
+          go build .
+        
+      - uses: actions/upload-artifact@v2
+        with:
+          name: osmosisd ${{ matrix.targetos }} ${{ matrix.arch }}
+          path: cmd/osmosisd/osmosisd
diff --git a/app/app.go b/app/app.go
index a9f2fdcdb..b8b7209b8 100644
--- a/app/app.go
+++ b/app/app.go
@@ -169,7 +169,7 @@ var (
 
 var _ App = (*OsmosisApp)(nil)
 
-// Gaia extends an ABCI application, but with most of its parameters exported.
+// Osmosis extends an ABCI application, but with most of its parameters exported.
 // They are exported for convenience in creating helper functions, as object
 // capabilities aren't needed for testing.
 type OsmosisApp struct {
@@ -227,7 +227,7 @@ func init() {
 	DefaultNodeHome = filepath.Join(userHomeDir, ".osmosisd")
 }
 
-// NewOsmosis returns a reference to an initialized Gaia.
+// NewOsmosis returns a reference to an initialized Osmosis.
 func NewOsmosisApp(
 	logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool,
 	homePath string, invCheckPeriod uint, encodingConfig appparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp),
@@ -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)
@@ -495,7 +498,7 @@ func NewOsmosisApp(
 		// Note: epochs' begin should be "real" start of epochs, we keep epochs beginblock at the beginning
 		epochstypes.ModuleName,
 		upgradetypes.ModuleName, minttypes.ModuleName, poolincentivestypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName,
-		evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName,
+		evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, capabilitytypes.ModuleName,
 	)
 	app.mm.SetOrderEndBlockers(
 		lockuptypes.ModuleName,
@@ -517,6 +520,7 @@ func NewOsmosisApp(
 		claimtypes.ModuleName,
 		incentivestypes.ModuleName,
 		epochstypes.ModuleName,
+		gammtypes.ModuleName,
 	)
 
 	app.mm.RegisterInvariants(&app.CrisisKeeper)
@@ -603,6 +607,7 @@ func (app *OsmosisApp) Name() string { return app.BaseApp.Name() }
 
 // BeginBlocker application updates every begin block
 func (app *OsmosisApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
+	forks(ctx, app)
 	return app.mm.BeginBlock(ctx, req)
 }
 
@@ -770,6 +775,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/app/forks.go b/app/forks.go
new file mode 100644
index 000000000..516feedd6
--- /dev/null
+++ b/app/forks.go
@@ -0,0 +1,47 @@
+package app
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+func forks(ctx sdk.Context, app *OsmosisApp) {
+	switch ctx.BlockHeight() {
+	case 712000:
+		fix_min_deposit_denom(ctx, app)
+		fix_min_commision_rate(ctx, app)
+	default:
+		// do nothing
+		return
+	}
+}
+
+// Fixes an error where minimum deposit was set to "500 osmo"
+// This denom does not exist, which makes it impossible for a proposal to go to a vote
+func fix_min_deposit_denom(ctx sdk.Context, app *OsmosisApp) {
+	var params = app.GovKeeper.GetDepositParams(ctx)
+	params.MinDeposit = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(500000000)))
+	app.GovKeeper.SetDepositParams(ctx, params)
+}
+
+// Fixes an error where validators can be created with a commission rate
+// less than the network minimum rate.
+func fix_min_commision_rate(ctx sdk.Context, app *OsmosisApp) {
+	// Upgrade every validators min-commission rate
+	validators := app.StakingKeeper.GetAllValidators(ctx)
+	minCommissionRate := app.StakingKeeper.GetParams(ctx).MinCommissionRate
+	for _, v := range validators {
+		if v.Commission.Rate.LT(minCommissionRate) {
+			comm, err := app.StakingKeeper.MustUpdateValidatorCommission(
+				ctx, v, minCommissionRate)
+			if err != nil {
+				panic(err)
+			}
+			v.Commission = comm
+
+			// call the before-modification hook since we're about to update the commission
+			app.StakingKeeper.BeforeValidatorModified(ctx, v.GetOperator())
+
+			app.StakingKeeper.SetValidator(ctx, v)
+		}
+	}
+}
diff --git a/cmd/osmosisd/cmd/airdrop.go b/cmd/osmosisd/cmd/airdrop.go
index cf9e28166..0117b05a1 100644
--- a/cmd/osmosisd/cmd/airdrop.go
+++ b/cmd/osmosisd/cmd/airdrop.go
@@ -69,9 +69,9 @@ func ExportAirdropSnapshotCmd() *cobra.Command {
 Sample genesis file:
 	https://raw.githubusercontent.com/cephalopodequipment/cosmoshub-3/master/genesis.json
 Example:
-	osmosisd export-airdrop-genesis uatom ~/.gaiad/config/genesis.json ../snapshot.json --osmo-supply=100000000000000
+	osmosisd export-airdrop-genesis uatom ~/.osmosisd/config/genesis.json ../snapshot.json --osmo-supply=100000000000000
 	- Check input genesis:
-		file is at ~/.gaiad/config/genesis.json
+		file is at ~/.osmosisd/config/genesis.json
 	- Snapshot
 		file is at "../snapshot.json"
 `,
diff --git a/cmd/osmosisd/cmd/genesis.go b/cmd/osmosisd/cmd/genesis.go
index be73ffd27..53307ea20 100644
--- a/cmd/osmosisd/cmd/genesis.go
+++ b/cmd/osmosisd/cmd/genesis.go
@@ -46,7 +46,7 @@ Examples include:
 Example:
 	osmosisd prepare-genesis mainnet osmosis-1
 	- Check input genesis:
-		file is at ~/.gaiad/config/genesis.json
+		file is at ~/.osmosisd/config/genesis.json
 `,
 		Args: cobra.ExactArgs(2),
 		RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/osmosisd/cmd/init.go b/cmd/osmosisd/cmd/init.go
index 9178b1235..70bf8ce48 100644
--- a/cmd/osmosisd/cmd/init.go
+++ b/cmd/osmosisd/cmd/init.go
@@ -7,6 +7,8 @@ import (
 	"os"
 	"path/filepath"
 	"time"
+	"strings"
+
 
 	"github.com/cosmos/go-bip39"
 	"github.com/pkg/errors"
@@ -80,6 +82,21 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
 			serverCtx := server.GetServerContextFromCmd(cmd)
 			config := serverCtx.Config
 
+
+			//This is a slice of SEED nodes, not peers.  They must be configured in seed mode. 
+			//An easy way to run a lightweight seed node is to use tenderseed: github.com/binaryholdings/tenderseed
+			
+			seeds := []string {
+			"085f62d67bbf9c501e8ac84d4533440a1eef6c45@95.217.196.54:26656"} // Notional
+		 
+			
+			
+
+			
+
+			//Override default settings in config.toml
+			config.P2P.Seeds = strings.Join(seeds[:],",")
+			config.P2P.MaxNumInboundPeers = 150
 			config.P2P.MaxNumOutboundPeers = 40
 			config.Mempool.Size = 10000
 			config.StateSync.TrustPeriod = 112 * time.Hour
@@ -87,6 +104,8 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
 
 			config.SetRoot(clientCtx.HomeDir)
 
+
+			//Override default settings in app.toml
 			appConfig := appcfg.DefaultConfig()
 			appConfig.API.Enable = true
 			appConfig.StateSync.SnapshotInterval = 1500
@@ -148,7 +167,7 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
 			genDoc.Validators = nil
 			genDoc.AppState = appState
 			if err = genutil.ExportGenesisFile(genDoc, genFile); err != nil {
-				return errors.Wrap(err, "Failed to export gensis file")
+				return errors.Wrap(err, "Failed to export genesis file")
 			}
 
 			toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
diff --git a/go.mod b/go.mod
index abcc76636..d91229249 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/osmosis-labs/osmosis
 go 1.15
 
 require (
-	github.com/cosmos/cosmos-sdk v0.42.6
+	github.com/cosmos/cosmos-sdk v0.42.9
 	github.com/cosmos/go-bip39 v1.0.0
 	github.com/cosmos/iavl v0.16.0
 	github.com/gogo/protobuf v1.3.3
@@ -29,4 +29,4 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
 
 replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.4
 
-replace github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.42.5-0.20210630232304-f792e47135c3
+replace github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20210819201800-7d5063b74305
diff --git a/go.sum b/go.sum
index 03dcce48b..b02df0ffa 100644
--- a/go.sum
+++ b/go.sum
@@ -408,10 +408,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
 github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
 github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/osmosis-labs/cosmos-sdk v0.42.5-0.20210628180307-261fe6ac5d31 h1:XlYFFBRX9vNdMQb+MCzBvlICoYR3c6ddAWTyrtgx1r8=
-github.com/osmosis-labs/cosmos-sdk v0.42.5-0.20210628180307-261fe6ac5d31/go.mod h1:kh37gwYQoWdgR7N/9zeqW2rJ7cnP2W4A7nqIaf6m3zg=
-github.com/osmosis-labs/cosmos-sdk v0.42.5-0.20210630232304-f792e47135c3 h1:RSmqvmlkqHf4AXwNDoRmerAVUFgjTkkujJiZVTtqNSA=
-github.com/osmosis-labs/cosmos-sdk v0.42.5-0.20210630232304-f792e47135c3/go.mod h1:kh37gwYQoWdgR7N/9zeqW2rJ7cnP2W4A7nqIaf6m3zg=
+github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20210819201800-7d5063b74305 h1:u/c19T1LAimpBOcmJEIcTn3qEILiMsZ4XqxhtDmnGvE=
+github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20210819201800-7d5063b74305/go.mod h1:SrclJP9lMXxz2fCbngxb0brsPNuZXqoQQ9VHuQ3Tpf4=
 github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
 github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
 github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
diff --git a/osmomath/math.go b/osmomath/math.go
new file mode 100644
index 000000000..1889531af
--- /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/proto/osmosis/gamm/v1beta1/genesis.proto b/proto/osmosis/gamm/v1beta1/genesis.proto
index 8f682fa18..1e815bcd6 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/scripts/unclaimed_airdrop/get_unclaimed_airdrop.py b/scripts/unclaimed_airdrop/get_unclaimed_airdrop.py
new file mode 100644
index 000000000..eff1f702f
--- /dev/null
+++ b/scripts/unclaimed_airdrop/get_unclaimed_airdrop.py
@@ -0,0 +1,60 @@
+### This script calculates the amount of the airdrop that is unclaimed,
+### including the 20% given to accounts who haven't done any of the claiming activities.
+### This lets us reason accurately about how much has been unclaimed.
+
+import json
+
+# path to file output by 
+# osmosisd export-derive-balances [state export] [output-filepath]
+filepath = "balances_breakdown.json"
+# read file
+with open(filepath, 'r') as myfile:
+    data=myfile.read()
+
+obj = json.loads(data)
+accts = obj['accounts']
+
+# get unclaimed osmo amount
+def get_base_unclaimed_amount(base_account):
+    unclaimed = base_account['unclaimed']
+    unclaimed_amt = 0
+    if len(unclaimed) != 0:
+        unclaimed_amt = int(unclaimed[0]['amount'])
+    return unclaimed_amt
+
+# get liquid osmo amount
+def get_liquid_osmo_balance(base_account):
+    liquid_osmo = 0
+    if len(base_account['balance']) != 0:
+        for p in base_account['balance']:
+            if p['denom'] == "uosmo":
+                liquid_osmo = int(p['amount'])
+    return liquid_osmo
+
+total_unclaimed_excluding_base_twenty = 0
+total_unclaimed_including_base_twenty = 0
+
+for k in accts.keys():
+    base = accts[k]
+    unclaimed_osmo = get_base_unclaimed_amount(base)
+    liquid_osmo = get_liquid_osmo_balance(base)
+    staked = int(base['staked']) != 0
+    bonded = len(base['bonded']) != 0
+
+    total_unclaimed_excluding_base_twenty += unclaimed_osmo
+    total_unclaimed_including_base_twenty += unclaimed_osmo
+
+    # We want to check if a user is inactive thus far, and if so include their liquid 20%.
+    # We do this by checking if they have no staked, no bonded
+    # and if their liquid balance = .25 * unclaimed bal
+    if unclaimed_osmo == 0:
+        continue
+
+    if not (staked or bonded):
+        # to account for rounding error, check equality with some margin.
+        if abs((unclaimed_osmo // 4) - liquid_osmo) < 1000000:
+            total_unclaimed_including_base_twenty += liquid_osmo
+
+print("unclaimed non-already-distributed balance", total_unclaimed_excluding_base_twenty / (10**6), "osmo")
+print("unclaimed & inactive", total_unclaimed_including_base_twenty/ (10**6), "osmo")
+print("simple prediction for unclaimed and inactive (div by .8)", (total_unclaimed_excluding_base_twenty / .8)/ (10**6), "osmo")
\ No newline at end of file
diff --git a/x/epochs/types/genesis.go b/x/epochs/types/genesis.go
index f0a9bfdbb..3387ecac3 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 000000000..9e6a15d85
--- /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/query.go b/x/gamm/client/cli/query.go
index 6a3587076..15a2e8998 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 37dcea8d5..9345a372a 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/keeper/invariants.go b/x/gamm/keeper/invariants.go
index 012d58b8c..e8168964d 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 fef062d46..dfc5d2b6b 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/math.go b/x/gamm/keeper/math.go
index 83e1afa74..2132eca29 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/params.go b/x/gamm/keeper/params.go
new file mode 100644
index 000000000..0c633bbc0
--- /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 0eff1a866..70f7f1a36 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/module.go b/x/gamm/module.go
index f3cfb208d..ff134856c 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 63c34f5de..3745a606e 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/01_concepts.md b/x/gamm/spec/01_concepts.md
index cbf7529df..10eeb1d7a 100644
--- a/x/gamm/spec/01_concepts.md
+++ b/x/gamm/spec/01_concepts.md
@@ -4,5 +4,50 @@ order: 1
 
 # Concepts
 
-The `gamm` module currently provides interfaces for balancer v1-AMMs.
-This will evolve over time into a repository with a generalized AMM interface.
+The concept of the `gamm` module is designed to handle assets of a chain using the AMM and its concept of pool shares. 
+
+## Pool
+
+### Creation of Pool
+
+At an initial creation of the pool, a fixed amount of 100 share token is minted in the pool and sent to the creator of the pool's account. Pool share denom is in the format of gamm/pool/{poolId} and is displayed in the format of GAMM-{poolId} to the user. Pool assets are sorted in alphabetical order by defualt.
+
+### Joining Pool
+
+When joining a pool, users provide maximum amount of tokens willing to deposit, while the front end takes care of the calculation of how many share tokens the user is eligible at the specific moment of sending the transaction. Calculation of exactly how many tokens are needed to get the designated share is done at the moment of procssing the transaction, validating that it does not exceed the maximum amount of token the user is willing to deposit. After the validation, the share of the pool is minted and sent to the user account. Joining the pool using a single asset is also possible.
+
+### Exiting Pool
+
+When exiting the pool, the user also probides the minimum amount of tokens they are willing to receive as they are returning the share of the pool. However, unlike joining a pool, exiting a pool requires the user to pay the exit fee, which is set as the param of the pool. The share of the user gets burnt. Exiting the pool using a single asset is also possible. 
+
++++[https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/pool_service.go](https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/pool_service.go)
+
+## Swap
+
+During the process of swapping a specific asset, the token user is putting into the pool is justified as `tokenIn`, while the token that would be omitted after the swap is justified as `tokenOut`  throughout the module.
+
+Given a tokenIn, the following calculations are done to calculate how much tokens are to be swapped and ommitted from the pool.
+
+- `tokenBalanceOut * [ 1 - { tokenBalanceIn / (tokenBalanceIn+(1-swapFee) * tokenAmountIn)}^(tokenWeightIn/tokenWeightOut)`
+
+The whole process is also able vice versa, the case where user provides tokenOut. The calculation  for the amount of token that the user should be putting in is done through the following formula.
+
+- `tokenBalanceIn * [{tokenBalanceOut / (tokenBalanceOut - tokenAmountOut)}^(tokenWeightOut/tokenWeightIn)-1] / tokenAmountIn`
+
+### Spot Price
+
+Meanwhile, calculation of the spot price with a swap fee is done using the following formula
+
+- `spotPrice / (1-swapFee)`
+
+where spotPrice is 
+
+- `(tokenBalanceIn / tokenWeightIn) / (tokenBalanceOut / tokenWeightOut)`
+
++++[https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/swap.go](https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/swap.go)
+
+### Multihop
+
+All tokens are swapped using multi-hop. That is, all swaps are routed via the ultimate cost-efficient way, swapping in and out from multiple pools in the process.
+
++++[https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/multihop.go](https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/keeper/multihop.go)
\ No newline at end of file
diff --git a/x/gamm/spec/04_params.md b/x/gamm/spec/04_params.md
new file mode 100644
index 000000000..4bde2ebb0
--- /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 e9d8238cb..f07b8da12 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 000000000..47b210273
--- /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 4022360b6..66dd5a334 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 000000000..59aeef798
--- /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/keeper/gauge.go b/x/incentives/keeper/gauge.go
index 22ed8bf6e..09de4ed74 100644
--- a/x/incentives/keeper/gauge.go
+++ b/x/incentives/keeper/gauge.go
@@ -8,6 +8,7 @@ import (
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/gogo/protobuf/proto"
 	epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types"
+	"github.com/osmosis-labs/osmosis/x/gamm/utils"
 	"github.com/osmosis-labs/osmosis/x/incentives/types"
 	lockuptypes "github.com/osmosis-labs/osmosis/x/lockup/types"
 	db "github.com/tendermint/tm-db"
@@ -306,6 +307,16 @@ func (k Keeper) Distribute(ctx sdk.Context, gauge types.Gauge) (sdk.Coins, error
 		if err := k.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, owner, distrCoins); err != nil {
 			return nil, err
 		}
+
+		ctx.EventManager().EmitEvents(sdk.Events{
+			sdk.NewEvent(
+				types.TypeEvtDistribution,
+				sdk.NewAttribute(types.AttributeGaugeID, utils.Uint64ToString(gauge.Id)),
+				sdk.NewAttribute(types.AttributeLockID, utils.Uint64ToString(lock.ID)),
+				sdk.NewAttribute(types.AttributeReceiver, lock.Owner),
+				sdk.NewAttribute(types.AttributeAmount, distrCoins.String()),
+			),
+		})
 		totalDistrCoins = totalDistrCoins.Add(distrCoins...)
 	}
 
diff --git a/x/incentives/types/events.go b/x/incentives/types/events.go
index 8751903e5..6519444e8 100644
--- a/x/incentives/types/events.go
+++ b/x/incentives/types/events.go
@@ -2,8 +2,12 @@ package types
 
 // event types
 const (
-	TypeEvtCreateGauge = "create_gauge"
-	TypeEvtAddToGauge  = "add_to_gauge"
+	TypeEvtCreateGauge  = "create_gauge"
+	TypeEvtAddToGauge   = "add_to_gauge"
+	TypeEvtDistribution = "distribution"
 
-	AttributeGaugeID = "gauge_id"
+	AttributeGaugeID  = "gauge_id"
+	AttributeLockID   = "lock_id"
+	AttributeReceiver = "receiver"
+	AttributeAmount   = "amount"
 )
diff --git a/x/incentives/types/params.go b/x/incentives/types/params.go
index c532cbaf9..353c6b12d 100644
--- a/x/incentives/types/params.go
+++ b/x/incentives/types/params.go
@@ -1,9 +1,8 @@
 package types
 
 import (
-	"fmt"
-
 	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
+	epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types"
 )
 
 // Parameter store keys
@@ -31,30 +30,15 @@ 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
 	}
-
 	return nil
-
 }
 
 // Implements params.ParamSet
 func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
 	return paramtypes.ParamSetPairs{
-		paramtypes.NewParamSetPair(KeyDistrEpochIdentifier, &p.DistrEpochIdentifier, validateDistrEpochIdentifier),
-	}
-}
-
-func validateDistrEpochIdentifier(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)
+		paramtypes.NewParamSetPair(KeyDistrEpochIdentifier, &p.DistrEpochIdentifier, epochtypes.ValidateEpochIdentifierInterface),
 	}
-
-	return nil
 }
diff --git a/x/lockup/keeper/lock.go b/x/lockup/keeper/lock.go
index bdfd99025..bd8d11cd2 100644
--- a/x/lockup/keeper/lock.go
+++ b/x/lockup/keeper/lock.go
@@ -281,6 +281,51 @@ func (k Keeper) UnlockPeriodLockByID(ctx sdk.Context, LockID uint64) (*types.Per
 	return lock, err
 }
 
+func (k Keeper) addTokensToLock(ctx sdk.Context, lock *types.PeriodLock, coins sdk.Coins) error {
+	lock.Coins = lock.Coins.Add(coins...)
+
+	err := k.setLock(ctx, *lock)
+	if err != nil {
+		return err
+	}
+
+	// modifications to accumulation store
+	for _, coin := range lock.Coins {
+		// remove previous store for the lock ID and add again with updated value
+		k.accumulationStore(ctx, coin.Denom).Remove(accumulationKey(lock.Duration, lock.ID))
+		k.accumulationStore(ctx, coin.Denom).Set(accumulationKey(lock.Duration, lock.ID), coin.Amount)
+	}
+
+	return nil
+}
+
+// AddTokensToLock locks more tokens into a lockup
+// This also saves the lock to the store.
+func (k Keeper) AddTokensToLockByID(ctx sdk.Context, owner sdk.AccAddress, lockID uint64, coins sdk.Coins) (*types.PeriodLock, error) {
+	lock, err := k.GetLockByID(ctx, lockID)
+	if err != nil {
+		return nil, err
+	}
+	if lock.Owner != owner.String() {
+		return nil, types.ErrNotLockOwner
+	}
+	if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, coins); err != nil {
+		return nil, err
+	}
+
+	err = k.addTokensToLock(ctx, lock, coins)
+	if err != nil {
+		return nil, err
+	}
+
+	if k.hooks == nil {
+		return lock, nil
+	}
+
+	k.hooks.OnTokenLocked(ctx, owner, lock.ID, coins, lock.Duration, lock.EndTime)
+	return lock, nil
+}
+
 // LockTokens lock tokens from an account for specified duration
 func (k Keeper) LockTokens(ctx sdk.Context, owner sdk.AccAddress, coins sdk.Coins, duration time.Duration) (types.PeriodLock, error) {
 	ID := k.GetLastLockID(ctx) + 1
@@ -311,12 +356,10 @@ func (k Keeper) ClearAllLockRefKeys(ctx sdk.Context) {
 
 // ResetLock reset lock to lock's previous state on InitGenesis
 func (k Keeper) ResetLock(ctx sdk.Context, lock types.PeriodLock) error {
-	store := ctx.KVStore(k.storeKey)
-	bz, err := proto.Marshal(&lock)
+	err := k.setLock(ctx, lock)
 	if err != nil {
 		return err
 	}
-	store.Set(lockStoreKey(lock.ID), bz)
 
 	// store refs by the status of unlock
 	if lock.IsUnlocking() {
@@ -331,6 +374,17 @@ func (k Keeper) ResetLock(ctx sdk.Context, lock types.PeriodLock) error {
 	return k.addLockRefs(ctx, types.KeyPrefixNotUnlocking, lock)
 }
 
+// setLock is a utility to store lock object into the store
+func (k Keeper) setLock(ctx sdk.Context, lock types.PeriodLock) error {
+	store := ctx.KVStore(k.storeKey)
+	bz, err := proto.Marshal(&lock)
+	if err != nil {
+		return err
+	}
+	store.Set(lockStoreKey(lock.ID), bz)
+	return nil
+}
+
 // Lock is a utility to lock coins into module account
 func (k Keeper) Lock(ctx sdk.Context, lock types.PeriodLock) error {
 	owner, err := sdk.AccAddressFromBech32(lock.Owner)
diff --git a/x/lockup/spec/05_keeper.md b/x/lockup/spec/05_keeper.md
index f8b4154bc..b4b9a717d 100644
--- a/x/lockup/spec/05_keeper.md
+++ b/x/lockup/spec/05_keeper.md
@@ -46,6 +46,8 @@ type Keeper interface {
     UnlockPeriodLockByID(sdk.Context, LockID uint64) (*types.PeriodLock, error)
     // LockTokens lock tokens from an account for specified duration
     LockTokens(sdk.Context, owner sdk.AccAddress, coins sdk.Coins, duration time.Duration) (types.PeriodLock, error)
+    // AddTokensToLock locks more tokens into a lockup
+    AddTokensToLock(ctx sdk.Context, owner sdk.AccAddress, lockID uint64, coins sdk.Coins) (*types.PeriodLock, error)
     // Lock is a utility to lock coins into module account
     Lock(sdk.Context, lock types.PeriodLock) error
     // Unlock is a utility to unlock coins from module account
diff --git a/x/mint/types/params.go b/x/mint/types/params.go
index 388945ada..9abec74b0 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 {


Test patch:
diff --git a/osmomath/math_test.go b/osmomath/math_test.go
new file mode 100644
index 000000000..096a685a2
--- /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 0af73bb36..51c4095cc 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/scripts/upgrades/3/test_script.sh b/scripts/upgrades/3/test_script.sh
new file mode 100644
index 000000000..de0323184
--- /dev/null
+++ b/scripts/upgrades/3/test_script.sh
@@ -0,0 +1,40 @@
+# Create a genesis.json for testing. The node that you this on will be your "validator"
+# It should be on version v3.0.0-rc0
+osmosisd init --chain-id=testing testing --home=$HOME/.osmosisd
+osmosisd keys add validator --keyring-backend=test --home=$HOME/.osmosisd
+osmosisd add-genesis-account $(osmosisd keys show validator -a --keyring-backend=test --home=$HOME/.osmosisd) 1000000000uosmo,1000000000valtoken --home=$HOME/.osmosisd
+sed -i -e "s/stake/uosmo/g" $HOME/.osmosisd/config/genesis.json
+osmosisd gentx validator 500000000uosmo --commission-rate="0.0" --keyring-backend=test --home=$HOME/.osmosisd --chain-id=testing
+osmosisd collect-gentxs --home=$HOME/.osmosisd
+
+cat $HOME/.osmosisd/config/genesis.json | jq '.initial_height="711800"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
+cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"]["denom"]="valtoken"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
+cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"]["amount"]="100"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
+cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="120s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
+cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["staking"]["params"]["min_commission_rate"]="0.050000000000000000"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
+
+# Now setup a second full node, and peer it with this v3.0.0-rc0 node.
+
+# start the chain on both machines
+osmosisd start
+# Create proposals
+
+osmosisd tx gov submit-proposal --title="existing passing prop" --description="passing prop"  --from=validator --deposit=1000valtoken --chain-id=testing --keyring-backend=test --broadcast-mode=block  --type="Text"
+osmosisd tx gov vote 1 yes --from=validator --keyring-backend=test --chain-id=testing --yes
+osmosisd tx gov submit-proposal --title="prop with enough osmo deposit" --description="prop w/ enough deposit"  --from=validator --deposit=500000000uosmo --chain-id=testing --keyring-backend=test --broadcast-mode=block  --type="Text"
+# Check that we have proposal 1 passed, and proposal 2 in deposit period
+osmosisd q gov proposals
+# CHeck that validator commission is under min_commission_rate
+osmosisd q staking validators
+# Wait for upgrade block.
+# Upgrade happened
+# your full node should have crashed with consensus failure
+
+# Now we test post-upgrade behavior is as intended
+
+# Everything in deposit stayed in deposit
+osmosisd q gov proposals
+# Check that commissions was bumped to min_commission_rate
+osmosisd q staking validators
+# pushes 2 into voting period
+osmosisd tx gov deposit 2 1valtoken --from=validator --keyring-backend=test --chain-id=testing --yes
\ No newline at end of file
diff --git a/x/epochs/genesis_test.go b/x/epochs/genesis_test.go
index 050b6ec21..60673004c 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/gamm/client/cli/cli_test.go b/x/gamm/client/cli/cli_test.go
index 974532e24..7011ea0f2 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/genesis_test.go b/x/gamm/genesis_test.go
index eac860593..e394b1991 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/keeper_test.go b/x/gamm/keeper/keeper_test.go
index 087382cda..3fcd6c46f 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_test.go b/x/gamm/keeper/math_test.go
index 7660beb69..0c400c053 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/pool_service_test.go b/x/gamm/keeper/pool_service_test.go
index c5a523fa8..10447922d 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 aa3a4423d..8fa6e880d 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/incentives/genesis_test.go b/x/incentives/genesis_test.go
index fd21caef6..c4d0660a1 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{
@@ -86,4 +89,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/lockup/keeper/lock_test.go b/x/lockup/keeper/lock_test.go
index 30eb66417..811ad2b31 100644
--- a/x/lockup/keeper/lock_test.go
+++ b/x/lockup/keeper/lock_test.go
@@ -258,6 +258,65 @@ func (suite *KeeperTestSuite) TestLockTokensAlot() {
 	// panic(1)
 }
 
+func (suite *KeeperTestSuite) TestAddTokensToLock() {
+	suite.SetupTest()
+
+	// lock coins
+	addr1 := sdk.AccAddress([]byte("addr1---------------"))
+	coins := sdk.Coins{sdk.NewInt64Coin("stake", 10)}
+	suite.LockTokens(addr1, coins, time.Second)
+
+	// check locks
+	locks, err := suite.app.LockupKeeper.GetPeriodLocks(suite.ctx)
+	suite.Require().NoError(err)
+	suite.Require().Len(locks, 1)
+	suite.Require().Equal(locks[0].Coins, coins)
+	// check accumulation store is correctly updated
+	accum := suite.app.LockupKeeper.GetPeriodLocksAccumulation(suite.ctx, types.QueryCondition{
+		LockQueryType: types.ByDuration,
+		Denom:         "stake",
+		Duration:      time.Second,
+	})
+	suite.Require().Equal(accum.String(), "10")
+
+	// add more tokens to lock
+	addCoins := sdk.Coins{sdk.NewInt64Coin("stake", 10)}
+	suite.app.BankKeeper.SetBalances(suite.ctx, addr1, addCoins)
+	_, err = suite.app.LockupKeeper.AddTokensToLockByID(suite.ctx, addr1, locks[0].ID, addCoins)
+	suite.Require().NoError(err)
+
+	// check locks after adding tokens to lock
+	locks, err = suite.app.LockupKeeper.GetPeriodLocks(suite.ctx)
+	suite.Require().NoError(err)
+	suite.Require().Len(locks, 1)
+	suite.Require().Equal(locks[0].Coins, coins.Add(addCoins...))
+
+	// check accumulation store is correctly updated
+	accum = suite.app.LockupKeeper.GetPeriodLocksAccumulation(suite.ctx, types.QueryCondition{
+		LockQueryType: types.ByDuration,
+		Denom:         "stake",
+		Duration:      time.Second,
+	})
+	suite.Require().Equal(accum.String(), "20")
+
+	// try to add tokens to unavailable lock
+	cacheCtx, _ := suite.ctx.CacheContext()
+	suite.app.BankKeeper.SetBalances(cacheCtx, addr1, addCoins)
+	_, err = suite.app.LockupKeeper.AddTokensToLockByID(cacheCtx, addr1, 1111, addCoins)
+	suite.Require().Error(err)
+
+	// try to add tokens with lack balance
+	cacheCtx, _ = suite.ctx.CacheContext()
+	_, err = suite.app.LockupKeeper.AddTokensToLockByID(cacheCtx, addr1, locks[0].ID, addCoins)
+	suite.Require().Error(err)
+
+	// try to add tokens to lock that is owned by others
+	addr2 := sdk.AccAddress([]byte("addr2---------------"))
+	suite.app.BankKeeper.SetBalances(cacheCtx, addr2, addCoins)
+	_, err = suite.app.LockupKeeper.AddTokensToLockByID(cacheCtx, addr2, locks[0].ID, addCoins)
+	suite.Require().Error(err)
+}
+
 func (suite *KeeperTestSuite) TestEndblockerWithdrawAllMaturedLockups() {
 	suite.SetupTest()
 
diff --git a/x/mint/genesis_test.go b/x/mint/genesis_test.go
new file mode 100644
index 000000000..2b4bafe61
--- /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/pool-incentives/keeper/keeper_test.go b/x/pool-incentives/keeper/keeper_test.go
index d32789e84..bdf3229ae 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)),