Fix computation of utilization time-weighted average
This commit is contained in:
parent
8a1c58e723
commit
a23afed7de
|
@ -93,8 +93,7 @@ pub fn token_update_index_and_rate(ctx: Context<TokenUpdateIndexAndRate>) -> Res
|
|||
{
|
||||
let mut some_bank = ctx.remaining_accounts[0].load_mut::<Bank>()?;
|
||||
|
||||
let now_ts_i80f48 = I80F48::from_num(now_ts);
|
||||
let diff_ts = I80F48::from_num(now_ts - some_bank.index_last_updated);
|
||||
let diff_ts = I80F48::from_num(cm!(now_ts - some_bank.index_last_updated));
|
||||
|
||||
let (deposit_index, borrow_index, borrow_fees) =
|
||||
some_bank.compute_index(indexed_total_deposits, indexed_total_borrows, diff_ts)?;
|
||||
|
@ -104,7 +103,7 @@ pub fn token_update_index_and_rate(ctx: Context<TokenUpdateIndexAndRate>) -> Res
|
|||
let new_avg_utilization = some_bank.compute_new_avg_utilization(
|
||||
indexed_total_deposits,
|
||||
indexed_total_borrows,
|
||||
now_ts_i80f48,
|
||||
now_ts,
|
||||
);
|
||||
|
||||
let price = oracle_price(
|
||||
|
|
|
@ -425,7 +425,7 @@ impl Bank {
|
|||
|
||||
// The loan fee rate is not distributed to depositors.
|
||||
let borrow_rate_with_fees = cm!(borrow_rate + self.loan_fee_rate);
|
||||
let borrow_fees = native_total_borrows * self.loan_fee_rate * diff_ts / YEAR_I80F48;
|
||||
let borrow_fees = cm!(native_total_borrows * self.loan_fee_rate * diff_ts / YEAR_I80F48);
|
||||
|
||||
let borrow_index = cm!(
|
||||
(self.borrow_index * borrow_rate_with_fees * diff_ts) / YEAR_I80F48 + self.borrow_index
|
||||
|
@ -479,9 +479,9 @@ impl Bank {
|
|||
&self,
|
||||
indexed_total_deposits: I80F48,
|
||||
indexed_total_borrows: I80F48,
|
||||
now_ts: I80F48,
|
||||
now_ts: i64,
|
||||
) -> I80F48 {
|
||||
if now_ts == I80F48::ZERO {
|
||||
if now_ts <= 0 {
|
||||
return I80F48::ZERO;
|
||||
}
|
||||
|
||||
|
@ -493,13 +493,18 @@ impl Bank {
|
|||
cm!(native_total_borrows / native_total_deposits)
|
||||
};
|
||||
|
||||
// combine old and new with relevant factors to form new avg_utilization
|
||||
// scaling factor for previous avg_utilization is old_ts/new_ts
|
||||
// scaling factor for instantaneous utilization is (new_ts - old_ts) / new_ts
|
||||
let bank_rate_last_updated_i80f48 = I80F48::from_num(self.bank_rate_last_updated);
|
||||
cm!((self.avg_utilization * bank_rate_last_updated_i80f48
|
||||
+ instantaneous_utilization * (now_ts - bank_rate_last_updated_i80f48))
|
||||
/ now_ts)
|
||||
// Compute a time-weighted average since bank_rate_last_updated.
|
||||
let previous_avg_time =
|
||||
I80F48::from_num(cm!(self.index_last_updated - self.bank_rate_last_updated));
|
||||
let diff_ts = I80F48::from_num(cm!(now_ts - self.index_last_updated));
|
||||
let new_avg_time = I80F48::from_num(cm!(now_ts - self.bank_rate_last_updated));
|
||||
if new_avg_time <= 0 {
|
||||
return instantaneous_utilization;
|
||||
}
|
||||
cm!(
|
||||
(self.avg_utilization * previous_avg_time + instantaneous_utilization * diff_ts)
|
||||
/ new_avg_time
|
||||
)
|
||||
}
|
||||
|
||||
// computes new optimal rates and max rate
|
||||
|
@ -667,28 +672,30 @@ mod tests {
|
|||
let mut bank = Bank::zeroed();
|
||||
bank.deposit_index = I80F48::from_num(1.0);
|
||||
bank.borrow_index = I80F48::from_num(1.0);
|
||||
bank.bank_rate_last_updated = 0;
|
||||
bank.bank_rate_last_updated = 1000;
|
||||
bank.index_last_updated = 1000;
|
||||
|
||||
let compute_new_avg_utilization_runner =
|
||||
|bank: &mut Bank, utilization: I80F48, now_ts: i64| {
|
||||
bank.avg_utilization = bank.compute_new_avg_utilization(
|
||||
I80F48::ONE,
|
||||
utilization,
|
||||
I80F48::from_num(now_ts),
|
||||
);
|
||||
bank.bank_rate_last_updated = now_ts;
|
||||
bank.avg_utilization =
|
||||
bank.compute_new_avg_utilization(I80F48::ONE, utilization, now_ts);
|
||||
bank.index_last_updated = now_ts;
|
||||
};
|
||||
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::ZERO, 0);
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::ZERO, 1000);
|
||||
assert_eq!(bank.avg_utilization, I80F48::ZERO);
|
||||
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::from_num(0.5), 10);
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::from_num(0.5), 1010);
|
||||
assert!((bank.avg_utilization - I80F48::from_num(0.5)).abs() < 0.0001);
|
||||
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::from_num(0.8), 15);
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::from_num(0.8), 1015);
|
||||
assert!((bank.avg_utilization - I80F48::from_num(0.6)).abs() < 0.0001);
|
||||
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::ONE, 20);
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::ONE, 1020);
|
||||
assert!((bank.avg_utilization - I80F48::from_num(0.7)).abs() < 0.0001);
|
||||
|
||||
bank.bank_rate_last_updated = 1020;
|
||||
compute_new_avg_utilization_runner(&mut bank, I80F48::ONE, 1040);
|
||||
assert_eq!(bank.avg_utilization, I80F48::ONE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ async fn test_token_update_index_and_rate() -> Result<(), TransportError> {
|
|||
.abs()
|
||||
< 0.1
|
||||
);
|
||||
assert!((bank_after.avg_utilization.to_num::<f64>() - utilization).abs() < 0.01);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue