Make slots_per_year configurable instead of a constant - #122
Merged
Conversation
Turning a reserve's APR into the per-slot rate interest actually accrues at needs a slots-per-year divisor, and that divisor is the cluster's slot time in disguise. Both ports carried it as SLOTS_PER_YEAR = 78_840_000, fixed at a 400ms slot. Solana is lowering the slot time, and a lower one raises the wall-clock rate every borrower pays with no line of either program changing and nothing in the config to show for it. Anchor: ReserveConfig gains slots_per_year, validate() rejects zero, and the owner retunes through the existing update_reserve_config. Quasar: Reserve gains slots_per_year, initialize_reserve takes it, and a new owner-only update_slots_per_year (discriminator 12) retunes it. That handler accrues at the old figure before storing the new one, so slots already elapsed are charged at the rate that was in force for them rather than repriced. Also drop the "at 400ms/slot" gloss from the price-staleness comments in lending, prop-amm and perpetual-futures. The window is counted in slots on purpose; what it comes to in seconds follows the cluster and tightens on its own.
`funding_rate_per_slot` was set at initialize_pool and never again. The rate is quoted per slot, so what a position costs per hour depends on the cluster's slot time as well as on the rate. Solana lowers the slot time over time, and a pool that outlives a reduction charges the heavier side more per hour than it was set up to, with no way to correct it short of a new pool. Add set_funding_rate to both ports (Quasar discriminator 7), owner-only. It advances the funding index at the old rate before storing the new one, so slots already elapsed are charged at the rate that was in force for them rather than repriced by the new one. The tests pin that settlement rather than just the write: a position held across a retune to double the rate pays one window at the old rate and one at the new, which is exactly 1.5x what a position opened afterwards pays over a single window. Comparing two windows in the same pool cancels the size and price scaling, so the assertion is on the rates alone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Move
slots_per_yearfrom a hardcoded constant to a configurable parameter in reserve configuration. This allows reserves to adapt to protocol changes in slot time without requiring code updates, preventing borrowers from being charged incorrect wall-clock rates when Solana lowers the slot time.Key Changes
Anchor lending program:
SLOTS_PER_YEARconstant fromconstants.rsslots_per_year: u64field toReserveConfigstructReserveConfig::validate()to reject zero valuesconfig.slots_per_yearinstead of the constantSLOTS_PER_YEARtest constant tocommon/mod.rsand updatedefault_config()rejects_zero_slots_per_yearandslots_per_year_scales_the_per_slot_rateQuasar lending program:
SLOTS_PER_YEARconstant fromconstants.rsslots_per_year: u64field toReservestate structupdate_slots_per_yearinstruction (discriminator 12) for owner-only retuninginitialize_reserveto acceptslots_per_yearparameterborrow_rate_per_slot()andaccrue_factor()to acceptslots_per_yearparameterretuning_slots_per_year_rescales_accrualdemonstrating the featureDocumentation updates:
constants.rsfiles that slot-based staleness windows tighten automatically as protocol lowers slot timeImplementation Details
update_slots_per_yearinstruction accrues interest at the old rate before storing the new divisor, ensuring slots already elapsed are charged at the rate that was in force for themhttps://claude.ai/code/session_01TCc6nwbMzXsG3fEom23KXW