Transaction fee
warning
Ideally this would not exist in a vacuum and instead benefit from a general explanation on Cardano transactions.
note
This file is hand-written and currently not checked for correctness. The domain is very small and hence this would make for a great testing ground for techniques to ensure consistent, but also approachable documentation.
This is a write-up of how transaction fees are calculated. In fact, the minimum transaction fee for transaction to be deemed valid by the Cardano ledger.
This document describes the situation as of
- Protocol version:
10 - Era:
Conway
See also:
- Formal ledger specification: Alonzo, Figure 4, minfee and Conway, chapter 4
- Haskell implementation: getConwayMinFeeTxUtxo and related functions
Inputs
- Transaction bytes, CBOR-encoded
- Resolved inputs (= unspent outputs), CBOR-encoded
- Protocol Parameters
minFeeConstantminFeeCoefficientminFeeReferenceScriptsprices.memoryprices.steps
warning
TODO: Include transaction CDDL to reference individual parts (e.g. transaction_output) TODO: Explain protocol parameters somewhere
Algorithm
At a high level, the fee is composed of
- a minimum constant,
- plus a cost per transaction byte,
- plus a cost per reference script byte,
- plus an execution cost per budgeted script redeemer.
Calculate the base fee by adding the minFeeConstant to (minFeeCoefficient * serialized transaction length in bytes). These numbers are all integers, so you shouldn’t end up with a fractional amount of lovelace.
warning
TODO: Explain resolving input and reference inputs
Next, calculate the untagged size of each scriptRef on each of the transaction inputs and reference inputs. Specifically, each scriptRef field is serialized as a cbor tag, an integer plutus version, and then the raw script bytes. We’re interested in the size of the raw script bytes only.
Next, calculate the reference script fee. First, sum up the length in bytes of each of script reference into scriptRefLengths. The minFeeReferenceScripts parameter consists of a base, a multiplier, and a range. (Note that in conway, the multiplier and the range are hard coded, rather than protocol parameters, but the intention is to change this at the next hardfork.)
To calculate the fee, starting from a baseFee of minFeeReferenceScripts.base and remaining bytes of sum(scriptRefLengths), until remaining bytes is zero, add baseFee * min(remainingBytes, minFeeReferenceScripts.range), scale baseFee by minFeeReferenceScripts.multiplier, and decrease remainingBytes by min(remainingBytes, minFeeReferenceScripts.range). This calculation can result in rational values (as the multiplier can be rational), and so you should take the ceiling as a last step.
Finally, to calculate the evaluation fee, for each redeemer, multiply the redeemer execution units budget (memory and steps) by the corresponding protocol parameters (prices.memory and prices.steps), and add them up. These are fractional parameters, so you may end with a fractional amount of lovelace, and you should take the ceiling.
The final minimum fee is the base fee, plus the reference script fee, plus the evaluation fee.
Example
Lets do a decently complex worked example, from mainnet transaction with id (body hash)
f06e17af7b0085b44bcc13f76008202c69865795841c692875810bc92948d609
The transaction bytes are:
84ac00838258209ea0d817dc67ce8046f6c2abc27267905c74374530c4684bb3c252ed6b97cc8702825820e3195e7888a83f3d1ef218e50675bfa10d9817a4a756b8ba26305f604c0f96e500825820285c77a9e62c0f87fedfcc91a630251ce2b7fcb9dd8d2fd8591c0d0aba46d4bc000183a300583911e0302560ced2fdcbfcb2602697df970cd0d6a38f94b32703f51c312bbc10fe312acd69e2e12cbc2cca05aa0e432e3dee65d5a9498344e4aa01821b00000082deef6e00a2581c5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114a1434941471b0000016f8a787b24581ce0302560ced2fdcbfcb2602697df970cd0d6a38f94b32703f51c312ba15820000de1406f79e3e55eef82b9d03cf62cc3d4a6d0d03b00bf7b1b43330f82977901028201d8185862d8799f581c6f79e3e55eef82b9d03cf62cc3d4a6d0d03b00bf7b1b43330f8297799f9f4040ff9f581c5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d11443494147ffff1b000000c823a3f15c18641864d87a80001a73c3be00ff8258390123a9f67af7e7e6d1aa0b495f68787649bb6f097d6648c2fa59c185e400168e1b0b38fe76f31427ee638adba1b7ad61ab8274ff4ecaa4109e821a001e8480a1581c5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114a1434941471afad8cc9182581d618ca0e08cdbc30fa0dd21833d7370d666493ecc28b136df179f97fb5d1a6079b955021a00092e4d031a08e498d705a1581df199e5aacf401fed0eb0e2993d72d423947f42342e8f848353d03efe6100081a08e491070b5820b159feadc14235013a7ac8e993b410e5cdbd69c5829cd06b463603f15a39e6660d818258209ea0d817dc67ce8046f6c2abc27267905c74374530c4684bb3c252ed6b97cc87020e81581c8ca0e08cdbc30fa0dd21833d7370d666493ecc28b136df179f97fb5d1082581d618ca0e08cdbc30fa0dd21833d7370d666493ecc28b136df179f97fb5d1a60369c62111a004c4b401283825820fa46a1d162c59cece3308c5a9d4db9ff2ea17f9c0146ff821c9b445588b017c900825820f5f1bdfad3eb4d67d2fc36f36f47fc2938cf6f001689184ab320735a28642cf2008258200258ec397cbd4a86951126bd2c423d62f71ec844430964cd0e14df2f951906a400a3008182582043be65bfb94286317d1274ff4c1d4890ddc524d04d1182c4c714e97e1985954858401a5d1672aed8d170f343c2d517d8475f3569df6e1db0741091a2fcc3aae92a520b9496e91a005544b8d1ae938525666ba732f8a88945fb8ba859f91b2636ee0706815901455901420100003323232323232322322253330053253330063370e900218039baa300130083754004264a66600e66e1d2000300837540022646600200264a66601266e1d2002300a3754002297adef6c6013756601c60166ea8004c8cc004004dd5980218059baa300e300b375400644a66601a0022980103d87a80001323232533300d3371e0166eb8c03800c4cdd2a4000660226e980052f5c026600a00a0046eacc038008c044008c03c004894ccc030004528099299980519b873371c6eb8c02cc03c00920024806852889980180180098078008b1929998050008a6103d87a800013374a9000198059806000a5eb80dd618059806180618041baa300b3008375400429408c02cc03000452613656375c002ae6955ceaab9e5573eae815d0aba24c011e581ce0302560ced2fdcbfcb2602697df970cd0d6a38f94b32703f51c312b00010583840000d87a9fd8799f000d9f9f02d87a8000ffffffff821a001024a21a13fcfa0f840002d8798082196ec71a007e3127840300d8798082199f5f1a00bc09d0f5f6
This is 1358 bytes and you can inspect it using https://cbor.nemo157.com/
Among the inputs and reference inputs, there are 2 inputs which, when resolved, contain reference scripts:
- reference input
f5f1bdfad3eb4d67d2fc36f36f47fc2938cf6f001689184ab320735a28642cf2#0with2469bytes - reference input
fa46a1d162c59cece3308c5a9d4db9ff2ea17f9c0146ff821c9b445588b017c9#0with15728bytes
And there are three redeemers:
- Spend#0 with a budget of
1057954memory units, and335346191steps - Spend#2 with a budget of
28359memory units, and8270119steps - Withdraw#0 with a budget of
40799memory units, and12323280steps
The protocol parameters at the time were:
minFeeConstant:155381lovelaceminFeeCoefficient:44lovelace per byteminFeeReferenceScripts:base:15lovelacemultiplier:1.2size increment:25600bytes
prices.memory:0.0577lovelace per memory unitprices.steps:0.0000721lovelace per step
Thus:
- The base fee is
155381 + 44 * 1358 = 215133lovelace. - The total reference scripts length is
2469 + 15728 = 18197and fall under the 25,600 byte increment, so it costs15lovelace per byte:15 * min(18197, 25600) = 15 * 18197 = 272955lovelace - And the execution costs are
ceil(1057954 * 0.0577 + 335346191 * 0.0000721 + 28359 * 0.0577 + 8270119 * 0.0000721 + 40799 * 0.0577 + 12323280 * 0.0000721) = ceil(90697.606839) = 90698lovelace.
Thus, the total minimum fee is 578786 lovelace.
Note that historically calculating this has been pretty opaque, and so many people have resorted to slightly padding the minimum fee, and I believe this is why the on-chain minimum fee (which is declared in the transaction body) is 601677 lovelace.