Skip to content

Commit

Permalink
account for program upgrade in borrow attribution calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
0xripleys committed Nov 29, 2023
1 parent 2b4fbce commit e0807ca
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 11 deletions.
10 changes: 7 additions & 3 deletions token-lending/program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,9 +1127,11 @@ fn update_borrow_attribution_values(
return Err(LendingError::InvalidAccountInput.into());

Check warning on line 1127 in token-lending/program/src/processor.rs

View check run for this annotation

Codecov / codecov/patch

token-lending/program/src/processor.rs#L1126-L1127

Added lines #L1126 - L1127 were not covered by tests
}

deposit_reserve.attributed_borrow_value = deposit_reserve
.attributed_borrow_value
.saturating_sub(collateral.attributed_borrow_value);
if obligation.updated_borrow_attribution_after_upgrade {
deposit_reserve.attributed_borrow_value = deposit_reserve
.attributed_borrow_value
.saturating_sub(collateral.attributed_borrow_value);
}

if obligation.deposited_value > Decimal::zero() {
collateral.attributed_borrow_value = collateral
Expand Down Expand Up @@ -1159,6 +1161,8 @@ fn update_borrow_attribution_values(
Reserve::pack(deposit_reserve, &mut deposit_reserve_info.data.borrow_mut())?;
}

obligation.updated_borrow_attribution_after_upgrade = true;

Ok(())
}

Expand Down
123 changes: 122 additions & 1 deletion token-lending/program/tests/attributed_borrows.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
#![cfg(feature = "test-bpf")]

use solana_sdk::compute_budget::ComputeBudgetInstruction;
use solend_sdk::instruction::refresh_obligation;

use crate::solend_program_test::custom_scenario;
use crate::solend_program_test::SolendProgramTest;
use crate::solend_program_test::User;
use solana_sdk::pubkey::Pubkey;
use solend_program::math::TryDiv;
use solend_program::processor::process_instruction;
use solend_sdk::state::ObligationCollateral;
use solend_sdk::state::ObligationLiquidity;
use solend_sdk::state::PROGRAM_VERSION;

use solana_sdk::instruction::InstructionError;
use solana_sdk::transaction::TransactionError;
Expand Down Expand Up @@ -30,7 +39,7 @@ use solana_program_test::*;

#[tokio::test]
async fn test_refresh_obligation() {
let (mut test, lending_market, reserves, obligations, users, lending_market_owner) =
let (mut test, lending_market, reserves, obligations, _users, lending_market_owner) =
custom_scenario(
&[
ReserveArgs {
Expand Down Expand Up @@ -851,3 +860,115 @@ async fn test_liquidate() {
Decimal::zero()
);
}

#[tokio::test]
async fn test_calculation_on_program_upgrade() {
let mut test = ProgramTest::new(
"solend_program",
solend_program::id(),
processor!(process_instruction),
);

let reserve_1 = Reserve {
version: PROGRAM_VERSION,
last_update: LastUpdate {
slot: 1,
stale: false,
},
attributed_borrow_value: Decimal::from(10u64),
liquidity: ReserveLiquidity {
market_price: Decimal::from(10u64),
mint_decimals: 0,
..ReserveLiquidity::default()
},
..Reserve::default()
};
let reserve_1_pubkey = Pubkey::new_unique();

test.add_packable_account(
reserve_1_pubkey,
u32::MAX as u64,
&reserve_1,
&solend_program::id(),
);

let reserve_2 = Reserve {
version: PROGRAM_VERSION,
last_update: LastUpdate {
slot: 1,
stale: false,
},
liquidity: ReserveLiquidity {
market_price: Decimal::from(10u64),
mint_decimals: 0,
..ReserveLiquidity::default()
},
..Reserve::default()
};
let reserve_2_pubkey = Pubkey::new_unique();
test.add_packable_account(
reserve_2_pubkey,
u32::MAX as u64,
&reserve_2,
&solend_program::id(),
);

let obligation_pubkey = Pubkey::new_unique();
let obligation = Obligation {
version: PROGRAM_VERSION,
deposits: vec![ObligationCollateral {
deposit_reserve: reserve_1_pubkey,
deposited_amount: 2u64,
market_value: Decimal::from(20u64),
attributed_borrow_value: Decimal::from(10u64),
}],
borrows: vec![ObligationLiquidity {
borrow_reserve: reserve_2_pubkey,
borrowed_amount_wads: Decimal::from(1u64),
..ObligationLiquidity::default()
}],
updated_borrow_attribution_after_upgrade: false,
..Obligation::default()
};

test.add_packable_account(
obligation_pubkey,
u32::MAX as u64,
&obligation,
&solend_program::id(),
);

let mut test = SolendProgramTest::start_with_test(test).await;

let ix = [refresh_obligation(
solend_program::id(),
obligation_pubkey,
vec![reserve_1_pubkey, reserve_2_pubkey],
)];

test.process_transaction(&ix, None).await.unwrap();

let reserve_1 = test.load_account::<Reserve>(reserve_1_pubkey).await;
assert_eq!(
reserve_1.account.attributed_borrow_value,
Decimal::from(20u64)
);

// run it again, this time make sure the borrow attribution value gets correctly subtracted
let ix = [
ComputeBudgetInstruction::set_compute_unit_price(1),
refresh_obligation(
solend_program::id(),
obligation_pubkey,
vec![reserve_1_pubkey, reserve_2_pubkey],
),
];

test.process_transaction(&ix, None).await.unwrap();

let reserve_1 = test.load_account::<Reserve>(reserve_1_pubkey).await;
assert_eq!(
reserve_1.account.attributed_borrow_value,
Decimal::from(20u64)
);
}
3 changes: 2 additions & 1 deletion token-lending/program/tests/init_obligation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ async fn test_success() {
allowed_borrow_value: Decimal::zero(),
unhealthy_borrow_value: Decimal::zero(),
super_unhealthy_borrow_value: Decimal::zero(),
borrowing_isolated_asset: false
borrowing_isolated_asset: false,
updated_borrow_attribution_after_upgrade: false
}
);
}
Expand Down
26 changes: 20 additions & 6 deletions token-lending/sdk/src/state/obligation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub struct Obligation {
pub super_unhealthy_borrow_value: Decimal,
/// True if the obligation is currently borrowing an isolated tier asset
pub borrowing_isolated_asset: bool,
/// Updated borrow attribution after upgrade. initially false when upgrading to v2.0.3
pub updated_borrow_attribution_after_upgrade: bool,
}

impl Obligation {
Expand Down Expand Up @@ -436,7 +438,8 @@ impl Pack for Obligation {
borrowed_value_upper_bound,
borrowing_isolated_asset,
super_unhealthy_borrow_value,
true_borrowed_value,
unweighted_borrowed_value,
updated_borrow_attribution_after_upgrade,
_padding,
deposits_len,
borrows_len,
Expand All @@ -456,7 +459,8 @@ impl Pack for Obligation {
1,
16,
16,
15,
1,
14,
1,
1,
OBLIGATION_COLLATERAL_LEN + (OBLIGATION_LIQUIDITY_LEN * (MAX_OBLIGATION_RESERVES - 1))
Expand All @@ -478,7 +482,11 @@ impl Pack for Obligation {
self.super_unhealthy_borrow_value,
super_unhealthy_borrow_value,
);
pack_decimal(self.unweighted_borrowed_value, true_borrowed_value);
pack_decimal(self.unweighted_borrowed_value, unweighted_borrowed_value);
pack_bool(
self.updated_borrow_attribution_after_upgrade,
updated_borrow_attribution_after_upgrade,
);

*deposits_len = u8::try_from(self.deposits.len()).unwrap().to_le_bytes();
*borrows_len = u8::try_from(self.borrows.len()).unwrap().to_le_bytes();
Expand Down Expand Up @@ -542,7 +550,8 @@ impl Pack for Obligation {
borrowed_value_upper_bound,
borrowing_isolated_asset,
super_unhealthy_borrow_value,
true_borrowed_value,
unweighted_borrowed_value,
updated_borrow_attribution_after_upgrade,
_padding,
deposits_len,
borrows_len,
Expand All @@ -562,7 +571,8 @@ impl Pack for Obligation {
1,
16,
16,
15,
1,
14,
1,
1,
OBLIGATION_COLLATERAL_LEN + (OBLIGATION_LIQUIDITY_LEN * (MAX_OBLIGATION_RESERVES - 1))
Expand Down Expand Up @@ -629,12 +639,15 @@ impl Pack for Obligation {
borrows,
deposited_value: unpack_decimal(deposited_value),
borrowed_value: unpack_decimal(borrowed_value),
unweighted_borrowed_value: unpack_decimal(true_borrowed_value),
unweighted_borrowed_value: unpack_decimal(unweighted_borrowed_value),
borrowed_value_upper_bound: unpack_decimal(borrowed_value_upper_bound),
allowed_borrow_value: unpack_decimal(allowed_borrow_value),
unhealthy_borrow_value: unpack_decimal(unhealthy_borrow_value),
super_unhealthy_borrow_value: unpack_decimal(super_unhealthy_borrow_value),
borrowing_isolated_asset: unpack_bool(borrowing_isolated_asset)?,
updated_borrow_attribution_after_upgrade: unpack_bool(
updated_borrow_attribution_after_upgrade,
)?,
})
}
}
Expand Down Expand Up @@ -685,6 +698,7 @@ mod test {
unhealthy_borrow_value: rand_decimal(),
super_unhealthy_borrow_value: rand_decimal(),
borrowing_isolated_asset: rng.gen(),
updated_borrow_attribution_after_upgrade: rng.gen(),
};

let mut packed = [0u8; OBLIGATION_LEN];
Expand Down

0 comments on commit e0807ca

Please sign in to comment.