Skip to content

Commit

Permalink
Allow whitelisted tx fee tokens based on conversion rate to OSMO (#394)
Browse files Browse the repository at this point in the history
* in progress

* in progress

* in progress

* update proto genesis basetokens -> basetoken

* passed txfees test

* working!

* address @antstalepresh review

* remove unnecessary file

* Update app/ante.go

* Apply comment suggestions from code review

Co-authored-by: Dev Ojha <[email protected]>

* comments from @ValarDragon review

* delete REST folder

* panic in initgenesis

* Update x/txfees/module.go

Co-authored-by: Dev Ojha <[email protected]>

* remove memkey

* remove old mempoolfeedecorator

* stuff happened

* switch to table driven tests

* mempool decorator tests

* register legacy amino codec

* fix lint

* add readme stub

* improve lint

* Update x/txfees/keeper/feedecorator.go

Co-authored-by: Dev Ojha <[email protected]>

* Update x/txfees/keeper/feedecorator.go

* Bump go mod versions

* Fix keeper for main updates

Co-authored-by: Dev Ojha <[email protected]>
Co-authored-by: ValarDragon <[email protected]>
  • Loading branch information
3 people authored Nov 5, 2021
1 parent 44460ef commit 2a240fa
Show file tree
Hide file tree
Showing 36 changed files with 4,447 additions and 9 deletions.
40 changes: 40 additions & 0 deletions app/ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

ante "github.com/cosmos/cosmos-sdk/x/auth/ante"

txfeeskeeper "github.com/osmosis-labs/osmosis/x/txfees/keeper"
txfeestypes "github.com/osmosis-labs/osmosis/x/txfees/types"
)

// Link to default ante handler used by cosmos sdk:
// https://github.com/cosmos/cosmos-sdk/blob/v0.43.0/x/auth/ante/ante.go#L41
func NewAnteHandler(
ak ante.AccountKeeper, bankKeeper authtypes.BankKeeper,
txFeesKeeper txfeeskeeper.Keeper, spotPriceCalculator txfeestypes.SpotPriceCalculator,
sigGasConsumer ante.SignatureVerificationGasConsumer,
signModeHandler signing.SignModeHandler,
) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
ante.NewRejectExtensionOptionsDecorator(),
// Use Mempool Fee Decorator from our txfees module instead of default one from auth
// https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/middleware/fee.go#L34
txfeeskeeper.NewMempoolFeeDecorator(txFeesKeeper),
ante.NewValidateBasicDecorator(),
ante.TxTimeoutHeightDecorator{},
ante.NewValidateMemoDecorator(ak),
ante.NewConsumeGasForTxSizeDecorator(ak),
ante.NewRejectFeeGranterDecorator(),
ante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
ante.NewValidateSigCountDecorator(ak),
ante.NewDeductFeeDecorator(ak, bankKeeper),
ante.NewSigGasConsumeDecorator(ak, sigGasConsumer),
ante.NewSigVerificationDecorator(ak, signModeHandler),
ante.NewIncrementSequenceDecorator(ak),
)
}
30 changes: 24 additions & 6 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ import (
poolincentivesclient "github.com/osmosis-labs/osmosis/x/pool-incentives/client"
poolincentiveskeeper "github.com/osmosis-labs/osmosis/x/pool-incentives/keeper"
poolincentivestypes "github.com/osmosis-labs/osmosis/x/pool-incentives/types"
"github.com/osmosis-labs/osmosis/x/txfees"
txfeeskeeper "github.com/osmosis-labs/osmosis/x/txfees/keeper"
txfeestypes "github.com/osmosis-labs/osmosis/x/txfees/types"
)

const appName = "OsmosisApp"
Expand Down Expand Up @@ -140,6 +143,7 @@ var (
transfer.AppModuleBasic{},
vesting.AppModuleBasic{},
gamm.AppModuleBasic{},
txfees.AppModuleBasic{},
incentives.AppModuleBasic{},
lockup.AppModuleBasic{},
poolincentives.AppModuleBasic{},
Expand All @@ -162,6 +166,7 @@ var (
incentivestypes.ModuleName: {authtypes.Minter, authtypes.Burner},
lockuptypes.ModuleName: {authtypes.Minter, authtypes.Burner},
poolincentivestypes.ModuleName: nil,
txfeestypes.ModuleName: nil,
}

// module accounts that are allowed to receive tokens
Expand Down Expand Up @@ -209,6 +214,7 @@ type OsmosisApp struct {
LockupKeeper lockupkeeper.Keeper
EpochsKeeper epochskeeper.Keeper
PoolIncentivesKeeper poolincentiveskeeper.Keeper
TxFeesKeeper txfeeskeeper.Keeper

// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
Expand Down Expand Up @@ -251,7 +257,7 @@ func NewOsmosisApp(
govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey,
evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey,
gammtypes.StoreKey, lockuptypes.StoreKey, claimtypes.StoreKey, incentivestypes.StoreKey,
epochstypes.StoreKey, poolincentivestypes.StoreKey,
epochstypes.StoreKey, poolincentivestypes.StoreKey, txfeestypes.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
Expand Down Expand Up @@ -407,6 +413,12 @@ func NewOsmosisApp(
),
)

app.TxFeesKeeper = txfeeskeeper.NewKeeper(
appCodec,
keys[txfeestypes.StoreKey],
app.GAMMKeeper,
)

app.LockupKeeper = *lockupKeeper.SetHooks(
lockuptypes.NewMultiLockupHooks(
// insert lockup hooks receivers here
Expand Down Expand Up @@ -471,6 +483,7 @@ func NewOsmosisApp(
transferModule,
claim.NewAppModule(appCodec, *app.ClaimKeeper),
gamm.NewAppModule(appCodec, app.GAMMKeeper, app.AccountKeeper, app.BankKeeper),
txfees.NewAppModule(appCodec, app.TxFeesKeeper),
incentives.NewAppModule(appCodec, app.IncentivesKeeper, app.AccountKeeper, app.BankKeeper, app.EpochsKeeper),
lockup.NewAppModule(appCodec, app.LockupKeeper, app.AccountKeeper, app.BankKeeper),
poolincentives.NewAppModule(appCodec, app.PoolIncentivesKeeper),
Expand Down Expand Up @@ -502,13 +515,15 @@ func NewOsmosisApp(
app.mm.SetOrderInitGenesis(
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName,
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
ibchost.ModuleName,
gammtypes.ModuleName,
txfeestypes.ModuleName,
genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
poolincentivestypes.ModuleName,
claimtypes.ModuleName,
incentivestypes.ModuleName,
epochstypes.ModuleName,
lockuptypes.ModuleName,
gammtypes.ModuleName,
)

app.mm.RegisterInvariants(&app.CrisisKeeper)
Expand All @@ -523,6 +538,8 @@ func NewOsmosisApp(
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
gamm.NewAppModule(appCodec, app.GAMMKeeper, app.AccountKeeper, app.BankKeeper),
txfees.NewAppModule(appCodec, app.TxFeesKeeper),
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
Expand All @@ -531,7 +548,6 @@ func NewOsmosisApp(
params.NewAppModule(app.ParamsKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
ibc.NewAppModule(app.IBCKeeper),
gamm.NewAppModule(appCodec, app.GAMMKeeper, app.AccountKeeper, app.BankKeeper),
incentives.NewAppModule(appCodec, app.IncentivesKeeper, app.AccountKeeper, app.BankKeeper, app.EpochsKeeper),
lockup.NewAppModule(appCodec, app.LockupKeeper, app.AccountKeeper, app.BankKeeper),
poolincentives.NewAppModule(appCodec, app.PoolIncentivesKeeper),
Expand All @@ -553,8 +569,10 @@ func NewOsmosisApp(
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.BankKeeper, ante.DefaultSigVerificationGasConsumer,
NewAnteHandler(
app.AccountKeeper, app.BankKeeper,
app.TxFeesKeeper, app.GAMMKeeper,
ante.DefaultSigVerificationGasConsumer,
encodingConfig.TxConfig.SignModeHandler(),
),
)
Expand Down
2 changes: 2 additions & 0 deletions app/params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const (
BaseCoinUnit = "uosmo"
OsmoExponent = 6

DefaultBondDenom = BaseCoinUnit

// Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
Bech32PrefixAccAddr = "osmo"
)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ require (
)

replace (
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211008194120-d0e63ff7691b
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211028213231-ce6f14aaa6a0
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
github.com/tendermint/tendermint => github.com/tendermint/tendermint v0.34.14
github.com/tendermint/tm-db => github.com/osmosis-labs/tm-db v0.6.5-0.20210911033928-ba9154613417
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211008194120-d0e63ff7691b h1:kt2khOeVohgBMYoSq1ZCjkzQXstQMH2Fsdn+3zaDHNs=
github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211008194120-d0e63ff7691b/go.mod h1:QByRyM6mubdL7o30ZuJTFWT2cwjmT+GT19XSYwyS7pc=
github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211028213231-ce6f14aaa6a0 h1:HgMEtjIjywY20h8F2EBrfEXeZkbb9jstPYhjYunOdxc=
github.com/osmosis-labs/cosmos-sdk v0.42.10-0.20211028213231-ce6f14aaa6a0/go.mod h1:QByRyM6mubdL7o30ZuJTFWT2cwjmT+GT19XSYwyS7pc=
github.com/osmosis-labs/tm-db v0.6.5-0.20210911033928-ba9154613417 h1:otchJDd2SjFWfs7Tse3ULblGcVWqMJ50BE02XCaqXOo=
github.com/osmosis-labs/tm-db v0.6.5-0.20210911033928-ba9154613417/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw=
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
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/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 osmo 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\"" ];
}
13 changes: 13 additions & 0 deletions proto/osmosis/txfees/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";
package osmosis.txfees.v1beta1;

import "gogoproto/gogo.proto";
import "osmosis/txfees/v1beta1/feetoken.proto";

option go_package = "github.com/osmosis-labs/osmosis/x/txfees/types";

// GenesisState defines the txfees module's genesis state.
message GenesisState {
string basedenom = 1;
repeated FeeToken feetokens = 2 [ (gogoproto.nullable) = false ];
}
25 changes: 25 additions & 0 deletions proto/osmosis/txfees/v1beta1/gov.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/x/txfees/types";

// UpdateFeeTokenProposal is a gov Content type for adding a new whitelisted fee
// token. It must specify a denom along with gamm pool ID to use as a spot price
// calculator. It can be used to add a new denom to the whitelist It can also be
// used to update the Pool to associate with the denom. If Pool ID is set to 0,
// it will remove the denom from the whitelisted set.
message UpdateFeeTokenProposal {
option (gogoproto.equal) = true;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;

string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ];
string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ];
FeeToken feetoken = 3 [
(gogoproto.moretags) = "yaml:\"fee_token\"",
(gogoproto.nullable) = false
];
}
49 changes: 49 additions & 0 deletions proto/osmosis/txfees/v1beta1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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";

option go_package = "github.com/osmosis-labs/osmosis/x/txfees/types";

service Query {
// FeeTokens returns a list of all the whitelisted 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";
}

rpc DenomPoolId(QueryDenomPoolIdRequest) returns (QueryDenomPoolIdResponse) {
option (google.api.http).get =
"/osmosis/txfees/v1beta1/denom_pool_id/{denom}";
}

rpc BaseDenom(QueryBaseDenomRequest) returns (QueryBaseDenomResponse) {
option (google.api.http).get = "/osmosis/txfees/v1beta1/base_denom";
}
}

message QueryFeeTokensRequest {}
message QueryFeeTokensResponse {

repeated FeeToken fee_tokens = 1 [
(gogoproto.moretags) = "yaml:\"fee_tokens\"",
(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\"" ];
}
1 change: 1 addition & 0 deletions x/mint/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func NewKeeper(
func (k Keeper) CreateDeveloperVestingModuleAccount(ctx sdk.Context, amount sdk.Coin) {
moduleAcc := authtypes.NewEmptyModuleAccount(
types.DeveloperVestingModuleAcctName, authtypes.Minter)

k.accountKeeper.SetModuleAccount(ctx, moduleAcc)

err := k.bankKeeper.MintCoins(ctx, types.DeveloperVestingModuleAcctName, sdk.NewCoins(amount))
Expand Down
3 changes: 3 additions & 0 deletions x/simulation/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ func GenAndDeliverTxWithRandFees(
return simtypes.NoOpMsg(moduleName, msg.Type(), "message doesn't leave room for fees"), nil, err
}

// Only allow fees in "uosmo"
coins = sdk.NewCoins(sdk.NewCoin("uosmo", coins.AmountOf("uosmo")))

fees, err = simtypes.RandomFees(r, ctx, coins)
if err != nil {
return simtypes.NoOpMsg(moduleName, msg.Type(), "unable to generate fees"), nil, err
Expand Down
3 changes: 3 additions & 0 deletions x/txfees/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Txfees

This module allows validators to define their min gas price is a single "base denom", but then allows users to define their tx fees in any whitelisted fee token. It does this by converting the whitelisted fee token to its equivalent value in base denom fee, using a "Spot Price calculator" (such as the gamm keeper).
Loading

0 comments on commit 2a240fa

Please sign in to comment.