Skip to content

CIP-0173? | Net Change Limit Parameter#1129

Open
Cerkoryn wants to merge 10 commits intocardano-foundation:masterfrom
Cerkoryn:ncl-parameter
Open

CIP-0173? | Net Change Limit Parameter#1129
Cerkoryn wants to merge 10 commits intocardano-foundation:masterfrom
Cerkoryn:ncl-parameter

Conversation

@Cerkoryn
Copy link
Copy Markdown
Contributor

@Cerkoryn Cerkoryn commented Jan 9, 2026

I think that this is an incredibly intuitive but much needed CIP that will substantially improve governance fatigue.

It is quite short and simple, but I am happy to take feedback and iterate on it until it satisfies community expectations.

(rendered)

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Jan 9, 2026

@Cerkoryn the result of our last open debate on similar subjects is that the CIP process cannot be used to mandate characteristics of budget processes or other strictly human (non-technical) organisational processes:

At this time we are only awaiting workload constraints — ongoing with CIP editors for a few months now — before drafting a proper Governance category CIP: so this category term can then be applied to technical procedures in the governance process. (Personally I have been waiting for some environmental factors, still pending resolution "after the holidays", before I have the time to prepare & submit a draft for this with other CIP editors).

Until a Governance CIP with such eligibility criteria is agreed upon by editors, reviewers & critics, and widely understood by governance actors, we can't begin reviewing any CIP like this. I would be happy recognising it as a Draft while that CIP is in the works: which is currently what we've had to do with all other CIP repo submissions which are ultimately about budget and human factors:

Then we can start admitting any eligible Governance proposals once we have a framework to impartially establish that they are technical and not just creating more territory for the governance "dumpster fire" to spread into... or worse, creating opportunities for agents influential in the CIP process to to influence budget processes without the usual due process of voting.

@Cerkoryn I do think you may have found an acceptable technical governance process with this parameter, but the number of human factors listed in Path to Active to even consider such a parameter is daunting: and has "human", "organisation", and "money" written between every one of those lines.

Unless you can already make an indisputable case that your proposal and its implementation are about technical procedure and nothing else, you could mark this as a Draft until that can be established... or until we have at least an acceptable draft of a Governance CIP indicating broad support for such parameter additions & their feasibility.

I would not be alone in trusting your own good will & experience in this matter but — as you will see when reading the arguments presented in #937 — we would not want to reduce the entire community's "governance fatigue" by pushing that fatigue into the CIP process and its dramatically limited resources & personnel: let alone the opportunities for undue influence and vested interest that this could create.

- The new parameters provide a standing, updatable definition of the net change limit for that review.

## Rationale: how does this CIP achieve its goals?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do feel that this problem could be probably be sufficiently solved via tooling

I'm not sure the benefits of asking node's to calculate this, over tooling

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this could be solved with tooling relatively easily. This CIP doesn't ask the node to calculate anything, just hold the parameter values.

- `netChangeLimit`: **positive integer percentage** (e.g., 20 means 20%). May be greater than 100.
- `netChangePeriod`: **positive integer** number of epochs used as the revenue lookback window (default **73** epochs, ~1 year).

These parameters are classified as **governance parameters** and are updatable via the standard protocol parameter change governance action. This CIP **recommends** a default value for `netChangePeriod` of **73 epochs** (approximately one year) to align with the Constitution's expected budget cadence; governance may adjust it as needed. The value of `netChangeLimit` is intentionally left to governance and will be selected through the implementation plan. The parameters do not introduce any new ledger enforcement rules for treasury withdrawals or budgets; instead, they are used by the Constitutional Committee to assess constitutionality.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameters do not introduce any new ledger enforcement rules for treasury withdrawals or budgets; instead, they are used by the Constitutional Committee to assess constitutionality.

Do we have evidence that this is a problem that the Constitutional Committee have?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the question. There is no problem here as I understand it. It's just saying that the CC will continue to do something that they already have to do, which is assess constitutionality of proposals according to the NCL.

The only difference is that this CIP would make the NCL a parameter instead of a governance action.

The CC must determine:

1. Treasury revenue over the prior `netChangePeriod` epochs.
2. Treasury outflows already **executed** within the same `netChangePeriod` lookback window.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are already asking CC to compute outflows, I feel they can probably also calculate the NCL and treasury inflows

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this CIP doesn't meaningfully change what the CC has to do with those calculations.

However, instead of the NCL being a fixed window, it is a rolling window defined by netChangePeriod.


This CIP introduces two protocol parameters that define the Net Change Limit (NCL):

- `netChangeLimit`: **positive integer percentage** (e.g., 20 means 20%). May be greater than 100.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `netChangeLimit`: **positive integer percentage** (e.g., 20 means 20%). May be greater than 100.
- `netChangeLimitMultiplier`: **positive integer percentage** (e.g., 20 means 20%). May be greater than 100.

maybe a rename on this would be more straight forward
this is based on how I have seen the term NCL used

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to keep it simple with the existing NCL (both name and acronym). Additionally, keeping the name the same happens to make it map cleanly to the existing NCL terminology in the Constitution.

However I realize that it is a percent instead of a flat number now, so maybe there is some room for discussion on this. Brainstorming some alternate ideas to keep the acronym consistent:

Net Change Level
Net Change Leverage
Normalized Change Limit
Normalized Change Level

Or if we want to drop the acronym we can call it Net Change Percent which seems simpler and more descriptive.

This CIP introduces two protocol parameters that define the Net Change Limit (NCL):

- `netChangeLimit`: **positive integer percentage** (e.g., 20 means 20%). May be greater than 100.
- `netChangePeriod`: **positive integer** number of epochs used as the revenue lookback window (default **73** epochs, ~1 year).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `netChangePeriod`: **positive integer** number of epochs used as the revenue lookback window (default **73** epochs, ~1 year).
- `prevNetChangePeriod`: **positive integer** number of epochs used as the revenue lookback window (default **73** epochs, ~1 year).

netChangePeriod implied, to me, that it was referencing as established active Net Change Limit.
Rather than some previous time frame.

(perhaps the way I read it)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this CIP the NCL would basically always be established as active, it would just be on a rolling timeframe.

For example if NCL is 73 epochs (1 year) and you submit a proposal today, I would then have to look back one year from today to see how much spending has been allocated during that window.

If you submit another proposal a month later, the window also shifts forward by a month.

In this sense there would never really be a a "previous" period because it would always be rolling.

Co-authored-by: Ryan <ryan.williams@intersectmbo.org>
@Cerkoryn
Copy link
Copy Markdown
Contributor Author

@rphair I could've sworn I typed up a lengthy reply, but it seems to have disappeared somehow. I'll re-write what I was trying to say here.

@Cerkoryn the result of our last open debate on similar subjects is that the CIP process cannot be used to mandate characteristics of budget processes or other strictly human (non-technical) organisational processes:

This is maybe walking the line a bit, but technically this CIP doesn't change anything at all about the human processes, which are all defined in the Constitution and would not need any changes at all. The text of the Constitution states that "A net change limit for the Cardano treasury's balance per period of time must be agreed by the DReps via an on-chain governance action". But it does NOT specify that it must be an Info Action. Technically this CIP could check all those boxes by introducing the netChangeLimit parameter initialized to 0 and then having dReps approve a Parameter Change governance action. From there it would be enforced by the CC in the exact same way with no changes to the human process.

@Cerkoryn I do think you may have found an acceptable technical governance process with this parameter, but the number of human factors listed in Path to Active to even consider such a parameter is daunting: and has "human", "organisation", and "money" written between every one of those lines.

Unless you can already make an indisputable case that your proposal and its implementation are about technical procedure and nothing else, you could mark this as a Draft until that can be established... or until we have at least an acceptable draft of a Governance CIP indicating broad support for such parameter additions & their feasibility.

I concede that this still very much on the border of what may be acceptable for a CIP and will defer to the CIP editors to make that decision. Also, I would be happy to help contribute to that Governance CIP and I have some ideas for that, but was waiting on a finalized version of CIP-???? | On-Chain Surveys and Polls before building out a proof-of-concept for what I have in mind.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Jan 21, 2026

@Cerkoryn I think there you have the boundary of why a CIP could be considered both acceptable and not acceptable for this issue, and therefore a key consideration to address in a Governance category CIP:

  • It should be acceptable if you reason that "that parameter is just a number" and all the CIP would practically do is indicate that the parameter comes from the chain... and therefore acceptable (i.e. a "technical" CIP).
  • However, others would argue (and I personally would fear) that a CIP changing the context of how this parameter is derived (from parameter updates vs. whatever NCL processes, checks & balances exist today) is replacing one human convention with another — with potentially much human disagreement over influence lost or gained — and therefore not acceptable (i.e. an "organisational" CIP).

This is why also above in #1129 (comment) (where I haven't tagged anyone yet) and over in #1131 (comment) which also suggests parameter additions as if they are a purely "technical" thing (where I tagged @katomm @thenic95 as veterans of community parameter discussion) I've invited those with experience in parameter governance to indicate what it would take to establish a safe & generally acceptable best practice for CIP parameter additions.

Once we have that, we can apply it to the CIP process immediately and use the same reasoning to fill out the more difficult parts of the pending Governance category-defining CIP. I'm hoping to have more time to devote to this soon — once some constraints on my own workflow have been lifted — and then will look forward to getting that draft posted & open for community feedback including @Cerkoryn your in-progress ideas.


waiting on a finalized version of #1107 before building out a proof-of-concept

On the potential relationship to:

... I've tagged the author again to indicate we're only waiting on his fixing of the metadata table entry before promoting this to candidate (pending other editors' agreement) and continuing review.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Jan 21, 2026

@Ryun1 @perturbing (cc @Cerkoryn) I don't want any uncertainty over how to involve other governance groups / processes / stakeholders to delay the review requested in this PR... and in fact discussion at a well-attended meeting might even help overcome any obstacles we face in getting the right review for the governance aspects of the problem.

So even though we can't be sure this is an admissible CIP yet, I think it should still be marked for Triage to bring those questions into the next meeting (as time permits, and perhaps without yet being able to grant a CIP number / candidate status): https://hackmd.io/@cip-editors/127

@rphair rphair added the State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. label Jan 21, 2026
@rphair rphair changed the title CIP-???? | Net Change Limit Parameter CIP-0173? | Net Change Limit Parameter Feb 4, 2026
Copy link
Copy Markdown
Collaborator

@rphair rphair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been confirmed at the CIP meeting today by the quorum of 2 editors present (cc @Ryun1) based on the reasoning supplied in #937 (comment) ... I've recorded those reasons there to ensure they can become part of the Governance proposal draft somehow since this proposal, as expected, has provided a good litmus test for acceptability as technical governance.

Though there would be a "can of worms" over which human influences might be changed along with the "seat" of the Net Change Limit, these would be common in inclusion of any CIP in any hard fork. But since we don't want to interrupt any discussion of Protocol Parameters in general, @Cerkoryn through the PC has agreed to:

  • ask the Parameter Committee if there are any objections to this proposal: especially in considering whether or not it would be a purely "technical" change to adopt this CIP;
  • also ask if any of the PC members would please consider reviewing the CIP itself (I've attempted to tag some above but we could try again now more emphatically).

Thanks again @Cerkoryn and please rename the CIP directory to CIP-0173 and update the link in your original posting. 🎉

---
CIP: ?
Title: Net Change Limit Parameter
Category: Ledger
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Category: Ledger
Category: Governance

Not much to change in Ledger to make this a reality: so most of the discussion around this will be in the Governance category & so that category will remain applicable as long as it continues to be clear this is only a technical change to the data structure used in Cardano governance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on Parameter Committee feedback, I am contemplating the idea of changing this CIP to let the NCL be enforced by the ledger instead of the Constitutional Committee. I think in that case it would still belong in the Ledger category if I am not mistaken? More info here.

Copy link
Copy Markdown
Collaborator

@rphair rphair Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes @Cerkoryn I think it would indeed revert to Ledger in that case: since we always try to target the CIP category to a product of 1) who needs to do the most work to achieve that improvement * 2) who most needs to provide review to establish feasibility of a CIP or completeness of a CPS. (cc @Ryun1 @perturbing to concur)

A confirmed plan to enforce an NCL parameter in the Ledger would indicate the Ledger category just as much as for CIP-1694 itself (which I believe should still remain outside the scope of the new Governance category by the same reasoning). — cc @lehins

In the meantime I'll decategorise this now (i.e. the GitHub label), to force us to re-assign the category after that decision is made.


## Abstract

The Cardano Constitution requires treasury withdrawals and budgets to respect a net change limit for the treasury balance. Today, that limit is set as a periodic governance value that expires, forcing repeated proposals and votes. This CIP converts the Net Change Limit (NCL) into two updatable protocol parameters: `netChangeLimit` (a percentage) and `netChangePeriod` (an epoch lookback count). Together, they define an adaptive cap based on recent treasury revenue:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Cerkoryn, as noted from the meeting, we also need to classify which Parameter group this is in since it would have an effect on the boundaries of how the parameters can be changed... I recall something like the choices being "economic" vs. "technical"? Please give us more details about that when you're ready & got all the necessary background information.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the parameter committee thinks the governance parameter category would suit this CIP the best in its current form. I posted more info about it here.

@rphair rphair added Category: Governance Technical Governance: pending definition in issue #937 State: Confirmed Candiate with CIP number (new PR) or update under review. and removed State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. labels Feb 4, 2026
@ptrdsh
Copy link
Copy Markdown
Contributor

ptrdsh commented Feb 5, 2026

Thanks for this initiative. NCL is a thorn in Governance in general and this would alleviate some of this.
However, I believe itd not be required as CIP, or as new parameter, because the constitution doesnt forbid the (current) NCL to be a formula, which means this concept can already be "enabled" through an info action that defines the NCL as [NCL=someFormula], indefinitely.
This would also allow us to keep the lane more open for alternatives to NCL altogether, as the whole concept is quite "questionable" anyway.

Assuming we would nevertheless introduce these parameters, I have a question on the formula. I might not understand it at the moment..
The cap formula is defined as: somePercentage * TreasuryInflowsInLastPeriod, whereby somePercentage could be >100.
This would be a fine approach if TreasuryInflows would be closer to where the chain needs them to be, and not expected to change drastically. It also doesnt reflect the need for more Treasury Funding early for "investments", and less Treasury Funding later for "maintenance" - as was/is the idea behind the staking reward (subsidy) formula.
Defining the cap as its defined now, would result in basically the same problem as today where we need to revisit the NCL every year, because today's chain revenue (treasury inflows) is very low and the NCLpercentage would need to be set at thousands of % to be equivalent to todays wishes.
If the spend of the treasury results in what we want - namely more chainRevenue - the percentage would need to be adapted very frequently.

In my views, a better formula would be:
chainRevenue + somePercentage * Treasury
This scales smoothly with the inflows while ensuring a transition (a smooth decay) from early subsidies to maintenance.

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

Cerkoryn commented Feb 5, 2026

Assuming we would nevertheless introduce these parameters, I have a question on the formula. I might not understand it at the moment.. The cap formula is defined as: somePercentage * TreasuryInflowsInLastPeriod, whereby somePercentage could be >100. This would be a fine approach if TreasuryInflows would be closer to where the chain needs them to be, and not expected to change drastically. It also doesnt reflect the need for more Treasury Funding early for "investments", and less Treasury Funding later for "maintenance" - as was/is the idea behind the staking reward (subsidy) formula. Defining the cap as its defined now, would result in basically the same problem as today where we need to revisit the NCL every year, because today's chain revenue (treasury inflows) is very low and the NCLpercentage would need to be set at thousands of % to be equivalent to todays wishes. If the spend of the treasury results in what we want - namely more chainRevenue - the percentage would need to be adapted very frequently.

In my views, a better formula would be: chainRevenue + somePercentage * Treasury This scales smoothly with the inflows while ensuring a transition (a smooth decay) from early subsidies to maintenance.

@ptrdsh perhaps I should clarify better in the CIP, but "revenue" is defined as fees + reserve emissions, not just fees alone. So as emissions dwindle, revenue dwindles, and the ability to spend more also dwindles. Similarly, increasing fees via more usage would allow for greater spending (if we wanted it) which incentivizes exactly the right behavior for driving usage to the chain.

For reference I built a flowchart on Cexplorer that calculated the 2025 revenue the way I described it available here.

You can see via mouseover that the treasury revenue (inflows) for 2025 was approximately 283M ADA. If we were to set the NCL at 100% then this would be the spending limit which is right in the ballpark of where the spending limit is being proposed anyways.
image

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

Cerkoryn commented Feb 5, 2026

@rphair comments from the Parameters committee are generally that this CIP is a "Good approach for tomorrow, but not a good approach for the day-after-tomorrow."

It was recommended that perhaps this CIP be re-worked to allow the ledger to enforce the withdrawal limit, rather than having to rely solely on the CC as an enforcement mechanism. This would be a bit of extra implementation work, but would alleviate some pressure on the CC and allow us to lean into the "code is law" ethos of Cardano.

It was also recommended that if these parameters are introduced they would best fit in the governance category with a 75% threshold requirement for dReps to change it.

In any case, I am happy to entertain alternative versions of this CIP depending on feedback.

@ptrdsh @kevinhammond Please feel free to add if I missed anything, thank you.

@ptrdsh
Copy link
Copy Markdown
Contributor

ptrdsh commented Feb 5, 2026

@Cerkoryn

"revenue" is defined as fees + reserve emissions

aahhh.. yeah that explains a lot. was confused that noone else flagged this before me. Then indeed its similar to my formula and decays sustainably. Yours piggybacks on the SPO incentives plus it self-references YoY, which I have to wrap my head around first. I think I like it, but my gut says caution.. should I muster up some smart thoughts, Ill let you know.

I havent seen the Sankey Diagram on cexplorer yet - holy shit its nice! 🤯 👏


Going a few sentences deeper into

"Good approach for tomorrow, but not a good approach for the day-after-tomorrow."

than just the "save CC some time" argument:
I want to express concerns about the long term value of this CIP, given that the NCL concept as a whole assumes an (annual or timebased) budgeting process, which is a corporate construct that doesnt reflect the needs of a decentralized, fast evolving system very well. It may be the best treasury control model we have right now, but its actually terrible. I, and noone I believe, has a better solution atm, so my argument is kinda void from the start, but Im afraid of locking us into the NCL "target spending" concept too deeply, should we come up with a better treasury control model at some point.

Cerkoryn and others added 4 commits February 5, 2026 15:30
@rphair rphair removed the Category: Governance Technical Governance: pending definition in issue #937 label Feb 6, 2026
@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Feb 6, 2026

Governance category removed pending discussion about whether this will be done in Ledger as per #1129 (comment) & #1129 (comment).

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Feb 12, 2026

@Cerkoryn it looks like as of 9d9576d you are committing to a Ledger scope for this CIP. I also think it is more properly future proof to take this "day after tomorrow" approach.

@lehins @WhatisRT this likely means your opinion about integrating this parameter — as suggested, or by your alternative recommendation — is now the top priority for review & we would be happy to hear what you think.

@rphair rphair added the Category: Ledger Proposals belonging to the 'Ledger' category. label Feb 12, 2026
@WhatisRT
Copy link
Copy Markdown
Contributor

I'm a bit surprised at this proposal - we have a constitution script for ensuring that proposals satisfy whatever properties should be required of them. Why not propose a feature to make the history of the treasury visible to that script? Then all of the discussion about what the logic should be, today and in the future, can be answered and implemented by the relevant committees, and it's perfectly future proof.

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

@WhatisRT your suggestion is to have the enforcement handled completely by the guardrails script? As opposed to either the ledger or the CC?

Just trying to make sure I understand correctly, but I think I see your point. I had written it with the thought in mind that a guardrail script could be additional enforcement mechanism that allows us to set upper and lower bounds (as we do with other parameters).

If we can put all the logic/state tracking in that script and avoid having the ledger do anything (other than hold the parameter values) that seems like a win to me.

@WhatisRT
Copy link
Copy Markdown
Contributor

@WhatisRT your suggestion is to have the enforcement handled completely by the guardrails script? As opposed to either the ledger or the CC?

Yes, that'd be my preferred solution to this issue.

@Crypto2099
Copy link
Copy Markdown
Collaborator

What if a new constitution is passed tomorrow and we fully remove the need/definition to have an NCL? Then we have a "dead" parameter living forever in the Ledger itself with no tangible benefit to the blockchain. I'm not convinced this makes sense, particularly because neither the guardrails script nor the ledger can look at/monitor historical state to know that X treasury withdrawal occurred while NCL Amount was Y and NCL Period was Z. So it will still/always come down to a matter of tooling and human interpretation either way. I would be more in favor of the community socially agreeing on common terms/JSON metadata standard for how the NCL is defined so that it's always clear what the NCL amount and period are without human interpretation rather than enshrining this at the ledger level.

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

@Crypto2099 I actually see it being removed from the Constitution and Info Actions as the preferred outcome. Having it be its own parameter enforced via "Code is Law" is much less overhead than having the CC have to manually review every single treasury withdrawal and make an interpretation decision.

I think the state tracking is tractable such that we will only need to maintain a single integer value for each of 73 epochs. If more than one withdrawal occurs during an epoch then they can simply be summed together. It also may be possible to optimize further by ignoring epochs where no withdrawals happen.

As far as enforcement, it would be done at enactment right before funds would move. Sum the funds already withdrawn, compute the cap, and then reject if the withdrawal exceeds the cap.

From a general CompSci perspective this is very trivial and I'm sure the ledger could do it if we wanted it to (though I am not an expert). However I am even less of an expert on Cardano smart contracts so I will have to defer to someone else who could explain how that state tracking could be done in a smart contract.

@Crypto2099
Copy link
Copy Markdown
Collaborator

@Crypto2099 I actually see it being removed from the Constitution and Info Actions as the preferred outcome. Having it be its own parameter enforced via "Code is Law" is much less overhead than having the CC have to manually review every single treasury withdrawal and make an interpretation decision.

I think the state tracking is tractable such that we will only need to maintain a single integer value for each of 73 epochs. If more than one withdrawal occurs during an epoch then they can simply be summed together. It also may be possible to optimize further by ignoring epochs where no withdrawals happen.

As far as enforcement, it would be done at enactment right before funds would move. Sum the funds already withdrawn, compute the cap, and then reject if the withdrawal exceeds the cap.

From a general CompSci perspective this is very trivial and I'm sure the ledger could do it if we wanted it to (though I am not an expert). However I am even less of an expert on Cardano smart contracts so I will have to defer to someone else who could explain how that state tracking could be done in a smart contract.

The state is not currently tractable via the ledger, the ledger only changes based on what is currently in it and what the potential outcome of the state change is (and that all the keys and other checks are valid). So while you reduce something down to "very trivial" because you're thinking in terms of a flat file/database variable you have to think about how much needs to be added to a stateless machine in order to track something like the value of an integer that can be modified an unlimited number of times over the preceding 365 days (the ledger never looks at its own history). This also creates a problem with race conditions in terms of who potentially gets funded or not, etc. Adding this NCL enforcement to the ledger is like using a sledgehammer to tap in a finishing nail... It might work but it's serious overkill and could cause more damage than it repairs in the process.

@ptrdsh
Copy link
Copy Markdown
Contributor

ptrdsh commented Feb 24, 2026

For what it's worth: Adam worded the same type of concern I had - locking us into NCL/creating dead weight - much more elegantly and clearly than I did by framing it as technical debt.
Since the option for "switching off" params exist for most values by setting them to 0, and that approach appears to have been acceptable so far or for other ideas, I do not consider this potential dead weight to be all that terrible.
Whether the benefits of using this parameter justifies the effort to build, is a different question.
I tend to be in camp "no", as outlined in my previous comments + adding support for Adam's perspectives.

Re guardrail script.. I'd be surprised if that's much easier, as we would introduce a new type of "virtual parameter" which only exists in between chain-law coded parameters and human-law constitution parameters - especially with custom logic on top?
A) Documentation nightmare.
B) maintenance nightmare.
C) needs a constitution update.

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

Cerkoryn commented Mar 3, 2026

Made some changes to simplify the CIP substantially. It is now one parameter, netChangeLimit with a fixed-73 epoch window which eliminates a lot of weird edge cases.

The design no longer requires the ledger to look back through an arbitrary amount of history either. Instead it proposes minimal, bounded, canonical state that is updated deterministically each epoch, with the guardrail script doing computation against that state. It does this by using a ring buffer with 73 entries each containing a tuple of (revenue, withdrawn) for each epoch.

The guardrail script runs just prior to enactment of a treasury withdrawal proposal. It computes the sum of all revenue and total ADA withdrawn over that 73 epoch period and then determines if netChangeLimit would be violated. If so then it blocks the withdrawal.

This would allow us to deterministically check the NCL via code without having to rely on a human element.

I'd like to think this hybrid solution gives us the best of both worlds (ledger vs script), but as always I am open to feedback.

@thenic95
Copy link
Copy Markdown

May I ask what the next steps are for this CIP?

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 30, 2026

@thenic95 @Cerkoryn I had misread the previous #1129 (comment) as the author saying "I'd like to think (about this new approach)" and I can see now that was scrambled. In any case we usually wait until the author says they're finished with their writing / commits before we tag everyone involved in prior discussion to see if all reservations have been satisfied and/or we get consensus that the idea & CIP are the best they can be.

Once that's done, generally one of the editors will review it in pre-publication detail & then green-check it into the next CIP meeting by marking Last Check. I think we can do this if there are confirmations & no remaining objections from prior reviewers @Ryun1 @ptrdsh @WhatisRT @Crypto2099 (cc @lehins: not heard from yet) & anyone else who enters the discussion from this point.

Copy link
Copy Markdown
Contributor

@lehins lehins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a fundamental flaw in this CIP: guardrails script cannot be used as described in this CIP. We could potentially make those exact ledger rules instead, but that has to be explicitly described that guardrails script is not involved and all this logic becomes part of the Ledger rules.
I highly recommend the author @Cerkoryn and others interested in this CIP to come to a Ledger working group, so we can have a proper discussion about this proposal. Next one is happening on Monday and we can make this CIP a topic for that meeting: https://luma.com/1dka4io2

This creates two problems:

- **Ambiguous source of truth.** Different actors can interpret different NCL references as authoritative.
- **Operational overhead.** Arithmetic admissibility checks remain largely procedural rather than being deterministically derived from canonical state.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canonical state is an orthogonal concept and it will be helpful not to mix the two

Suggested change
- **Operational overhead.** Arithmetic admissibility checks remain largely procedural rather than being deterministically derived from canonical state.
- **Operational overhead.** Arithmetic admissibility checks remain largely procedural rather than being deterministically derived from the ledger state.


This CIP resolves those problems by using:

- a fixed 73-epoch rolling window (no mutable period parameter),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How was 73 value derived and should it be expressed in a form of a new protocol parameter?
What happens if epochs will have a different length. Right now it is not a customizable option, but there are no guarantees it will not change in some distant future hard fork. Should we just say it should always be equal to 365 days?

This CIP resolves those problems by using:

- a fixed 73-epoch rolling window (no mutable period parameter),
- canonical ledger state for window revenue and withdrawals, and
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, canonical is not relevant here

Suggested change
- canonical ledger state for window revenue and withdrawals, and
- ledger state for window revenue and withdrawals, and


- a fixed 73-epoch rolling window (no mutable period parameter),
- canonical ledger state for window revenue and withdrawals, and
- a guardrail-script enactment check against that state.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plutus scripts never have access to the ledger state, as such this statement is incorrect. Maybe

Suggested change
- a guardrail-script enactment check against that state.
- a guardrail-script enactment check against that information in the state, which will have to be included in the transaction


At an epoch transition, the check MUST use the pre-write snapshot of all 73 entries, including the pointed overwrite entry before it is replaced.

At enactment-time evaluation of a Treasury Withdrawal with amount `w`, the guardrail script MUST compute:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guardrails script can only be executed at the time of proposal, not at the time of enactment. A very simple explanation of why this is the case: there is nobody around to pay for the collateral on the epoch boundary when enactment actually happens. In other words, scripts are always executed when they are part of a transaction, not at any arbitrary point, because if we did allow that, then a buggy script could brick the whole blockchain.


At each epoch transition, the ledger MUST:

1. perform Treasury Withdrawal guardrail checks for boundary enactment against the pre-write 73-entry snapshot,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, guardrails checks can't happen on the epoch boundary


## Rationale: how does this CIP achieve its goals?

- **Canonical on-chain state with script policy enforcement.** The ledger provides deterministic state and the guardrail script enforces at enactment.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Suggested change
- **Canonical on-chain state with script policy enforcement.** The ledger provides deterministic state and the guardrail script enforces at enactment.
- **Ledger state with script policy enforcement.** The ledger provides deterministic state and the guardrail script enforces at enactment.


1. `windowRevenue = sum(entry.revenue for all 73 entries)`
2. `windowWithdrawn = sum(entry.withdrawn for all 73 entries)`
3. `effectiveRevenue = max(windowRevenue, 0)`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intend this in your formula? Cause otherwise I don't understand why the need for introduction of effectiveRevenue and usage of max

Suggested change
3. `effectiveRevenue = max(windowRevenue, 0)`
3. `effectiveRevenue = max(windowRevenue - windowWithdrawn, 0)`

@WhatisRT
Copy link
Copy Markdown
Contributor

WhatisRT commented Apr 1, 2026

I missed the updated CIP, sorry about that. I do agree with the points @lehins makes, running scripts at the epoch boundary is bad for a bunch of reasons (let me also mention performance here).

The issue that running the scripts at the epoch boundary is trying to solve is of course that you can have multiple parallel proposals that don't know about each other, so when proposing you don't know what the state is your proposal is going to be applied against. Phrased like that, there's an obvious solution: add hash protection to treasury withdrawals.

It has the downside that treasury withdrawals now need to happen in a pre-defined order. The benefit is that it is now possible to compute the state of the treasury (or at least the sum of all withdrawals in a time frame, since the treasury could also grow an unknown amount) at the time the withdrawal would happen.

@lehins
Copy link
Copy Markdown
Contributor

lehins commented Apr 1, 2026

add hash protection to treasury withdrawals.

@WhatisRT I remember this being discussed when we were implementing Conway, and the downside was that one TreasuryWithdrawal would interfere with another.

For example, if we have two competing proposals Ta and Tb, which another unrelated proposal should depend on?

     Ta -- ?
   /
T0
   \
     Tb -- ?

I don't believe community will accept this sort of change to the Cardano Governance, as this downside "treasury withdrawals now need to happen in a pre-defined order" seems to me will be quite controversial.

@thenic95
Copy link
Copy Markdown

thenic95 commented Apr 2, 2026

I highly recommend the author @Cerkoryn and others interested in this CIP to come to a Ledger working group, so we can have a proper discussion about this proposal. Next one is happening on Monday, and we can make this CIP a topic for that meeting: https://luma.com/1dka4io2

@lehins would it be possible to make this a topic of the following session? April 6 is Easter Monday for many people, and it will be difficult to participate on that day.

@thenic95
Copy link
Copy Markdown

thenic95 commented Apr 2, 2026

@lehins If I understand correctly, in your proposed scenario with an NCL parameter (or similar check), the validation only occurs when a treasury withdrawal Governance Action (GA) is submitted. At that exact moment, the system verifies how many lovelaces have already flowed out of the treasury during the defined NCL term.

The flaw in this approach is that it fails to account for active, pending treasury withdrawals that are live but haven't been enacted yet.

Because the system only checks against enacted withdrawals at the time of submission, we could accidentally exceed the NCL limit if multiple pending GAs are eventually approved.

Here is how that could happen:

  • The Limit: The NCL is set to 300M ADA, and 250M ADA has already been withdrawn.

  • The Pending Actions: Two new treasury withdrawals are live, requesting 25M ADA each. If both pass, we hit our exact maximum of 300M ADA.

  • The Loophole: While those two are still pending, someone submits a third withdrawal for 10M ADA. Because the first two haven't been enacted yet, the system only sees the initial 250M ADA spent. The 10M ADA transaction passes the submission check.

  • The Result: If all three are approved by voters, 310M ADA is withdrawn, breaking the NCL.

Despite this edge case, I still believe we should implement the NCL check. We can reasonably rely on the "social layer" of Cardano governance to identify this overlapping overspend and vote down the excess requests. Once the pending GAs are either passed or rejected, the on-chain NCL would quickly catch up to reality.

It might make sense to maybe rename the net change limit to net change threshold.

@lehins
Copy link
Copy Markdown
Contributor

lehins commented Apr 2, 2026

@lehins would it be possible to make this a topic of the following session? April 6 is Easter Monday for many people, and it will be difficult to participate on that day.

@thenic95 Thank you for pointing this out. Turns out it is a holiday for me as well 😄

I've rescheduled the meeting for April 13 instead

@lehins
Copy link
Copy Markdown
Contributor

lehins commented Apr 2, 2026

If I understand correctly, in your proposed scenario with an NCL parameter (or similar check), the validation only occurs when a treasury withdrawal Governance Action (GA) is submitted. At that exact moment, the system verifies how many lovelaces have already flowed out of the treasury during the defined NCL term.

The flaw in this approach is that it fails to account for active, pending treasury withdrawals that are live but haven't been enacted yet.

You are totally right about the flaw and we are very much aware of it. That is my point is to convey how it works today, it is not my suggestion.
In the scenario I pointed out in #1129 (comment) the problem is that with introduction of TreasuryWithdrawal dependencies upon submission of proposal creates contention and requires speculation on which proposals will be enacted first and which ones will not be enacted at all. This is not only impossible to predict, but also creates a conflict within the community that submit TreasuryWithdrawal proposals.

I still believe we should implement the NCL check. We can reasonably rely on the "social layer" of Cardano governance to identify this overlapping overspend and vote down the excess requests.

We already have this reliance on social layer and IMHO this CIP is somewhat unnecessary. That being said, I am not trying to oppose this CIP, I am just trying to make sure it is accurately stated. If community wants this extra protection we will implement it. We just can't use guardrails script for implementing the logic that was proposed in the CIP.

@Cerkoryn
Copy link
Copy Markdown
Contributor Author

Cerkoryn commented Apr 2, 2026

Happy to submit another update to this CIP to improve upon what @lehins has mentioned here. Based on my understanding, the best path forward is likely something like this:

-Enforcement is done by ledger only (not guardrail script)
-Enforcement happens at ratification, not submission (to mitigate simultaneous conflicting withdrawals as @thenic95 pointed out)

But I will hold off until after the 13 April LWG meeting so that we can hash it out more thoroughly there first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Category: Ledger Proposals belonging to the 'Ledger' category. State: Confirmed Candiate with CIP number (new PR) or update under review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants