thanks for the WFC
I’ve added a small comment here about how the deployed issuance curve works today (plus a couple of extra ancillary implementation tasks that should be part of an eventual implementation of #1939 )
The WFC referendum never states that it’s real-time; rather, the issuance formula causes the burned amount to be re-minted. This obviously occurs on Pi Day, according to the formula:
per_era_payout = 0.1314 * (cap - issue_at_step) / eras_per_year
It’s not possible to perform what you’re suggesting—burning at the protocol level—without this effect occurring.
The curve is re-evaluated at each step, you are right about that. But the re-evaluation does not read the chain’s live total issuance. When the hard cap started, the curve was pinned to a snapshot of total issuance taken at that moment (March 14th, 2026), from then on it’s a function of time only (and not of live total issuance). So in your example cap - issue_at_step is measured against the curve’s own value and not against TotalIssuance. And since nothing in the emission path is reading the total issuance, with current code burning 100M DOT wouldn’t change what we are going to emit in the next step so there would be no automatic re-mint. Note how total issuance is ignored here and how runtime calls the issue() method here.
We can discuss if this is aligned or not with the intention of #1710 - it probably didn’t matter post #1710 + DAP and before ref #1926 (where all burns were meant to be redirected to DAP buffer), but now this matters in a world where we are allowing to burn again.
Again, this doesn’t hurt the proposal in #1939 at all and doesn’t make the introduction of the burn account less valid.
That doesn’t make sense to me. The curve Dom presented to the community is asymptotic to the hard cap and continues indefinitely; it isn’t a finite series of emissions based on a fixed snapshot.
The formula I gave you is the one Dom presented to the community and the one that was supposed to be implemented. So are you saying that the implementation differs from that formula, with issue_at_step effectively being based on a fixed March 14th snapshot rather than the actual issuance value at each step?
If so, that is a very significant discrepancy between the formula presented to the community and what was actually implemented. This is very serious.
Moreover, there is already a video from back then in which Gav discusses burning from the treasury and explicitly acknowledges the re-minting effect.
Dom is also the one who implemented it here
The current implementation is asymptotic to 2.1B and continues indefinitely - exactly as Dom presented . The PR that implemented 1710 describes it in exactly those terms:“a general stepped curve, asymptotic to some defined amount by moving a percentage closer to that amount per step”. Being anchored on a starting value and being asymptotic are not alternatives, it is both in the implemented version.
In a world with no burns, the two formulas are arithmetically equivalent. The anchor is total issuance as of March 14 2026, and over each step the schedule mints exactly the step size, so live total issuance at every step boundary equals the curve’s own value. 0.1314 × (cap − issue_at_step) returns the same number either way.
They diverge if something reduces total issuance outside the schedule - and until now with the introduction of DAP, on AH fees, slashes, XCM fees etc goes to the DAP + treasury burn is disabled . #1926 changes the equation re-introducing real burns and that’s why I raised the point.
I would not frame it as the implementation contradicting what was presented. But now we need to answer what to do if we reintroduce real burn. There are two approaches at least:
- the curve keeps its anchor and we end below 2.1B by whatever is burned
or - it is re-anchored on live issuance and burns are gradually re-minted then
It would be great if you can share Gav’s video too. Was before the DAP model (where so far burn are redirected to DAP buffer so they do not touch total issuance)?
In my opinion, the 2.1B DOT hard cap only defines the maximum amount that can be issued under the issuance model.
If the code is indeed as you describe, then you are right that a protocol-level burn could be implemented.
Alternatively, we can use the burn account. I think this burn account is necessary because it allows anyone to permanently burn DOT, and also other tokens or assets.
I believe we can use the burn account both if we keep issuance curve as it is today (and then the extra runtime API to return cap, live total issuance, inactive issuance, the permanently frozen balance in the burn account I was mentioning in the WFC’s comment becomes very handy) or if we re-anchor on live issuance. If we actually do the latter, then burning account is probably the only sane way to go.
And it’s probably good to settle also on what the expected behavior of the issuance curve is and align the implementation accordingly.
Yes, but I think there is an important distinction here.
My proposal does not require changing the current issuance curve or re-anchoring it to live TotalIssuance.
There are simply two ways to reintroduce burning:
- Restore protocol-level burning, which would reduce TotalIssuance while leaving the current issuance mechanism unchanged.
- Use a permanent burn account, which would make the tokens permanently inaccessible without reducing TotalIssuance.
Agree and I think there is another important bit to clarify.
Today, an explicit extrinsic Balances::burn is not redirected to DAP buffer, so today it already reduces TotalIssuance and because the emission curve never reads total issuance there is no re-mint. Since every other sink on the chain (dust, slashes, fees, …) is routed to the DAP, nothing else moves total issuance either. So a burn that permanently reduces issuance, leaves the schedule untouched and is never minted back is available right now with no code changes. Issuance simply ends up at 2.1B minus whatever is burned.
Before the current discussion in #1926 and #1939, I would have imagined that Balances::burn would have been eventually made configurable to route to DAP (for Polkadot) or to actually burn (for other chain like Kusama), but if now the intention is to actually allow voluntary burns reducing total issuance without re-minting , we are already good with no further changes in code (again, assuming that we are fine with emission curve ignoring live issuance).
#1926 asks for the JAKMB revenue to be burned “automatically and at protocol level, with no discretionary step in between”, and one way to get that is one line at the revenue hook of whatever pallet sells JAMKB, dropping the credit rather than depositing it to a given account. There is no need to introduce a burn account to achieve that (Kusama runtime configures slashes, dust, fees, etc to do exactly this - we can do exactly the same on Polkadot for the specific JAMKB case leaving the rest routed to DAP) . This is not a new pattern in the code and doesn’t require any new account to be involved.
So to summarize, assuming we are fine with the current emission curve and the current semantics of Balances::burn, the following would work without the need of a burn account:
- JAMKB revenue: we burn at revenue hook once we implement that. Will be automatic, no discretionary step, will reduce total issuance.
- Voluntary burns: keep using `Balances::burn`, total issuance decreased, no re-minting because of how issuance curve works
To improve UX / explorers / everyone’s life, it would be beneficial to expose a TotalBurned counter or equivalent, together with live issuance, hard cap etc.
Again, this is an alternative to what #1939 suggests if we want to consider that. A burn account where we send automatically JAMKB revenues and where voluntary burns end also achieves the same. Total issuance would be unchanged, so again to improve UX, we could expose via a single runtime API all info needed at once (live issuance, total burn freezed in the burn account, cap, etc) so e.g. an explorer doesn’t have fetch info in multiple places or hard-code anything.
Considering the above (so that we have two options to achieve both JAMKB revenues permanently burned + voluntary burns), I see it most as an implementation detail.
Also the voluntary burn is in place today already with no code changes. And we are not so close to implement JAMKB revenue mechanism to have to settle on a strategy or another today.
My 2c: I am keen to set on the stone the community consensus around burn + we need to track and expose how much we burn, but I would let to the implementer(s) to choose the most convenient solution for JAMKB when time comes, without needing to enforce #1939.
I think there is one important advantage that the burn account provides that is difficult to achieve otherwise: simplicity.
A user could simply send DOT to a well-known, canonical burn address, just like sending tokens to any other address.
This means that even an investor who knows very little about Polkadot could permanently burn DOT without needing to understand Balances::burn, use a specific extrinsic or app, or even leave their exchange.
If the community prefers a canonical burn account, its existence doesn’t need to be justified by technical necessity alone. It can be justified by simplicity, accessibility and standardization.
Agree on the simplicity / accessibility bit for voluntary burns