How Fees Work in Babylon
An early version of the Babylon network fees & developer royalty collection mechanism will be released with Scrypto v0.5 this month. This is something that has been asked about a great deal by developers, node runners, and the larger community; this article will lay out the basics of the system and then get down to some details relevant for developers. Everything that follows in this post describes plans for the upcoming Babylon release, and is not related to how fees are calculated in the current Olympia mainnet.
Fees are the XRD required to be paid to run a transaction. Fees reflect the burden each transaction puts on the network, most notably in the areas of how work-intensive it is to compute the result, and how much permanent storage it requires. On the Radix Public Network, fees are also where royalties are accounted for. Royalties are set by developers who deploy code or run applications on the network, and allow them to collect a “use fee” every time their work gets used in a transaction.
The total fee is the sum of the costs the network assesses for running the transaction, plus the sum of any royalties specified in the various components the transaction makes use of, either directly or indirectly. In times when demand exceeds network capacity, users may specify an optional “tip” percentage which amplifies the network portion of the fee (royalty payments are unaffected); this extra amount is directly awarded to the validator leading the consensus round.
Unlike other networks, it is quite straightforward on Radix for a transaction’s fees to be paid for by someone other than the signer(s), or to have the fee payments split up among multiple parties. More details on how that works a bit further down the page.
As with Olympia, the goal is that network fees should remain relatively stable in terms of USD cost. This is achieved by having a fee table, which describes the CostUnits associated with a given operation, and a fiat value multiplier, which is used to compute a cost in XRD for a given amount of CostUnits.
For each section of code to be run, the system determines a price for that section, taking the following steps:
- Apply the fee table to each operation in the section, and sum up the total CostUnits required to run it.
- Multiply by the fiat value multiplier to compute the base network XRD cost.
- Multiply by the user’s tip multiplier, if one was specified.
- Add any royalties incurred.
This gives the total XRD cost to run a section of code. If the transaction’s fee reserve (to be described next!) has sufficient balance to pay this, this cost is deducted from the reserve and the transaction continues execution. If not, the transaction fails at this point, and any already-spent fees are forfeited.
Changes in the market price of XRD can be addressed by updating the fiat value multiplier. Changes for the price of a particular operation are accomplished with a fee table update. In either case, these are then adopted via a coordinated protocol update.
Fees can be paid from any vault containing XRD. Remember that, on Radix, tokens (including XRD) aren’t directly “held” by a keypair - they’re always stored in vaults owned by components. In order to identify where a fee is being paid from, the transaction needs to call some component which will lock some XRD with which to pay the fee, establishing the fee reserve to begin paying from. Most commonly, this will be an Account component under the signer’s control, but it’s easy to imagine other models.
For example, someone might run a subscription service which allows users to set up a credit card with which to pay their fees. The service issues a non-fungible badge to each of its users, and subscribers pass their unique badge to the service’s on-ledger component each time they wish it to pay their fee. At the end of the month, the service charges the user’s credit card based on how much XRD it paid on their behalf. Or, more simply, say you run an exchange application which makes a profit on each trade. You might automatically lock a fee payment for a certain percentage of that profit, allowing users with sufficiently large trades to have their entire fee covered by the application. Or imagine a game which uses tokens of its own creation for the in-game economy, and has players submit transactions for certain actions, but doesn’t want its players to worry about acquiring XRD in order to pay for those transactions. The game could run a service which automatically pays the fees on behalf of its players, and recoups that cost elsewhere.
It isn’t necessary to pay the entire fee from a single source…additional XRD may be locked for fee payment throughout the course of the transaction. This allows for a model where profit-generating applications can “chip in” for some amount of the fee without necessarily having to cover the entire cost.
At this point you may be wondering how your transaction pays the cost of the operations which lead up to that first locking of a fee. The answer is that the network automatically grants a small loan to all transactions, establishing a fixed amount of CostUnits which can be consumed before the fee reserve is initially established, at which point the loan must be fully repaid in order for execution to continue. If the transaction exceeds the loan amount without locking a sufficient amount to proceed, then the transaction is simply rejected and no record of it is kept.
Transactions which successfully repay their loan, but then fail to complete (either due to a logical abort or running out of fee reserve during execution) are marked as failed. Failed transactions still spend whatever fees (and royalties, if any) were consumed up until the point they failed. If a transaction completes successfully without spending all its fee reserve, the unspent amount is returned to the vault it was locked from.
What happens to spent fees?
50% of the base network fee is burnt. Of the remaining 50%, 25% of that goes directly to the validator who lead the round, and 75% gets added to a pool which is split among the validator set at the end of each epoch according to their participation and subject to penalties for missed proposals, similar to how network emissions work. All of these numbers reflect current planning, and are not yet finalized.
Any tip fees are immediately paid to the validator who led the round.
Any royalties paid to a component are placed in a system-generated vault owned by that component. The component’s instantiator may claim them using a badge automatically created at instantiation time.
Any royalties paid to a blueprint creator are placed in a system-generated vault owned by the package containing the blueprint. The developer who deployed the package may claim them using a badge automatically created at deployment time.
Q&A Lightning Round
How do I calculate the fee for a transaction I want to run?
More information about this will be released before Betanet.
So I can do something in my transaction to get XRD, deposit it somewhere I control, and use it to pay the fee?
Good idea, but no. XRD locked for the purpose of paying fees has to be already present in the vault at the very start of the transaction. This prevents an assortment of nefarious activities.
Can’t trolls just submit a bunch of transactions which intentionally use up the entire loan and get rejected, thereby wasting network time for free?
Part of validation upon submission to a Gateway includes ensuring that the transaction is able to repay its loan. As much as possible, the intent is to keep the burden of this “sanity check” to nodes not participating in the validator set. Strategies for handling malicious nodes which try to force bad transactions into the mempool are beyond the scope of this article.
Wait a minute, if I run a component which locks a fee based on an expected profit, what if the user’s transaction spends the fee but then aborts? The transaction rolls back and I won’t get my profit, but I’ll have spent the fee!
There’s some nuance that isn’t covered above in the locking of fees. It’s possible for a component to specify at locking time that the fee is only to be paid if the transaction succeeds. In other words, the transaction’s normal fee reserve must cover execution up to completion, at which point the system will first “backpay” from this other class of locked XRD (which could be sufficient to cover the entire transaction’s cost).
Can I pay fees in something other than XRD?
No, fees are always paid in XRD.
How is this “tip multiplier” different from a “gas price?”
The network has a hard base fee, which users can quickly revert to once periods of oversaturation end. Combined with the very fast round time of the Radix Network, wallet software will have the necessary tools to avoid the “unnecessarily slow to correct” problems commonly seen with the gas price mechanism on Ethereum.
You said cost is calculated “per section” when executing. What constitutes a section?
A section is a block of code which is guaranteed to execute together, within a single stack frame. A conditional statement, a method or functional call, a return statement…all of these will mark the end of a section.
This system doesn’t prevent front-running!
Correct. This is a complicated problem, and after extensive research and debate the decision was made that this isn’t something that will be tackled at Babylon launch. However, do bear in mind that the novel transaction model Radix uses allows for the trivial addition of “guardrails” to any transaction, in order to easily prevent undesired outcomes like sandwich trades.
How do you calculate what values go in the fee table?
Very painfully, with a lot of benchmarking. At the release of Scrypto v0.5, the initial table will be generated by throwing darts at a wall, and will in no way resemble the values which ultimately ship with Babylon. There will be some basic tuning with more realistic numbers done by Betanet.
I want to split up royalties for my component/blueprint based on some system of my own devising. Is this possible?
Sure. You’ll have to code up something which can hold the claim badge and divvy out the proceeds accordingly, and have that component actually claim the royalties. If this turns out to be a popular pattern, someone will code up blueprints that employ common sharing mechanisms, and you’ll be able to just use those off-the-shelf instead.
But what about at Xi’an, how does the fee model account for <something>?
While there has been quite a bit of thinking on what comes next, there is much to learn from Babylon network operation before a fee model for Xi’an can be fleshed out and committed to.