Linear-yield reduction for late staking
Description
For stake-pool bonds and solo validator bonds, the following code is used to calculate the amount of YTs that should be minted for a deposit.
// Calculations here round down intentionally to remove risk of rounding error attacks.
pub fn calc_yt_to_mint(&self, lst_state: &LstState, deposit_amount: u64, now: i64) -> u64 {
let principal_lamports = lst_state.lamports_for_lst(deposit_amount);
let numerator =
U192::try_from(
self.maturity_ts
.checked_sub(now)
.expect("underflow")
).expect("u64");
let denominator = U192::try_from(
self.maturity_ts
.checked_sub(self.issuance_ts)
.expect("underflow"),
)
.expect("u64");
U192::from(principal_lamports)
.checked_mul(numerator)
.expect("overflow")
.checked_mul(U192::from(PT_YT_DECIMAL_FACTOR))
.expect("overflow")
.checked_div(denominator)
.expect("overflow")
.checked_div(U192::from(LAMPORTS_PER_SOL))
.expect("overflow")
.as_u64()
}Note that the formula for the amount of yield tokens that are minted is linear over time.
Impact
This allows an attacker to deposit a large amount of tokens just before the bond matures, capturing a large portion of the yield while only depositing into the bond for a very short time. Because of compound-interest effects, the earlier depositors should theoretically have a much larger share of the yields as they have contributed to a larger share of the yields. In practice, depositing just before a reward-distribution event has significant advantages. Potentially, an attacker could cycle through many bonds, depositing in all of them at the last second and being entitled to a significant portion of the yield despite not contributing to it.
Recommendations
Change the economic incentives so that earlier depositors are properly rewarded.