Runtime Fees

Runtime fees are measured in Gas. Gas price will be discussed separately.

When a transaction is converted into a receipt, the signer account is charged for the full cost of the transaction. This cost consists of extra attached gas, attached deposits and the transaction fee.

The total transaction fee is the sum of the following:

  • A fee for creation of the receipt
  • A fee for every action

Every Fee consists of 3 values measured in gas:

  • send_sir and send_not_sir - the gas burned when the action is being created to be sent to a receiver.
    • send_sir is used when current_account_id == receiver_id (current_account_id is a signer_id for a signed transaction).
    • send_not_sir is used when current_account_id != receiver_id
  • execution - the gas burned when the action is being executed on the receiver's account.

Burning gas is different from charging gas:

  • Burnt gas is not refunded.
  • Charged gas can potentially be refunded in case the execution stopped earlier and the remaining actions are not going to be executed. So the charged gas for the remaining actions can be refunded.

Receipt creation cost

There are 2 types of receipts:

A transaction is converted into an ActionReceipt. Data receipts are used for data dependencies and will be discussed separately.

The Fee for an action receipt creation is described in the config action_receipt_creation_config.

Example: when a signed transaction is being converted into a receipt, the gas for action_receipt_creation_config.send is being burned immediately, while the gas for action_receipt_creation_config.execution is only charged, but not burned. It'll be burned when the newly created receipt is executed on the receiver's account.

Fees for actions

Every Action has a corresponding Fee(s) described in the config action_creation_config. Similar to a receipt creation costs, the send gas is burned when an action is added to a receipt to be sent, and the execution gas is only charged, but not burned.

Fees are either a base fee or a fee per byte of some data within the action.

Here is the list of actions and their corresponding fees:

Example

Let's say we have the following transaction:


#![allow(unused)]
fn main() {
Transaction {
    signer_id: "alice.near",
    public_key: "2onVGYTFwyaGetWckywk92ngBiZeNpBeEjuzSznEdhRE",
    nonce: 23,
    receiver_id: "lockup.alice.near",
    block_hash: "3CwEMonK6MmKgjKePiFYgydbAvxhhqCPHKuDMnUcGGTK",
    actions: [
        Action::CreateAccount(CreateAccountAction {}),
        Action::Transfer(TransferAction {
            deposit: 100000000000000000000000000,
        }),
        Action::DeployContract(DeployContractAction {
            code: vec![/*<...128000 bytes...>*/],
        }),
        Action::FunctionCall(FunctionCallAction {
            method_name: "new",
            args: b"{\"owner_id\": \"alice.near\"}".to_vec(),
            gas: 25000000000000,
            deposit: 0,
        }),
    ],
}
}

It has signer_id != receiver_id so it will use send_not_sir for send fees.

It contains 4 actions with 2 actions that requires to compute number of bytes. We assume code in DeployContractAction contains 128000 bytes. And FunctionCallAction has method_name with length of 3 and args length of 26, so total of 29.

First let's compute the the amount that will be burned immediately for sending a receipt.

burnt_gas = \
    config.action_receipt_creation_config.send_not_sir + \
    config.action_creation_config.create_account_cost.send_not_sir + \
    config.action_creation_config.transfer_cost.send_not_sir + \
    config.action_creation_config.deploy_contract_cost.send_not_sir + \
    128000 * config.action_creation_config.deploy_contract_cost_per_byte.send_not_sir + \
    config.action_creation_config.function_call_cost.send_not_sir + \
    29 * config.action_creation_config.function_call_cost_per_byte.send_not_sir

Now, by using burnt_gas, we can calculate the total transaction fee

total_transaction_fee = burnt_gas + \
    config.action_receipt_creation_config.execution + \
    config.action_creation_config.create_account_cost.execution + \
    config.action_creation_config.transfer_cost.execution + \
    config.action_creation_config.deploy_contract_cost.execution + \
    128000 * config.action_creation_config.deploy_contract_cost_per_byte.execution + \
    config.action_creation_config.function_call_cost.execution + \
    29 * config.action_creation_config.function_call_cost_per_byte.execution

This total_transaction_fee is the amount of gas required to create a new receipt from the transaction.

NOTE: There are extra amounts required to prepay for deposit in TransferAction and gas in FunctionCallAction, but this is not part of the total transaction fee.