-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Note
as the original project in https://github.com/solana-labs/solana-program-library is recently marked as archived, I have no way to add the PR directly to it. So i open the ticket to track it here. the original solana program is https://github.com/solana-labs/solana-program-library/tree/master/token-lendinghttps://github.com/solana-labs/solana-program-library/tree/master/token-lending
TL;DR
when creating ObligationLiquidity, it uses default value 1 for cumulative_borrow_rate_wads, but in fact, as borrowers borrowing from the system, the cumulative_borrow_rate_wads of a reserve can go up, higher than 1.
Detailed Explanation
In the original logic, when a borrower is borrowing a token from a reserve, it need to check if the borrow liquidity is here, using an upsert-like operation.
solana-token-lending/program/src/processor/process_borrow_obligation_liquidity.rs
Lines 151 to 153 in fc09679
| obligation | |
| .find_or_add_liquidity_to_borrows(*borrow_reserve_info.key)? | |
| .borrow(borrow_amount)?; |
So, if this borrower's obligation is first time to borrow from this reseve, it needs to create a new instance of ObligationLiquidity into current Obligation to track this borrow (and following borrows for the same borrower borrowing the same token).
solana-token-lending/program/src/state/obligation/mod.rs
Lines 103 to 104 in d8da90d
| let liquidity = ObligationLiquidity::new(borrow_reserve); | |
| self.borrows.push(liquidity); |
The issue is ObligationLiquidity::new, as in line 26, using Decimal::one() as the cumulative_borrow_rate_wads.
| impl ObligationLiquidity { | |
| pub fn new(borrow_reserve: Pubkey) -> Self { | |
| Self { | |
| borrow_reserve, | |
| cumulative_borrow_rate_wads: Decimal::one(), | |
| ..Default::default() | |
| } | |
| } |
This can be a major issue, sets cumulative_borrow_rate_wads to 1, that's because in the whole system, only refresh obligation instruction can update the value of cumulative_borrow_rate_wads in accrue_interest
| liquidity.accrue_interest(borrow_reserve.liquidity.cumulative_borrow_rate_wads)?; |
if the ObligationLiquidity first time gets refrehsed, as in below. let's say, if Alice first time want to borrow from a reserve. but, Bob previously borrowed from the same reserve. At the time Alice is borrowing, the cumulative_borrow_rate_wads from the reseve can be higher than 1. but, it still stores 1 as the cumulative_borrow_rate_wads. that results in compounded_interest_rate incorrectly higher that it actually is.
| let compounded_interest_rate: Rate = cumulative_borrow_rate_wads | |
| .try_div(self.cumulative_borrow_rate_wads)? | |
| .try_into()?; | |
| self.borrowed_amount_wads = self | |
| .borrowed_amount_wads | |
| .try_mul(compounded_interest_rate)?; |
How to fix this
To fix this issue, cumulative_borrow_rate_wads of the moment of creating a new ObligationLiquidity should be saved from the reserve. not using default value 1.