From 155638c8f68f76d9191b6f6292089313afba9f88 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 22 Jul 2022 11:48:02 -0500 Subject: [PATCH 1/2] Twap: Add twapkeeper wiring --- app/apptesting/gamm.go | 18 ++++++++++++++ app/apptesting/test_suite.go | 10 ++++++++ app/keepers/keepers.go | 11 +++++++++ app/keepers/keys.go | 4 +++- app/keepers/modules.go | 2 ++ app/modules.go | 6 ++++- app/upgrades/v11/constants.go | 6 ++++- x/gamm/keeper/pool.go | 7 ++++++ x/gamm/twap/abci.go | 13 ----------- x/gamm/twap/hook_listener.go | 31 ++++++++++++++++++++---- x/gamm/twap/keeper.go | 27 +++++++++++++++++---- x/gamm/twap/module.go | 44 ++++++++++++----------------------- x/gamm/twap/store.go | 9 +++---- 13 files changed, 131 insertions(+), 57 deletions(-) delete mode 100644 x/gamm/twap/abci.go diff --git a/app/apptesting/gamm.go b/app/apptesting/gamm.go index f269249be34..a6de6def851 100644 --- a/app/apptesting/gamm.go +++ b/app/apptesting/gamm.go @@ -96,3 +96,21 @@ func (s *KeeperTestHelper) PrepareBalancerPoolWithPoolAsset(assets []balancer.Po s.NoError(err) return poolId } + +func (s *KeeperTestHelper) RunBasicSwap(poolId uint64) { + denoms, err := s.App.GAMMKeeper.GetPoolDenoms(s.Ctx, poolId) + s.Require().NoError(err) + + swapIn := sdk.NewCoins(sdk.NewCoin(denoms[0], sdk.NewInt(1000))) + s.FundAcc(s.TestAccs[0], swapIn) + + msg := gammtypes.MsgSwapExactAmountIn{ + Sender: string(s.TestAccs[0]), + Routes: []gammtypes.SwapAmountInRoute{{PoolId: poolId, TokenOutDenom: denoms[1]}}, + TokenIn: swapIn[0], + TokenOutMinAmount: sdk.ZeroInt(), + } + // TODO: switch to message + _, err = s.App.GAMMKeeper.SwapExactAmountIn(s.Ctx, s.TestAccs[0], poolId, msg.TokenIn, denoms[1], msg.TokenOutMinAmount) + s.Require().NoError(err) +} diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index 9f7a6ecf6eb..152a5a7d3c1 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -61,6 +61,16 @@ func (s *KeeperTestHelper) CreateTestContext() sdk.Context { return sdk.NewContext(ms, tmtypes.Header{}, false, logger) } +// CreateTestContext creates a test context. +func (s *KeeperTestHelper) Commit() { + oldHeight := s.Ctx.BlockHeight() + oldHeader := s.Ctx.BlockHeader() + s.App.Commit() + newHeader := tmtypes.Header{Height: oldHeight + 1, ChainID: oldHeader.ChainID, Time: time.Now().UTC()} + s.App.BeginBlock(abci.RequestBeginBlock{Header: newHeader}) + s.Ctx = s.App.GetBaseApp().NewContext(false, newHeader) +} + // FundAcc funds target address with specified amount. func (s *KeeperTestHelper) FundAcc(acc sdk.AccAddress, amounts sdk.Coins) { err := simapp.FundAccount(s.App.BankKeeper, s.Ctx, acc, amounts) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 90121bd8fd4..aeecb95a0e5 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -52,6 +52,8 @@ import ( epochskeeper "github.com/osmosis-labs/osmosis/v10/x/epochs/keeper" epochstypes "github.com/osmosis-labs/osmosis/v10/x/epochs/types" gammkeeper "github.com/osmosis-labs/osmosis/v10/x/gamm/keeper" + "github.com/osmosis-labs/osmosis/v10/x/gamm/twap" + twaptypes "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" gammtypes "github.com/osmosis-labs/osmosis/v10/x/gamm/types" incentiveskeeper "github.com/osmosis-labs/osmosis/v10/x/incentives/keeper" incentivestypes "github.com/osmosis-labs/osmosis/v10/x/incentives/types" @@ -98,6 +100,7 @@ type AppKeepers struct { TransferKeeper *ibctransferkeeper.Keeper EvidenceKeeper *evidencekeeper.Keeper GAMMKeeper *gammkeeper.Keeper + TwapKeeper *twap.Keeper LockupKeeper *lockupkeeper.Keeper EpochsKeeper *epochskeeper.Keeper IncentivesKeeper *incentiveskeeper.Keeper @@ -241,6 +244,12 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.AccountKeeper, appKeepers.BankKeeper, appKeepers.DistrKeeper) appKeepers.GAMMKeeper = &gammKeeper + appKeepers.TwapKeeper = twap.NewKeeper( + appKeepers.keys[twaptypes.StoreKey], + appKeepers.tkeys[twaptypes.TransientStoreKey], + appKeepers.GetSubspace(twaptypes.ModuleName), + appKeepers.GAMMKeeper) + appKeepers.LockupKeeper = lockupkeeper.NewKeeper( appCodec, appKeepers.keys[lockuptypes.StoreKey], @@ -454,6 +463,7 @@ func (appKeepers *AppKeepers) SetupHooks() { gammtypes.NewMultiGammHooks( // insert gamm hooks receivers here appKeepers.PoolIncentivesKeeper.Hooks(), + appKeepers.TwapKeeper.GammHooks(), ), ) @@ -512,6 +522,7 @@ func KVStoreKeys() []string { ibctransfertypes.StoreKey, capabilitytypes.StoreKey, gammtypes.StoreKey, + twaptypes.StoreKey, lockuptypes.StoreKey, incentivestypes.StoreKey, epochstypes.StoreKey, diff --git a/app/keepers/keys.go b/app/keepers/keys.go index 350f50a7279..c3dc16a6bd8 100644 --- a/app/keepers/keys.go +++ b/app/keepers/keys.go @@ -4,6 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + + twaptypes "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" ) // GenerateKeys generates new keys (KV Store, Transient store, and memory store). @@ -13,7 +15,7 @@ func (appKeepers *AppKeepers) GenerateKeys() { appKeepers.keys = sdk.NewKVStoreKeys(KVStoreKeys()...) // Define transient store keys - appKeepers.tkeys = sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + appKeepers.tkeys = sdk.NewTransientStoreKeys(paramstypes.TStoreKey, twaptypes.TransientStoreKey) // MemKeys are for information that is stored only in RAM. appKeepers.memKeys = sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) diff --git a/app/keepers/modules.go b/app/keepers/modules.go index cf6555b3252..07218549e7b 100644 --- a/app/keepers/modules.go +++ b/app/keepers/modules.go @@ -30,6 +30,7 @@ import ( _ "github.com/osmosis-labs/osmosis/v10/client/docs/statik" "github.com/osmosis-labs/osmosis/v10/x/epochs" "github.com/osmosis-labs/osmosis/v10/x/gamm" + "github.com/osmosis-labs/osmosis/v10/x/gamm/twap" "github.com/osmosis-labs/osmosis/v10/x/incentives" "github.com/osmosis-labs/osmosis/v10/x/lockup" "github.com/osmosis-labs/osmosis/v10/x/mint" @@ -74,6 +75,7 @@ var AppModuleBasics = []module.AppModuleBasic{ transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, gamm.AppModuleBasic{}, + twap.AppModuleBasic{}, txfees.AppModuleBasic{}, incentives.AppModuleBasic{}, lockup.AppModuleBasic{}, diff --git a/app/modules.go b/app/modules.go index ba9e72149ea..382131bbb71 100644 --- a/app/modules.go +++ b/app/modules.go @@ -47,6 +47,8 @@ import ( "github.com/osmosis-labs/osmosis/v10/x/epochs" epochstypes "github.com/osmosis-labs/osmosis/v10/x/epochs/types" "github.com/osmosis-labs/osmosis/v10/x/gamm" + "github.com/osmosis-labs/osmosis/v10/x/gamm/twap" + twaptypes "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" gammtypes "github.com/osmosis-labs/osmosis/v10/x/gamm/types" "github.com/osmosis-labs/osmosis/v10/x/incentives" incentivestypes "github.com/osmosis-labs/osmosis/v10/x/incentives/types" @@ -121,6 +123,7 @@ func appModules( params.NewAppModule(*app.ParamsKeeper), app.TransferModule, gamm.NewAppModule(appCodec, *app.GAMMKeeper, app.AccountKeeper, app.BankKeeper), + twap.NewAppModule(*app.TwapKeeper), txfees.NewAppModule(appCodec, *app.TxFeesKeeper), incentives.NewAppModule(appCodec, *app.IncentivesKeeper, app.AccountKeeper, app.BankKeeper, app.EpochsKeeper), lockup.NewAppModule(appCodec, *app.LockupKeeper, app.AccountKeeper, app.BankKeeper), @@ -165,7 +168,7 @@ func orderBeginBlockers(allModuleNames []string) []string { // OrderEndBlockers returns EndBlockers (crisis, govtypes, staking) with no relative order. func OrderEndBlockers(allModuleNames []string) []string { ord := partialord.NewPartialOrdering(allModuleNames) - // only Osmosis modules with endblock code are: crisis, govtypes, staking + // only Osmosis modules with endblock code are: twap, crisis, govtypes, staking // we don't care about the relative ordering between them. return ord.TotalOrdering() } @@ -190,6 +193,7 @@ func OrderInitGenesis(allModuleNames []string) []string { ibchost.ModuleName, icatypes.ModuleName, gammtypes.ModuleName, + twaptypes.ModuleName, txfeestypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, diff --git a/app/upgrades/v11/constants.go b/app/upgrades/v11/constants.go index fa9fa4455c7..6a1cc34ff4a 100644 --- a/app/upgrades/v11/constants.go +++ b/app/upgrades/v11/constants.go @@ -2,6 +2,7 @@ package v11 import ( "github.com/osmosis-labs/osmosis/v10/app/upgrades" + twaptypes "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" store "github.com/cosmos/cosmos-sdk/store/types" ) @@ -12,5 +13,8 @@ const UpgradeName = "v11" var Upgrade = upgrades.Upgrade{ UpgradeName: UpgradeName, CreateUpgradeHandler: CreateUpgradeHandler, - StoreUpgrades: store.StoreUpgrades{}, + StoreUpgrades: store.StoreUpgrades{ + Added: []string{twaptypes.StoreKey}, + Deleted: []string{}, // double check bech32ibc + }, } diff --git a/x/gamm/keeper/pool.go b/x/gamm/keeper/pool.go index 9617ffb3f03..dae14c7a654 100644 --- a/x/gamm/keeper/pool.go +++ b/x/gamm/keeper/pool.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/osmosis-labs/osmosis/v10/osmoutils" "github.com/osmosis-labs/osmosis/v10/x/gamm/pool-models/balancer" "github.com/osmosis-labs/osmosis/v10/x/gamm/pool-models/stableswap" "github.com/osmosis-labs/osmosis/v10/x/gamm/types" @@ -197,6 +198,12 @@ func (k Keeper) DeletePool(ctx sdk.Context, poolId uint64) error { // return nil // } +func (k Keeper) GetPoolDenoms(ctx sdk.Context, poolId uint64) ([]string, error) { + pool, err := k.GetPoolAndPoke(ctx, poolId) + denoms := osmoutils.CoinsDenoms(pool.GetTotalPoolLiquidity(ctx)) + return denoms, err +} + // setNextPoolNumber sets next pool number. func (k Keeper) setNextPoolNumber(ctx sdk.Context, poolNumber uint64) { store := ctx.KVStore(k.storeKey) diff --git a/x/gamm/twap/abci.go b/x/gamm/twap/abci.go deleted file mode 100644 index 060da2b2525..00000000000 --- a/x/gamm/twap/abci.go +++ /dev/null @@ -1,13 +0,0 @@ -package twap - -import sdk "github.com/cosmos/cosmos-sdk/types" - -func (k twapkeeper) endBlockLogic(ctx sdk.Context) { - // TODO: Update TWAP entries - // step 1: Get all altered pool ids - changedPoolIds := k.getChangedPools(ctx) - if len(changedPoolIds) == 0 { - return - } - // 'altered pool ids' should be automatically cleared -} diff --git a/x/gamm/twap/hook_listener.go b/x/gamm/twap/hook_listener.go index 2a5163577d4..cad053ab64a 100644 --- a/x/gamm/twap/hook_listener.go +++ b/x/gamm/twap/hook_listener.go @@ -1,29 +1,52 @@ package twap import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + epochtypes "github.com/osmosis-labs/osmosis/v10/x/epochs/types" "github.com/osmosis-labs/osmosis/v10/x/gamm/types" ) var _ types.GammHooks = &gammhook{} +var _ epochtypes.EpochHooks = &epochhook{} + +type epochhook struct { + k Keeper +} + +func (hook *epochhook) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) { + if epochIdentifier == hook.k.PruneEpochIdentifier(ctx) { + fmt.Println("restore logic in subsequent PR") + // hook.k.pruneOldTwaps(ctx) + } +} + +func (hook *epochhook) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) {} type gammhook struct { - k twapkeeper + k Keeper +} + +func (k Keeper) GammHooks() types.GammHooks { + return &gammhook{k} } // AfterPoolCreated is called after CreatePool func (hook *gammhook) AfterPoolCreated(ctx sdk.Context, sender sdk.AccAddress, poolId uint64) { - // TODO: Log pool creation to begin creating TWAPs for it + // err := hook.k.afterCreatePool(ctx, poolId) + // // Will halt pool creation + // if err != nil { + // panic(err) + // } } func (hook *gammhook) AfterSwap(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, input sdk.Coins, output sdk.Coins) { - // Log that this pool had a potential spot price change hook.k.trackChangedPool(ctx, poolId) } func (hook *gammhook) AfterJoinPool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, enterCoins sdk.Coins, shareOutAmount sdk.Int) { - // Log that this pool had a potential spot price change hook.k.trackChangedPool(ctx, poolId) } diff --git a/x/gamm/twap/keeper.go b/x/gamm/twap/keeper.go index b3a189b2701..46ad1cccbe3 100644 --- a/x/gamm/twap/keeper.go +++ b/x/gamm/twap/keeper.go @@ -1,8 +1,27 @@ package twap -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" -type twapkeeper struct { - // storeKey sdk.StoreKey - transientKey sdk.TransientStoreKey + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" +) + +type Keeper struct { + storeKey sdk.StoreKey + transientKey *sdk.TransientStoreKey + + paramSpace paramtypes.Subspace + + ammkeeper types.AmmInterface +} + +func NewKeeper(storeKey sdk.StoreKey, transientKey *sdk.TransientStoreKey, paramSpace paramtypes.Subspace, ammKeeper types.AmmInterface) *Keeper { + return &Keeper{storeKey: storeKey, transientKey: transientKey, paramSpace: paramSpace, ammkeeper: ammKeeper} +} + +// TODO: make this read from a parameter, or hardcode it. +func (k *Keeper) PruneEpochIdentifier(ctx sdk.Context) string { + return "daily" } diff --git a/x/gamm/twap/module.go b/x/gamm/twap/module.go index e15b401601f..178c65219f5 100644 --- a/x/gamm/twap/module.go +++ b/x/gamm/twap/module.go @@ -1,7 +1,6 @@ package twap import ( - "context" "encoding/json" "fmt" @@ -16,9 +15,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/osmosis-labs/osmosis/v10/x/gamm/keeper" - twaptypes "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" - "github.com/osmosis-labs/osmosis/v10/x/gamm/types" + "github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types" ) var ( @@ -27,27 +24,24 @@ var ( ) type AppModuleBasic struct { - cdc codec.Codec } -func (AppModuleBasic) Name() string { return twaptypes.ModuleName } +func (AppModuleBasic) Name() string { return types.ModuleName } func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { } func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return json.RawMessage{} - // return cdc.MustMarshalJSON(types.DefaultGenesis()) + return cdc.MustMarshalJSON(&types.GenesisState{}) } // ValidateGenesis performs genesis state validation for the gamm module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - // 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() - 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() } //--------------------------------------- @@ -56,7 +50,7 @@ func (b AppModuleBasic) RegisterRESTRoutes(ctx client.Context, r *mux.Router) { } func (b AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) //nolint:errcheck + // types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) //nolint:errcheck } func (b AppModuleBasic) GetTxCmd() *cobra.Command { @@ -76,23 +70,16 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) type AppModule struct { AppModuleBasic - ak types.AccountKeeper - bk types.BankKeeper - gk keeper.Keeper - tk twapkeeper + k Keeper } func (am AppModule) RegisterServices(cfg module.Configurator) { } -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, - accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, -) AppModule { +func NewAppModule(twapKeeper Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{cdc: cdc}, - gk: keeper, - ak: accountKeeper, - bk: bankKeeper, + AppModuleBasic: AppModuleBasic{}, + k: twapKeeper, } } @@ -128,10 +115,9 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw // BeginBlock performs a no-op. func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} -// EndBlock returns the end blocker for the gamm module. It returns no validator -// updates. +// EndBlock performs a no-op. func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - am.tk.endBlockLogic(ctx) + // am.k.endBlock(ctx) return []abci.ValidatorUpdate{} } diff --git a/x/gamm/twap/store.go b/x/gamm/twap/store.go index 171a678f897..5a95438881c 100644 --- a/x/gamm/twap/store.go +++ b/x/gamm/twap/store.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (k twapkeeper) trackChangedPool(ctx sdk.Context, poolId uint64) { - store := ctx.TransientStore(&k.transientKey) +func (k Keeper) trackChangedPool(ctx sdk.Context, poolId uint64) { + store := ctx.TransientStore(k.transientKey) poolIdBz := make([]byte, 8) binary.LittleEndian.PutUint64(poolIdBz, poolId) // just has to not be empty, for store to work / not register as a delete. @@ -15,8 +15,9 @@ func (k twapkeeper) trackChangedPool(ctx sdk.Context, poolId uint64) { store.Set(poolIdBz, sentinelExistsValue) } -func (k twapkeeper) getChangedPools(ctx sdk.Context) []uint64 { - store := ctx.TransientStore(&k.transientKey) +//nolint:unused,deadcode +func (k Keeper) getChangedPools(ctx sdk.Context) []uint64 { + store := ctx.TransientStore(k.transientKey) iter := store.Iterator(nil, nil) defer iter.Close() From 3aac1b282c203866b088042466ddc49a0fec59d3 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 22 Jul 2022 12:17:54 -0500 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c6bbe25e4d..d2687f58418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,9 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -* [#2016](https://github.com/osmosis-labs/osmosis/pull/2016) Add fixed 10000 gas cost for each Balancer swap -* [$2147](https://github.com/osmosis-labs/osmosis/pull/2147) Set MaxAgeNumBlocks in v11 Upgrade Handler to two weeks. - ### Breaking Changes @@ -54,6 +51,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#1825](https://github.com/osmosis-labs/osmosis/pull/1825) Fixes Interchain Accounts (host side) by adding it to AppModuleBasics * [#1699](https://github.com/osmosis-labs/osmosis/pull/1699) Fixes bug in sig fig rounding on spot price queries for small values * [#1994](https://github.com/osmosis-labs/osmosis/pull/1994) Removed bech32ibc module +* [#2016](https://github.com/osmosis-labs/osmosis/pull/2016) Add fixed 10000 gas cost for each Balancer swap +* [#2147](https://github.com/osmosis-labs/osmosis/pull/2147) Set MaxAgeNumBlocks in v11 Upgrade Handler to two weeks. +* [#2193](https://github.com/osmosis-labs/osmosis/pull/2193) Add TwapKeeper to the Osmosis app #### Golang API breaks @@ -66,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#1630](https://github.com/osmosis-labs/osmosis/pull/1630) Delete the v043_temp module, now that we're on an updated SDK version. * [#1667](https://github.com/osmosis-labs/osmosis/pull/1673) Move wasm-bindings code out of app package into its own root level package. * [#2013](https://github.com/osmosis-labs/osmosis/pull/2013) Make `SetParams`, `SetPool`, `SetTotalLiquidity`, and `SetDenomLiquidity` GAMM APIs private -*[#1857](https://github.com/osmosis-labs/osmosis/pull/1857) x/mint rename GetLastHalvenEpochNum to GetLastReductionEpochNum +* [#1857](https://github.com/osmosis-labs/osmosis/pull/1857) x/mint rename GetLastHalvenEpochNum to GetLastReductionEpochNum ### Features