Skip to main content

Gas and Fees

On the Humans.ai network, users are required to pay a fee to submit transactions. Since fees are managed differently on Ethereum and Cosmos, it's essential to understand how the Humans.ai blockchain implements an Ethereum-type fee calculation that is compatible with the Cosmos SDK.

This overview covers the fundamentals of gas calculation, how to provide fees for transactions, and how the Ethereum-type fee calculation utilizes a fee market (EIP1559) to prioritize transactions.

It's important to note that the fees paid for interacting with smart contracts on Humans.ai can generate revenue for smart contract deployers. For more information on this, visit develop.

Prerequisite Readings

Basics

Why do Transactions Need Fees?

If transactions can be submitted to a network without any cost, it creates an vulnerability that can be exploited by a few actors who can flood the network with a large number of fraudulent transactions, rendering it unusable.

To address this issue, the concept of "gas" was introduced, which is a resource that is consumed during the execution of transactions. In practice, a small amount of gas is spent on each step of code execution, effectively charging for the use of a validator's resources and preventing malicious actors from bringing the network to a halt at will.

What is Gas?

In essence, gas serves as a measure of the computational effort required to execute a transaction. It represents the amount of work that needs to be done to evaluate and carry out a particular task. More complex transactions, such as those that involve multiple steps or multiple validators, demand more gas compared to simpler transactions that only require a single step.

When discussing a transaction, "gas" refers to the total amount of gas needed for its execution. For instance, a transaction may need 300,000 gas units to be executed.

To put it simply, gas can be thought of as the "fuel" that powers the execution of transactions. Just as electricity is needed to power a house or factory, or fuel is needed to run a car, gas is required to facilitate the processing of transactions.

More on Gas:

How is Gas Calculated?

It's difficult to determine the exact gas cost of a transaction without actually running it. However, you can use the Cosmos SDK to simulating the transaction and get an accurate estimate of the gas cost. Alternatively, you can estimate the gas cost based on the transaction fields and data, such as the number of bytecode operations in the EVM, which have a known amount of gas.

More on Gas Calculations:

How does Gas Relate to Fees?

While gas refers to the computational work required for execution, fees refer to the amount of tokens that must be spent to execute a transaction. The formula for calculating fees is:

Total Fees = Gas * Gas Price (the price per unit of gas)

For example, if "gas" was measured in kilowatt-hours (kWh), the "gas price" would be the rate (in dollars per kWh) determined by your energy provider. In this case, the "fees" would be equivalent to your electricity bill. Just as with electricity, the gas price can fluctuate throughout the day depending on network traffic.

You can find more on Gas vs. Fees here:

How are Fees Handled on Cosmos?

Gas fees on Cosmos are straightforward for users. They specify two fields:

  1. GasLimit: The upper bound on execution gas, also known as GasWanted.
  2. Fees or GasPrice: One of these fields is used to specify or calculate transaction fees. The node will consume all provided fees and then execute the transaction. If the GasLimit is insufficient during execution, the transaction will fail, and changes will be rolled back without refunding fees.

Cosmos SDK-based chain validators can specify min-gas-prices they enforce when selecting transactions for blocks. As a result, transactions with insufficient fees may be delayed or fail.

At the start of each block, fees from the previous block are allocated to validators and delegators, who can withdraw and spend them.

How are Fees Handled on Ethereum?

Fees on Ethereum have evolved over time with multiple implementations.

Initially, transactions included a GasPrice and GasLimit specified by the user, similar to Cosmos SDK transactions. Block proposers received the entire gas fee, and they selected transactions to include based on this.

With EIP-1559 and the London Hard fork, the gas calculation changed. The GasPrice was split into two components: BaseFee and PriorityFee. The BaseFee is automatically calculated based on the block size and is burned once the block is mined. The PriorityFee serves as a tip for proposers and goes to them as an incentive to include the transaction in a block.

Gas Price = Base Fee + Priority Fee

Within a transaction, users can specify a max_fee_per_gas corresponding to the total GasPrice and a max_priority_fee_per_gas corresponding to a maximum PriorityFee, in addition to specifying the gas_limit as before. All surplus gas that was not required for execution is refunded to the user.

More information on Ethereum Fees:

Implementation

How are Gas and Fees Handled on Humans.ai?

Humans.ai is a Cosmos SDK chain that integrates EVM compatibility through a module. As a result, all EVM transactions are converted into Cosmos SDK transactions and update the Cosmos SDK-managed state.

Since all transactions are represented as Cosmos SDK transactions, the fee management process is consistent across execution layers. The fee management process involves standard Cosmos SDK logic, Ethereum logic, and custom Humans.ai logic. The fee_collector module collects fees and distributes them to validators and delegators. There are a few key differences in the fee management process:

  1. Fee Market Module

    Humans.ai tracks the gas supplied for each block and utilizes that to determine a base charge for upcoming EVM transactions, enabling EVM dynamic pricing and transaction priority as described by EIP-1559. This allows Humans.ai's EVM layer to enable EIP-1559 gas and fee computation.

    Each node applies EIP-1559 fee logic for EVM transactions instead of using its local min-gas-prices configuration; the gas price must simply be higher than both the global min-gas-price and the block's BaseFee, with the excess being treated as a priority tip. As a result, validators can calculate Ethereum fees without using the Cosmos SDK fee logic.

    The BaseFee on Humans.ai is awarded to validators and delegators rather than being burned, unlike on Ethereum. The global min-gas-price parameter, which is now set to zero but can be modified via Governance, also serves as the bottom boundary for the BaseFee.

  2. EVM Gas Refunds

    For EVM transactions, Humans.ai returns a portion (at least 50% by default) of the unused gas to mimic how Ethereum currently behaves.

Detailed Timeline

  1. Nodes execute the previous block and run the EndBlock hook
    • As part of this hook, the FeeMarket (EIP-1559) module tracks the total TransientGasWanted from the transactions on this block. This will be used for the next block’s BaseFee.
  2. Nodes receive transactions for a subsequent block and gossip these transactions to peers
    • These can be sorted and prioritized by the included fee price (using EIP-1559 fee priority mechanics for EVM transactions - code snippet), to be included in the next block
  3. Nodes run BeginBlock for the subsequent block
    • The FeeMarket module calculates the BaseFee (code snippet) to be applied for this block using the total GasWanted from the previous block.
    • The Distribution module distributes the previous block’s fee rewards to validators and delegators
  4. For each valid transaction that will be included in this block, nodes perform the following:
    • They run an AnteHandler corresponding to the transaction type. This process:
      1. Performs basic transaction validation
      2. Verifies the fees provided are greater than the global and local minimum validator values and greater than the BaseFee calculated
      3. (For Ethereum transactions) Preemptively consumes gas for the EVM transaction
      4. Deducts the transaction fees from the user and transfers them to the fee_collector module
      5. Increments the TransientGasWanted in the current block, to be used to calculate the next block’s BaseFee
    • Then, for standard Cosmos Transactions, nodes:
      1. Execute the transaction and update the state
      2. Consume gas for the transaction
    • For Ethereum Transactions, nodes:
      1. Execute the transaction and update the state
      2. Calculate the gas used and compare it to the gas supplied, then refund a designated portion of the surplus
  5. Nodes run EndBlock for this block and store the block’s GasWanted

Detailed Mechanics

Cosmos Gas

In the Cosmos SDK, the consumption of gas is monitored and recorded in two distinct meters: the GasMeter and the BlockGasMeter.

The GasMeter is responsible for tracking the gas consumed during state transitions, and it is reset after every transaction execution.

On the other hand, the BlockGasMeter keeps track of the total gas consumption within a block and ensures that it does not exceed a predefined limit. This limit is defined in the Tendermint consensus parameters and can be modified through governance parameter change proposals.

It's worth noting that the gas cost of an interaction in the Cosmos SDK is proportional to the size of the parameters, unlike Ethereum's uint256 values, which have a fixed size. In Cosmos SDK, numerical values are represented using dynamically sized Big.Int types.

For further information about gas and its role in the Cosmos SDK, you can refer to the project's documentation here.

Matching EVM Gas consumption

Humans.ai is an EVM-compatible chain that supports Ethereum Web3 tooling. For this reason, gas consumption must be equivalent to other EVMs, most importantly Ethereum.

The main difference between EVM and Cosmos state transitions is that the EVM uses a gas table for each OPCODE, whereas Cosmos uses a GasConfig that charges gas for each CRUD operation by setting a flat and per-byte cost for accessing the database.

To match the gas consumed by the EVM, the gas consumption logic from the SDK is ignored, and instead, the gas consumed is calculated by subtracting the state transition leftover gas plus refund from the gas limit defined on the message.

To ignore the SDK gas consumption, we reset the transaction GasMeter count to 0 and manually set it to the gasUsed value computed by the EVM module at the end of the execution.

AnteHandler

The Cosmos SDK AnteHandler performs basic checks prior to transaction execution. These checks are usually signature verification, transaction field validation, transaction fees, etc.

Regarding gas consumption and fees, the AnteHandler checks that the user has enough balance to cover the tx cost (amount plus fees) as well as checking that the gas limit defined in the message is greater or equal than the computed intrinsic gas for the message.

Gas Refunds

In the EVM, the gas allocation can be defined before the execution. The entire gas amount is utilized at the start of the execution, during the AnteHandler phase, and any remaining gas is returned to the user if there is any left after the execution. The EVM can also specify a gas refund for the user, but it is restricted to a fraction of the used gas, depending on the fork/version being employed.

Zero-Fee Transactions

In Cosmos, the AnteHandler does not enforce a minimum gas price, as it relies on the local node/validator to check min-gas-prices. This means that validators can set different minimum fees, potentially allowing end users to submit 0 fee transactions if at least one validator accepts them.

In Humans.ai, this means that transactions with 0 fees are possible for non-EVM transaction types. EVM transactions cannot have 0 fees due to the inherent gas requirement. This is checked by the EVM's stateless validation function (ValidateBasic) and the custom AnteHandler defined by Humans.ai.

Gas Estimation

Ethereum offers a JSON-RPC endpoint called eth_estimateGas to assist users in setting an appropriate gas limit for their transactions.

In Humans.ai, a special query API called EstimateGas is utilized to perform a binary search for the optimal gas value. This is necessary because the gas required for a transaction may exceed the value returned by the EVM after applying the transaction. To find the minimum gas needed, the same transaction is applied repeatedly until the optimal value is discovered.

To prevent changes from being persisted in the state during the execution, a cache context is used throughout the process.

Developers can generate a precise estimate for Cosmos Txs using the transaction simulation provided by the Cosmos SDK.

Cross-Chain Gas and Fees

In the scenario where a user transfers tokens from Chain A to Humans.ai via IBC-transfer and wishes to execute a transaction on Humans.ai, but lacks the necessary Humans.ai tokens to cover fees, the Cosmos SDK's Tips feature comes into play. This feature enables the user to utilize a different token, in this case, tokens from Chain A, to cover fees.

To use a tip to pay for transaction fees, the user signs a transaction with a tip and zero fees and sends it to a fee relayer. The fee relayer then covers the fee in the native currency (Humans.ai in this case) and receives the tip as payment, acting as an intermediary exchange.

Dealing with gas and fees with the Humans.ai CLI

Users should take into account their options while broadcasting a transaction using the Humans.ai CLI client. When submitting a transaction to the network, you should take into account these three flags:

  • --fees: fees to pay along with transaction; eg: 10aheart. Defaults to the required fees.
  • --gas: the gas limit to set per-transaction; the default value is 200000.
  • --gas-prices: gas prices to determine the transaction fee (e.g. 10aheart).

All of them do not, however, have to be defined for every transaction. The appropriate pairings are:

  • --fees=auto: estimates fees and gas automatically (same behavior as --gas=auto). Throws an error if using any other fees-related flag (e.i, --gas-prices , --fees)
  • --gas=auto: same behavior as --fees=auto. Throws an error if using any other fees-related flag (e.i, --gas-prices , --fees)
  • --gas={int}: uses the specified gas amount and the required fees for the transaction
  • --fees={int}{denom}: uses the specified fees for the tx. Uses gas default value (200000) for the tx.
  • --fees={int}{denom} --gas={int}: uses specified gas and fees. Calculates gas-prices with the provided params
  • --gas-prices={int}{denom}: uses the provided gas price and the default gas amount (200000)
  • --gas-prices={int}{denom} --gas={int}: uses the gas specified on for the tx and calculates the fee with the corresponding parameters.

The user experience is more straightforward for new users who opt for the first two options, while the latter are geared towards more advanced users who desire greater control over the parameters.

The auto flag was introduced to automatically calculate the required gas and fees for executing a transaction, making it easier for new users or developers to perform transactions without having to specify exact gas and fees values.

However, there may be instances where the auto flag fails to accurately estimate the gas and fees due to network congestion. In such cases, a higher value for the --gas-adjustment flag can be used to overcome this issue. The default value for this flag is 1.2, and increasing it to a value such as 1.3 can help retry the transaction successfully.

It is not possible to combine the --gas-prices and --fees flags, as doing so will result in an error message stating that both fees and gas prices cannot be provided.

It's important to note that the above combinations may still fail if the provided fees or gas amount is insufficient. In such cases, the CLI will display an error message with a specific reason for the failure. For example, the message might indicate that the provided fees or gas amount is too low:

raw_log: 'out of gas in location: submit proposal; gasWanted: 200000, gasUsed: 263940.
Please retry with a gas (--gas flag) amount higher than gasUsed: out of gas'