diff --git a/app/apptesting/events.go b/app/apptesting/events.go index cdfae502886..87d705cf944 100644 --- a/app/apptesting/events.go +++ b/app/apptesting/events.go @@ -7,7 +7,7 @@ import ( // AssertEventEmitted asserts that ctx's event manager has emitted the given number of events // of the given type. -func (s *KeeperTestHelper) AssertEventEmitted(ctx sdk.Context, eventTypeExpected string, numEventsExpected int) { +func (s *KeeperTestHelper) AssertEventEmitted(ctx sdk.Context, eventTypeExpected string, numEventsExpected int, msgAndArgs ...interface{}) { allEvents := ctx.EventManager().Events() // filter out other events actualEvents := make([]sdk.Event, 0) @@ -16,7 +16,7 @@ func (s *KeeperTestHelper) AssertEventEmitted(ctx sdk.Context, eventTypeExpected actualEvents = append(actualEvents, event) } } - s.Equal(numEventsExpected, len(actualEvents)) + s.Equal(numEventsExpected, len(actualEvents), msgAndArgs...) } func (s *KeeperTestHelper) FindEvent(events []sdk.Event, name string) sdk.Event { diff --git a/proto/osmosis/txfees/v1beta1/feetoken.proto b/proto/osmosis/txfees/v1beta1/feetoken.proto new file mode 100644 index 00000000000..5e41f2b3849 --- /dev/null +++ b/proto/osmosis/txfees/v1beta1/feetoken.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package osmosis.txfees.v1beta1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v15/x/txfees/types"; + +// FeeToken is a struct that specifies a coin denom, and pool ID pair. +// This marks the token as eligible for use as a tx fee asset in Osmosis. +// Its price in osmo is derived through looking at the provided pool ID. +// The pool ID must have base denom as one of its assets. +message FeeToken { + option (gogoproto.equal) = true; + + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + uint64 poolID = 2 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; +} \ No newline at end of file diff --git a/proto/osmosis/txfees/v1beta1/genesis.proto b/proto/osmosis/txfees/v1beta1/genesis.proto new file mode 100644 index 00000000000..22972bee0e9 --- /dev/null +++ b/proto/osmosis/txfees/v1beta1/genesis.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package osmosis.txfees.v1beta1; + +import "gogoproto/gogo.proto"; +import "osmosis/txfees/v1beta1/feetoken.proto"; + + +option go_package = "github.com/osmosis-labs/osmosis/v15/x/txfees/types"; + +// GenesisState defines the txfees module's genesis state. +message GenesisState { + // params are all the parameters of the module + Params params = 1 [ (gogoproto.nullable) = false ]; + string basedenom = 2; + repeated FeeToken feetokens = 3 [ (gogoproto.nullable) = false ]; +} + + +// Params holds parameters for the incentives module +message Params { + // epoch_identifier is what epoch type swap and burn will be triggered by + // (day, week, etc.) + string epoch_identifier = 1 + [ (gogoproto.moretags) = "yaml:\"epoch_identifier\"" ]; +} diff --git a/proto/osmosis/txfees/v1beta1/query.proto b/proto/osmosis/txfees/v1beta1/query.proto new file mode 100644 index 00000000000..007fad19317 --- /dev/null +++ b/proto/osmosis/txfees/v1beta1/query.proto @@ -0,0 +1,88 @@ +syntax = "proto3"; +package osmosis.txfees.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/duration.proto"; + +import "osmosis/txfees/v1beta1/feetoken.proto"; +import "osmosis/txfees/v1beta1/genesis.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v15/x/txfees/types"; + +service Query { + // Params returns params. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/osmosis/txfees/v1beta1/params"; + } + + + // FeeTokens returns a list of all the accepted fee tokens and their + // corresponding pools. It does not include the BaseDenom, which has its own + // query endpoint + rpc FeeTokens(QueryFeeTokensRequest) returns (QueryFeeTokensResponse) { + option (google.api.http).get = "/osmosis/txfees/v1beta1/fee_tokens"; + } + + // DenomSpotPrice returns all spot prices by each registered token denom. + rpc DenomSpotPrice(QueryDenomSpotPriceRequest) + returns (QueryDenomSpotPriceResponse) { + option (google.api.http).get = + "/osmosis/txfees/v1beta1/spot_price_by_denom"; + } + + // Returns the poolID for a specified denom input. + rpc DenomPoolId(QueryDenomPoolIdRequest) returns (QueryDenomPoolIdResponse) { + option (google.api.http).get = + "/osmosis/txfees/v1beta1/denom_pool_id/{denom}"; + } + + // Returns a list of all base denom tokens and their corresponding pools. + rpc BaseDenom(QueryBaseDenomRequest) returns (QueryBaseDenomResponse) { + option (google.api.http).get = "/osmosis/txfees/v1beta1/base_denom"; + } +} + + +message QueryParamsRequest {} +message QueryParamsResponse { + Params params = 1 [ (gogoproto.nullable) = false ]; +} + + +message QueryFeeTokensRequest {} +message QueryFeeTokensResponse { + repeated FeeToken fee_tokens = 1 [ + (gogoproto.moretags) = "yaml:\"fee_tokens\"", + (gogoproto.nullable) = false + ]; +} + +// QueryDenomSpotPriceRequest defines grpc request structure for querying spot +// price for the specified tx fee denom +message QueryDenomSpotPriceRequest { + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; +} + +// QueryDenomSpotPriceRequest defines grpc response structure for querying spot +// price for the specified tx fee denom +message QueryDenomSpotPriceResponse { + uint64 poolID = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; + string spot_price = 2 [ + (gogoproto.moretags) = "yaml:\"spot_price\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +message QueryDenomPoolIdRequest { + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; +} +message QueryDenomPoolIdResponse { + uint64 poolID = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; +} + +message QueryBaseDenomRequest {} +message QueryBaseDenomResponse { + string base_denom = 1 [ (gogoproto.moretags) = "yaml:\"base_denom\"" ]; +} diff --git a/x/gamm/keeper/keeper.go b/x/gamm/keeper/keeper.go index 63e845e0b6c..ea154ce2e29 100644 --- a/x/gamm/keeper/keeper.go +++ b/x/gamm/keeper/keeper.go @@ -34,6 +34,7 @@ type Keeper struct { bankKeeper types.BankKeeper communityPoolKeeper types.CommunityPoolKeeper poolManager types.PoolManager + txfeeKeeper types.TxFeeKeeper } func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, communityPoolKeeper types.CommunityPoolKeeper) Keeper { @@ -51,6 +52,17 @@ func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace p if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } + + if accountKeeper == nil { + panic("account keeper is nil") + } + if bankKeeper == nil { + panic("bank keeper is nil") + } + if communityPoolKeeper == nil { + panic("community pool keeper is nil") + } + return Keeper{ storeKey: storeKey, cdc: cdc, @@ -73,10 +85,18 @@ func (k *Keeper) SetHooks(gh types.GammHooks) *Keeper { return k } +// SetPoolManager sets the pool manager. +// must be called when initializing the keeper. func (k *Keeper) SetPoolManager(poolManager types.PoolManager) { k.poolManager = poolManager } +// SetTxFees sets the tx fees keeper. +// must be called when initializing the keeper. +func (k *Keeper) SetTxFees(txfees types.TxFeeKeeper) { + k.txfeeKeeper = txfees +} + // GetParams returns the total set params. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.paramSpace.GetParamSet(ctx, ¶ms) diff --git a/x/gamm/keeper/msg_server.go b/x/gamm/keeper/msg_server.go index 0f1538645db..8b4b4c14aa0 100644 --- a/x/gamm/keeper/msg_server.go +++ b/x/gamm/keeper/msg_server.go @@ -8,6 +8,7 @@ import ( "github.com/osmosis-labs/osmosis/v15/osmoutils" "github.com/osmosis-labs/osmosis/v15/x/gamm/pool-models/balancer" "github.com/osmosis-labs/osmosis/v15/x/gamm/types" + poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" ) type msgServer struct { @@ -178,7 +179,9 @@ func (server msgServer) SwapExactAmountIn(goCtx context.Context, msg *types.MsgS return nil, err } - err = server.keeper.chargeTakerFeeSwapAmountIn(ctx, takerFeesCoins, sender, msg.Routes) + //first pool for taker fee swaps if needed + takerFeeRoute := msg.Routes[0] + err = server.keeper.chargeTakerFee(ctx, takerFeesCoins, sender, takerFeeRoute) if err != nil { return nil, err } @@ -221,7 +224,16 @@ func (server msgServer) SwapExactAmountOut(goCtx context.Context, msg *types.Msg tokenInCoin := sdk.NewCoin(msg.Routes[0].TokenInDenom, tokenInAmount) tokenInAmountWithTakerFee, takerFeeCoin := server.keeper.AddTakerFee(tokenInCoin, takerFee) - err = server.keeper.chargeTakerFeeSwapAmountOut(ctx, takerFeeCoin, sender, msg.Routes, msg.TokenOut.Denom) + //first pool for taker fee swaps if needed + takerFeeRoute := poolmanagertypes.SwapAmountInRoute{} + takerFeeRoute.PoolId = msg.Routes[0].PoolId + if len(msg.Routes) > 1 { + takerFeeRoute.TokenOutDenom = msg.Routes[1].TokenInDenom + } else { + takerFeeRoute.TokenOutDenom = msg.TokenOutDenom() + } + + err = server.keeper.chargeTakerFee(ctx, takerFeeCoin, sender, takerFeeRoute) if err != nil { return nil, err } diff --git a/x/gamm/keeper/msg_server_events_test.go b/x/gamm/keeper/msg_server_events_test.go index a32018b9984..40024ddb4e8 100644 --- a/x/gamm/keeper/msg_server_events_test.go +++ b/x/gamm/keeper/msg_server_events_test.go @@ -3,8 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - + "github.com/osmosis-labs/osmosis/v15/app/apptesting" "github.com/osmosis-labs/osmosis/v15/x/gamm/keeper" "github.com/osmosis-labs/osmosis/v15/x/gamm/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" @@ -29,8 +28,8 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { tokenIn sdk.Coin tokenOutMinAmount sdk.Int expectError bool - expectedBurnEvents bool expectedSwapEvents int + expectedTakerFeeSwap bool expectedMessageEvents int }{ "zero hops": { @@ -42,62 +41,59 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { "one hop": { routes: []poolmanagertypes.SwapAmountInRoute{ { - PoolId: 1, + PoolId: 3, TokenOutDenom: "bar", }, }, tokenIn: sdk.NewCoin("udym", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), expectedSwapEvents: 1, - expectedBurnEvents: true, - expectedMessageEvents: 4, // 1 gamm + 2 bank send for swap + 1 bank send when burn + expectedMessageEvents: 4, // 1 gamm + 2 bank send for swap + 1 bank send }, "one hop - taker fee swap": { routes: []poolmanagertypes.SwapAmountInRoute{ { - PoolId: 1, - TokenOutDenom: "udym", + PoolId: 4, + TokenOutDenom: "bar", }, }, - tokenIn: sdk.NewCoin("bar", sdk.NewInt(tokenIn)), + tokenIn: sdk.NewCoin("baz", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), expectedSwapEvents: 2, - expectedBurnEvents: true, - expectedMessageEvents: 6, // 1 gamm + 2 bank send for swap + 2 taker fee swap + 1 bank send when burn + expectedTakerFeeSwap: true, + expectedMessageEvents: 6, // 1 gamm + 2 bank send for swap + 2 swap taker fee + 1 bank send when burn }, "two hops": { routes: []poolmanagertypes.SwapAmountInRoute{ { - PoolId: 1, + PoolId: 3, TokenOutDenom: "bar", }, { - PoolId: 2, + PoolId: 4, TokenOutDenom: "baz", }, }, tokenIn: sdk.NewCoin("udym", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), expectedSwapEvents: 2, - expectedBurnEvents: true, expectedMessageEvents: 6, // 1 gamm + 4 swap + 1 burn }, "two hops - taker fee swap": { routes: []poolmanagertypes.SwapAmountInRoute{ { - PoolId: 1, + PoolId: 2, TokenOutDenom: "bar", }, { - PoolId: 2, + PoolId: 3, TokenOutDenom: "udym", }, }, tokenIn: sdk.NewCoin("foo", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), - expectedBurnEvents: true, - expectedSwapEvents: 4, //2 for the swap + 2 for taker fee - expectedMessageEvents: 10, // 1 gamm + 8 swap + 1 burn + expectedSwapEvents: 2, //2 for the swap + expectedMessageEvents: 6, // 1 gamm + 4 swap + 1 burn }, "invalid - two hops, denom does not exist": { routes: []poolmanagertypes.SwapAmountInRoute{ @@ -117,37 +113,44 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { } for name, tc := range testcases { - suite.Run(name, func() { - suite.Setup() - ctx := suite.Ctx + suite.Setup() + ctx := suite.Ctx + suite.App.TxFeesKeeper.SetBaseDenom(ctx, "udym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - suite.PrepareBalancerPool() - suite.PrepareBalancerPool() + pool1coins := []sdk.Coin{sdk.NewCoin("udym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) - // Reset event counts to 0 by creating a new manager. - ctx = ctx.WithEventManager(sdk.NewEventManager()) - suite.Equal(0, len(ctx.EventManager().Events())) + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("udym", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) - response, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenIn: tc.tokenIn, - TokenOutMinAmount: tc.tokenOutMinAmount, - }) + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) - if !tc.expectError { - suite.NoError(err) - suite.NotNil(response) - } - if tc.expectedBurnEvents { - suite.AssertEventEmitted(ctx, banktypes.EventTypeCoinBurn, 1) - } + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents) - suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents) + // Reset event counts to 0 by creating a new manager. + ctx = ctx.WithEventManager(sdk.NewEventManager()) + suite.Equal(0, len(ctx.EventManager().Events())) + + response, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenIn: tc.tokenIn, + TokenOutMinAmount: tc.tokenOutMinAmount, }) + + if !tc.expectError { + suite.Require().NoError(err, name) + suite.Require().NotNil(response, name) + } + + suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) + suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents, name) } } @@ -164,75 +167,52 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { tokenOut sdk.Coin tokenInMaxAmount sdk.Int expectError bool - expectedBurnEvents bool expectedSwapEvents int expectedMessageEvents int }{ - // "zero hops": { - // routes: []poolmanagertypes.SwapAmountOutRoute{}, - // tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)), - // tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - // expectError: true, - // }, - // "one hop": { - // routes: []poolmanagertypes.SwapAmountOutRoute{ - // { - // PoolId: 1, - // TokenInDenom: "udym", - // }, - // }, - // tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)), - // tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - // expectedBurnEvents: true, - // expectedSwapEvents: 1, - // expectedMessageEvents: 4, // 1 gamm + 2 for swap + 1 for burn - // }, "one hop - with taker fee": { routes: []poolmanagertypes.SwapAmountOutRoute{ { - PoolId: 1, + PoolId: 3, TokenInDenom: "bar", }, }, tokenOut: sdk.NewCoin("udym", sdk.NewInt(tokenOut)), tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - expectedBurnEvents: true, - expectedSwapEvents: 2, - expectedMessageEvents: 6, // 1 gamm + 2 for swap + 2 swap for taker fee + 1 for send to burn + expectedSwapEvents: 1, + expectedMessageEvents: 4, // 1 gamm + 2 for swap + 1 for send }, "two hops": { routes: []poolmanagertypes.SwapAmountOutRoute{ { - PoolId: 1, + PoolId: 3, TokenInDenom: "udym", }, { PoolId: 2, - TokenInDenom: "baz", + TokenInDenom: "bar", }, }, tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)), tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - expectedBurnEvents: true, expectedSwapEvents: 2, expectedMessageEvents: 6, // 1 gamm + 4 for swap + 1 for send to community }, "two hops - taker fee swap": { routes: []poolmanagertypes.SwapAmountOutRoute{ { - PoolId: 1, + PoolId: 3, TokenInDenom: "bar", }, { - PoolId: 2, + PoolId: 1, TokenInDenom: "udym", }, }, tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)), tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - expectedBurnEvents: true, - expectedSwapEvents: 3, - expectedMessageEvents: 8, // 1 gamm + 4 for swap + 2 for taker fee swap + 1 for send to burn + expectedSwapEvents: 2, + expectedMessageEvents: 6, // 1 gamm + 4 for swap + 1 for send to burn }, "invalid - two hops, denom does not exist": { routes: []poolmanagertypes.SwapAmountOutRoute{ @@ -252,38 +232,44 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { } for name, tc := range testcases { - suite.Run(name, func() { - suite.Setup() - ctx := suite.Ctx + suite.Setup() + ctx := suite.Ctx + suite.App.TxFeesKeeper.SetBaseDenom(ctx, "udym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - suite.PrepareBalancerPool() - suite.PrepareBalancerPool() + pool1coins := []sdk.Coin{sdk.NewCoin("udym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) - // Reset event counts to 0 by creating a new manager. - ctx = ctx.WithEventManager(sdk.NewEventManager()) - suite.Equal(0, len(ctx.EventManager().Events())) + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("udym", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) - response, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenOut: tc.tokenOut, - TokenInMaxAmount: tc.tokenInMaxAmount, - }) + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) - if !tc.expectError { - suite.NoError(err) - suite.NotNil(response) - } + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - if tc.expectedBurnEvents { - suite.AssertEventEmitted(ctx, banktypes.EventTypeCoinBurn, 1) - } + // Reset event counts to 0 by creating a new manager. + ctx = ctx.WithEventManager(sdk.NewEventManager()) + suite.Equal(0, len(ctx.EventManager().Events())) - suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents) - suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents) + response, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenOut: tc.tokenOut, + TokenInMaxAmount: tc.tokenInMaxAmount, }) + + if !tc.expectError { + suite.Require().NoError(err, name) + suite.Require().NotNil(response, name) + } + + suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) + suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents, name) } } diff --git a/x/gamm/keeper/taker_fee.go b/x/gamm/keeper/taker_fee.go index 05ceca88dee..6c19b2280eb 100644 --- a/x/gamm/keeper/taker_fee.go +++ b/x/gamm/keeper/taker_fee.go @@ -1,109 +1,60 @@ package keeper import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/osmosis-labs/osmosis/v15/osmoutils" - "github.com/osmosis-labs/osmosis/v15/x/gamm/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" + txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) -const ( - defaultTakerFeeDenom = "udym" -) - -// possibilites for takerFeeCoin: -// 1. DYM -> taker fee is already in DYM -// 2. any other denom -> DYM (taker fee will be swapped and burned) -// 3. Base denom -> find pool with DYM -// 4. any other denom -> make swap on first pool (to swap for base denom) than find pool with DYM -func (k Keeper) chargeTakerFeeSwapAmountOut(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sdk.AccAddress, outRoutes []poolmanagertypes.SwapAmountOutRoute, denomOut string) error { - if takerFeeCoin.Denom == defaultTakerFeeDenom { - return k.swapAndBurn(ctx, sender, nil, takerFeeCoin) +// ChargeTakerFee charges the taker fee to the sender +// If the taker fee coin is the base denom, send it to the txfees module +// If the taker fee coin is a registered fee token, send it to the txfees module +// If the taker fee coin is not supported, swap it to the base denom on the first pool, then send it to the txfees module +func (k Keeper) chargeTakerFee(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sdk.AccAddress, route poolmanagertypes.SwapAmountInRoute) error { + // Check if the taker fee coin is the base denom + denom, err := k.txfeeKeeper.GetBaseDenom(ctx) + if err != nil { + return err } - - //transcode the outRoutes to inRoutes - firstPool := poolmanagertypes.SwapAmountInRoute{} - firstPool.PoolId = outRoutes[0].PoolId - if len(outRoutes) > 1 { - firstPool.TokenOutDenom = outRoutes[1].TokenInDenom - } else { - firstPool.TokenOutDenom = denomOut + if takerFeeCoin.Denom == denom { + return k.sendToTxFees(ctx, sender, takerFeeCoin) } - return k.swapAndBurn(ctx, sender, []poolmanagertypes.SwapAmountInRoute{firstPool}, takerFeeCoin) -} - -// possibilites for takerFeeCoin: -// 1. DYM -> taker fee is already in DYM -// 2. any other denom -> DYM (taker fee will be swapped and burned) -// 3. Base denom -> find pool with DYM -// 4. any other denom -> make swap on first pool (to swap for base denom) than find pool with DYM -func (k Keeper) chargeTakerFeeSwapAmountIn(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sdk.AccAddress, routes []poolmanagertypes.SwapAmountInRoute) error { - if takerFeeCoin.Denom == defaultTakerFeeDenom { - return k.swapAndBurn(ctx, sender, nil, takerFeeCoin) + // Check if the taker fee coin is a registered fee token + _, err = k.txfeeKeeper.GetFeeToken(ctx, takerFeeCoin.Denom) + if err == nil { + return k.sendToTxFees(ctx, sender, takerFeeCoin) } - return k.swapAndBurn(ctx, sender, []poolmanagertypes.SwapAmountInRoute{routes[0]}, takerFeeCoin) -} - -// swapAndBurn swaps the taker fee coin to DYM and then burns it. -// if routes is nil, it directly burns the taker fee coin witout swaps -// if routes is not nil, it uses the first route to swap the taker fee coin to base denom -// if the first route's output denom is not DYM but other base denom, it finds the pool with this base denom and DYM -func (k Keeper) swapAndBurn(ctx sdk.Context, sender sdk.AccAddress, routes []poolmanagertypes.SwapAmountInRoute, tokenIn sdk.Coin) error { - if len(routes) == 0 { - return k.burnTakerFee(ctx, tokenIn, sender) - } - - var routeForTakerFee []poolmanagertypes.SwapAmountInRoute - firstPool := routes[0] - - // Do the swap of this fee token denom to base denom. - if firstPool.TokenOutDenom == defaultTakerFeeDenom { - routeForTakerFee = []poolmanagertypes.SwapAmountInRoute{firstPool} - } else { - params := k.GetParams(ctx) - //if tokenIn is base denom, we need to find the pool with DYM - isBaseDenom, _ := params.PoolCreationFee.Find(tokenIn.Denom) - if isBaseDenom { - route, err := k.findPoolWithTakerFeeDenom(ctx, tokenIn.Denom) - if err != nil { - ctx.Logger().Error("failed to find swapping route to DYM", "error", err) - return k.communityPoolKeeper.FundCommunityPool(ctx, sdk.NewCoins(tokenIn), sender) - } - routeForTakerFee = []poolmanagertypes.SwapAmountInRoute{route} - } else { - //If swap needed, add the first pool to the route (to swap for base denom) - route, err := k.findPoolWithTakerFeeDenom(ctx, firstPool.TokenOutDenom) - if err != nil { - ctx.Logger().Error("failed to find swapping route to DYM", "error", err) - return k.communityPoolKeeper.FundCommunityPool(ctx, sdk.NewCoins(tokenIn), sender) - } - routeForTakerFee = []poolmanagertypes.SwapAmountInRoute{firstPool, route} - } + // If not supported denom, swap on the first pool to get some pool base denom, which has liquidity with DYM + ctx.Logger().Debug("taker fee coin is not supported by txfee module, requires swap", "takerFeeCoin", takerFeeCoin) + swappedTakerFee, err := k.swapTakerFee(ctx, sender, route, takerFeeCoin) + if err != nil { + return err } - //double check the denom before burning - if routeForTakerFee[len(routeForTakerFee)-1].TokenOutDenom != defaultTakerFeeDenom { - ctx.Logger().Error("wrong route to burn Taker Fee", "tokenIn", tokenIn, "routes", routeForTakerFee) - return k.communityPoolKeeper.FundCommunityPool(ctx, sdk.NewCoins(tokenIn), sender) - } + return k.sendToTxFees(ctx, sender, swappedTakerFee) +} +// swapTakerFee swaps the taker fee coin to the base denom on the first pool +func (k Keeper) swapTakerFee(ctx sdk.Context, sender sdk.AccAddress, route poolmanagertypes.SwapAmountInRoute, tokenIn sdk.Coin) (sdk.Coin, error) { minAmountOut := sdk.ZeroInt() - burnTokens := sdk.Coin{} - out, err := k.poolManager.RouteExactAmountIn(ctx, sender, routeForTakerFee, tokenIn, minAmountOut) + swapRoutes := poolmanagertypes.SwapAmountInRoutes{route} + out, err := k.poolManager.RouteExactAmountIn(ctx, sender, swapRoutes, tokenIn, minAmountOut) if err != nil { - return err + return sdk.Coin{}, err } - burnTokens.Amount = out - burnTokens.Denom = defaultTakerFeeDenom + coin := sdk.NewCoin(route.TokenOutDenom, out) + return coin, nil +} - return k.burnTakerFee(ctx, burnTokens, sender) +// sendToTxFees sends the taker fee coin to the txfees module +func (k Keeper) sendToTxFees(ctx sdk.Context, sender sdk.AccAddress, takerFeeCoin sdk.Coin) error { + return k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, txfeestypes.ModuleName, sdk.NewCoins(takerFeeCoin)) } +/* ---------------------------------- Utils --------------------------------- */ // Returns remaining amount in to swap, and takerFeeCoins. // returns (1 - takerFee) * tokenIn, takerFee * tokenIn func (k Keeper) SubTakerFee(tokenIn sdk.Coin, takerFee sdk.Dec) (sdk.Coin, sdk.Coin) { @@ -120,45 +71,3 @@ func (k Keeper) AddTakerFee(tokenIn sdk.Coin, takerFee sdk.Dec) (sdk.Coin, sdk.C takerFeeCoin := sdk.NewCoin(tokenIn.Denom, tokenInAfterAddTakerFee.Amount.Sub(tokenIn.Amount)) return tokenInAfterAddTakerFee, takerFeeCoin } - -// BurnPoolShareFromAccount burns `amount` of the given pools shares held by `addr`. -func (k Keeper) burnTakerFee(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sdk.AccAddress) error { - amt := sdk.NewCoins(takerFeeCoin) - err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amt) - if err != nil { - return err - } - - err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, amt) - if err != nil { - return err - } - - return nil -} - -// find route from denom to defaultTakerFeeDenom by iterating all pools -func (k Keeper) findPoolWithTakerFeeDenom(ctx sdk.Context, fromDenom string) (poolmanagertypes.SwapAmountInRoute, error) { - route := poolmanagertypes.SwapAmountInRoute{} - - iter := k.iterator(ctx, types.KeyPrefixPools) - defer iter.Close() //nolint:errcheck - - for ; iter.Valid(); iter.Next() { - pool, err := k.UnmarshalPool(iter.Value()) - if err != nil { - return route, err - } - - poolDenoms := osmoutils.CoinsDenoms(pool.GetTotalPoolLiquidity(ctx)) - - //check if poolDenoms contains both fromDenom and defaultTakerFeeDenom - if contains(poolDenoms, fromDenom) && contains(poolDenoms, defaultTakerFeeDenom) { - route.PoolId = pool.GetId() - route.TokenOutDenom = defaultTakerFeeDenom - return route, nil - } - } - - return route, fmt.Errorf("failed to find pool with %s and %s", fromDenom, defaultTakerFeeDenom) -} diff --git a/x/gamm/keeper/taker_fee_test.go b/x/gamm/keeper/taker_fee_test.go index 6ddeacf6124..11d06a2432a 100644 --- a/x/gamm/keeper/taker_fee_test.go +++ b/x/gamm/keeper/taker_fee_test.go @@ -8,15 +8,17 @@ import ( "github.com/osmosis-labs/osmosis/v15/x/gamm/keeper" "github.com/osmosis-labs/osmosis/v15/x/gamm/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" + txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) /* ----------------------------- Testing ExactIn ---------------------------- */ -func (suite *KeeperTestSuite) TestDYMIsBurned_ExactIn() { +func (suite *KeeperTestSuite) TestTakerFeeCharged_ExactIn() { tokenInAmt := int64(100000) testcases := map[string]struct { routes []poolmanagertypes.SwapAmountInRoute tokenIn sdk.Coin tokenOutMinAmount sdk.Int + expectSwap bool expectError bool }{ "zero hops": { @@ -95,6 +97,9 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactIn() { for name, tc := range testcases { suite.SetupTest() + + suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "udym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) params := suite.App.GAMMKeeper.GetParams(suite.Ctx) params.PoolCreationFee = sdk.NewCoins( @@ -118,11 +123,9 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactIn() { pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} suite.PrepareBalancerPoolWithCoins(pool4coins...) - //check total supply before swap - suppliesBefore := make(map[string]sdk.Int) - suppliesBefore["udym"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "udym").Amount - suppliesBefore["foo"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "foo").Amount - suppliesBefore["bar"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "bar").Amount + //get the balance of txfees before swap + moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) + balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) // check taker fee is not 0 suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) @@ -140,24 +143,23 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactIn() { } suite.Require().NoError(err, name) - // check total supply after swap - suppliesAfter := make(map[string]sdk.Int) - suppliesAfter["udym"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "udym").Amount - suppliesAfter["foo"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "foo").Amount - suppliesAfter["bar"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "bar").Amount + //get the balance of txfees after swap + balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - //validate total supply is reduced by taker fee - suite.Require().True(suppliesAfter["udym"].LT(suppliesBefore["udym"]), name) - suite.Require().True(suppliesAfter["foo"].Equal(suppliesBefore["foo"]), name) - suite.Require().True(suppliesAfter["bar"].Equal(suppliesBefore["bar"]), name) + testDenom := tc.tokenIn.Denom + if tc.expectSwap { + testDenom = tc.routes[0].TokenOutDenom + } + suite.Require().True(balancesAfter.AmountOf(testDenom).GT(balancesBefore.AmountOf(testDenom)), name) } } -func (suite *KeeperTestSuite) TestDYMIsBurned_ExactOut() { +func (suite *KeeperTestSuite) TestTakerFeeCharged_ExactOut() { tokenInAmt := int64(100000) testcases := map[string]struct { routes []poolmanagertypes.SwapAmountOutRoute tokenOut sdk.Coin + expectSwap bool expectError bool }{ "zero hops": { @@ -215,20 +217,24 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactOut() { tokenOut: sdk.NewCoin("baz", sdk.NewInt(tokenInAmt)), expectError: false, }, - "usdc swap with dym": { + "baz swap with usdc": { routes: []poolmanagertypes.SwapAmountOutRoute{ { - PoolId: 3, - TokenInDenom: "bar", + PoolId: 4, + TokenInDenom: "baz", }, }, - tokenOut: sdk.NewCoin("udym", sdk.NewInt(tokenInAmt)), + tokenOut: sdk.NewCoin("bar", sdk.NewInt(tokenInAmt)), + expectSwap: true, expectError: false, }, } for name, tc := range testcases { suite.SetupTest() + + suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "udym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) params := suite.App.GAMMKeeper.GetParams(suite.Ctx) params.PoolCreationFee = sdk.NewCoins( @@ -252,11 +258,9 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactOut() { pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("baz", sdk.NewInt(100000000))} suite.PrepareBalancerPoolWithCoins(pool4coins...) - //check total supply before swap - suppliesBefore := make(map[string]sdk.Int) - suppliesBefore["udym"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "udym").Amount - suppliesBefore["foo"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "foo").Amount - suppliesBefore["bar"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "bar").Amount + //get the balance of txfees before swap + moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) + balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) // check taker fee is not 0 suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) @@ -274,16 +278,14 @@ func (suite *KeeperTestSuite) TestDYMIsBurned_ExactOut() { } suite.Require().NoError(err, name) - // check total supply after swap - suppliesAfter := make(map[string]sdk.Int) - suppliesAfter["udym"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "udym").Amount - suppliesAfter["foo"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "foo").Amount - suppliesAfter["bar"] = suite.App.BankKeeper.GetSupply(suite.Ctx, "bar").Amount + //get the balance of txfees after swap + balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - //validate total supply is reduced by taker fee - suite.Require().True(suppliesAfter["udym"].LT(suppliesBefore["udym"]), name) - suite.Require().True(suppliesAfter["foo"].Equal(suppliesBefore["foo"]), name) - suite.Require().True(suppliesAfter["bar"].Equal(suppliesBefore["bar"]), name) + testDenom := tc.routes[0].TokenInDenom + if tc.expectSwap { + testDenom = tc.tokenOut.Denom + } + suite.Require().True(balancesAfter.AmountOf(testDenom).GT(balancesBefore.AmountOf(testDenom)), testDenom, name) } } diff --git a/x/gamm/types/events.go b/x/gamm/types/events.go index 4ce8bd4a184..6a1cfa41344 100644 --- a/x/gamm/types/events.go +++ b/x/gamm/types/events.go @@ -15,5 +15,3 @@ const ( AttributeKeyTokensIn = "tokens_in" AttributeKeyTokensOut = "tokens_out" ) - -//FIXME: Add events for taker fee diff --git a/x/gamm/types/expected_keepers.go b/x/gamm/types/expected_keepers.go index 8498d2e720a..b51e38a35b3 100644 --- a/x/gamm/types/expected_keepers.go +++ b/x/gamm/types/expected_keepers.go @@ -6,6 +6,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" + txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) // AccountKeeper defines the account contract that must be fulfilled when @@ -78,3 +79,8 @@ type PoolManager interface { GetPoolModule(ctx sdk.Context, poolId uint64) (poolmanagertypes.SwapI, error) } + +type TxFeeKeeper interface { + GetFeeToken(ctx sdk.Context, denom string) (txfeestypes.FeeToken, error) + GetBaseDenom(ctx sdk.Context) (denom string, err error) +} diff --git a/x/incentives/keeper/gauge_test.go b/x/incentives/keeper/gauge_test.go index 418ec23fc1c..dfe879b37e7 100644 --- a/x/incentives/keeper/gauge_test.go +++ b/x/incentives/keeper/gauge_test.go @@ -299,6 +299,9 @@ func (suite *KeeperTestSuite) TestChargeFeeIfSufficientFeeDenomBalance() { suite.Run(name, func() { suite.SetupTest() + err := suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "udym") + suite.Require().NoError(err) + testAccount := suite.TestAccs[0] ctx := suite.Ctx @@ -312,7 +315,7 @@ func (suite *KeeperTestSuite) TestChargeFeeIfSufficientFeeDenomBalance() { oldBalanceAmount := bankKeeper.GetBalance(ctx, testAccount, "udym").Amount // System under test. - err := incentivesKeepers.ChargeFeeIfSufficientFeeDenomBalance(ctx, testAccount, sdk.NewInt(tc.feeToCharge), tc.gaugeCoins) + err = incentivesKeepers.ChargeFeeIfSufficientFeeDenomBalance(ctx, testAccount, sdk.NewInt(tc.feeToCharge), tc.gaugeCoins) // Assertions. newBalanceAmount := bankKeeper.GetBalance(ctx, testAccount, "udym").Amount diff --git a/x/incentives/keeper/msg_server_test.go b/x/incentives/keeper/msg_server_test.go index b0f10ed7e78..1aacd0fd7de 100644 --- a/x/incentives/keeper/msg_server_test.go +++ b/x/incentives/keeper/msg_server_test.go @@ -78,6 +78,9 @@ func (suite *KeeperTestSuite) TestCreateGauge_Fee() { for _, tc := range tests { suite.SetupTest() + err := suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "udym") + suite.Require().NoError(err) + testAccountPubkey := secp256k1.GenPrivKeyFromSecret([]byte("acc")).PubKey() testAccountAddress := sdk.AccAddress(testAccountPubkey.Address()) @@ -112,7 +115,7 @@ func (suite *KeeperTestSuite) TestCreateGauge_Fee() { NumEpochsPaidOver: 1, } // System under test. - _, err := msgServer.CreateGauge(sdk.WrapSDKContext(ctx), msg) + _, err = msgServer.CreateGauge(sdk.WrapSDKContext(ctx), msg) if tc.expectErr { suite.Require().Error(err) @@ -188,6 +191,9 @@ func (suite *KeeperTestSuite) TestAddToGauge_Fee() { for _, tc := range tests { suite.SetupTest() + err := suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "udym") + suite.Require().NoError(err) + testAccountPubkey := secp256k1.GenPrivKeyFromSecret([]byte("acc")).PubKey() testAccountAddress := sdk.AccAddress(testAccountPubkey.Address()) // testAccountAddress := suite.TestAccs[0] @@ -221,7 +227,7 @@ func (suite *KeeperTestSuite) TestAddToGauge_Fee() { Rewards: tc.gaugeAddition, } - _, err := msgServer.AddToGauge(sdk.WrapSDKContext(ctx), msg) + _, err = msgServer.AddToGauge(sdk.WrapSDKContext(ctx), msg) if tc.expectErr { suite.Require().Error(err) diff --git a/x/poolmanager/types/expected_keepers.go b/x/poolmanager/types/expected_keepers.go new file mode 100644 index 00000000000..782c2e35507 --- /dev/null +++ b/x/poolmanager/types/expected_keepers.go @@ -0,0 +1,68 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// AccountI defines the account contract that must be fulfilled when +// creating a x/gamm keeper. +type AccountI interface { + NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + SetAccount(ctx sdk.Context, acc authtypes.AccountI) +} + +// BankI defines the banking contract that must be fulfilled when +// creating a x/gamm keeper. +type BankI interface { + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) +} + +// TODO: godoc +type SwapI interface { + InitializePool(ctx sdk.Context, pool PoolI, creatorAddress sdk.AccAddress) error + + GetPool(ctx sdk.Context, poolId uint64) (PoolI, error) + + SwapExactAmountIn( + ctx sdk.Context, + sender sdk.AccAddress, + pool PoolI, + tokenIn sdk.Coin, + tokenOutDenom string, + tokenOutMinAmount sdk.Int, + swapFee sdk.Dec, + ) (sdk.Int, error) + // CalcOutAmtGivenIn calculates the amount of tokenOut given tokenIn and the pool's current state. + // Returns error if the given pool is not a CFMM pool. Returns error on internal calculations. + CalcOutAmtGivenIn( + ctx sdk.Context, + poolI PoolI, + tokenIn sdk.Coin, + tokenOutDenom string, + swapFee sdk.Dec, + ) (tokenOut sdk.Coin, err error) + + SwapExactAmountOut( + ctx sdk.Context, + sender sdk.AccAddress, + pool PoolI, + tokenInDenom string, + tokenInMaxAmount sdk.Int, + tokenOut sdk.Coin, + swapFee sdk.Dec, + ) (tokenInAmount sdk.Int, err error) + // CalcInAmtGivenOut calculates the amount of tokenIn given tokenOut and the pool's current state. + // Returns error if the given pool is not a CFMM pool. Returns error on internal calculations. + CalcInAmtGivenOut( + ctx sdk.Context, + poolI PoolI, + tokenOut sdk.Coin, + tokenInDenom string, + swapFee sdk.Dec, + ) (tokenIn sdk.Coin, err error) +} diff --git a/x/poolmanager/types/routes.go b/x/poolmanager/types/routes.go index f4ac94fe850..ae90eb62046 100644 --- a/x/poolmanager/types/routes.go +++ b/x/poolmanager/types/routes.go @@ -2,71 +2,8 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -// AccountI defines the account contract that must be fulfilled when -// creating a x/gamm keeper. -type AccountI interface { - NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI - GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI - SetAccount(ctx sdk.Context, acc authtypes.AccountI) -} - -// BankI defines the banking contract that must be fulfilled when -// creating a x/gamm keeper. -type BankI interface { - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) -} - -// TODO: godoc -type SwapI interface { - InitializePool(ctx sdk.Context, pool PoolI, creatorAddress sdk.AccAddress) error - - GetPool(ctx sdk.Context, poolId uint64) (PoolI, error) - - SwapExactAmountIn( - ctx sdk.Context, - sender sdk.AccAddress, - pool PoolI, - tokenIn sdk.Coin, - tokenOutDenom string, - tokenOutMinAmount sdk.Int, - swapFee sdk.Dec, - ) (sdk.Int, error) - // CalcOutAmtGivenIn calculates the amount of tokenOut given tokenIn and the pool's current state. - // Returns error if the given pool is not a CFMM pool. Returns error on internal calculations. - CalcOutAmtGivenIn( - ctx sdk.Context, - poolI PoolI, - tokenIn sdk.Coin, - tokenOutDenom string, - swapFee sdk.Dec, - ) (tokenOut sdk.Coin, err error) - - SwapExactAmountOut( - ctx sdk.Context, - sender sdk.AccAddress, - pool PoolI, - tokenInDenom string, - tokenInMaxAmount sdk.Int, - tokenOut sdk.Coin, - swapFee sdk.Dec, - ) (tokenInAmount sdk.Int, err error) - // CalcInAmtGivenOut calculates the amount of tokenIn given tokenOut and the pool's current state. - // Returns error if the given pool is not a CFMM pool. Returns error on internal calculations. - CalcInAmtGivenOut( - ctx sdk.Context, - poolI PoolI, - tokenOut sdk.Coin, - tokenInDenom string, - swapFee sdk.Dec, - ) (tokenIn sdk.Coin, err error) -} - type SwapAmountInRoutes []SwapAmountInRoute func (routes SwapAmountInRoutes) Validate() error { diff --git a/x/txfees/README.md b/x/txfees/README.md new file mode 100644 index 00000000000..3ca2f947bf2 --- /dev/null +++ b/x/txfees/README.md @@ -0,0 +1,56 @@ +# Txfees + +The txfees modules allows nodes to easily support many tokens for usage as txfees, while letting node operators only specify their tx fee parameters for a single "base" asset. +This is done by having this module maintain an allow-list of token denoms which can be used as tx fees, each with some associated metadata. +Then this metadata is used in tandem with a "Spot Price Calculator" provided to the module, to convert the provided tx fees into their equivalent value in the base denomination. +Currently the only supported metadata & spot price calculator is using a GAMM pool ID & the GAMM keeper. + +## State Changes + +* Adds a whitelist of tokens that can be used as fees on the chain. + * Any token not on this list cannot be provided as a tx fee. + * Any fee that is paid with a token that is on this list but is + not the base denom will be collected in a separate module + account to be batched and swapped into the base denom at the end + of each epoch. +* Adds a new SDK message for creating governance proposals for adding new TxFee denoms. + +## Local Mempool Filters Added + +* If you specify a min-tx-fee in the $BASEDENOM then + * Your node will allow any tx w/ tx fee in the whitelist of fees, and a sufficient osmo-equivalent price to enter your mempool + * The osmo-equivalent price for determining sufficiency is rechecked after every block. (During the mempools RecheckTx) + * TODO: further consider if we want to take this tradeoff. Allows someone who manipulates price for one block to flush txs using that asset as fee from most of the networks' mempools. + * The simple alternative is only check fee equivalency at a txs entry into the mempool, which allows someone to manipulate price down to have many txs enter the chain at low cost. + * Another alternative is to use TWAP instead of Spot Price once it is available on-chain + * The former concern isn't very worrisome as long as some nodes have 0 min tx fees. +* A separate min-gas-fee can be set on every node for arbitrage txs. Methods of detecting an arb tx atm + * does start token of a swap = final token of swap (definitionally correct) + * does it have multiple swap messages, with different tx ins. If so, we assume its an arb. + * This has false positives, but is intended to avoid the obvious solution of splitting an arb into multiple messages. + * We record all denoms seen across all swaps, and see if any duplicates. (TODO) + * Contains both JoinPool and ExitPool messages in one tx. + * Has some false positives. + * These false positives seem like they primarily will get hit during batching of many distinct operations, not really in one atomic action. +* A max wanted gas per any tx can be set to filter out attack txes. +* If tx wanted gas > than predefined threshold of 1M, then separate 'min-gas-price-for-high-gas-tx' option used to calculate min gas price. + +## Queries + +base-denom + +- Query the base fee denom + +denom-pool-id + +- Query the pool id associated with a specific whitelisted fee token + +fee-tokens + +- Query the list of non-basedenom fee tokens and their associated pool ids + +## Future directions + +* Want to add in a system to add in general "tx fee credits" for different on-chain usages + * e.g. making 0 fee txs under certain usecases +* If other chains would like to use this, we should brainstorm mechanisms for extending the metadata proto fields diff --git a/x/txfees/ante/feedecorator.go b/x/txfees/ante/feedecorator.go new file mode 100644 index 00000000000..aa2fe3e129e --- /dev/null +++ b/x/txfees/ante/feedecorator.go @@ -0,0 +1,234 @@ +package ante + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + keeper "github.com/osmosis-labs/osmosis/v15/x/txfees/keeper" +) + +const ( + gasEstimationMempoolDecorator = 50_000 +) + +// MempoolFeeDecorator will check if the transaction's fee is at least as large +// as the local validator's minimum gasFee (defined in validator config). +// If fee is too low, decorator returns error and tx is rejected from mempool. +// Note this only applies when ctx.CheckTx = true +// If fee is high enough or not CheckTx, then call next AnteHandler +// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator. +type MempoolFeeDecorator struct { + TxFeesKeeper keeper.Keeper +} + +func NewMempoolFeeDecorator(txFeesKeeper keeper.Keeper) MempoolFeeDecorator { + return MempoolFeeDecorator{ + TxFeesKeeper: txFeesKeeper, + } +} + +func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if simulate { + ctx.GasMeter().ConsumeGas(gasEstimationMempoolDecorator, "mempool decorator") + return next(ctx, tx, simulate) + } + + if ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + } + + //Skip on deliverTx, as in Cosmos-SDK + // (https://github.com/cosmos/cosmos-sdk/blob/60e6274d0fdaeb86da4521f7ee8b8b2178a845b5/x/auth/ante/validator_tx_fee.go#L24) + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + return next(ctx, tx, simulate) + } + + baseDenom, err := mfd.TxFeesKeeper.GetBaseDenom(ctx) + if err != nil { + return ctx, err + } + minBaseGasPrice := ctx.MinGasPrices().AmountOf(baseDenom) + + // If minBaseGasPrice is zero, then we don't need to check the fee. Continue + if minBaseGasPrice.IsZero() { + return next(ctx, tx, simulate) + } + + feeCoins := feeTx.GetFee() + if feeCoins.IsZero() { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "no fees provided") + } + // You should only be able to pay with one fee token in a single tx + if len(feeCoins) > 1 { + return ctx, sdkerrors.Wrapf(types.ErrTooManyFeeCoins, + "Expected 1 fee denom attached, got %d", len(feeCoins)) + } + // If there is a fee attached to the tx, make sure the fee denom is a denom accepted by the chain + feeDenom := feeCoins.GetDenomByIndex(0) + if feeDenom != baseDenom { + _, err := mfd.TxFeesKeeper.GetFeeToken(ctx, feeDenom) + if err != nil { + return ctx, err + } + } + + // The minimum base gas price is in udym, convert the fee denom's worth to udym terms. + // Then compare if its sufficient for paying the tx fee. + err = mfd.IsSufficientFee(ctx, minBaseGasPrice, feeTx.GetGas(), feeCoins[0]) + if err != nil { + return ctx, err + } + + return next(ctx, tx, simulate) +} + +// IsSufficientFee checks if the feeCoin provided (in any asset), is worth enough udym at current spot prices +// to pay the gas cost of this tx. +func (mfd MempoolFeeDecorator) IsSufficientFee(ctx sdk.Context, minBaseGasPrice sdk.Dec, gasRequested uint64, feeCoin sdk.Coin) error { + baseDenom, err := mfd.TxFeesKeeper.GetBaseDenom(ctx) + if err != nil { + return err + } + + // Determine the required fees by multiplying the required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdk.NewDec(int64(gasRequested)) + requiredBaseFee := sdk.NewCoin(baseDenom, minBaseGasPrice.Mul(glDec).Ceil().RoundInt()) + + convertedFee, err := mfd.TxFeesKeeper.ConvertToBaseToken(ctx, feeCoin) + if err != nil { + return err + } + // check to ensure that the convertedFee should always be greater than or equal to the requireBaseFee + if !(convertedFee.IsGTE(requiredBaseFee)) { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s which converts to %s. required: %s", feeCoin, convertedFee, requiredBaseFee) + } + + return nil +} + +// DeductFeeDecorator deducts fees from the first signer of the tx. +// If the first signer does not have the funds to pay for the fees, we return an InsufficientFunds error. +// We call next AnteHandler if fees successfully deducted. +// +// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator +type DeductFeeDecorator struct { + ak types.AccountKeeper + bankKeeper types.BankKeeper + feegrantKeeper types.FeegrantKeeper + txFeesKeeper keeper.Keeper +} + +func NewDeductFeeDecorator(tk keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, fk types.FeegrantKeeper) DeductFeeDecorator { + return DeductFeeDecorator{ + ak: ak, + bankKeeper: bk, + feegrantKeeper: fk, + txFeesKeeper: tk, + } +} + +func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + // checks to make sure the module account has been set to collect fees in non-base token + if addr := dfd.ak.GetModuleAddress(types.ModuleName); addr == nil { + return ctx, fmt.Errorf("txfees module account (%s) has not been set", types.ModuleName) + } + + // checks to make sure the module account has been set to collect fees in base token + if addr := dfd.ak.GetModuleAddress(types.FeeCollectorName); addr == nil { + return ctx, fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) + } + + // fee can be in any denom (checked for validity later) + fee := feeTx.GetFee() + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + // set the fee payer as the default address to deduct fees from + deductFeesFrom := feePayer + + if len(fee) > 1 { + return ctx, sdkerrors.Wrapf(types.ErrTooManyFeeCoins, + "Expected 1 fee denom attached, got %d", len(fee)) + } + + // If a fee granter was set, deduct fee from the fee granter's account. + if feeGranter != nil { + if dfd.feegrantKeeper == nil { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants is not enabled") + } else if !feeGranter.Equals(feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()) + if err != nil { + return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) + } + } + + // if no errors, change the account that is charged for fees to the fee granter + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) + } + + // deducts the fees and transfer them to the module account + if !feeTx.GetFee().IsZero() { + err = DeductFees(dfd.txFeesKeeper, dfd.bankKeeper, ctx, deductFeesFromAcc, feeTx.GetFee()) + if err != nil { + return ctx, err + } + } + + ctx.EventManager().EmitEvents(sdk.Events{sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, feeTx.GetFee().String()), + )}) + + return next(ctx, tx, simulate) +} + +// DeductFees deducts fees from the given account and transfers them to the set module account. +func DeductFees(txFeesKeeper types.TxFeesKeeper, bankKeeper types.BankKeeper, ctx sdk.Context, acc authtypes.AccountI, fees sdk.Coins) error { + // Checks the validity of the fee tokens (sorted, have positive amount, valid and unique denomination) + if !fees.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + + // pulls base denom from TxFeesKeeper (should be udym) + baseDenom, err := txFeesKeeper.GetBaseDenom(ctx) + if err != nil { + return err + } + + // fees in base denom, sent to the fee collector for distribution + if fees[0].Denom == baseDenom { + // sends to FeeCollectorName module account + err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + } else { + // sends to the txfees module to be swapped and burned + err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.ModuleName, fees) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + } + + return nil +} diff --git a/x/txfees/client/cli/query.go b/x/txfees/client/cli/query.go new file mode 100644 index 00000000000..dac246b5ec1 --- /dev/null +++ b/x/txfees/client/cli/query.go @@ -0,0 +1,56 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/osmosis-labs/osmosis/v15/osmoutils/osmocli" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +// GetQueryCmd returns the cli query commands for this module. +func GetQueryCmd() *cobra.Command { + cmd := osmocli.QueryIndexCmd(types.ModuleName) + + cmd.AddCommand( + GetCmdFeeTokens(), + GetCmdDenomPoolID(), + GetCmdBaseDenom(), + osmocli.GetParams[*types.QueryParamsRequest]( + types.ModuleName, types.NewQueryClient), + ) + + return cmd +} + +func GetCmdFeeTokens() *cobra.Command { + return osmocli.SimpleQueryCmd[*types.QueryFeeTokensRequest]( + "fee-tokens", + "Query the list of non-basedenom fee tokens and their associated pool ids", + `{{.Short}}{{.ExampleHeader}} +{{.CommandPrefix}} fee-tokens +`, + types.ModuleName, types.NewQueryClient, + ) +} + +func GetCmdDenomPoolID() *cobra.Command { + return osmocli.SimpleQueryCmd[*types.QueryDenomPoolIdRequest]( + "denom-pool-id", + "Query the pool id associated with a specific whitelisted fee token", + `{{.Short}}{{.ExampleHeader}} +{{.CommandPrefix}} denom-pool-id [denom] +`, + types.ModuleName, types.NewQueryClient, + ) +} + +func GetCmdBaseDenom() *cobra.Command { + return osmocli.SimpleQueryCmd[*types.QueryBaseDenomRequest]( + "base-denom", + "Query the base fee denom", + `{{.Short}}{{.ExampleHeader}} +{{.CommandPrefix}} base-denom +`, + types.ModuleName, types.NewQueryClient, + ) +} diff --git a/x/txfees/client/cli/query_test.go b/x/txfees/client/cli/query_test.go new file mode 100644 index 00000000000..82cf3766a64 --- /dev/null +++ b/x/txfees/client/cli/query_test.go @@ -0,0 +1,80 @@ +package cli_test + +import ( + gocontext "context" + "testing" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v15/app/apptesting" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +type QueryTestSuite struct { + apptesting.KeeperTestHelper + queryClient types.QueryClient +} + +func (s *QueryTestSuite) SetupSuite() { + s.Setup() + s.queryClient = types.NewQueryClient(s.QueryHelper) + + // set up pool + poolAssets := []sdk.Coin{ + sdk.NewInt64Coin("uosmo", 1000000), + sdk.NewInt64Coin("stake", 120000000), + } + s.PrepareBalancerPoolWithCoins(poolAssets...) + + s.Commit() +} + +func (s *QueryTestSuite) TestQueriesNeverAlterState() { + testCases := []struct { + name string + query string + input interface{} + output interface{} + }{ + { + "Query base denom", + "/osmosis.txfees.v1beta1.Query/BaseDenom", + &types.QueryBaseDenomRequest{}, + &types.QueryBaseDenomResponse{}, + }, + { + "Query poolID by denom", + "/osmosis.txfees.v1beta1.Query/DenomPoolId", + &types.QueryDenomPoolIdRequest{Denom: "uosmo"}, + &types.QueryDenomPoolIdResponse{}, + }, + { + "Query spot price by denom", + "/osmosis.txfees.v1beta1.Query/DenomSpotPrice", + &types.QueryDenomSpotPriceRequest{Denom: "uosmo"}, + &types.QueryDenomSpotPriceResponse{}, + }, + { + "Query fee tokens", + "/osmosis.txfees.v1beta1.Query/FeeTokens", + &types.QueryFeeTokensRequest{}, + &types.QueryFeeTokensResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupSuite() + err := s.QueryHelper.Invoke(gocontext.Background(), tc.query, tc.input, tc.output) + s.Require().NoError(err) + s.StateNotAltered() + }) + } +} + +func TestQueryTestSuite(t *testing.T) { + suite.Run(t, new(QueryTestSuite)) +} diff --git a/x/txfees/keeper/feedecorator_test.go b/x/txfees/keeper/feedecorator_test.go new file mode 100644 index 00000000000..c284f141184 --- /dev/null +++ b/x/txfees/keeper/feedecorator_test.go @@ -0,0 +1,188 @@ +package keeper_test + +import ( + "fmt" + + clienttx "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/ante" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +func (suite *KeeperTestSuite) TestFeeDecorator() { + baseDenom := sdk.DefaultBondDenom + baseGas := uint64(10000) + point1BaseDenomMinGasPrices := sdk.NewDecCoins(sdk.NewDecCoinFromDec(baseDenom, + sdk.MustNewDecFromStr("0.1"))) + + // uion is setup with a relative price of 1:1 + uion := "uion" + + type testcase struct { + name string + txFee sdk.Coins + minGasPrices sdk.DecCoins // if blank, set to 0 + gasRequested uint64 // if blank, set to base gas + isCheckTx bool + isSimulate bool // if blank, is false + expectPass bool + } + + tests := []testcase{} + txType := []string{"delivertx", "checktx"} + for isCheckTx := 0; isCheckTx <= 1; isCheckTx++ { + tests = append(tests, []testcase{ + { + name: fmt.Sprintf("no min gas price - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(baseDenom, 1000)), + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + { + name: fmt.Sprintf("no min gas price, no fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(), + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + { + name: fmt.Sprintf("no min gas price, invalid fee token - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin("uatom", 1000)), + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + { + name: fmt.Sprintf("multiple fee coins - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(baseDenom, 1), sdk.NewInt64Coin(uion, 1)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: false, + }, + { + name: fmt.Sprintf("no fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: isCheckTx != 1, //should pass on deliverTx, fail on checkTx + }, + { + name: fmt.Sprintf("works with valid basedenom fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(baseDenom, 1000)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + { + name: fmt.Sprintf("insufficient valid basedenom fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(baseDenom, 10)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: isCheckTx != 1, //should pass on deliverTx, fail on checkTx + }, + { + name: fmt.Sprintf("works with valid converted fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(uion, 1000)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + { + name: fmt.Sprintf("insufficient valid converted fee - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin(uion, 10)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: isCheckTx != 1, + }, + { + name: fmt.Sprintf("invalid fee denom - %s", txType[isCheckTx]), + txFee: sdk.NewCoins(sdk.NewInt64Coin("moooooo", 1000)), + minGasPrices: point1BaseDenomMinGasPrices, + isCheckTx: isCheckTx == 1, + expectPass: isCheckTx != 1, //should pass on deliverTx, fail on checkTx, + }, + { + name: "min gas price not containing basedenom gets treated as min gas price 0", + txFee: sdk.NewCoins(sdk.NewInt64Coin(uion, 1000)), + minGasPrices: sdk.NewDecCoins(sdk.NewInt64DecCoin(uion, 1000000)), + isCheckTx: isCheckTx == 1, + expectPass: true, + }, + }...) + } + + for _, tc := range tests { + // reset pool and accounts for each test + suite.SetupTest(false) + + // setup uion with 1:1 fee + suite.PrepareBalancerPoolWithCoins( + sdk.NewInt64Coin(sdk.DefaultBondDenom, 500), + sdk.NewInt64Coin(uion, 500), + ) + + if tc.minGasPrices == nil { + tc.minGasPrices = sdk.NewDecCoins() + } + if tc.gasRequested == 0 { + tc.gasRequested = baseGas + } + suite.Ctx = suite.Ctx.WithIsCheckTx(tc.isCheckTx).WithMinGasPrices(tc.minGasPrices) + + // TxBuilder components reset for every test case + txconfig := suite.App.GetTxConfig() + txBuilder := txconfig.NewTxBuilder() + priv0, _, addr0 := testdata.KeyTestPubAddr() + acc1 := suite.App.AccountKeeper.NewAccountWithAddress(suite.Ctx, addr0) + suite.App.AccountKeeper.SetAccount(suite.Ctx, acc1) + msgs := []sdk.Msg{testdata.NewTestMsg(addr0)} + signerData := authsigning.SignerData{ + ChainID: suite.Ctx.ChainID(), + AccountNumber: 0, + Sequence: 0, + } + + gasLimit := tc.gasRequested + + sigV2, err := clienttx.SignWithPrivKey( + txconfig.SignModeHandler().DefaultMode(), signerData, + txBuilder, priv0, txconfig, 0) + suite.Require().NoError(err, "test: %s", tc.name) + err = txBuilder.SetSignatures(sigV2) + suite.Require().NoError(err, "test: %s", tc.name) + + bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr0, tc.txFee) + tx := suite.BuildTx(txBuilder, msgs, sigV2, "", tc.txFee, gasLimit) + + mfd := ante.NewMempoolFeeDecorator(*suite.App.TxFeesKeeper) + dfd := ante.NewDeductFeeDecorator(*suite.App.TxFeesKeeper, suite.App.AccountKeeper, suite.App.BankKeeper, nil) + antehandlerMFD := sdk.ChainAnteDecorators(mfd, dfd) + _, err = antehandlerMFD(suite.Ctx, tx, tc.isSimulate) + + if tc.expectPass { + suite.Require().NoError(err, "test: %s", tc.name) + // ensure fee was collected + if !tc.txFee.IsZero() { + var moduleName string + //check dym in the fee collector + if tc.txFee[0].Denom == baseDenom { + moduleName = types.FeeCollectorName + } else { + moduleName = types.ModuleName + } + + moduleAddr := suite.App.AccountKeeper.GetModuleAddress(moduleName) + suite.Require().Equal(tc.txFee[0], suite.App.BankKeeper.GetBalance(suite.Ctx, moduleAddr, tc.txFee[0].Denom), tc.name) + } else { + // ensure no fee was collected + moduleAddr := suite.App.AccountKeeper.GetModuleAddress(types.ModuleName) + suite.Require().Equal(sdk.NewCoins(), suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddr), tc.name) + } + } else { + suite.Require().Error(err, "test: %s", tc.name) + } + } +} diff --git a/x/txfees/keeper/feetokens.go b/x/txfees/keeper/feetokens.go new file mode 100644 index 00000000000..7a3cc586078 --- /dev/null +++ b/x/txfees/keeper/feetokens.go @@ -0,0 +1,161 @@ +package keeper + +import ( + "github.com/gogo/protobuf/proto" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ConvertToBaseToken converts a fee amount in a whitelisted fee token to the base fee token amount. +func (k Keeper) ConvertToBaseToken(ctx sdk.Context, inputFee sdk.Coin) (sdk.Coin, error) { + baseDenom, err := k.GetBaseDenom(ctx) + if err != nil { + return sdk.Coin{}, err + } + + if inputFee.Denom == baseDenom { + return inputFee, nil + } + + feeToken, err := k.GetFeeToken(ctx, inputFee.Denom) + if err != nil { + return sdk.Coin{}, err + } + + spotPrice, err := k.spotPriceCalculator.CalculateSpotPrice(ctx, feeToken.PoolID, baseDenom, feeToken.Denom) + if err != nil { + return sdk.Coin{}, err + } + + return sdk.NewCoin(baseDenom, spotPrice.MulInt(inputFee.Amount).RoundInt()), nil +} + +// GetFeeToken returns the fee token record for a specific denom, +// In our case the baseDenom is udym. +func (k Keeper) GetBaseDenom(ctx sdk.Context) (denom string, err error) { + store := ctx.KVStore(k.storeKey) + + if !store.Has(types.BaseDenomKey) { + return "", types.ErrNoBaseDenom + } + + bz := store.Get(types.BaseDenomKey) + + return string(bz), nil +} + +// SetBaseDenom sets the base fee denom for the chain. Should only be used once. +func (k Keeper) SetBaseDenom(ctx sdk.Context, denom string) error { + store := ctx.KVStore(k.storeKey) + + err := sdk.ValidateDenom(denom) + if err != nil { + return err + } + + store.Set(types.BaseDenomKey, []byte(denom)) + return nil +} + +// ValidateFeeToken validates that a fee token record is valid +// It checks: +// - The denom exists +// - The denom is not the base denom +// - The gamm pool exists +// - The gamm pool includes the base token and fee token. +func (k Keeper) ValidateFeeToken(ctx sdk.Context, feeToken types.FeeToken) error { + baseDenom, err := k.GetBaseDenom(ctx) + if err != nil { + return err + } + if baseDenom == feeToken.Denom { + return sdkerrors.Wrap(types.ErrInvalidFeeToken, "cannot add basedenom as a whitelisted fee token") + } + // This not returning an error implies that: + // - feeToken.Denom exists + // - feeToken.PoolID exists + // - feeToken.PoolID has both feeToken.Denom and baseDenom + _, err = k.spotPriceCalculator.CalculateSpotPrice(ctx, feeToken.PoolID, feeToken.Denom, baseDenom) + + return err +} + +// GetFeeToken returns a unique fee token record for a specific denom. +// If the denom doesn't exist, returns an error. +func (k Keeper) GetFeeToken(ctx sdk.Context, denom string) (types.FeeToken, error) { + prefixStore := k.GetFeeTokensStore(ctx) + if !prefixStore.Has([]byte(denom)) { + return types.FeeToken{}, sdkerrors.Wrapf(types.ErrInvalidFeeToken, "%s", denom) + } + bz := prefixStore.Get([]byte(denom)) + + feeToken := types.FeeToken{} + err := proto.Unmarshal(bz, &feeToken) + if err != nil { + return types.FeeToken{}, err + } + + return feeToken, nil +} + +// setFeeToken sets a new fee token record for a specific denom. +// PoolID is just the pool to swap rate between alt fee token and native fee token. +// If the feeToken pool ID is 0, deletes the fee Token entry. +func (k Keeper) setFeeToken(ctx sdk.Context, feeToken types.FeeToken) error { + prefixStore := k.GetFeeTokensStore(ctx) + + if feeToken.PoolID == 0 { + if prefixStore.Has([]byte(feeToken.Denom)) { + prefixStore.Delete([]byte(feeToken.Denom)) + } + return nil + } + + err := k.ValidateFeeToken(ctx, feeToken) + if err != nil { + return err + } + + bz, err := proto.Marshal(&feeToken) + if err != nil { + return err + } + + prefixStore.Set([]byte(feeToken.Denom), bz) + return nil +} + +func (k Keeper) GetFeeTokens(ctx sdk.Context) (feetokens []types.FeeToken) { + prefixStore := k.GetFeeTokensStore(ctx) + + // this entire store just contains FeeTokens, so iterate over all entries. + iterator := prefixStore.Iterator(nil, nil) + defer iterator.Close() + + feeTokens := []types.FeeToken{} + + for ; iterator.Valid(); iterator.Next() { + feeToken := types.FeeToken{} + + err := proto.Unmarshal(iterator.Value(), &feeToken) + if err != nil { + panic(err) + } + + feeTokens = append(feeTokens, feeToken) + } + return feeTokens +} + +func (k Keeper) SetFeeTokens(ctx sdk.Context, feetokens []types.FeeToken) error { + for _, feeToken := range feetokens { + err := k.setFeeToken(ctx, feeToken) + if err != nil { + return err + } + } + return nil +} diff --git a/x/txfees/keeper/feetokens_test.go b/x/txfees/keeper/feetokens_test.go new file mode 100644 index 00000000000..b0c4148f5ce --- /dev/null +++ b/x/txfees/keeper/feetokens_test.go @@ -0,0 +1,84 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (suite *KeeperTestSuite) TestBaseDenom() { + suite.SetupTest(false) + + // Test getting basedenom (should be default from genesis) + baseDenom, err := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(sdk.DefaultBondDenom, baseDenom) + + converted, err := suite.App.TxFeesKeeper.ConvertToBaseToken(suite.Ctx, sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)) + suite.Require().True(converted.IsEqual(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10))) + suite.Require().NoError(err) +} + +func (suite *KeeperTestSuite) TestFeeTokenConversions() { + baseDenom := sdk.DefaultBondDenom + + tests := []struct { + name string + baseDenomPoolInput sdk.Coin + feeTokenPoolInput sdk.Coin + inputFee sdk.Coin + expectedConvertable bool + expectedOutput sdk.Coin + }{ + { + name: "equal value", + baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 100), + feeTokenPoolInput: sdk.NewInt64Coin("uion", 100), + inputFee: sdk.NewInt64Coin("uion", 10), + expectedOutput: sdk.NewInt64Coin(baseDenom, 10), + expectedConvertable: true, + }, + { + name: "unequal value", + baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 100), + feeTokenPoolInput: sdk.NewInt64Coin("foo", 200), + inputFee: sdk.NewInt64Coin("foo", 10), + // expected to get approximately 5 base denom + // foo supply / stake supply = 200 / 100 = 2 foo for 1 stake + // 10 foo in / 2 foo for 1 stake = 5 base denom + expectedOutput: sdk.NewInt64Coin(baseDenom, 5), + expectedConvertable: true, + }, + { + name: "basedenom value", + baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 100), + feeTokenPoolInput: sdk.NewInt64Coin("foo", 200), + inputFee: sdk.NewInt64Coin(baseDenom, 10), + expectedOutput: sdk.NewInt64Coin(baseDenom, 10), + expectedConvertable: true, + }, + { + name: "convert non-existent", + baseDenomPoolInput: sdk.NewInt64Coin(baseDenom, 100), + feeTokenPoolInput: sdk.NewInt64Coin("uion", 200), + inputFee: sdk.NewInt64Coin("foo", 10), + expectedOutput: sdk.Coin{}, + expectedConvertable: false, + }, + } + + for _, tc := range tests { + suite.SetupTest(false) + + _ = suite.PrepareBalancerPoolWithCoins( + tc.baseDenomPoolInput, + tc.feeTokenPoolInput, + ) + + converted, err := suite.App.TxFeesKeeper.ConvertToBaseToken(suite.Ctx, tc.inputFee) + if tc.expectedConvertable { + suite.Require().NoError(err, "test: %s", tc.name) + suite.Require().Equal(tc.expectedOutput, converted) + } else { + suite.Require().Error(err, "test: %s", tc.name) + } + } +} diff --git a/x/txfees/keeper/genesis.go b/x/txfees/keeper/genesis.go new file mode 100644 index 00000000000..7b8573b74eb --- /dev/null +++ b/x/txfees/keeper/genesis.go @@ -0,0 +1,44 @@ +package keeper + +import ( + "fmt" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// InitGenesis initializes the txfees module's state from a provided genesis +// state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + recipientAcc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName) + if recipientAcc == nil { + panic(fmt.Sprintf("module account %s does not exist", types.ModuleName)) + } + + k.SetParams(ctx, genState.Params) + + err := k.SetBaseDenom(ctx, genState.Basedenom) + if err != nil { + panic(err) + } + err = k.SetFeeTokens(ctx, genState.Feetokens) + if err != nil { + panic(err) + } + + epochIdentifier := k.GetParams(ctx).EpochIdentifier + info := k.epochKeeper.GetEpochInfo(ctx, epochIdentifier) + if info.Identifier == "" { + panic(fmt.Sprintf("epoch info for identifier %s does not exist", epochIdentifier)) + } +} + +// ExportGenesis returns the txfees module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Basedenom, _ = k.GetBaseDenom(ctx) + genesis.Feetokens = k.GetFeeTokens(ctx) + genesis.Params = k.GetParams(ctx) + return genesis +} diff --git a/x/txfees/keeper/grpc_query.go b/x/txfees/keeper/grpc_query.go new file mode 100644 index 00000000000..7f0f5429507 --- /dev/null +++ b/x/txfees/keeper/grpc_query.go @@ -0,0 +1,95 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +var _ types.QueryServer = Querier{} + +// Querier defines a wrapper around the x/txfees keeper providing gRPC method +// handlers. +type Querier struct { + Keeper +} + +func NewQuerier(k Keeper) Querier { + return Querier{Keeper: k} +} + +func (q Querier) Params(ctx context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + params := q.Keeper.GetParams(sdkCtx) + + return &types.QueryParamsResponse{Params: params}, nil +} + +func (q Querier) FeeTokens(ctx context.Context, _ *types.QueryFeeTokensRequest) (*types.QueryFeeTokensResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + feeTokens := q.Keeper.GetFeeTokens(sdkCtx) + + return &types.QueryFeeTokensResponse{FeeTokens: feeTokens}, nil +} + +func (q Querier) DenomSpotPrice(ctx context.Context, req *types.QueryDenomSpotPriceRequest) (*types.QueryDenomSpotPriceResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if len(req.Denom) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty denom") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + baseDenom, err := q.GetBaseDenom(sdkCtx) + if err != nil { + return nil, err + } + + feeToken, err := q.GetFeeToken(sdkCtx, req.Denom) + if err != nil { + return nil, err + } + + spotPrice, err := q.spotPriceCalculator.CalculateSpotPrice(sdkCtx, feeToken.PoolID, baseDenom, feeToken.Denom) + if err != nil { + return nil, err + } + + return &types.QueryDenomSpotPriceResponse{PoolID: feeToken.PoolID, SpotPrice: spotPrice}, nil +} + +func (q Querier) DenomPoolId(ctx context.Context, req *types.QueryDenomPoolIdRequest) (*types.QueryDenomPoolIdResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if len(req.Denom) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty denom") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + feeToken, err := q.Keeper.GetFeeToken(sdkCtx, req.GetDenom()) + if err != nil { + return nil, err + } + + return &types.QueryDenomPoolIdResponse{PoolID: feeToken.GetPoolID()}, nil +} + +func (q Querier) BaseDenom(ctx context.Context, _ *types.QueryBaseDenomRequest) (*types.QueryBaseDenomResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + baseDenom, err := q.Keeper.GetBaseDenom(sdkCtx) + if err != nil { + return nil, err + } + + return &types.QueryBaseDenomResponse{BaseDenom: baseDenom}, nil +} diff --git a/x/txfees/keeper/hooks.go b/x/txfees/keeper/hooks.go new file mode 100644 index 00000000000..f7514677901 --- /dev/null +++ b/x/txfees/keeper/hooks.go @@ -0,0 +1,164 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + epochstypes "github.com/osmosis-labs/osmosis/v15/x/epochs/types" + gammtypes "github.com/osmosis-labs/osmosis/v15/x/gamm/types" + poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" + txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +// Hooks is the wrapper struct for the txfees keeper. +type Hooks struct { + k Keeper +} + +var _ epochstypes.EpochHooks = Hooks{} +var _ gammtypes.GammHooks = Hooks{} + +// Return the wrapper struct +func (k Keeper) Hooks() Hooks { + return Hooks{k} +} + +/* -------------------------------------------------------------------------- */ +/* epoch hooks */ +/* -------------------------------------------------------------------------- */ +func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { + return nil +} + +// at the end of each epoch, swap all non-DYM fees into DYM and burn them +func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { + if epochIdentifier != k.GetParams(ctx).EpochIdentifier { + return nil + } + + moduleAddr := k.accountKeeper.GetModuleAddress(txfeestypes.ModuleName) + baseDenom, _ := k.GetBaseDenom(ctx) + + //get all balances of this module + balances := k.bankKeeper.GetAllBalances(ctx, moduleAddr) + + //swap all to dym + for _, coinBalance := range balances { + if coinBalance.Denom == baseDenom { + continue + } + if coinBalance.Amount.IsZero() { + continue + } + + feetoken, err := k.GetFeeToken(ctx, coinBalance.Denom) + if err != nil { + k.Logger(ctx).Error("unknown fee token", "denom", coinBalance.Denom, "error", err) + continue + } + + // Do the swap of this fee token denom to base denom. + route := []poolmanagertypes.SwapAmountInRoute{ + { + PoolId: feetoken.PoolID, + TokenOutDenom: baseDenom, + }, + } + _, err = k.poolManager.RouteExactAmountIn(ctx, moduleAddr, route, coinBalance, sdk.ZeroInt()) + if err != nil { + k.Logger(ctx).Error("failed to swap fee token to base token", "error", err) + continue + } + } + + // Get all of the txfee payout denom in the module account + baseDenomCoins := sdk.NewCoins(k.bankKeeper.GetBalance(ctx, moduleAddr, baseDenom)) + err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, baseDenomCoins) + if err != nil { + return err + } + + return nil +} + +func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { + return h.k.BeforeEpochStart(ctx, epochIdentifier, epochNumber) +} + +func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { + return h.k.AfterEpochEnd(ctx, epochIdentifier, epochNumber) +} + +/* -------------------------------------------------------------------------- */ +/* pool hooks */ +/* -------------------------------------------------------------------------- */ + +// AfterPoolCreated creates a gauge for each pool’s lockable duration. +func (h Hooks) AfterPoolCreated(ctx sdk.Context, sender sdk.AccAddress, poolId uint64) { + //check if base denom included in the pool + baseDenom, err := h.k.GetBaseDenom(ctx) + if err != nil { + h.k.Logger(ctx).Error("failed to get base denom", "error", err) + return + } + denoms, err := h.k.spotPriceCalculator.GetPoolDenoms(ctx, poolId) + if err != nil { + h.k.Logger(ctx).Error("failed to get pool denoms", "error", err) + return + } + + if len(denoms) != 2 { + h.k.Logger(ctx).Debug("expecting pools of 2 assets", "denoms", denoms) + return + } + if !contains(denoms, baseDenom) { + h.k.Logger(ctx).Debug("base denom not included in the pool. skipping", "baseDenom", baseDenom, "denoms", denoms) + return + } + + //get the non-native denom + var nonNativeDenom string + if denoms[0] == baseDenom { + nonNativeDenom = denoms[1] + } else { + nonNativeDenom = denoms[0] + } + + _, err = h.k.GetFeeToken(ctx, nonNativeDenom) + if err == nil { + h.k.Logger(ctx).Error("fee token already exists", "denom", nonNativeDenom) + return + } + + feeToken := txfeestypes.FeeToken{ + PoolID: poolId, + Denom: nonNativeDenom, + } + err = h.k.setFeeToken(ctx, feeToken) + if err != nil { + h.k.Logger(ctx).Error("failed to set fee token", "error", err) + return + } +} + +// AfterJoinPool hook is a noop. +func (h Hooks) AfterJoinPool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, enterCoins sdk.Coins, shareOutAmount sdk.Int) { +} + +// AfterExitPool hook is a noop. +func (h Hooks) AfterExitPool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, shareInAmount sdk.Int, exitCoins sdk.Coins) { +} + +// AfterSwap hook is a noop. +func (h Hooks) AfterSwap(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, input sdk.Coins, output sdk.Coins) { +} + +func contains(strarr []string, str string) bool { + for _, v := range strarr { + if v == str { + return true + } + } + + return false +} diff --git a/x/txfees/keeper/hooks_test.go b/x/txfees/keeper/hooks_test.go new file mode 100644 index 00000000000..46f7d79f02b --- /dev/null +++ b/x/txfees/keeper/hooks_test.go @@ -0,0 +1,213 @@ +package keeper_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +func (suite *KeeperTestSuite) TestTxFeesAfterEpochEnd() { + uion := "uion" + atom := "atom" + + baseDenom := sdk.DefaultBondDenom + + tests := []struct { + name string + coins sdk.Coins + expectPass bool + }{ + { + name: "DYM is burned", + coins: sdk.Coins{sdk.NewInt64Coin(baseDenom, 100000)}, + expectPass: true, + }, + { + name: "One non-dym fee token (uion)", + coins: sdk.Coins{sdk.NewInt64Coin(uion, 1000)}, + expectPass: true, + }, + { + name: "Multiple non-dym fee token", + coins: sdk.Coins{sdk.NewInt64Coin(baseDenom, 2000), sdk.NewInt64Coin(uion, 30000)}, + expectPass: true, + }, + { + name: "unknown fee token", + coins: sdk.Coins{sdk.NewInt64Coin(atom, 2000)}, + expectPass: false, + }, + } + + for _, tc := range tests { + suite.SetupTest(false) + + // create pools for three separate fee tokens + suite.PrepareBalancerPoolWithCoins(sdk.NewCoin(baseDenom, sdk.NewInt(1000000000000)), sdk.NewCoin(uion, sdk.NewInt(5000))) + + moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(types.ModuleName) + err := bankutil.FundModuleAccount(suite.App.BankKeeper, suite.Ctx, types.ModuleName, tc.coins) + suite.Require().NoError(err) + balances := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + suite.Assert().Equal(balances, tc.coins, tc.name) + + totalSupplyBefore := suite.App.BankKeeper.GetSupply(suite.Ctx, baseDenom).Amount + + // End of epoch, so all the non-osmo fee amount should be swapped to osmo and burned + futureCtx := suite.Ctx.WithBlockTime(time.Now().Add(time.Minute)) + suite.App.TxFeesKeeper.AfterEpochEnd(futureCtx, "day", int64(1)) + + // check the balance of the native-basedenom in module + balances = suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + totalSupplyAfter := suite.App.BankKeeper.GetSupply(suite.Ctx, baseDenom).Amount + if tc.expectPass { + //Check for DYM burn + suite.Assert().True(balances.IsZero(), tc.name) + suite.Require().True(totalSupplyAfter.LT(totalSupplyBefore), tc.name) + } else { + suite.Assert().False(balances.IsZero(), tc.name) + suite.Require().True(totalSupplyAfter.Equal(totalSupplyBefore), tc.name) + } + } +} + +//TODO: pool hooks +/* + +func (suite *KeeperTestSuite) TestUpgradeFeeTokenProposals() { + suite.SetupTest(false) + + uionPoolId := suite.PrepareBalancerPoolWithCoins( + sdk.NewInt64Coin(sdk.DefaultBondDenom, 500), + sdk.NewInt64Coin("uion", 500), + ) + + uionPoolId2 := suite.PrepareBalancerPoolWithCoins( + sdk.NewInt64Coin(sdk.DefaultBondDenom, 500), + sdk.NewInt64Coin("uion", 500), + ) + + // Make pool with fee token but no OSMO and make sure governance proposal fails + noBasePoolId := suite.PrepareBalancerPoolWithCoins( + sdk.NewInt64Coin("uion", 500), + sdk.NewInt64Coin("foo", 500), + ) + + // Create correct pool and governance proposal + fooPoolId := suite.PrepareBalancerPoolWithCoins( + sdk.NewInt64Coin(sdk.DefaultBondDenom, 500), + sdk.NewInt64Coin("foo", 1000), + ) + + tests := []struct { + name string + feeToken string + poolId uint64 + expectPass bool + }{ + { + name: "uion pool", + feeToken: "uion", + poolId: uionPoolId, + expectPass: true, + }, + { + name: "try with basedenom", + feeToken: sdk.DefaultBondDenom, + poolId: uionPoolId, + expectPass: false, + }, + { + name: "proposal with non-existent pool", + feeToken: "foo", + poolId: 100000000000, + expectPass: false, + }, + { + name: "proposal with wrong pool for fee token", + feeToken: "foo", + poolId: uionPoolId, + expectPass: false, + }, + { + name: "proposal with pool with no base denom", + feeToken: "foo", + poolId: noBasePoolId, + expectPass: false, + }, + { + name: "proposal to add foo correctly", + feeToken: "foo", + poolId: fooPoolId, + expectPass: true, + }, + { + name: "proposal to replace pool for fee token", + feeToken: "uion", + poolId: uionPoolId2, + expectPass: true, + }, + { + name: "proposal to replace uion as fee denom", + feeToken: "uion", + poolId: 0, + expectPass: true, + }, + } + + for _, tc := range tests { + suite.Run(tc.name, func() { + feeTokensBefore := suite.App.TxFeesKeeper.GetFeeTokens(suite.Ctx) + + // Add a new whitelisted fee token via a governance proposal + err := suite.ExecuteUpgradeFeeTokenProposal(tc.feeToken, tc.poolId) + + feeTokensAfter := suite.App.TxFeesKeeper.GetFeeTokens(suite.Ctx) + + if tc.expectPass { + // Make sure no error during setting of proposal + suite.Require().NoError(err, "test: %s", tc.name) + + // For a proposal that adds a feetoken + if tc.poolId != 0 { + // Make sure the length of fee tokens is >= before + suite.Require().GreaterOrEqual(len(feeTokensAfter), len(feeTokensBefore), "test: %s", tc.name) + // Ensure that the fee token is convertable to base token + _, err := suite.App.TxFeesKeeper.ConvertToBaseToken(suite.Ctx, sdk.NewInt64Coin(tc.feeToken, 10)) + suite.Require().NoError(err, "test: %s", tc.name) + // make sure the queried poolId is the same as expected + queriedPoolId, err := suite.queryClient.DenomPoolId(suite.Ctx.Context(), + &types.QueryDenomPoolIdRequest{ + Denom: tc.feeToken, + }, + ) + suite.Require().NoError(err, "test: %s", tc.name) + suite.Require().Equal(tc.poolId, queriedPoolId.GetPoolID(), "test: %s", tc.name) + } else { + // if this proposal deleted a fee token + // ensure that the length of fee tokens is <= to before + suite.Require().LessOrEqual(len(feeTokensAfter), len(feeTokensBefore), "test: %s", tc.name) + // Ensure that the fee token is not convertable to base token + _, err := suite.App.TxFeesKeeper.ConvertToBaseToken(suite.Ctx, sdk.NewInt64Coin(tc.feeToken, 10)) + suite.Require().Error(err, "test: %s", tc.name) + // make sure the queried poolId errors + _, err = suite.queryClient.DenomPoolId(suite.Ctx.Context(), + &types.QueryDenomPoolIdRequest{ + Denom: tc.feeToken, + }, + ) + suite.Require().Error(err, "test: %s", tc.name) + } + } else { + // Make sure errors during setting of proposal + suite.Require().Error(err, "test: %s", tc.name) + // fee tokens should be the same + suite.Require().Equal(len(feeTokensAfter), len(feeTokensBefore), "test: %s", tc.name) + } + }) + } +} +*/ diff --git a/x/txfees/keeper/keeper.go b/x/txfees/keeper/keeper.go new file mode 100644 index 00000000000..9eafddce661 --- /dev/null +++ b/x/txfees/keeper/keeper.go @@ -0,0 +1,70 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +type Keeper struct { + storeKey storetypes.StoreKey + paramSpace paramtypes.Subspace + + accountKeeper types.AccountKeeper + epochKeeper types.EpochKeeper + bankKeeper types.BankKeeper + poolManager types.PoolManager + spotPriceCalculator types.SpotPriceCalculator +} + +var _ types.TxFeesKeeper = (*Keeper)(nil) + +func NewKeeper( + storeKey storetypes.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + epochKeeper types.EpochKeeper, + bankKeeper types.BankKeeper, + poolManager types.PoolManager, + spotPriceCalculator types.SpotPriceCalculator, +) Keeper { + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + storeKey: storeKey, + paramSpace: paramSpace, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + epochKeeper: epochKeeper, + poolManager: poolManager, + spotPriceCalculator: spotPriceCalculator, + } +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +func (k Keeper) GetFeeTokensStore(ctx sdk.Context) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.FeeTokensStorePrefix) +} + +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the total set of params. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/x/txfees/keeper/keeper_test.go b/x/txfees/keeper/keeper_test.go new file mode 100644 index 00000000000..456b2bfb8b5 --- /dev/null +++ b/x/txfees/keeper/keeper_test.go @@ -0,0 +1,37 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v15/app/apptesting" +) + +type KeeperTestSuite struct { + apptesting.KeeperTestHelper +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) SetupTest(isCheckTx bool) { + suite.Setup() + + // Mint some assets to the accounts. + for _, acc := range suite.TestAccs { + suite.FundAcc(acc, + sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000000000)), + sdk.NewCoin("uosmo", sdk.NewInt(100000000000000000)), // Needed for pool creation fee + sdk.NewCoin("uion", sdk.NewInt(10000000)), + sdk.NewCoin("atom", sdk.NewInt(10000000)), + sdk.NewCoin("ust", sdk.NewInt(10000000)), + sdk.NewCoin("foo", sdk.NewInt(10000000)), + sdk.NewCoin("bar", sdk.NewInt(10000000)), + )) + } +} diff --git a/x/txfees/module.go b/x/txfees/module.go new file mode 100644 index 00000000000..bc936223c8b --- /dev/null +++ b/x/txfees/module.go @@ -0,0 +1,172 @@ +/* +The txfees modules allows nodes to easily support many +tokens for usage as txfees, while letting node operators +only specify their tx fee parameters for a single "base" asset. + +- Accepts any token that has LP with base denom +*/ +package txfees + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/osmosis-labs/osmosis/v15/x/txfees/client/cli" + "github.com/osmosis-labs/osmosis/v15/x/txfees/keeper" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +const ModuleName = types.ModuleName + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the txfees module. +type AppModuleBasic struct{} + +func NewAppModuleBasic() AppModuleBasic { + return AppModuleBasic{} +} + +// Name returns the txfees module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { +} + +// RegisterInterfaces registers the module's interface types. +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { +} + +// DefaultGenesis returns the txfees module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the txfee 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() +} + +// RegisterRESTRoutes is a no-op. Needed to meet AppModuleBasic interface. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + //nolint:errcheck + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) +} + +// GetTxCmd returns the txfees module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +// GetQueryCmd returns the txfees module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the txfees module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +func NewAppModule(keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(), + keeper: keeper, + } +} + +// Name returns the txfees module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the txfees module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute returns the txfees module's query routing key. +func (AppModule) QuerierRoute() string { return "" } + +// LegacyQuerierHandler is a no-op. Needed to meet AppModule interface. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return func(sdk.Context, []string, abci.RequestQuery) ([]byte, error) { + return nil, fmt.Errorf("legacy querier not supported for the x/%s module", types.ModuleName) + } +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) +} + +// RegisterInvariants registers the txfees module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the txfees module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + if genState.Basedenom == "" { + panic("genState.Basedenom must be set for txfees") + } + + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the txfees module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the txfees module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the txfees module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } diff --git a/x/txfees/types/errors.go b/x/txfees/types/errors.go new file mode 100644 index 00000000000..9e1ab036f87 --- /dev/null +++ b/x/txfees/types/errors.go @@ -0,0 +1,14 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/txfees module errors. +var ( + ErrNoBaseDenom = sdkerrors.Register(ModuleName, 1, "no base denom was set") + ErrTooManyFeeCoins = sdkerrors.Register(ModuleName, 2, "too many fee coins. only accepts fees in one denom") + ErrInvalidFeeToken = sdkerrors.Register(ModuleName, 3, "invalid fee token") +) diff --git a/x/txfees/types/expected_keepers.go b/x/txfees/types/expected_keepers.go new file mode 100644 index 00000000000..75fba8175e1 --- /dev/null +++ b/x/txfees/types/expected_keepers.go @@ -0,0 +1,58 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + epochtypes "github.com/osmosis-labs/osmosis/v15/x/epochs/types" + poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" +) + +// SpotPriceCalculator defines the contract that must be fulfilled by a spot price calculator +// The x/gamm keeper is expected to satisfy this interface. +type SpotPriceCalculator interface { + CalculateSpotPrice(ctx sdk.Context, poolId uint64, quoteDenom, baseDenom string) (sdk.Dec, error) + GetPoolDenoms(ctx sdk.Context, poolId uint64) ([]string, error) +} + +// PoolManager defines the contract needed for swap related APIs. +type PoolManager interface { + RouteExactAmountIn( + ctx sdk.Context, + sender sdk.AccAddress, + routes []poolmanagertypes.SwapAmountInRoute, + tokenIn sdk.Coin, + tokenOutMinAmount sdk.Int) (tokenOutAmount sdk.Int, err error) +} + +type EpochKeeper interface { + GetEpochInfo(ctx sdk.Context, identifier string) epochtypes.EpochInfo +} + +// AccountKeeper defines the contract needed for AccountKeeper related APIs. +// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators. +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + GetModuleAddress(moduleName string) sdk.AccAddress + GetModuleAccount(ctx sdk.Context, moduleName string) authtypes.ModuleAccountI +} + +// FeegrantKeeper defines the expected feegrant keeper. +type FeegrantKeeper interface { + UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error +} + +// BankKeeper defines the contract needed for supply related APIs (noalias) +type BankKeeper interface { + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error +} + +// TxFeesKeeper defines the expected transaction fee keeper +type TxFeesKeeper interface { + ConvertToBaseToken(ctx sdk.Context, inputFee sdk.Coin) (sdk.Coin, error) + GetBaseDenom(ctx sdk.Context) (denom string, err error) + GetFeeToken(ctx sdk.Context, denom string) (FeeToken, error) +} diff --git a/x/txfees/types/feetoken.pb.go b/x/txfees/types/feetoken.pb.go new file mode 100644 index 00000000000..989b6e86dd3 --- /dev/null +++ b/x/txfees/types/feetoken.pb.go @@ -0,0 +1,388 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/txfees/v1beta1/feetoken.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// FeeToken is a struct that specifies a coin denom, and pool ID pair. +// This marks the token as eligible for use as a tx fee asset in Osmosis. +// Its price in osmo is derived through looking at the provided pool ID. +// The pool ID must have base denom as one of its assets. +type FeeToken struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + PoolID uint64 `protobuf:"varint,2,opt,name=poolID,proto3" json:"poolID,omitempty" yaml:"pool_id"` +} + +func (m *FeeToken) Reset() { *m = FeeToken{} } +func (m *FeeToken) String() string { return proto.CompactTextString(m) } +func (*FeeToken) ProtoMessage() {} +func (*FeeToken) Descriptor() ([]byte, []int) { + return fileDescriptor_c50689857adfcfe0, []int{0} +} +func (m *FeeToken) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeeToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeeToken.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 *FeeToken) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeeToken.Merge(m, src) +} +func (m *FeeToken) XXX_Size() int { + return m.Size() +} +func (m *FeeToken) XXX_DiscardUnknown() { + xxx_messageInfo_FeeToken.DiscardUnknown(m) +} + +var xxx_messageInfo_FeeToken proto.InternalMessageInfo + +func (m *FeeToken) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *FeeToken) GetPoolID() uint64 { + if m != nil { + return m.PoolID + } + return 0 +} + +func init() { + proto.RegisterType((*FeeToken)(nil), "osmosis.txfees.v1beta1.FeeToken") +} + +func init() { + proto.RegisterFile("osmosis/txfees/v1beta1/feetoken.proto", fileDescriptor_c50689857adfcfe0) +} + +var fileDescriptor_c50689857adfcfe0 = []byte{ + // 236 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcd, 0x2f, 0xce, 0xcd, + 0x2f, 0xce, 0x2c, 0xd6, 0x2f, 0xa9, 0x48, 0x4b, 0x4d, 0x2d, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, + 0x49, 0x34, 0xd4, 0x4f, 0x4b, 0x4d, 0x2d, 0xc9, 0xcf, 0x4e, 0xcd, 0xd3, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x12, 0x83, 0x2a, 0xd3, 0x83, 0x28, 0xd3, 0x83, 0x2a, 0x93, 0x12, 0x49, 0xcf, 0x4f, + 0xcf, 0x07, 0x2b, 0xd1, 0x07, 0xb1, 0x20, 0xaa, 0x95, 0x52, 0xb8, 0x38, 0xdc, 0x52, 0x53, 0x43, + 0x40, 0xfa, 0x85, 0xd4, 0xb8, 0x58, 0x53, 0x52, 0xf3, 0xf2, 0x73, 0x25, 0x18, 0x15, 0x18, 0x35, + 0x38, 0x9d, 0x04, 0x3e, 0xdd, 0x93, 0xe7, 0xa9, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x02, 0x0b, 0x2b, + 0x05, 0x41, 0xa4, 0x85, 0xb4, 0xb8, 0xd8, 0x0a, 0xf2, 0xf3, 0x73, 0x3c, 0x5d, 0x24, 0x98, 0x14, + 0x18, 0x35, 0x58, 0x9c, 0x84, 0x3e, 0xdd, 0x93, 0xe7, 0x83, 0x28, 0x04, 0x89, 0xc7, 0x67, 0xa6, + 0x28, 0x05, 0x41, 0x55, 0x58, 0xb1, 0xbc, 0x58, 0x20, 0xcf, 0xe8, 0xe4, 0x73, 0xe2, 0x91, 0x1c, + 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, + 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x46, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, + 0xf9, 0xb9, 0xfa, 0x50, 0x87, 0xeb, 0xe6, 0x24, 0x26, 0x15, 0xc3, 0x38, 0xfa, 0x65, 0x86, 0xa6, + 0xfa, 0x15, 0x30, 0x2f, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x9d, 0x6e, 0x0c, 0x08, + 0x00, 0x00, 0xff, 0xff, 0xec, 0x68, 0xb6, 0x00, 0x11, 0x01, 0x00, 0x00, +} + +func (this *FeeToken) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*FeeToken) + if !ok { + that2, ok := that.(FeeToken) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if this.PoolID != that1.PoolID { + return false + } + return true +} +func (m *FeeToken) 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 *FeeToken) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeeToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PoolID != 0 { + i = encodeVarintFeetoken(dAtA, i, uint64(m.PoolID)) + i-- + dAtA[i] = 0x10 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintFeetoken(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintFeetoken(dAtA []byte, offset int, v uint64) int { + offset -= sovFeetoken(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FeeToken) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovFeetoken(uint64(l)) + } + if m.PoolID != 0 { + n += 1 + sovFeetoken(uint64(m.PoolID)) + } + return n +} + +func sovFeetoken(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozFeetoken(x uint64) (n int) { + return sovFeetoken(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FeeToken) 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 ErrIntOverflowFeetoken + } + 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: FeeToken: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeeToken: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFeetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFeetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) + } + m.PoolID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipFeetoken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFeetoken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipFeetoken(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFeetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFeetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFeetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthFeetoken + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupFeetoken + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthFeetoken + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthFeetoken = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowFeetoken = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupFeetoken = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/txfees/types/genesis.go b/x/txfees/types/genesis.go new file mode 100644 index 00000000000..4580d51109c --- /dev/null +++ b/x/txfees/types/genesis.go @@ -0,0 +1,36 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// DefaultGenesis returns the default txfee genesis state. +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + Basedenom: sdk.DefaultBondDenom, + Feetokens: []FeeToken{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. It does not verify that the corresponding pool IDs actually exist. +// This is done in InitGenesis. +func (gs GenesisState) Validate() error { + err := sdk.ValidateDenom(gs.Basedenom) + if err != nil { + return err + } + + err = gs.Params.Validate() + if err != nil { + return err + } + + for _, feeToken := range gs.Feetokens { + err := sdk.ValidateDenom(feeToken.Denom) + if err != nil { + return err + } + } + + return nil +} diff --git a/x/txfees/types/genesis.pb.go b/x/txfees/types/genesis.pb.go new file mode 100644 index 00000000000..d5c29860c54 --- /dev/null +++ b/x/txfees/types/genesis.pb.go @@ -0,0 +1,617 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/txfees/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the txfees module's genesis state. +type GenesisState struct { + // params are all the parameters of the module + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + Basedenom string `protobuf:"bytes,2,opt,name=basedenom,proto3" json:"basedenom,omitempty"` + Feetokens []FeeToken `protobuf:"bytes,3,rep,name=feetokens,proto3" json:"feetokens"` +} + +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_4423c18e3d020b37, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetBasedenom() string { + if m != nil { + return m.Basedenom + } + return "" +} + +func (m *GenesisState) GetFeetokens() []FeeToken { + if m != nil { + return m.Feetokens + } + return nil +} + +// Params holds parameters for the incentives module +type Params struct { + // epoch_identifier is what epoch type swap and burn will be triggered by + // (day, week, etc.) + EpochIdentifier string `protobuf:"bytes,1,opt,name=epoch_identifier,json=epochIdentifier,proto3" json:"epoch_identifier,omitempty" yaml:"epoch_identifier"` +} + +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_4423c18e3d020b37, []int{1} +} +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) GetEpochIdentifier() string { + if m != nil { + return m.EpochIdentifier + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "osmosis.txfees.v1beta1.GenesisState") + proto.RegisterType((*Params)(nil), "osmosis.txfees.v1beta1.Params") +} + +func init() { + proto.RegisterFile("osmosis/txfees/v1beta1/genesis.proto", fileDescriptor_4423c18e3d020b37) +} + +var fileDescriptor_4423c18e3d020b37 = []byte{ + // 316 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc9, 0x2f, 0xce, 0xcd, + 0x2f, 0xce, 0x2c, 0xd6, 0x2f, 0xa9, 0x48, 0x4b, 0x4d, 0x2d, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, + 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, + 0x17, 0x12, 0x83, 0xaa, 0xd2, 0x83, 0xa8, 0xd2, 0x83, 0xaa, 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, + 0x07, 0x2b, 0xd1, 0x07, 0xb1, 0x20, 0xaa, 0xa5, 0x54, 0x71, 0x98, 0x99, 0x96, 0x9a, 0x5a, 0x92, + 0x9f, 0x9d, 0x9a, 0x07, 0x51, 0xa6, 0xb4, 0x81, 0x91, 0x8b, 0xc7, 0x1d, 0x62, 0x4d, 0x70, 0x49, + 0x62, 0x49, 0xaa, 0x90, 0x0d, 0x17, 0x5b, 0x41, 0x62, 0x51, 0x62, 0x6e, 0xb1, 0x04, 0xa3, 0x02, + 0xa3, 0x06, 0xb7, 0x91, 0x9c, 0x1e, 0x76, 0x6b, 0xf5, 0x02, 0xc0, 0xaa, 0x9c, 0x58, 0x4e, 0xdc, + 0x93, 0x67, 0x08, 0x82, 0xea, 0x11, 0x92, 0xe1, 0xe2, 0x4c, 0x4a, 0x2c, 0x4e, 0x4d, 0x49, 0xcd, + 0xcb, 0xcf, 0x95, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x0c, 0x42, 0x08, 0x08, 0xb9, 0x70, 0x71, 0xc2, + 0xac, 0x2f, 0x96, 0x60, 0x56, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0x65, 0xbc, 0x5b, 0x6a, 0x6a, + 0x08, 0x48, 0x21, 0xd4, 0x02, 0x84, 0x46, 0xa5, 0x00, 0x2e, 0x36, 0x88, 0xdd, 0x42, 0x6e, 0x5c, + 0x02, 0xa9, 0x05, 0xf9, 0xc9, 0x19, 0xf1, 0x99, 0x29, 0xa9, 0x79, 0x25, 0x99, 0x69, 0x99, 0xa9, + 0x45, 0x60, 0x57, 0x73, 0x3a, 0x49, 0x7f, 0xba, 0x27, 0x2f, 0x5e, 0x99, 0x98, 0x9b, 0x63, 0xa5, + 0x84, 0xae, 0x42, 0x29, 0x88, 0x1f, 0x2c, 0xe4, 0x09, 0x17, 0x71, 0xf2, 0x39, 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, 0xa3, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, + 0xfc, 0x5c, 0x7d, 0xa8, 0x43, 0x75, 0x73, 0x12, 0x93, 0x8a, 0x61, 0x1c, 0xfd, 0x32, 0x43, 0x53, + 0xfd, 0x0a, 0x58, 0x18, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x43, 0xd6, 0x18, 0x10, + 0x00, 0x00, 0xff, 0xff, 0x0b, 0xe0, 0x97, 0x45, 0xd6, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Feetokens) > 0 { + for iNdEx := len(m.Feetokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Feetokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Basedenom) > 0 { + i -= len(m.Basedenom) + copy(dAtA[i:], m.Basedenom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Basedenom))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Params.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 *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.EpochIdentifier) > 0 { + i -= len(m.EpochIdentifier) + copy(dAtA[i:], m.EpochIdentifier) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.EpochIdentifier))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = len(m.Basedenom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.Feetokens) > 0 { + for _, e := range m.Feetokens { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.EpochIdentifier) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Basedenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Basedenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Feetokens", 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.Feetokens = append(m.Feetokens, FeeToken{}) + if err := m.Feetokens[len(m.Feetokens)-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) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +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 EpochIdentifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EpochIdentifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/txfees/types/keys.go b/x/txfees/types/keys.go new file mode 100644 index 00000000000..50665c99261 --- /dev/null +++ b/x/txfees/types/keys.go @@ -0,0 +1,23 @@ +package types + +const ( + // ModuleName defines the module name. + ModuleName = "txfees" + + // StoreKey defines the primary module store key. + StoreKey = ModuleName + + // RouterKey is the message route for slashing. + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // FeeCollectorName the module account name for the fee collector account address. + FeeCollectorName = "fee_collector" +) + +var ( + BaseDenomKey = []byte("base_denom") + FeeTokensStorePrefix = []byte("fee_tokens") +) diff --git a/x/txfees/types/params.go b/x/txfees/types/params.go new file mode 100644 index 00000000000..70fabded4c9 --- /dev/null +++ b/x/txfees/types/params.go @@ -0,0 +1,53 @@ +package types + +import ( + "fmt" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +// Parameter store keys. +var ( + KeyEpochIdentifier = []byte("EpochIdentifier") +) + +// ParamTable for gamm module. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +func NewParams(epochIdentifier string) Params { + return Params{ + EpochIdentifier: epochIdentifier, + } +} + +// default gamm module parameters. +func DefaultParams() Params { + return Params{ + EpochIdentifier: "day", + } +} + +// validate params. +func (p Params) Validate() error { + return validateString(p.EpochIdentifier) +} + +// Implements params.ParamSet. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyEpochIdentifier, &p.EpochIdentifier, validateString), + } +} + +func validateString(i interface{}) error { + v, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if v == "" { + return fmt.Errorf("cannot be empty") + } + return nil +} diff --git a/x/txfees/types/query.pb.go b/x/txfees/types/query.pb.go new file mode 100644 index 00000000000..d0a33024747 --- /dev/null +++ b/x/txfees/types/query.pb.go @@ -0,0 +1,2005 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/txfees/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.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 *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +type QueryFeeTokensRequest struct { +} + +func (m *QueryFeeTokensRequest) Reset() { *m = QueryFeeTokensRequest{} } +func (m *QueryFeeTokensRequest) String() string { return proto.CompactTextString(m) } +func (*QueryFeeTokensRequest) ProtoMessage() {} +func (*QueryFeeTokensRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{2} +} +func (m *QueryFeeTokensRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeTokensRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeTokensRequest.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 *QueryFeeTokensRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeTokensRequest.Merge(m, src) +} +func (m *QueryFeeTokensRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeTokensRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeTokensRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeTokensRequest proto.InternalMessageInfo + +type QueryFeeTokensResponse struct { + FeeTokens []FeeToken `protobuf:"bytes,1,rep,name=fee_tokens,json=feeTokens,proto3" json:"fee_tokens" yaml:"fee_tokens"` +} + +func (m *QueryFeeTokensResponse) Reset() { *m = QueryFeeTokensResponse{} } +func (m *QueryFeeTokensResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeeTokensResponse) ProtoMessage() {} +func (*QueryFeeTokensResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{3} +} +func (m *QueryFeeTokensResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeTokensResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeTokensResponse.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 *QueryFeeTokensResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeTokensResponse.Merge(m, src) +} +func (m *QueryFeeTokensResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeTokensResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeTokensResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeTokensResponse proto.InternalMessageInfo + +func (m *QueryFeeTokensResponse) GetFeeTokens() []FeeToken { + if m != nil { + return m.FeeTokens + } + return nil +} + +// QueryDenomSpotPriceRequest defines grpc request structure for querying spot +// price for the specified tx fee denom +type QueryDenomSpotPriceRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` +} + +func (m *QueryDenomSpotPriceRequest) Reset() { *m = QueryDenomSpotPriceRequest{} } +func (m *QueryDenomSpotPriceRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomSpotPriceRequest) ProtoMessage() {} +func (*QueryDenomSpotPriceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{4} +} +func (m *QueryDenomSpotPriceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomSpotPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomSpotPriceRequest.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 *QueryDenomSpotPriceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomSpotPriceRequest.Merge(m, src) +} +func (m *QueryDenomSpotPriceRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomSpotPriceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomSpotPriceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomSpotPriceRequest proto.InternalMessageInfo + +func (m *QueryDenomSpotPriceRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// QueryDenomSpotPriceRequest defines grpc response structure for querying spot +// price for the specified tx fee denom +type QueryDenomSpotPriceResponse struct { + PoolID uint64 `protobuf:"varint,1,opt,name=poolID,proto3" json:"poolID,omitempty" yaml:"pool_id"` + SpotPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=spot_price,json=spotPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"spot_price" yaml:"spot_price"` +} + +func (m *QueryDenomSpotPriceResponse) Reset() { *m = QueryDenomSpotPriceResponse{} } +func (m *QueryDenomSpotPriceResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomSpotPriceResponse) ProtoMessage() {} +func (*QueryDenomSpotPriceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{5} +} +func (m *QueryDenomSpotPriceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomSpotPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomSpotPriceResponse.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 *QueryDenomSpotPriceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomSpotPriceResponse.Merge(m, src) +} +func (m *QueryDenomSpotPriceResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomSpotPriceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomSpotPriceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomSpotPriceResponse proto.InternalMessageInfo + +func (m *QueryDenomSpotPriceResponse) GetPoolID() uint64 { + if m != nil { + return m.PoolID + } + return 0 +} + +type QueryDenomPoolIdRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` +} + +func (m *QueryDenomPoolIdRequest) Reset() { *m = QueryDenomPoolIdRequest{} } +func (m *QueryDenomPoolIdRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomPoolIdRequest) ProtoMessage() {} +func (*QueryDenomPoolIdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{6} +} +func (m *QueryDenomPoolIdRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomPoolIdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomPoolIdRequest.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 *QueryDenomPoolIdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomPoolIdRequest.Merge(m, src) +} +func (m *QueryDenomPoolIdRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomPoolIdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomPoolIdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomPoolIdRequest proto.InternalMessageInfo + +func (m *QueryDenomPoolIdRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type QueryDenomPoolIdResponse struct { + PoolID uint64 `protobuf:"varint,1,opt,name=poolID,proto3" json:"poolID,omitempty" yaml:"pool_id"` +} + +func (m *QueryDenomPoolIdResponse) Reset() { *m = QueryDenomPoolIdResponse{} } +func (m *QueryDenomPoolIdResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomPoolIdResponse) ProtoMessage() {} +func (*QueryDenomPoolIdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{7} +} +func (m *QueryDenomPoolIdResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomPoolIdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomPoolIdResponse.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 *QueryDenomPoolIdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomPoolIdResponse.Merge(m, src) +} +func (m *QueryDenomPoolIdResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomPoolIdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomPoolIdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomPoolIdResponse proto.InternalMessageInfo + +func (m *QueryDenomPoolIdResponse) GetPoolID() uint64 { + if m != nil { + return m.PoolID + } + return 0 +} + +type QueryBaseDenomRequest struct { +} + +func (m *QueryBaseDenomRequest) Reset() { *m = QueryBaseDenomRequest{} } +func (m *QueryBaseDenomRequest) String() string { return proto.CompactTextString(m) } +func (*QueryBaseDenomRequest) ProtoMessage() {} +func (*QueryBaseDenomRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{8} +} +func (m *QueryBaseDenomRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBaseDenomRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBaseDenomRequest.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 *QueryBaseDenomRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBaseDenomRequest.Merge(m, src) +} +func (m *QueryBaseDenomRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryBaseDenomRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBaseDenomRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBaseDenomRequest proto.InternalMessageInfo + +type QueryBaseDenomResponse struct { + BaseDenom string `protobuf:"bytes,1,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` +} + +func (m *QueryBaseDenomResponse) Reset() { *m = QueryBaseDenomResponse{} } +func (m *QueryBaseDenomResponse) String() string { return proto.CompactTextString(m) } +func (*QueryBaseDenomResponse) ProtoMessage() {} +func (*QueryBaseDenomResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6cbc1b48c44dfdd6, []int{9} +} +func (m *QueryBaseDenomResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBaseDenomResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBaseDenomResponse.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 *QueryBaseDenomResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBaseDenomResponse.Merge(m, src) +} +func (m *QueryBaseDenomResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryBaseDenomResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBaseDenomResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBaseDenomResponse proto.InternalMessageInfo + +func (m *QueryBaseDenomResponse) GetBaseDenom() string { + if m != nil { + return m.BaseDenom + } + return "" +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "osmosis.txfees.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "osmosis.txfees.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryFeeTokensRequest)(nil), "osmosis.txfees.v1beta1.QueryFeeTokensRequest") + proto.RegisterType((*QueryFeeTokensResponse)(nil), "osmosis.txfees.v1beta1.QueryFeeTokensResponse") + proto.RegisterType((*QueryDenomSpotPriceRequest)(nil), "osmosis.txfees.v1beta1.QueryDenomSpotPriceRequest") + proto.RegisterType((*QueryDenomSpotPriceResponse)(nil), "osmosis.txfees.v1beta1.QueryDenomSpotPriceResponse") + proto.RegisterType((*QueryDenomPoolIdRequest)(nil), "osmosis.txfees.v1beta1.QueryDenomPoolIdRequest") + proto.RegisterType((*QueryDenomPoolIdResponse)(nil), "osmosis.txfees.v1beta1.QueryDenomPoolIdResponse") + proto.RegisterType((*QueryBaseDenomRequest)(nil), "osmosis.txfees.v1beta1.QueryBaseDenomRequest") + proto.RegisterType((*QueryBaseDenomResponse)(nil), "osmosis.txfees.v1beta1.QueryBaseDenomResponse") +} + +func init() { + proto.RegisterFile("osmosis/txfees/v1beta1/query.proto", fileDescriptor_6cbc1b48c44dfdd6) +} + +var fileDescriptor_6cbc1b48c44dfdd6 = []byte{ + // 688 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xbf, 0x6f, 0xd3, 0x40, + 0x18, 0x8d, 0x4b, 0x1b, 0x29, 0x57, 0x54, 0xc1, 0xd1, 0x5f, 0x18, 0xe4, 0x54, 0xa7, 0x52, 0x55, + 0xad, 0xe2, 0xa3, 0x29, 0x5d, 0x10, 0x0b, 0x26, 0xaa, 0x84, 0x84, 0x50, 0x71, 0x99, 0xba, 0x58, + 0x76, 0x72, 0x31, 0x56, 0x13, 0x9f, 0x9b, 0xbb, 0x54, 0x8d, 0x10, 0x0b, 0x1b, 0x1b, 0x12, 0x12, + 0x33, 0x1b, 0x13, 0xfc, 0x1d, 0x1d, 0x2b, 0xb1, 0x20, 0x86, 0x08, 0x35, 0xfc, 0x05, 0xf9, 0x0b, + 0x90, 0xcf, 0xe7, 0x38, 0xbf, 0xdc, 0x24, 0x53, 0xe2, 0xfb, 0xde, 0xf7, 0xde, 0xfb, 0x72, 0xef, + 0x73, 0x00, 0xa2, 0xac, 0x4e, 0x99, 0xc7, 0x30, 0xbf, 0xa8, 0x12, 0xc2, 0xf0, 0xf9, 0x9e, 0x43, + 0xb8, 0xbd, 0x87, 0xcf, 0x9a, 0xa4, 0xd1, 0xd2, 0x83, 0x06, 0xe5, 0x14, 0xae, 0x4a, 0x8c, 0x1e, + 0x61, 0x74, 0x89, 0x51, 0x97, 0x5d, 0xea, 0x52, 0x01, 0xc1, 0xe1, 0xb7, 0x08, 0xad, 0x3e, 0x74, + 0x29, 0x75, 0x6b, 0x04, 0xdb, 0x81, 0x87, 0x6d, 0xdf, 0xa7, 0xdc, 0xe6, 0x1e, 0xf5, 0x99, 0xac, + 0x6a, 0xb2, 0x2a, 0x9e, 0x9c, 0x66, 0x15, 0x57, 0x9a, 0x0d, 0x01, 0x90, 0xf5, 0x47, 0x29, 0x7e, + 0xaa, 0x84, 0x70, 0x7a, 0x4a, 0x62, 0xd8, 0x66, 0x0a, 0xcc, 0x25, 0x3e, 0x09, 0x9d, 0x0a, 0x14, + 0x5a, 0x06, 0xf0, 0x4d, 0x38, 0xc7, 0x91, 0xdd, 0xb0, 0xeb, 0xcc, 0x24, 0x67, 0x4d, 0xc2, 0x38, + 0x3a, 0x06, 0xf7, 0x06, 0x4e, 0x59, 0x40, 0x7d, 0x46, 0xe0, 0x33, 0x90, 0x0d, 0xc4, 0xc9, 0xba, + 0xb2, 0xa1, 0x6c, 0x2f, 0x16, 0x35, 0x7d, 0xfc, 0xd8, 0x7a, 0xd4, 0x67, 0xcc, 0x5f, 0xb6, 0xf3, + 0x19, 0x53, 0xf6, 0xa0, 0x35, 0xb0, 0x22, 0x48, 0x0f, 0x09, 0x79, 0x1b, 0xfa, 0xec, 0xa9, 0x71, + 0xb0, 0x3a, 0x5c, 0x90, 0x82, 0x27, 0x00, 0x54, 0x09, 0xb1, 0xc4, 0x58, 0xa1, 0xe8, 0xad, 0xed, + 0xc5, 0xe2, 0x46, 0x9a, 0x68, 0xdc, 0x6e, 0xdc, 0x0f, 0x65, 0xbb, 0xed, 0xfc, 0xdd, 0x96, 0x5d, + 0xaf, 0x3d, 0x45, 0x09, 0x03, 0x32, 0x73, 0xd5, 0x58, 0x03, 0x95, 0x80, 0x2a, 0x54, 0x4b, 0xc4, + 0xa7, 0xf5, 0xe3, 0x80, 0xf2, 0xa3, 0x86, 0x57, 0x26, 0xd2, 0x13, 0xdc, 0x02, 0x0b, 0x95, 0xb0, + 0x20, 0x26, 0xcd, 0x19, 0x77, 0xba, 0xed, 0xfc, 0xed, 0x88, 0x4e, 0x1c, 0x23, 0x33, 0x2a, 0xa3, + 0x1f, 0x0a, 0x78, 0x30, 0x96, 0x46, 0x4e, 0xb0, 0x03, 0xb2, 0x01, 0xa5, 0xb5, 0x97, 0x25, 0x41, + 0x34, 0x6f, 0xc0, 0x6e, 0x3b, 0xbf, 0x14, 0x11, 0x85, 0xe7, 0x96, 0x57, 0x41, 0xa6, 0x44, 0x40, + 0x07, 0x00, 0x16, 0x50, 0x6e, 0x05, 0x21, 0xc3, 0xfa, 0x9c, 0x10, 0x7e, 0x11, 0xce, 0xf2, 0xa7, + 0x9d, 0xdf, 0x72, 0x3d, 0xfe, 0xae, 0xe9, 0xe8, 0x65, 0x5a, 0xc7, 0x65, 0xf1, 0x03, 0xc8, 0x8f, + 0x02, 0xab, 0x9c, 0x62, 0xde, 0x0a, 0x08, 0xd3, 0x4b, 0xa4, 0x9c, 0x4c, 0x9d, 0x30, 0x21, 0x33, + 0xc7, 0x62, 0x5f, 0xe8, 0x39, 0x58, 0x4b, 0xec, 0x1e, 0x85, 0xba, 0x95, 0x59, 0x47, 0x3e, 0x04, + 0xeb, 0xa3, 0x14, 0xb3, 0x8f, 0xdb, 0xcb, 0x83, 0x61, 0x33, 0x22, 0xb8, 0xe2, 0x3c, 0xbc, 0x96, + 0x79, 0xe8, 0x2b, 0x48, 0xfa, 0x27, 0x00, 0x38, 0x36, 0x23, 0x56, 0xbf, 0xcf, 0x95, 0x64, 0xe6, + 0xa4, 0x86, 0xcc, 0x9c, 0x13, 0x77, 0x17, 0xbf, 0x65, 0xc1, 0x82, 0x20, 0x84, 0x9f, 0x14, 0x90, + 0x8d, 0xb2, 0x09, 0x77, 0xd2, 0x62, 0x34, 0xba, 0x0e, 0xea, 0xee, 0x54, 0xd8, 0xc8, 0x23, 0xda, + 0xfa, 0xf8, 0xeb, 0xdf, 0x97, 0xb9, 0x0d, 0xa8, 0xe1, 0x94, 0x05, 0x8c, 0xd6, 0x01, 0x7e, 0x55, + 0x40, 0xae, 0x97, 0x78, 0x58, 0xb8, 0x51, 0x62, 0x78, 0x65, 0x54, 0x7d, 0x5a, 0xb8, 0x34, 0xb5, + 0x23, 0x4c, 0x6d, 0x42, 0x84, 0xd3, 0x5f, 0x1e, 0x72, 0x49, 0xe0, 0x4f, 0x05, 0x2c, 0x0d, 0xa6, + 0x19, 0x16, 0x6f, 0x94, 0x1b, 0xbb, 0x41, 0xea, 0xfe, 0x4c, 0x3d, 0xd2, 0xe7, 0xbe, 0xf0, 0x59, + 0x80, 0xbb, 0x69, 0x3e, 0x93, 0x58, 0x5b, 0x4e, 0x2b, 0xba, 0x6b, 0xf8, 0x5d, 0x01, 0x8b, 0x7d, + 0x61, 0x84, 0x78, 0xb2, 0xf2, 0x40, 0xf2, 0xd5, 0xc7, 0xd3, 0x37, 0x48, 0x9f, 0x07, 0xc2, 0x27, + 0x86, 0x85, 0x34, 0x9f, 0xc2, 0x99, 0x25, 0x33, 0x8f, 0xdf, 0x8b, 0xc7, 0x0f, 0xe2, 0xce, 0x7b, + 0xa9, 0x9e, 0x70, 0xe7, 0xc3, 0x6b, 0x31, 0xe1, 0xce, 0x47, 0x96, 0x65, 0xf2, 0x9d, 0x27, 0xeb, + 0x62, 0xbc, 0xba, 0xbc, 0xd6, 0x94, 0xab, 0x6b, 0x4d, 0xf9, 0x7b, 0xad, 0x29, 0x9f, 0x3b, 0x5a, + 0xe6, 0xaa, 0xa3, 0x65, 0x7e, 0x77, 0xb4, 0xcc, 0x49, 0xb1, 0xef, 0xc5, 0x23, 0x79, 0x0a, 0x35, + 0xdb, 0x61, 0x3d, 0xd2, 0xf3, 0xbd, 0x03, 0x7c, 0x11, 0x53, 0x8b, 0x17, 0x91, 0x93, 0x15, 0xff, + 0x2d, 0xfb, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x63, 0xd6, 0x9d, 0xde, 0x3a, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params returns params. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // FeeTokens returns a list of all the accepted fee tokens and their + // corresponding pools. It does not include the BaseDenom, which has its own + // query endpoint + FeeTokens(ctx context.Context, in *QueryFeeTokensRequest, opts ...grpc.CallOption) (*QueryFeeTokensResponse, error) + // DenomSpotPrice returns all spot prices by each registered token denom. + DenomSpotPrice(ctx context.Context, in *QueryDenomSpotPriceRequest, opts ...grpc.CallOption) (*QueryDenomSpotPriceResponse, error) + // Returns the poolID for a specified denom input. + DenomPoolId(ctx context.Context, in *QueryDenomPoolIdRequest, opts ...grpc.CallOption) (*QueryDenomPoolIdResponse, error) + // Returns a list of all base denom tokens and their corresponding pools. + BaseDenom(ctx context.Context, in *QueryBaseDenomRequest, opts ...grpc.CallOption) (*QueryBaseDenomResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/osmosis.txfees.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) FeeTokens(ctx context.Context, in *QueryFeeTokensRequest, opts ...grpc.CallOption) (*QueryFeeTokensResponse, error) { + out := new(QueryFeeTokensResponse) + err := c.cc.Invoke(ctx, "/osmosis.txfees.v1beta1.Query/FeeTokens", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomSpotPrice(ctx context.Context, in *QueryDenomSpotPriceRequest, opts ...grpc.CallOption) (*QueryDenomSpotPriceResponse, error) { + out := new(QueryDenomSpotPriceResponse) + err := c.cc.Invoke(ctx, "/osmosis.txfees.v1beta1.Query/DenomSpotPrice", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomPoolId(ctx context.Context, in *QueryDenomPoolIdRequest, opts ...grpc.CallOption) (*QueryDenomPoolIdResponse, error) { + out := new(QueryDenomPoolIdResponse) + err := c.cc.Invoke(ctx, "/osmosis.txfees.v1beta1.Query/DenomPoolId", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) BaseDenom(ctx context.Context, in *QueryBaseDenomRequest, opts ...grpc.CallOption) (*QueryBaseDenomResponse, error) { + out := new(QueryBaseDenomResponse) + err := c.cc.Invoke(ctx, "/osmosis.txfees.v1beta1.Query/BaseDenom", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params returns params. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // FeeTokens returns a list of all the accepted fee tokens and their + // corresponding pools. It does not include the BaseDenom, which has its own + // query endpoint + FeeTokens(context.Context, *QueryFeeTokensRequest) (*QueryFeeTokensResponse, error) + // DenomSpotPrice returns all spot prices by each registered token denom. + DenomSpotPrice(context.Context, *QueryDenomSpotPriceRequest) (*QueryDenomSpotPriceResponse, error) + // Returns the poolID for a specified denom input. + DenomPoolId(context.Context, *QueryDenomPoolIdRequest) (*QueryDenomPoolIdResponse, error) + // Returns a list of all base denom tokens and their corresponding pools. + BaseDenom(context.Context, *QueryBaseDenomRequest) (*QueryBaseDenomResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) FeeTokens(ctx context.Context, req *QueryFeeTokensRequest) (*QueryFeeTokensResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeeTokens not implemented") +} +func (*UnimplementedQueryServer) DenomSpotPrice(ctx context.Context, req *QueryDenomSpotPriceRequest) (*QueryDenomSpotPriceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomSpotPrice not implemented") +} +func (*UnimplementedQueryServer) DenomPoolId(ctx context.Context, req *QueryDenomPoolIdRequest) (*QueryDenomPoolIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomPoolId not implemented") +} +func (*UnimplementedQueryServer) BaseDenom(ctx context.Context, req *QueryBaseDenomRequest) (*QueryBaseDenomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BaseDenom not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.txfees.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_FeeTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeeTokensRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeeTokens(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.txfees.v1beta1.Query/FeeTokens", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeeTokens(ctx, req.(*QueryFeeTokensRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomSpotPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomSpotPriceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomSpotPrice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.txfees.v1beta1.Query/DenomSpotPrice", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomSpotPrice(ctx, req.(*QueryDenomSpotPriceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomPoolId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomPoolIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomPoolId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.txfees.v1beta1.Query/DenomPoolId", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomPoolId(ctx, req.(*QueryDenomPoolIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_BaseDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryBaseDenomRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).BaseDenom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.txfees.v1beta1.Query/BaseDenom", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).BaseDenom(ctx, req.(*QueryBaseDenomRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "osmosis.txfees.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "FeeTokens", + Handler: _Query_FeeTokens_Handler, + }, + { + MethodName: "DenomSpotPrice", + Handler: _Query_DenomSpotPrice_Handler, + }, + { + MethodName: "DenomPoolId", + Handler: _Query_DenomPoolId_Handler, + }, + { + MethodName: "BaseDenom", + Handler: _Query_BaseDenom_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "osmosis/txfees/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) 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 *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryFeeTokensRequest) 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 *QueryFeeTokensRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeTokensRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryFeeTokensResponse) 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 *QueryFeeTokensResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeTokensResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FeeTokens) > 0 { + for iNdEx := len(m.FeeTokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeTokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomSpotPriceRequest) 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 *QueryDenomSpotPriceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomSpotPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomSpotPriceResponse) 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 *QueryDenomSpotPriceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomSpotPriceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.SpotPrice.Size() + i -= size + if _, err := m.SpotPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.PoolID != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomPoolIdRequest) 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 *QueryDenomPoolIdRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomPoolIdRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomPoolIdResponse) 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 *QueryDenomPoolIdResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomPoolIdResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PoolID != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryBaseDenomRequest) 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 *QueryBaseDenomRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBaseDenomRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryBaseDenomResponse) 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 *QueryBaseDenomResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBaseDenomResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BaseDenom) > 0 { + i -= len(m.BaseDenom) + copy(dAtA[i:], m.BaseDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BaseDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryFeeTokensRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryFeeTokensResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.FeeTokens) > 0 { + for _, e := range m.FeeTokens { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryDenomSpotPriceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomSpotPriceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolID != 0 { + n += 1 + sovQuery(uint64(m.PoolID)) + } + l = m.SpotPrice.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryDenomPoolIdRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomPoolIdResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolID != 0 { + n += 1 + sovQuery(uint64(m.PoolID)) + } + return n +} + +func (m *QueryBaseDenomRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryBaseDenomResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.BaseDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) 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 ErrIntOverflowQuery + } + 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) 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 ErrIntOverflowQuery + } + 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + 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 := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFeeTokensRequest) 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 ErrIntOverflowQuery + } + 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: QueryFeeTokensRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeTokensRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFeeTokensResponse) 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 ErrIntOverflowQuery + } + 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: QueryFeeTokensResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeTokensResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeTokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeTokens = append(m.FeeTokens, FeeToken{}) + if err := m.FeeTokens[len(m.FeeTokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomSpotPriceRequest) 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 ErrIntOverflowQuery + } + 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: QueryDenomSpotPriceRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomSpotPriceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomSpotPriceResponse) 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 ErrIntOverflowQuery + } + 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: QueryDenomSpotPriceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomSpotPriceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) + } + m.PoolID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpotPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SpotPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomPoolIdRequest) 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 ErrIntOverflowQuery + } + 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: QueryDenomPoolIdRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomPoolIdRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomPoolIdResponse) 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 ErrIntOverflowQuery + } + 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: QueryDenomPoolIdResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomPoolIdResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) + } + m.PoolID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBaseDenomRequest) 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 ErrIntOverflowQuery + } + 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: QueryBaseDenomRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBaseDenomRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBaseDenomResponse) 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 ErrIntOverflowQuery + } + 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: QueryBaseDenomResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBaseDenomResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/txfees/types/query.pb.gw.go b/x/txfees/types/query.pb.gw.go new file mode 100644 index 00000000000..7512d94b48a --- /dev/null +++ b/x/txfees/types/query.pb.gw.go @@ -0,0 +1,467 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: osmosis/txfees/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_FeeTokens_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeTokensRequest + var metadata runtime.ServerMetadata + + msg, err := client.FeeTokens(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeeTokens_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeTokensRequest + var metadata runtime.ServerMetadata + + msg, err := server.FeeTokens(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_DenomSpotPrice_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_DenomSpotPrice_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomSpotPriceRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomSpotPrice_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DenomSpotPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomSpotPrice_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomSpotPriceRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomSpotPrice_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DenomSpotPrice(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_DenomPoolId_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomPoolIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := client.DenomPoolId(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomPoolId_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomPoolIdRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := server.DenomPoolId(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_BaseDenom_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBaseDenomRequest + var metadata runtime.ServerMetadata + + msg, err := client.BaseDenom(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_BaseDenom_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBaseDenomRequest + var metadata runtime.ServerMetadata + + msg, err := server.BaseDenom(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeeTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_FeeTokens_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomSpotPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomSpotPrice_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomSpotPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomPoolId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomPoolId_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomPoolId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_BaseDenom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_BaseDenom_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BaseDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeeTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_FeeTokens_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomSpotPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomSpotPrice_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomSpotPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomPoolId_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomPoolId_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomPoolId_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_BaseDenom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_BaseDenom_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BaseDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "txfees", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_FeeTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "txfees", "v1beta1", "fee_tokens"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomSpotPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "txfees", "v1beta1", "spot_price_by_denom"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomPoolId_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"osmosis", "txfees", "v1beta1", "denom_pool_id", "denom"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_BaseDenom_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "txfees", "v1beta1", "base_denom"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_FeeTokens_0 = runtime.ForwardResponseMessage + + forward_Query_DenomSpotPrice_0 = runtime.ForwardResponseMessage + + forward_Query_DenomPoolId_0 = runtime.ForwardResponseMessage + + forward_Query_BaseDenom_0 = runtime.ForwardResponseMessage +)