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

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:

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

FacetActionPrevious ImplementationNew Implementation
ConvertFacetReplace0x7Bab1D09727BE8F0427c6DD1d503b3D4BA697D930x1F421eC312C60f9f6E9f6F79e0E56f496aE27e4e
ConvertGettersFacetAdd / Replace0x115E83Bcb217A06D13210009e7CD8b44cE1af5090xfBaD01D4C722B0850444DD63dc273aD2c1C0d321
PipelineConvertFacetReplace0x1C3ecf2ae6bD491d112F5A2CEa5927A2314374370x7a28DFd0e5BBf281e0a853BFEb4609FF093D0BD1
GaugeFacetAdd / Replace0x25cE5E07e26b4140086F28834DEA1c092Fc10f900x55C0e1643e70f9Fb7eEb8c640A303ad9DE263302
SeasonFacetReplace0xa932CaB249fc9ddd073cdB5d40Bf304a50025CD60x5D1f0c38835A0fb55B5Df11341ae217F1f8a01DA
ApprovalFacetReplace0xA7DF4372b0404Cd468703451950e2af8615996b20x65d67f299A4Ad1CfF49a6C77A2Fb463A86643Ab4
SeasonGettersFacetReplace0xF3D017981D0818274210661BA3cc85D143aFA78E0xab2a1bC987e64C4bE13fFB090b01A5888a345C9e
ClaimFacetReplace0xcbb67C0dADf1c2774215d8AFd4fEF34C7741474B0x8738F66d4a0431B084b7fF8f59097312A5B5531F
SiloGettersFacetReplace0x48F040332c3CcCcF620E3Ed6bBab3d117c9238Ca0xa66113Be17098B2594aBA1614055fCc31B3abd67
GaugeGettersFacetReplace0xB1Cb5aA3c2e91268aAe9C97d59AD90D8DF979DA30x07d6EDB2E4afad408beadAAf30bC21b8F804d1F7
OracleFacetReplace0x72827F9a9C3F4A0e36C7DE20BB7B830ABF385D2E0x7256FAd9Eb704173aFE2185D1A44EDF826FF6C86

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.

LibraryPrevious ImplementationNew ImplementationUsed By
LibEvaluate0xfad4e8659830d22ce9e4d87eaef52674bf805fdb0x9a2848cbde1d2fcaeebb712fd8f1eb65a4bda874SeasonFacet
LibGauge0x573c652702091e7265688902ef63c82e21917b4f0xd749370071c7fe42bbe7b81dfa85ba8ec24864b0SeasonFacet
LibIncentive0x6fac8752c40475c83720acbad2f0c324762433500x5630463e432cbd8ddb870d646213011da9166889SeasonFacet
LibShipping0xab1d90c08dfa6d4c520dad967e97c5eee1d61af20xd8a274fcabe2a5cfc1c18b1f844f7fb2941d38f5SeasonFacet
LibWellMinting0xa31576ac3be233a845e665b98bc384b51e1f4b780x9500f6e8742ecb924af9c97922851d648b613d07SeasonFacet, SeasonGettersFacet
LibFlood0x8595c632071edec9ab2cd84350d8eef46f1815770xc4667d3a3c7c0c42a5bf351f98861963b2597f51SeasonFacet
LibGerminate0x30f89cd09b92938864b819a552471f2c8771c83d0xc6f5423a60acd02f0c8d8d6d5281caa00899b0f9SeasonFacet
LibConvert0xcce6631b13ee44ad9d8146241b20f10c1a803aa20x812d9a79aea7db58bc3b0a149ba2694ef37fd1ddConvertFacet
LibPipelineConvert0xb387ad744cc1a80ab629eea5ca15459076719a7a (ConvertFacet); 0xc7ed19335fcfc73552394dd911cdd56db1ac5e56 (PipelineConvertFacet)0xad2f28b08ff993ee8faaeb20235234ade0773022ConvertFacet, PipelineConvertFacet
LibSilo0x5a686e6024d1d40994ae99979ceb63bf67724b04 (ConvertFacet); 0x85e7554e3af2cfb5ec7a90b53b15b6730055905c (PipelineConvertFacet, ClaimFacet)0xf5daf4e2ca77cf48f4ec17d10f0b48a8c2ca9e5cClaimFacet, ConvertFacet, PipelineConvertFacet
LibTokenSilo0x0da233676f46427c31928f5f85678d6737f4ec7e (ConvertFacet); 0x31b1b337778948f2d5a1f70722cef7cca1b72e06 (PipelineConvertFacet, ClaimFacet)0xecc6509f71b74c9b14f035d35fb9113519f88bb5ClaimFacet, ConvertFacet, PipelineConvertFacet

Function Changes

Event Changes