Fees on Namada

Fees on Namada

In order to settle the market for Namada blockspace demand, fees are coupled with transactions. In order for any namada transaction to be considered valid, the correct corresponding fee must be paid. The exact fee is set by the user, and must be greater than or equal to the minimum gas-price set by governance, which is included in the genesis file under gas_cost.

How fees are paid

Fees are always paid from the balance of an implicit address. When explicitly stated, the gas fee is paid by the --gas-payer flag. If no --gas-payer flag is specified, the gas fee is paid by the first key in the --signing-keys flag, if those are specified. If no --signing-keys flag is specified, the client will try to infer the signer from the source of the transaction and use that account as the fee payer.

First consider the example of a simple transfer:

namadac transparent-transfer \
  --source my-acc \
  --target validator-1 \
  --token NAM \
  --amount 10 \

With no --gas-payer or --signing-keys explicitly provided, the client will infer the proper account related to my-acc from which to take the fees. If my-acc is an implicit address, the fees will be taken directly from it. If it is an established address, the fees will be taken from the implicit address associated with my-acc (usually the account used to initialize the established address).

However, another gas payer can be specified in this transaction by providing another implicit address for which the user owns the private key:

namadac transparent-transfer \
  --source my-acc \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --gas-payer my-other-acc

Now consider the example of a transfer from a 2-of-n multisignature account:

namadac transparent-transfer \
  --source my-multisig \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --signing-keys key1,key2

In this case, the fees will be taken from the first key provided to --signing-keys: key1. As before, any gas payer can be specified by supplying the desired key to the --gas-payer argument like such:

namadac transparent-transfer \
  --source my-multisig \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --signing-keys key1,key2 \
  --gas-payer key2

For testnet purposes, we recommend using the faucet to source NAM for transaction fees.

How fees are calculated

The fee for a transaction is calculated by multiplying gas-limit by the gas price. Both the --gas-limit and the --gas-price can be specified by the user. If neither is specified, the default gas limit and minimum gas price is used. The default gas limit for any transaction is currently set to 200_000.

The minimum gas price is set in the genesis file under minimum_gas_price. One can query the minimum gas prices for all tokens accepted for gas payment in a network with:

namadac query-protocol-parameters

How to set the gas price and gas limit

It is recommended to set the gas-limit based on the transaction being conducted. In order to estimate the gas-limit for a particular transaction, the --dry-run-wrapper argument should be provided. This means that the transaction is simulated, but not yet sent to the ledger.

For example, the following command will simulate a transfer transaction, and return the gas used:

namadac transfer \
  --source my-acc \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --signing-keys key1 \
  --dry-run-wrapper

Which will output something along the lines of

Dry-run result: Transaction consumed 147850 gas. Inner transaction <tx-hash> was successfully applied.

This means that we could reasonably make this transfer transaction with a gas-limit of 150000.

Hence, when making the transfer, we could specify the gas-limit as follows:

namadac transfer \
  --source my-acc \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --signing-keys key1 \
  --gas-limit 150000

If for some reason, we wanted to pay a higher gas fee, we could also specify that as follows:

namadac transfer \
  --source my-acc \
  --target validator-1 \
  --token NAM \
  --amount 10 \
  --signing-keys key1 \
  --gas-limit 150000 \
  --gas-price 0.01

This might incentivise validators to prioritise this transaction above those with a lower gas price.

Paying fees with tokens in the MASP

It is also possible to pay for fees using the MASP when dealing with a transfer transaction involving shielded inputs (shielding, shielded, and unshielding transfers both natively and with IBC). The purpose of this is to ensure that a user can make transactions on-chain even if they may not have NAM in their transparent balance. This is yet another incentive for users to keep the maximum amount of assets in the MASP. On top of this, paying fees via the MASP is required to prevent information leakage that could defy the purpose of the shielded pool.

When dealing with MASP fee payment, the client will try to deduct the fees from the source of the shielded transaction and unshield them to the transparent balance of the --gas-payer (or the address corresponding to the first key in the --signing-keys) before being paid to the block proposer. If the shielded account does not have enough funds to cover the gas cost, the user must specify the --gas-spending-key flag and set it the alias of another spending key in your wallet. The client will try to combine the residual balances of the original sender and this extra key to cover the entirety of the fees.

For example, if the user has a spending key spending-key-1 in their wallet, and they want to pay for the fees of a shielded transfer transaction using the MASP, they would run the following command:

namadac transfer \
  --source spending-key-1 \
  --target payment-addr-b \
  --token OSMO \
  --amount 10 \
  --gas-payer my-implicit \

If spending-key-1 cannot cover for the entire cost, the user can specify an additional spending key for fee payment:

namadac transfer \
  --source spending-key-1 \
  --target payment-addr-b \
  --token OSMO \
  --amount 10 \
  --gas-payer my-implicit \
  --gas-spending-key spending-key-2

In these examples, my-implicit may only have an OSMO balance in their transparent balance, but spending-key-1 (and possibly spending-key-2) may have a positive NAM balance in their shielded balance. In this case, the NAM will be unshielded to the transparent balance of my-implicit and then used to pay for the transaction fee. So it is requried to unshield just the difference between the gas cost and the transparent balance of the gas payer implicit address.

It is also possible to use MASP fee payment to pay fees for non-MASP transactions. To do so, the user should create a transaction batch where the first transaction is a MASP transaction that unshields the funds for fee payment to the fee payer's address. The actual intended transaction can then be attached as the second transaction of the batch.

Using a disposable gas payer

It is also possible to use a disposable gas payer to pay for transaction fees. This is useful (and recommended) in cases where the user does not want to leak information and reveal the identity of the --gas-payer to prevent correlation. In order to use a disposable gas payer, the user must include the --disposable-gas-payer flag. The fees will be deducted from the shielded balance of the shielded transactions source (and optionally from the balance of the --gas-spending-key when provided) and unshielded to the transparent balance of an ephemeral transparent address before being paid by the ephemeral address.

For example, if the user has the same two spending keys from the previous example in their wallet, and they want to pay for the fees of an unshield transfer transaction using a disposable address, they would run the following command:

namadac unshield \
  --source spending-key-1 \
  --target addr-b \
  --token OSMO \
  --amount 10 \
  --gas-spending-key spending-key-2 \
  --disposable-gas-payer