From 6eee90a1c165433eb249b4e8c99baf3d37c45fb4 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Mon, 3 Jun 2024 16:14:00 -0400 Subject: [PATCH] docs: create `UPGRADING` guide (#92) * fix spec * doc and sensible min values * code * information udpate * linkto * fix everythign * fix everythign * fix everythign * fix * annotate * annotate * suggestion * lint --- INTEGRATIONS.md | 81 +++++++++++++++ README.md | 116 ++++++++++++++++------ UPGRADING.md | 38 +++++++ proto/feemarket/feemarket/v1/params.proto | 2 +- x/feemarket/types/eip1559.go | 6 +- x/feemarket/types/eip1559_aimd.go | 4 +- 6 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 INTEGRATIONS.md create mode 100644 UPGRADING.md diff --git a/INTEGRATIONS.md b/INTEGRATIONS.md new file mode 100644 index 0000000..023eeb2 --- /dev/null +++ b/INTEGRATIONS.md @@ -0,0 +1,81 @@ +# Gas Price Queries for Integrations + +Because `x/feemarket` uses a dynamic fee, end-users will need to query the module for the current `gasPrice` to use when building a transaction. + +A summary for the flow to query this information is as follows: + +* Create an RPC connection with the chain +* Create a `feemarket` client +* Submit the `GasPrice` query +* Use the `gasPrice` to populate the Tx fee field. + +Extensive querying information can be seen in the module [spec](./README.md#query). + +The specific query for `GasPrices` can be found [here](./README.md#gas-prices). + +## Code Snippet + +Wallet, relayers, and other users will want to add programmatic ways to query this before building their transactions. Below is an example of how a user could implement this lightweight query in Go: + +### Create A gRPC Connection + +First, a base connection to the chain you are querying must be created. + +A chain gRPC (below) or CometBFT ABCI RPC connection can be created: + +```go + // Set up gRPC connection to chain + cc, err := grpc.NewClient(endpoint, insecure.NewCredentials()) + if err != nil { + panic(err) + } + defer cc.Close() +``` + +### Create a FeeMarket Query Client + +An `x/feemarket` query client can then be created using the created gRPC connection. + +This client exposes all [queries](./README.md#query) that the `x/feemarket` module exposes. + +```go + // Create FeeMarketClient with underlying gRPC connection + feeMarketClient := feemarkettypes.NewQueryClient(cc) +``` + +### Query Gas Prices + +The `gas price` (as an `sdk.DecCoin`) can be queried using the `GasPrice` query. This query requires the desired coin denomination for the fee to be paid with. + +The query will return an error if the given denomination is not supported. + +```go + gasPrice, err := feeMarketClient.GasPrice(ctx, &feemarkettypes.GasPriceRequest{ + Denom: denom, + }) + if err != nil { + panic(err) + } +``` + +### Using `gasPrice` to construct a transaction + +There are two ways to construct a transaction with `gasPrice`: + +1. Provide the minimum fee: `feeAmount = gasPrice * gasLimit` (`gasLimit` gives the maximum amount of gas a transaction can consume. You can obtain appropriate `gasLimit` by simulating a transaction to see how much gas it consumes under normal conditions). +2. Provide a "tip" in addition to the minimum fee: `feeAmount=gasPrice * gasLimit + tip` This will be paid to the block proposer and result in your transaction being placed ahead of others with lower tips (or being included in the block instead of others when the block is full) + +### Understanding Fee Deducted + +The actual amount of fee deducted from the fee payer is based on gas consumed, not `gasLimit`. + +The amount consumed is equal to the `inferredTip + gasPrice * gasConsumed`, where `inferredTip = feeAmount - gasLimit * gasPrice` (This may be different than the tip you specified when building the transaction because the `gasPrice` on chain may have changed since when you queried it.) + +## Examples of Other EIP-1559 Integrations + +The [Osmosis](https://github.com/osmosis-labs/osmosis) Blockchain has a similar EIP-1559 feemarket that has been integrated by wallets and relayers. Below are some examples as to how different projects query the dynamic fee for transactions: + +* [Keplr Wallet EIP-1559 BaseFee Query](https://github.com/chainapsis/keplr-wallet/blob/b0a96c2c713d8163ce840fcd5abbac4eb612607c/packages/stores/src/query/osmosis/base-fee/index.ts#L18) +* [Cosmos-Relayer EIP-1559 BaseFee Query](https://github.com/cosmos/relayer/blob/9b140b664fe6b10161af1093ccd26627b942742e/relayer/chains/cosmos/fee_market.go#L13) +* [Hermes Relayer EIP-1559 Fee Query](https://github.com/informalsystems/hermes/blob/fc8376ba98e4b595e446b366b736a0c046d6026a/crates/relayer/src/chain/cosmos/eip_base_fee.rs#L15) + * Note: Hermes also already implements a query `x/feemarket` seen [here](https://github.com/informalsystems/hermes/blob/fc8376ba98e4b595e446b366b736a0c046d6026a/crates/relayer/src/chain/cosmos/eip_base_fee.rs#L33) diff --git a/README.md b/README.md index 30efaa9..c054b6a 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,18 @@ This document specifies the feemarket module. The feemarket module is an implementation of the Additive Increase Multiplicative Decrease (AIMD) EIP-1559 feemarket. More information about the implementation can be found [here](./x/feemarket/README.md). -This module is planned to be used in the Cosmos Hub. +## Upgrading to FeeMarket -## Status +More information about upgrading your chain to `x/feemarket` can be found in our dedicated [guide](./UPGRADING.md). -The team has not yet completed acceptance testing of the feemarket. We do not recommend integrating it until final testing has been completed (expected May 2024), and we have removed this warning from the readme. +## Important Considerations for End-Users + +Wallets, relayers and other end-users should refer to our [guide](./INTEGRATIONS.md) for using dynamic fees for transaction submission. ## Contents * [State](#state) - * [BaseFee](#basefee) + * [GasPrice](#gas-price) * [LearningRate](#learningrate) * [Window](#window) * [Index](#index) @@ -56,10 +58,10 @@ aforementioned state: * State: `0x02 |ProtocolBuffer(State)` -### BaseFee +### GasPrice -BaseFee is the current base fee. This is denominated in the fee per gas -unit. +GasPrice is the current gas price. This is denominated in the fee per gas +unit in the base fee denom. ### LearningRate @@ -80,9 +82,9 @@ Index is the index of the current block in the block utilization window. // the current base fee, learning rate, and block utilization within the // specified AIMD window. message State { - // BaseFee is the current base fee. This is denominated in the fee per gas + // BaseGasPrice is the current base fee. This is denominated in the fee per gas // unit. - string base_fee = 1 [ + string base_gas_price = 1 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false @@ -123,8 +125,11 @@ type FeeMarketKeeper interface { // Set the params in the store. SetParams(ctx sdk.Context, params types.Params) error - // Get the current minimum gas prices (base fee) from the store. - GetMinGasPrices(ctx sdk.Context) (sdk.Coins, error) + // Get the minimum gas price for a given denom from the store. + GetMinGasPrice(ctx sdk.Context, denom string) (sdk.DecCoin, error) { + + // Get the current minimum gas prices from the store. + GetMinGasPrices(ctx sdk.Context) (sdk.DecCoins, error) } ``` @@ -150,7 +155,6 @@ The message handling can fail if: * signer is not the gov module account address. - ## Events The feemarket module emits the following events: @@ -232,10 +236,10 @@ Delta is the amount we additively increase/decrease the base fee when the net block utilization difference in the window is above/below the target utilization. -### MinBaseFee +### MinBaseGasPrice -MinBaseFee determines the initial base fee of the module and the global -minimum for the network. This is denominated in fee per gas unit. +MinBaseGasPrice determines the initial gas price of the module and the global +minimum for the network. This is denominated in fee per gas unit in the `FeeDenom`. ### MinLearningRate @@ -300,7 +304,7 @@ message Params { (gogoproto.nullable) = false ]; - // Delta is the amount we additively increase/decrease the base fee when the + // Delta is the amount we additively increase/decrease the gas price when the // net block utilization difference in the window is above/below the target // utilization. string delta = 4 [ @@ -309,10 +313,10 @@ message Params { (gogoproto.nullable) = false ]; - // MinBaseFee determines the initial base fee of the module and the global + // MinBaseGasPrice determines the initial gas price of the module and the global // minimum // for the network. This is denominated in fee per gas unit. - string min_base_fee = 5 [ + string MinBaseGasPrice = 5 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false @@ -386,7 +390,7 @@ alpha: "0.000000000000000000" beta: "1.000000000000000000" delta: "0.000000000000000000" enabled: true -fee_denom: stake +fee_denom: skip max_block_utilization: "30000000" max_learning_rate: "0.125000000000000000" min_base_fee: "1.000000000000000000" @@ -420,24 +424,44 @@ window: - "0" ``` -##### base-fee +##### gas-price + +The `gas-price` command allows users to query the current gas-price for a given denom. + +```shell +feemarketd query feemarket gas-price [denom ][flags] +``` + +Example: + +```shell +feemarketd query feemarket gas-price skip +``` + +Example Output: + +```yml +1000000skip +``` + +##### gas-prices -The `base-fee` command allows users to query the current base-fee. +The `gas-prices` command allows users to query the current gas-price for all supported denoms. ```shell -feemarketd query feemarket base-fee [flags] +feemarketd query feemarket gas-prices [flags] ``` Example: ```shell -feemarketd query feemarket base-fee +feemarketd query feemarket gas-prices ``` Example Output: ```yml -1000000stake +1000000stake,100000skip ``` ## gRPC @@ -475,7 +499,7 @@ Example Output: "targetBlockUtilization": "15000000", "maxBlockUtilization": "30000000", "window": "1", - "feeDenom": "stake", + "feeDenom": "skip", "enabled": true } } @@ -502,7 +526,7 @@ Example Output: ```json { "state": { - "baseFee": "1000000", + "baseGasPrice": "1000000", "learningRate": "125000000000000000", "window": [ "0" @@ -511,12 +535,40 @@ Example Output: } ``` -### BaseFee +### GasPrice + +The `GasPrice` endpoint allows users to query the current on-chain gas price for a given denom. + +```shell +feemarket.feemarket.v1.Query/GasPrice +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{"denom": "skip"}' \ + localhost:9090 \ + feemarket.feemarket.v1.Query/GasPrice/ +``` + +Example Output: + +```json +{ + "price": { + "denom": "skip", + "amount": "1000000" + } +} +``` + +### GasPrices -The `BaseFee` endpoint allows users to query the current on-chain base-fee. +The `GasPrices` endpoint allows users to query the current on-chain gas prices for all denoms. ```shell -feemarket.feemarket.v1.Query/BaseFee +feemarket.feemarket.v1.Query/GasPrices ``` Example: @@ -524,16 +576,16 @@ Example: ```shell grpcurl -plaintext \ localhost:9090 \ - feemarket.feemarket.v1.Query/BaseFee + feemarket.feemarket.v1.Query/GasPrices ``` Example Output: ```json { - "fees": [ + "prices": [ { - "denom": "stake", + "denom": "skip", "amount": "1000000" } ] diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 0000000..c7efbc0 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,38 @@ +# Upgrading Your Chain to Use FeeMarket + +## Code Changes + +To integrate your chain with `x/feemarket`, the following steps should be performed: + +### Add the Module to Your App + +* The `FeeMarketKeeper` must be added to your application as seen [here](https://github.com/skip-mev/feemarket/blob/0f83e172c92a02db45f83bf89065fd9543967729/tests/app/app.go#L163). +* A `DenomResolver` (if desired) must be set in your application as seen [here](https://github.com/skip-mev/feemarket/blob/0f83e172c92a02db45f83bf89065fd9543967729/tests/app/app.go#L509). +* `Ante` and `Post` handlers must be configured and set with the application `FeeMarketKeeper` as seen [here](https://github.com/skip-mev/feemarket/blob/0f83e172c92a02db45f83bf89065fd9543967729/tests/app/app.go#L513). + +### Determine Parameters + +We provide sensible default parameters for running either the [EIP-1559](https://github.com/skip-mev/feemarket/blob/0f83e172c92a02db45f83bf89065fd9543967729/x/feemarket/types/eip1559.go#L56) or [AIMD EIP-1559](https://github.com/skip-mev/feemarket/blob/0f83e172c92a02db45f83bf89065fd9543967729/x/feemarket/types/eip1559_aimd.go#L65) feemarkets. + +> **Note** +> +> The default parameters use the default Cosmos SDK bond denomination. The should be modified to your chain's fee denomination. + +## Changes for End-Users + +With the addition of `x/feemarket`, there are some important changes that end-users must be aware of. + +1. A non-zero fee is _always required_ for all transactions. + 1. Pre-`x/feemarket` validators were able to set their `MinGasPrice` field locally, meaning it was possibly for some to have no required fees. This is no longer true as there is always a non-zero global fee for transactions. +2. Fees are no longer static. + 1. The `gas price` will change with market activity, so to ensure that transactions will be included, wallets, relayers, etc. will need to query `x/feemarket` for the current fee state. See the [Querying Gas Price](#querying-gas-price-) section below. +3. Fees _must_ always be a single coin denomination. + 1. Example `--fees skip` is valid while `--fees 10stake,10skip` is invalid + +> **Note** +> +> Fees are still paid using the `fees` [field](https://github.com/cosmos/cosmos-sdk/blob/d1aab15790570bff77aa0b8652288a276205efb0/proto/cosmos/tx/v1beta1/tx.proto#L214) of a Cosmos SDK Transaction as they were before. + +### Querying Gas Price + +Information on how to query and use dynamic gas prices can be found [here](./INTEGRATIONS.md). diff --git a/proto/feemarket/feemarket/v1/params.proto b/proto/feemarket/feemarket/v1/params.proto index 13f74cf..4796a3a 100644 --- a/proto/feemarket/feemarket/v1/params.proto +++ b/proto/feemarket/feemarket/v1/params.proto @@ -35,7 +35,7 @@ message Params { (gogoproto.nullable) = false ]; - // Delta is the amount we additively increase/decrease the base fee when the + // Delta is the amount we additively increase/decrease the gas price when the // net block utilization difference in the window is above/below the target // utilization. string delta = 4 [ diff --git a/x/feemarket/types/eip1559.go b/x/feemarket/types/eip1559.go index 7247613..b72bf57 100644 --- a/x/feemarket/types/eip1559.go +++ b/x/feemarket/types/eip1559.go @@ -35,10 +35,8 @@ var ( // on Ethereum. This denominated in units of gas consumed in a block. DefaultMaxBlockUtilization uint64 = 30_000_000 - // DefaultMinBaseGasPrice is the default minimum base fee. This is the default - // on Ethereum. Note that Ethereum is denominated in 1e18 wei. Cosmos chains will - // likely want to change this to 1e6. - DefaultMinBaseGasPrice = math.LegacyMustNewDecFromStr("1") + // DefaultMinBaseGasPrice is the default minimum base fee. + DefaultMinBaseGasPrice = math.LegacyOneDec() // DefaultMinLearningRate is not used in the base EIP-1559 implementation. DefaultMinLearningRate = math.LegacyMustNewDecFromStr("0.125") diff --git a/x/feemarket/types/eip1559_aimd.go b/x/feemarket/types/eip1559_aimd.go index 3c3ce58..3aefc00 100644 --- a/x/feemarket/types/eip1559_aimd.go +++ b/x/feemarket/types/eip1559_aimd.go @@ -43,9 +43,7 @@ var ( // consumed in a block. DefaultAIMDMaxBlockSize uint64 = 30_000_000 - // DefaultAIMDMinBaseFee is the default minimum base fee. This is the - // default on Ethereum. Note that ethereum is denominated in 1e18 wei. - // Cosmos chains will likely want to change this to 1e6. + // DefaultAIMDMinBaseFee is the default minimum base fee. DefaultAIMDMinBaseFee = math.LegacyMustNewDecFromStr("1000000000") // DefaultAIMDMinLearningRate is the default minimum learning rate.