PI-7: Dynamic Convert Down Penalty
Executed on March 25, 2025 at 20:44 UTC.
Summary
Introduce a Dynamic Stalk Penalty to Pinto -> LP Converts as a function of the L2SR and a bounded counter determined by whether previous Seasons were spent above or below the value target.
Decrease the Excessively High Price threshold () to account for the higher volatility above the value target that this Dynamic Stalk Penalty potentially creates.
Links
- Implementation Commit:
4c3d94586f988dd944d6444fe492fff155962201
Problem
Previously, when the price of Pinto crossed above its value target, the Convert Down Penalty went from 100% (i.e., loss of Grown Stalk above the non-Germinating minimum) to 0% (i.e., no Penalty). Given the overwhelming preference demonstrated by Depositors to hold LP over Pinto in the Silo, as soon as the Convert Penalty went to 0, there were Pinto -> LP Converts that returned the price to its value target. This had the effect of keeping the time the price spent above its value target to an absolute minimum.
While this minimized the amount of minting, which can minimize downside volatility, it also compromised the protocol’s ability to oscillate across the value target, and to spend comparable amounts of time above and below the value target, which decreases utility and therefore long-term demand.
The binary between a 100% penalty and no penalty to Convert Down also favored users with automated execution, concentrating the distribution of LP Deposits and therefore control of the ability to Convert Up when the price is below its value target. A widespread distribution of LP and Pinto ownership is healthier for the protocol than a concentrated one.
Solution
Introduce a Dynamic Stalk Penalty for Pinto -> LP Converts as a function of the L2SR and a counter from 0 to 12 that increases by 1 when a Season has and decreases by 1 otherwise. The penalty ratio ranges from 0% to 100% of the Stalk accumulated from Seeds of the Converted Deposit. The penalty preserves the minimum Grown Stalk required for the output Deposit to remain non-Germinating.
The Stalk Penalty Factor updates according to the counter rule below.
To implement this system, introduce a CONVERT_DOWN_PENALTY gauge system that updates the Dynamic Stalk Penalty incurred by Pinto -> LP Converts.
We define the Stalk Penalty Factor in Season () for a given Season of PI-7 deployment (), maximum Stalk Penalty Factor ( ), and time-weighted average Pinto supply delta over the previous Season () as:
We define the Dynamic Stalk Penalty for Pinto -> LP Converts () for a given instantaneous Pump-reserve price of the output Well , , , L2SR at the end of the previous Season (), optimal L2SR (), and as:

The stored penalty ratio is initialized to 0. These normalized equations omit fixed-point rounding. The applied loss is rounded upward and capped to preserve the non-Germinating minimum. If supplied Grown Stalk is already below that minimum, this helper leaves it unchanged and applies no additional loss. The chart shows the decaying Dynamic Stalk Penalty as Seasons are spent above the value target:
- The blue line shows the penalty when is equal to 40%.
- The purple line shows the penalty when is equal to 20%.
- The green line shows the penalty when is equal to 10%.
Decrease (excessivePriceThreshold) from $1.05 to $1.025.
Rationale
With the introduction of a Dynamic Stalk Penalty for Pinto -> LP Converts that uses a gauge that increases by 1 each Season the protocol logs a and decreases by 1 each Season the protocol logs a , from 0-12, the protocol can discover the Stalk Penalty at which Converts are disincentivized sufficiently to enable the protocol to keep the price above the value target and then oscillate the penalty above and below this penalty % to incentivize the protocol to alternate each Season above and below the value target. This should lead to more oscillations across the value target, and therefore utility for Pinto.
The logarithmic factor falls most sharply when the counter first increases from zero, then falls more slowly with each additional increase. This favors reaching a Season with a after an extended period where for multiple Seasons. The aim is to let the price move above its target after a prolonged period below it, while making smaller adjustments when the price is already alternating around the target.
The L2SR is factored into the Penalty because at higher liquidity levels the protocol is more comfortable spending more time above the value target and printing more Pinto, so it should further disincentivize Converts in those instances than when it has lower liquidity.
The Excessively High Price threshold () is lowered from $1.05 to $1.025 so Pinto-to-LP Converts can bypass the Dynamic Stalk Penalty once the output Well’s price exceeds $1.025. Allowing them to bypass the penalty at a lower price helps limit how far and how long the price stays above the target, reducing the risk of excessive minting.
Contract Changes
Initialization
InitPI7.init() at 0xd44375790b7ef3d2b0d9b0b96cac0476fcdee568 lowered excessivePriceThreshold from 1.05e6 ($1.05) to 1.025e6 ($1.025). It added the CONVERT_DOWN_PENALTY gauge with penalty ratio 0, counter 0, a counter step of 1 per Season, and a counter cap of 12.
Facet Changes
Other Contract / Parameter Changes
ApprovalFacet, SeasonGettersFacet, ClaimFacet, SiloGettersFacet, GaugeGettersFacet, and OracleFacet retained their own source files and interfaces. SeasonFacet changed only a comment in its own source. Shared dependencies can still change. The externally linked libraries below were redeployed. A changed deployment address does not imply every library function changed. ConvertGettersFacet, GaugeFacet, ApprovalFacet, SiloGettersFacet, GaugeGettersFacet, and OracleFacet have no externally linked libraries in their new deployed metadata.
Function Changes
- Updated
convert()andpipelineConvert()to apply the Dynamic Stalk Penalty to Pinto-to-LP Converts before redepositing. The shared internalLibConvert.downPenalizedGrownStalk()rounds the calculated loss upward and preserves the minimum Grown Stalk required for a non-Germinating output Deposit. If the supplied Grown Stalk is below that minimum, it returns the input unchanged and zero loss. This additional penalty is applied after the existing conversion calculations and does not replace their penalties.
- Added
ConvertGettersFacet.downPenalizedGrownStalk(), which returns the remaining and lost Grown Stalk for the supplied Well, PDV, and Grown Stalk. This preview excludes other changes made during a Convert.
- Added
convertDownPenaltyGauge(bytes,bytes,bytes), which returns an encoded penalty ratio and updated counter, followed by unchanged gauge data. The counter increases by 1 when the time-weighted Pinto supply delta is positive and decreases by 1 otherwise, bounded between 0 and 12. A zero computed L2SR retains the previous ratio while updating the counter. The existing gauge engagement path stores the returned values.
- Added
getGaugeData(GaugeId), which returns the gauge’s encoded configuration data.
- Added an instantaneous output-Well price check in
LibConvert. A price strictly above $1.025 bypasses the penalty. The check uses instantaneous Pump reserves and requires a successful USD oracle lookup. AddedLibDeltaB.instantReserves(), which returns an empty array if the Pump read reverts. An empty instantaneous reserve result causes the penalty price-check path to revert. The shared capped-reserve path interprets an empty result from the separate capped-reserve helper as zero delta rather than falling back to old reserves.
Event Changes
- Added
ConvertDownPenalty(uint256 stalkLost), emitted by both Pinto-to-LP conversion routes with the Grown Stalk lost to this penalty, including when the loss is zero.
- Initialization emitted the existing
AddedGaugeevent for the newCONVERT_DOWN_PENALTYgauge. The existingEngaged(GaugeId,bytes)event reports this gauge’s encoded stored ratio and counter when the gauge is engaged.