The Provenance Blockchain message fees module manages additional fees that can be applied to transaction messages specified through governance, providing an important economic tool for securing the proof-of-stake network by incentivizing staking and preventing spam. These additional fees are assessed based on message types and fee schedules persisted on-chain, can be denominated in any currency with optional distribution splits, and work alongside base gas fees to create a comprehensive fee structure that maintains backwards compatibility while enabling enhanced network economics and custom fee assessment capabilities for smart contracts.
ConceptsAdditional Msg FeesAdding Custom Additional Fee from Wasm ContractBase FeeTotal FeesAdditional Fee Assessed in Base Denom (nhash)Authz and Wasmd MessagesSimulation and Calculating the Additional Fee to be PaidRelated ResourcesStateMsgFee StructureState ManagementField Detailsmsg_type_urladditional_feerecipientrecipient_basis_pointsMessagesMsgAssessCustomMsgFeeRequestField Detailsnameamountrecipientfromrecipient_basis_pointsRelated ResourcesEventsAny TxTx with Additional FeeTx Summary EventEventMsgFee FieldsAdd/Update/Remove ProposalRelated ResourcesQueriesMessage Fees Query MessagesParamsQueryParamsRequestQueryParamsResponseQueryAllMsgFeesQueryAllMsgFeesRequestQueryAllMsgFeesResponseCalculateTxFeesCalculateTxFeesRequestCalculateTxFeesResponseParamsParametersParameter DetailsFloorGasPriceNhashPerUsdMilSpecial Topics
Concepts
Additional Msg Fees
Fees is one of the most important tools available to secure a PoS network since it incentives staking and encourages spam prevention etc.
As part of the provenance blockchain economics certain messages may require an additional fee to be paid in addition to the normal gas consumption.
Additional fees are assessed and finally consumed based on msgType of the msgs contained in the transaction, and the fee schedule that is persisted on chain. These additional fees are created/updated/removed by governance through
AddMsgFeeProposal
, UpdateMsgFeeProposal
, and RemoveMsgFeeProposal
proposals.Additional fee can be in any denom. This can be split to an optional bech32 account address with basis points.
Adding Custom Additional Fee from Wasm Contract
Creators of wasm contracts have the ability to dispatch an
MsgAssessCustomMsgFeeRequest
that charges a custom fee defined by the creator of the contract. The set fee will be split between the fee module and a specified address in the msg.Base Fee
Base fee is the current fee implementation. Fees are paid in base denom and determined by gas value passed into the Tx. The value collected remains the same.
Total Fees
Total fees = Additional Fees (if any) + Base Fee
Total fees continue to be passed as
sdk.Coins
the Tx accepts for fee entry currently.Example:
usd.example
is the denom (assuming there is a marker/coin of type usd.example
) in which additional fee is being charged in:shell--fees 382199010nhash,99usd.example
Additional Fee Assessed in Base Denom (nhash)
To preserve backwards compatibility of all invokes, clients continue accepting fees in
sdk.Coins
type Coins []Coin
, and because the code needs to distinguish between base fee and additional fee, the msgfees module introduces an additional param, called DefaultFloorGasPrice
to differentiate between base fee and additional fee when additional fee is in same denom as default base denom (nhash).This fee is charged initially by the antehandler, if any excess fee is left, once additional fee are paid, that's collected at the end of the Tx also (same as current behavior).
Example:
- Additional fee = 10000nhash
- Gas = 10000
- Fee passed in = 19070000nhash
In this client passes in an extra 10000nhash (1905 * 10000 + 10000 = 19060000nhash). Current behavior is maintained and tx passes and charges 19050000 initially and 1000 nhash plus 1000nhash extra fee passed in the deliverTx stage. Thus, this will protect against future changes like priority mempool as well as keep current behavior same as current production.
Authz and Wasmd Messages
Authz and wasmd messages are dispatched via the submessages route, so they get charged and assessed the same additional fee if set on a submessage, caveat being they forfeit all their fees if they fail (since we have no way upfront of knowing what the submessages maybe).
Example: Let's say a
MsgSend
has a fee of 100usd.local and a smart contract does 3 MsgSend operations as per the logic of the smart contract, the code will expect additional fees of 300 usd.local (3 msgs x 100usd.local) to be present for the Tx to be successful.Simulation and Calculating the Additional Fee to be Paid
Current simulation method looks like this:
java// Source: https://github.com/provenance-io/provenance val cosmosService = cosmos.tx.v1beta1.ServiceGrpc.newBlockingStub(channel) cosmosService.simulate(SimulateRequest.newBuilder().setTx(txFinal).build()).gasInfo.gasUsed
In the future we recommend using the method:
java// Source: https://github.com/provenance-io/provenance val msgFeeClient = io.provenance.msgfees.v1.QueryGrpc.newBlockingStub(channel) msgFeeClient.calculateTxFees(CalculateTxFeesRequest.newBuilder().setTx(txFinal).build())
Or from the command line as:
shellprovenanced tx simulate <required params>
Related Resources
- GitHub Repository: provenance-io/provenance
- Assess Fee Specifications: Message Fees Messages Documentation
- Parameters Documentation: Message Fees Parameters Documentation
State
The Provenance Blockchain message fees module stores its state using the MsgFee structure, which defines message-based fees on the blockchain and includes the message type URL, additional fee amount in any denomination, optional recipient address for fee distribution, and basis points for calculating the recipient's portion of the fee. This state is created and managed through governance proposals and enables flexible fee structures where fees can be split between recipients and the fee collector using a basis points system that supports up to 10,000 basis points for precise percentage allocations.
MsgFee Structure
The core of what gets stored on the blockchain to define a message-based fee:
protobuf// Source: https://github.com/provenance-io/provenance // MsgFee is the core of what gets stored on the blockchain to define a msg-based fee. message MsgFee { // msg_type_url is the type-url of the message with the added fee, e.g. "/cosmos.bank.v1beta1.MsgSend". string msg_type_url = 1; // additional_fee is the extra fee that is required for the given message type (can be in any denom). cosmos.base.v1beta1.Coin additional_fee = 2 [(gogoproto.nullable) = false]; // recipient is an option address that will receive a portion of the additional fee. // There can only be a recipient if the recipient_basis_points is not zero. string recipient = 3; // recipient_basis_points is an optional portion of the additional fee to be sent to the recipient. // Must be between 0 and 10,000 (inclusive). // // If there is a recipient, this must not be zero. If there is not a recipient, this must be zero. // // The recipient will receive additional_fee * recipient_basis_points / 10,000. // The fee collector will receive the rest, i.e. additional_fee * (10,000 - recipient_basis_points) / 10,000. uint32 recipient_basis_points = 4; }
State Management
This state is created via governance proposals.
Field Details
msg_type_url
The type-url of the message with the added fee, e.g.
/cosmos.bank.v1beta1.MsgSend
.additional_fee
The extra fee that is required for the given message type (can be in any denom).
recipient
An optional address that will receive a portion of the additional fee. There can only be a recipient if the
recipient_basis_points
is not zero.recipient_basis_points
An optional portion of the additional fee to be sent to the recipient. Must be between 0 and 10,000 (inclusive).
Fee Distribution Logic:
- If there is a recipient, this must not be zero
- If there is not a recipient, this must be zero
- The recipient will receive:
additional_fee * recipient_basis_points / 10,000
- The fee collector will receive the rest:
additional_fee * (10,000 - recipient_basis_points) / 10,000
Messages
The Provenance Blockchain message fees module provides the MsgAssessCustomMsgFeeRequest message that enables smart contracts and applications to charge custom fees for their usage. This message allows for flexible fee assessment with optional recipient addresses and basis points distribution, supporting both USD and nhash denominations with automatic conversion capabilities, where USD amounts are specified in mils (1234 = $1.234) and can be automatically converted to nhash using the configured conversion rate parameter.
MsgAssessCustomMsgFeeRequest
A custom fee is applied when this message is broadcast. This would be used in a smart contract to charge a custom fee for the usage.
protobuf// Source: https://github.com/provenance-io/provenance // MsgAssessCustomMsgFeeRequest defines an sdk.Msg type message MsgAssessCustomMsgFeeRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = true; // optional short name for custom msg fee, this will be emitted as a property of the event string name = 1; // amount of additional fee that must be paid cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false]; // optional recipient address, the basis points amount is sent to the recipient string recipient = 3; // the signer of the msg string from = 4; // optional basis points 0 - 10,000 for recipient defaults to 10,000 string recipient_basis_points = 5; }
Field Details
name
Optional short name for custom message fee. This will be emitted as a property of the event.
amount
Amount of additional fee that must be paid. The amount must be in
usd
or nhash
else the message will not pass validation.If the amount is specified as
usd
this will be converted to nhash
using the UsdConversionRate
parameter.Note:
usd
and UsdConversionRate
are specified in mils. Example: 1234 = $1.234recipient
Optional bech32 address of an account that will receive the amount calculated from the
recipient_basis_points
.If the
recipient_basis_points
is left empty the whole amount
will be sent to the recipient. The remainder is sent to the Fee Module.from
The signer of the message.
recipient_basis_points
Optional basis points 0 - 10,000 for recipient defaults to 10,000.
Related Resources
- GitHub Repository: provenance-io/provenance
- Documentation: Provenance Blockchain Developer Portal
Events
The Provenance Blockchain message fees module emits comprehensive events to track fee collection and distribution throughout transaction processing. These events include standard fee tracking for all transactions showing total fees and minimum fees charged, additional fee breakdown events for transactions with message-specific fees, detailed summary events that provide JSON-formatted lists of fee information by message type and recipient, and governance proposal events for fee management operations, ensuring complete transparency and auditability of the fee system.
Any Tx
If a Tx was successful, or if it failed, but the min fee was charged, these two events are emitted:
Type | Attribute Key | Attribute Value |
tx | fee | total fee (coins) |
tx | min_fee_charged | floor gas price * gas (coins) |
Tx with Additional Fee
If there are tx msgs that have additional fees, and those fees were successfully charged, a breakdown event will be emitted.
Type:
tx
Attribute Key | Attribute Value |
additionalfee | additional fee charged (coins) |
basefee | total fee - additional fee, should always cover gas costs (coins) |
Tx Summary Event
If there are tx msgs that have additional fees, and those fees were successfully charged, a summary event will be emitted.
Type:
provenance.msgfees.v1.EventMsgFees
Type | Attribute Key | Attribute Value |
EventMsgFees | MsgFees | A JSON list of EventMsgFee entries summarizing each msg type and recipient. |
EventMsgFee Fields
Each
EventMsgFee
has the following fields:Field Name | Field Value |
type_url | The type url for the tx msg that has a msg fee. |
count | A count of txs with this msg type. |
total | The total amount of additional fees for this msg type and recipient (type_url count * msg fee = total) |
recipient | the bech32 address that the fee was sent to. An empty string indicates the module is the recipient. |
Add/Update/Remove Proposal
Governance proposals events (for proposed msg fees) will continue to be emitted by cosmos sdk.
go// Source: https://github.com/cosmos/cosmos-sdk/blob/master/x/gov/spec/04_events.md // Governance events documentation available at the above GitHub link
Related Resources
- Cosmos SDK Gov Events: https://github.com/cosmos/cosmos-sdk/blob/master/x/gov/spec/04_events.md
Queries
Message Fees Query Messages
The Provenance Blockchain message fees module provides a comprehensive query service for accessing fee-related information and calculating transaction costs. The query service includes endpoints for retrieving module parameters, querying all message fees configured on the blockchain, and calculating estimated fees for transactions including both additional message-based fees and gas costs, enabling developers to accurately estimate and plan for transaction expenses before execution.
Params
Queries the parameters for the x/msgfees module.
HTTP Endpoint:
GET /provenance/msgfees/v1/params
Request:
QueryParamsRequest
Response: QueryParamsResponse
QueryParamsRequest
protobuf// Source: https://github.com/provenance-io/provenance // QueryParamsRequest is the request type for the Query/Params RPC method. message QueryParamsRequest {}
QueryParamsResponse
protobuf// Source: https://github.com/provenance-io/provenance // QueryParamsResponse is the response type for the Query/Params RPC method. message QueryParamsResponse { // params defines the parameters of the module. Params params = 1 [(gogoproto.nullable) = false]; }
QueryAllMsgFees
Query all messages which have fees associated with them.
HTTP Endpoint:
GET /provenance/msgfees/v1/all
Request:
QueryAllMsgFeesRequest
Response: QueryAllMsgFeesResponse
QueryAllMsgFeesRequest
protobuf// Source: https://github.com/provenance-io/provenance // QueryAllMsgFeesRequest queries all Msg which have fees associated with them. message QueryAllMsgFeesRequest { // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageRequest pagination = 2; }
QueryAllMsgFeesResponse
protobuf// Source: https://github.com/provenance-io/provenance // response for querying all msg's with fees associated with them message QueryAllMsgFeesResponse { repeated MsgFee msg_fees = 1; // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageResponse pagination = 2; }
CalculateTxFees
Simulates executing a transaction for estimating gas usage and additional fees.
HTTP Endpoint:
POST /provenance/tx/v1/calculate_msg_based_fee
Request:
CalculateTxFeesRequest
Response: CalculateTxFeesResponse
CalculateTxFeesRequest
protobuf// Source: https://github.com/provenance-io/provenance // CalculateTxFeesRequest is the request type for the Query RPC method. message CalculateTxFeesRequest { // tx_bytes is the transaction to simulate. bytes tx_bytes = 1; // default_base_denom is used to set the denom used for gas fees // if not set it will default to nhash. string default_base_denom = 2; // gas_adjustment is the adjustment factor to be multiplied against the estimate returned by the tx simulation float gas_adjustment = 3; }
CalculateTxFeesResponse
protobuf// Source: https://github.com/provenance-io/provenance // CalculateTxFeesResponse is the response type for the Query RPC method. message CalculateTxFeesResponse { // additional_fees are the amount of coins to be for addition msg fees repeated cosmos.base.v1beta1.Coin additional_fees = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (amino.dont_omitempty) = true, (amino.encoding) = "legacy_coins" ]; // total_fees are the total amount of fees needed for the transactions (msg fees + gas fee) // note: the gas fee is calculated with the floor gas price module param. repeated cosmos.base.v1beta1.Coin total_fees = 2 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (amino.dont_omitempty) = true, (amino.encoding) = "legacy_coins" ]; // estimated_gas is the amount of gas needed for the transaction uint64 estimated_gas = 3; }
protobuf// Example Query Service Definition // Source: https://github.com/provenance-io/provenance service Query { // Params queries the parameters for x/msgfees rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/provenance/msgfees/v1/params"; } // Query all Msgs which have fees associated with them. rpc QueryAllMsgFees(QueryAllMsgFeesRequest) returns (QueryAllMsgFeesResponse) { option (google.api.http).get = "/provenance/msgfees/v1/all"; } // CalculateTxFees simulates executing a transaction for estimating gas usage and additional fees. rpc CalculateTxFees(CalculateTxFeesRequest) returns (CalculateTxFeesResponse) { option (google.api.http) = { post: "/provenance/tx/v1/calculate_msg_based_fee" body: "*" }; } }
Params
The Provenance Blockchain message fees module contains configurable parameters that control fee calculation and currency conversion within the fee system. These parameters include the FloorGasPrice which sets the base denomination value for calculating base fees when both base and additional fees are charged in the same denomination, and NhashPerUsdMil which establishes the conversion rate between nhash and USD denominated in mils, enabling flexible fee structures and accurate currency conversions for transaction cost calculations.
Parameters
The MsgFee module contains the following parameters:
Key | Type | Example |
FloorGasPrice | uint32 | "1905" |
NhashPerUsdMil | uint64 | "14285714" |
Parameter Details
FloorGasPrice
FloorGasPrice is the value of base denom that is charged for calculating base fees, for when base fee and additional fee are charged in the base denom.
Type:
uint32
Example: "1905"
NhashPerUsdMil
NhashPerUsdMil is the number of nhash per usd mil.
Type:
uint64
Example: "14285714"
go// Example parameter structure // Source: https://github.com/provenance-io/provenance type Params struct { FloorGasPrice uint32 `json:"floor_gas_price"` NhashPerUsdMil uint64 `json:"nhash_per_usd_mil"` }