CIP-0173? | Net Change Limit Parameter#1129
CIP-0173? | Net Change Limit Parameter#1129Cerkoryn wants to merge 10 commits intocardano-foundation:masterfrom
Conversation
|
@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 Until a
Then we can start admitting any eligible @Cerkoryn I do think you may have found an acceptable technical governance process with this parameter, but the number of human factors listed in 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 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? | ||
|
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
If we are already asking CC to compute outflows, I feel they can probably also calculate the NCL and treasury inflows
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
| - `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
There was a problem hiding this comment.
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). |
There was a problem hiding this comment.
| - `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)
There was a problem hiding this comment.
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>
|
@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.
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
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. |
|
@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
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
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. |
|
@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 |
rphair
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
| 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
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.
|
Thanks for this initiative. NCL is a thorn in Governance in general and this would alleviate some of this. Assuming we would nevertheless introduce these parameters, I have a question on the formula. I might not understand it at the moment.. In my views, a better formula would be: |
@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. |
|
@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. |
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
than just the "save CC some time" argument: |
Co-authored-by: Robert Phair <rphair@cosd.com>
Co-authored-by: Robert Phair <rphair@cosd.com>
|
|
|
@Cerkoryn it looks like as of 9d9576d you are committing to a @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. |
|
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. |
|
@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. |
Yes, that'd be my preferred solution to this issue. |
|
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. |
|
@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. |
|
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. 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? |
|
Made some changes to simplify the CIP substantially. It is now one parameter, 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 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. |
|
May I ask what the next steps are for this CIP? |
|
@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 |
lehins
left a comment
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
canonical state is an orthogonal concept and it will be helpful not to mix the two
| - **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), |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Ditto, canonical is not relevant here
| - 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. |
There was a problem hiding this comment.
Plutus scripts never have access to the ledger state, as such this statement is incorrect. Maybe
| - 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: |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Ditto.
| - **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)` |
There was a problem hiding this comment.
Did you intend this in your formula? Cause otherwise I don't understand why the need for introduction of effectiveRevenue and usage of max
| 3. `effectiveRevenue = max(windowRevenue, 0)` | |
| 3. `effectiveRevenue = max(windowRevenue - windowWithdrawn, 0)` |
|
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. |
@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 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. |
@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. |
|
@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:
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. |
@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 |
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.
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. |
|
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) But I will hold off until after the 13 April LWG meeting so that we can hash it out more thoroughly there first. |

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)