Skip to content

Commit

Permalink
Merge pull request #28 from dymensionxyz/txfees
Browse files Browse the repository at this point in the history
feat: Add ability to pay tx fees with various tokens
  • Loading branch information
mtsitrin authored Dec 7, 2023
2 parents 80c1036 + 5b0d85d commit fc957b9
Show file tree
Hide file tree
Showing 38 changed files with 5,723 additions and 331 deletions.
4 changes: 2 additions & 2 deletions app/apptesting/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 {
Expand Down
17 changes: 17 additions & 0 deletions proto/osmosis/txfees/v1beta1/feetoken.proto
Original file line number Diff line number Diff line change
@@ -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\"" ];
}
25 changes: 25 additions & 0 deletions proto/osmosis/txfees/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
@@ -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\"" ];
}
88 changes: 88 additions & 0 deletions proto/osmosis/txfees/v1beta1/query.proto
Original file line number Diff line number Diff line change
@@ -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\"" ];
}
20 changes: 20 additions & 0 deletions x/gamm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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, &params)
Expand Down
16 changes: 14 additions & 2 deletions x/gamm/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
Loading

0 comments on commit fc957b9

Please sign in to comment.