DocsLibraryTransaction Fees

Transaction Fees

Transaction Fees in protokit are implementable using protocol hooks.

Protokit’s library offers a default implementation for adding transaction fees to your appchain.

Concept

The implementation currently supports one tokenId in which fees will be deducted. If a user doesn’t have enough of that token to pay for a given runtime execution, the transaction will either not be included or will fail upon execution, depending on the circumstances.

How much fee a given runtime method costs is dependent on the complexity (circuit size) of that runtime method, but can be overridden by the user.

Fee calculation

If not overridden, the transaction hook will automatically analyse all runtime methods to determine their row count (how big the logic is and therefore how log it takes to prove). This value is called the weight of the method.

In addition to that, the user has to specify a basefee and perWeightUnitFee. With that, the formula to determine the fee amount is:

feeamount=basefee+perWeightUnitFeeweightfeeamount = basefee + perWeightUnitFee * weight

Setup

The TransactionFeeHook depends on a Balances runtime module to be registered under the name Balances

Add to the mandatory protocol modules:

Protocol.from(VanillaProtocolModules.mandatoryModules({
  TransactionFee: TransactionFeeHook
}))

or, it is already included in the default modules:

Protocol.from(VanillaProtocolModules.with({}))

Configuration

The TransactionFee module has a set of configuration values that can be used to configure fee accounting.

  • tokenId: The protokit TokenId that fees should be deducted in
  • feeRecipient: PublicKey to the account that fees are sent to
  • baseFee: The base fee amount, charged independently of the complexity of the invoked runtime method
  • perWeightUnitFee: Fee per weight unit - weight unit is defined as being directly proportional to the runtime method’s number of rows (Fee calculation)
  • method: Allows overriding of baseFee, weight and perWeightUnitFee
  // ...
  Protocol: {
    // ...
    TransactionFee: {
      tokenId: 0n,
      feeRecipient: feeRecipientPublicKey.toBase58(),
      baseFee: 10000n,
      perWeightUnitFee: 1n,
      methods: {
        // Drip in this case is overridden to be free (0 + 0 * 0)
        "Faucet.drip": {
          baseFee: 0n,
          weight: 0n,
          perWeightUnitFee: 0n,
        },
      },
    },
  },