diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/admin/collect_protocol_fees.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/admin/collect_protocol_fees.rs index 2e0b0061..b7f71b1c 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/admin/collect_protocol_fees.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/admin/collect_protocol_fees.rs @@ -16,7 +16,9 @@ pub fn handle_collect_protocol_fees(context: Context) -> Re let reserve = &mut context.accounts.reserve; // Fees are a claim on liquidity; only what is currently un-borrowed can be paid // out right now. Any remainder stays owed until borrowers repay. - let amount = reserve.accumulated_protocol_fees.min(reserve.available_liquidity); + let amount = reserve + .accumulated_protocol_fees + .min(reserve.available_liquidity); require!(amount > 0, LendingError::NothingToCollect); reserve.accumulated_protocol_fees = reserve diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/admin/initialize_reserve.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/admin/initialize_reserve.rs index 16bd5c8b..e69bf8e6 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/admin/initialize_reserve.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/admin/initialize_reserve.rs @@ -6,7 +6,10 @@ use crate::constants::{ }; use crate::state::{LendingMarket, PriceFeed, Reserve, ReserveConfig}; -pub fn handle_initialize_reserve(context: Context, config: ReserveConfig) -> Result<()> { +pub fn handle_initialize_reserve( + context: Context, + config: ReserveConfig, +) -> Result<()> { config.validate()?; let reserve = &mut context.accounts.reserve; diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/liquidate_obligation.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/liquidate_obligation.rs index 4fddd3bc..e79d541a 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/liquidate_obligation.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/liquidate_obligation.rs @@ -61,7 +61,8 @@ pub fn handle_liquidate_obligation( repay_reserve.config.close_factor_bps as u128, BPS_DENOMINATOR, )?; - let repay = liquidity_amount.min(u64::try_from(max_repay).map_err(|_| LendingError::MathOverflow)?); + let repay = + liquidity_amount.min(u64::try_from(max_repay).map_err(|_| LendingError::MathOverflow)?); require!(repay > 0, LendingError::ZeroAmount); // Collateral to seize: value of the repayment plus the bonus, converted into @@ -99,8 +100,8 @@ pub fn handle_liquidate_obligation( LendingError::LiquidationTooLarge ); - let scaled_removed = - mul_div_floor(repay as u128, FIXED_POINT_SCALE, accumulation_factor)?.min(borrowed_principal); + let scaled_removed = mul_div_floor(repay as u128, FIXED_POINT_SCALE, accumulation_factor)? + .min(borrowed_principal); // Effects: repay side. { @@ -150,14 +151,25 @@ pub fn handle_liquidate_obligation( )?; let bump = [obligation_bump]; - let seeds: [&[u8]; 4] = [OBLIGATION_SEED, lending_market.as_ref(), owner.as_ref(), &bump]; + let seeds: [&[u8]; 4] = [ + OBLIGATION_SEED, + lending_market.as_ref(), + owner.as_ref(), + &bump, + ]; transfer_checked( CpiContext::new_with_signer( context.accounts.token_program.key(), TransferChecked { - from: context.accounts.obligation_collateral_vault.to_account_info(), + from: context + .accounts + .obligation_collateral_vault + .to_account_info(), mint: context.accounts.collateral_share_mint.to_account_info(), - to: context.accounts.liquidator_collateral_dest.to_account_info(), + to: context + .accounts + .liquidator_collateral_dest + .to_account_info(), authority: context.accounts.obligation.to_account_info(), }, &[&seeds], diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/redeem_reserve_collateral.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/redeem_reserve_collateral.rs index 7ece3a5d..c1caf242 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/redeem_reserve_collateral.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/redeem_reserve_collateral.rs @@ -21,13 +21,17 @@ pub fn handle_redeem_reserve_collateral( let reserve = &mut context.accounts.reserve; reserve.require_refreshed()?; - require!(reserve.share_mint_supply > 0, LendingError::InsufficientReserveLiquidity); + require!( + reserve.share_mint_supply > 0, + LendingError::InsufficientReserveLiquidity + ); let liquidity_amount = mul_div_floor( share_amount as u128, reserve.total_liquidity()?, reserve.total_shares()?, )?; - let liquidity_amount = u64::try_from(liquidity_amount).map_err(|_| LendingError::MathOverflow)?; + let liquidity_amount = + u64::try_from(liquidity_amount).map_err(|_| LendingError::MathOverflow)?; require!( liquidity_amount <= reserve.available_liquidity, LendingError::InsufficientReserveLiquidity diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/refresh_obligation.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/refresh_obligation.rs index 758113ca..b3b9db6f 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/refresh_obligation.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/refresh_obligation.rs @@ -27,8 +27,13 @@ pub fn handle_refresh_obligation(context: Context) -> Result< let mut unhealthy_borrow_value: u128 = 0; for collateral in obligation.deposits.iter_mut() { - let (reserve, price_scaled) = - read_pair(accounts, &mut cursor, collateral.reserve, lending_market, slot)?; + let (reserve, price_scaled) = read_pair( + accounts, + &mut cursor, + collateral.reserve, + lending_market, + slot, + )?; let liquidity = mul_div_floor( collateral.deposited_shares as u128, @@ -36,7 +41,12 @@ pub fn handle_refresh_obligation(context: Context) -> Result< reserve.total_shares()?, )?; let liquidity = u64::try_from(liquidity).map_err(|_| LendingError::MathOverflow)?; - let value = market_value(liquidity, reserve.liquidity_decimals, price_scaled, Rounding::Down)?; + let value = market_value( + liquidity, + reserve.liquidity_decimals, + price_scaled, + Rounding::Down, + )?; collateral.market_value = value; deposited_value = deposited_value diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/repay_obligation_liquidity.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/repay_obligation_liquidity.rs index d71a4217..7d36c2de 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/repay_obligation_liquidity.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/repay_obligation_liquidity.rs @@ -31,7 +31,8 @@ pub fn handle_repay_obligation_liquidity( let repay = liquidity_amount.min(debt_now); require!(repay > 0, LendingError::ZeroAmount); - let scaled_removed = mul_div_floor(repay as u128, FIXED_POINT_SCALE, index)?.min(borrowed_principal); + let scaled_removed = + mul_div_floor(repay as u128, FIXED_POINT_SCALE, index)?.min(borrowed_principal); { let reserve = &mut context.accounts.reserve; diff --git a/finance/lending/anchor-v1/programs/lending/src/instructions/withdraw_obligation_collateral.rs b/finance/lending/anchor-v1/programs/lending/src/instructions/withdraw_obligation_collateral.rs index ac603c5f..b31becfc 100644 --- a/finance/lending/anchor-v1/programs/lending/src/instructions/withdraw_obligation_collateral.rs +++ b/finance/lending/anchor-v1/programs/lending/src/instructions/withdraw_obligation_collateral.rs @@ -41,7 +41,8 @@ pub fn handle_withdraw_obligation_collateral( reserve.total_liquidity()?, reserve.total_shares()?, )?; - let removed_liquidity = u64::try_from(removed_liquidity).map_err(|_| LendingError::MathOverflow)?; + let removed_liquidity = + u64::try_from(removed_liquidity).map_err(|_| LendingError::MathOverflow)?; let removed_value = market_value( removed_liquidity, reserve.liquidity_decimals, diff --git a/finance/lending/anchor-v1/programs/lending/src/lib.rs b/finance/lending/anchor-v1/programs/lending/src/lib.rs index 462b3be7..4527fba1 100644 --- a/finance/lending/anchor-v1/programs/lending/src/lib.rs +++ b/finance/lending/anchor-v1/programs/lending/src/lib.rs @@ -2,8 +2,8 @@ use anchor_lang::prelude::*; pub mod constants; pub mod errors; -pub mod math; pub mod instructions; +pub mod math; pub mod state; use instructions::*; @@ -22,7 +22,10 @@ pub mod lending { instructions::handle_initialize_lending_market(context, market_id) } - pub fn initialize_reserve(context: Context, config: ReserveConfig) -> Result<()> { + pub fn initialize_reserve( + context: Context, + config: ReserveConfig, + ) -> Result<()> { instructions::handle_initialize_reserve(context, config) } diff --git a/finance/lending/anchor-v1/programs/lending/src/state/obligation.rs b/finance/lending/anchor-v1/programs/lending/src/state/obligation.rs index 20be5b92..cc6ded7a 100644 --- a/finance/lending/anchor-v1/programs/lending/src/state/obligation.rs +++ b/finance/lending/anchor-v1/programs/lending/src/state/obligation.rs @@ -75,7 +75,11 @@ impl Obligation { /// Index of the collateral entry for `reserve`, creating an empty one if the /// obligation has room. Used when posting collateral. pub fn upsert_collateral(&mut self, reserve: Pubkey) -> Result { - if let Some(index) = self.deposits.iter().position(|entry| entry.reserve == reserve) { + if let Some(index) = self + .deposits + .iter() + .position(|entry| entry.reserve == reserve) + { return Ok(index); } require!( @@ -93,7 +97,11 @@ impl Obligation { /// Index of the borrow entry for `reserve`, creating an empty one if the /// obligation has room. Used when borrowing. pub fn upsert_borrow(&mut self, reserve: Pubkey) -> Result { - if let Some(index) = self.borrows.iter().position(|entry| entry.reserve == reserve) { + if let Some(index) = self + .borrows + .iter() + .position(|entry| entry.reserve == reserve) + { return Ok(index); } require!( diff --git a/finance/lending/anchor-v1/programs/lending/src/state/price_feed.rs b/finance/lending/anchor-v1/programs/lending/src/state/price_feed.rs index cedfa148..eff98e87 100644 --- a/finance/lending/anchor-v1/programs/lending/src/state/price_feed.rs +++ b/finance/lending/anchor-v1/programs/lending/src/state/price_feed.rs @@ -45,7 +45,10 @@ impl PriceFeed { let age = current_slot .checked_sub(self.last_updated_slot) .ok_or(LendingError::MathOverflow)?; - require!(age <= MAX_PRICE_STALENESS_SLOTS, LendingError::StalePriceFeed); + require!( + age <= MAX_PRICE_STALENESS_SLOTS, + LendingError::StalePriceFeed + ); // Restart handling. A cluster halt stops the slot count but not the // wall clock, so after a restart a feed can look fresh in slots while diff --git a/finance/lending/anchor-v1/programs/lending/src/state/reserve.rs b/finance/lending/anchor-v1/programs/lending/src/state/reserve.rs index 34bd8263..db844ac4 100644 --- a/finance/lending/anchor-v1/programs/lending/src/state/reserve.rs +++ b/finance/lending/anchor-v1/programs/lending/src/state/reserve.rs @@ -189,7 +189,11 @@ impl Reserve { if gross == 0 { return Ok(0); } - mul_div_floor(self.current_borrowed_amount()? as u128, BPS_DENOMINATOR, gross) + mul_div_floor( + self.current_borrowed_amount()? as u128, + BPS_DENOMINATOR, + gross, + ) } /// Per-second borrow rate (FIXED_POINT_SCALE-scaled) from the kinked curve: diff --git a/finance/lending/anchor-v1/programs/lending/tests/common/mod.rs b/finance/lending/anchor-v1/programs/lending/tests/common/mod.rs index b396c847..ef59d250 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/common/mod.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/common/mod.rs @@ -118,7 +118,9 @@ impl Env { } pub fn current_slot(&self) -> u64 { - self.svm.get_sysvar::().slot + self.svm + .get_sysvar::() + .slot } /// Create a second lending market owned by `market_owner`, for tests that @@ -141,7 +143,13 @@ impl Env { .to_account_metas(None), data: lending::instruction::InitializeLendingMarket { market_id }.data(), }; - send(&mut self.svm, vec![instruction], &[market_owner], &market_owner.pubkey()).unwrap(); + send( + &mut self.svm, + vec![instruction], + &[market_owner], + &market_owner.pubkey(), + ) + .unwrap(); market } @@ -181,7 +189,13 @@ impl Env { .to_account_metas(None), data: lending::instruction::InitializeReserve { config }.data(), }; - send(&mut self.svm, vec![instruction], &[market_owner], &market_owner.pubkey()).unwrap(); + send( + &mut self.svm, + vec![instruction], + &[market_owner], + &market_owner.pubkey(), + ) + .unwrap(); ReserveHandle { mint, @@ -194,7 +208,9 @@ impl Env { } pub fn current_timestamp(&self) -> i64 { - self.svm.get_sysvar::().unix_timestamp + self.svm + .get_sysvar::() + .unix_timestamp } /// Advance the slot only, leaving the Clock's timestamp where it is. Price @@ -209,7 +225,9 @@ impl Env { /// Move the Clock's timestamp by `seconds` (backwards when negative), /// leaving the slot where it is. Interest accrues on this clock. pub fn shift_timestamp(&mut self, seconds: i64) { - let mut clock = self.svm.get_sysvar::(); + let mut clock = self + .svm + .get_sysvar::(); clock.unix_timestamp += seconds; self.svm.set_sysvar(&clock); self.svm.expire_blockhash(); @@ -228,9 +246,10 @@ impl Env { /// Simulate a cluster restart at `slot`: prices stamped at or before it /// must be rejected until the publisher posts again. pub fn set_last_restart_slot(&mut self, slot: u64) { - self.svm.set_sysvar(&solana_sysvar::last_restart_slot::LastRestartSlot { - last_restart_slot: slot, - }); + self.svm + .set_sysvar(&solana_sysvar::last_restart_slot::LastRestartSlot { + last_restart_slot: slot, + }); } /// The feed PDA the market owner writes for `mint`: seeded by the owner's @@ -390,7 +409,12 @@ impl Env { .data(), }; let refresh = self.refresh_reserve_ix(handle); - send(&mut self.svm, vec![refresh, deposit], &[user], &user.pubkey())?; + send( + &mut self.svm, + vec![refresh, deposit], + &[user], + &user.pubkey(), + )?; Ok(user_share) } @@ -422,11 +446,20 @@ impl Env { data: lending::instruction::RedeemReserveCollateral { share_amount }.data(), }; let refresh = self.refresh_reserve_ix(handle); - send(&mut self.svm, vec![refresh, redeem], &[user], &user.pubkey()) + send( + &mut self.svm, + vec![refresh, redeem], + &[user], + &user.pubkey(), + ) } pub fn initialize_obligation(&mut self, user: &Keypair) -> Pubkey { - let obligation = pda(&[OBLIGATION_SEED, self.market.as_ref(), user.pubkey().as_ref()]); + let obligation = pda(&[ + OBLIGATION_SEED, + self.market.as_ref(), + user.pubkey().as_ref(), + ]); let instruction = Instruction { program_id: lending::id(), accounts: lending::accounts::InitializeObligation { @@ -494,7 +527,8 @@ impl Env { deposit_reserves: &[&ReserveHandle], borrow_reserves: &[&ReserveHandle], ) -> Instruction { - let mut accounts = lending::accounts::RefreshObligation { obligation }.to_account_metas(None); + let mut accounts = + lending::accounts::RefreshObligation { obligation }.to_account_metas(None); for handle in deposit_reserves.iter().chain(borrow_reserves.iter()) { accounts.push(AccountMeta::new_readonly(handle.reserve, false)); accounts.push(AccountMeta::new_readonly(handle.price_feed, false)); @@ -540,7 +574,11 @@ impl Env { refresh_set.push(borrow); let mut instructions = self.refresh_all_ix(&refresh_set); - instructions.push(self.refresh_obligation_ix(obligation, existing_deposits, existing_borrows)); + instructions.push(self.refresh_obligation_ix( + obligation, + existing_deposits, + existing_borrows, + )); instructions.push(self.borrow_ix(user, obligation, borrow, amount)); send(&mut self.svm, instructions, &[user], &user.pubkey()) } @@ -635,7 +673,11 @@ impl Env { all.extend_from_slice(borrow_reserves); let mut instructions = self.refresh_all_ix(&all); - instructions.push(self.refresh_obligation_ix(obligation, deposit_reserves, borrow_reserves)); + instructions.push(self.refresh_obligation_ix( + obligation, + deposit_reserves, + borrow_reserves, + )); instructions.push(Instruction { program_id: lending::id(), accounts: lending::accounts::WithdrawObligationCollateral { @@ -683,7 +725,11 @@ impl Env { let mut all: Vec<&ReserveHandle> = deposit_reserves.to_vec(); all.extend_from_slice(borrow_reserves); let mut instructions = self.refresh_all_ix(&all); - instructions.push(self.refresh_obligation_ix(obligation, deposit_reserves, borrow_reserves)); + instructions.push(self.refresh_obligation_ix( + obligation, + deposit_reserves, + borrow_reserves, + )); instructions.push(Instruction { program_id: lending::id(), accounts: lending::accounts::LiquidateObligation { @@ -707,7 +753,12 @@ impl Env { } .data(), }); - send(&mut self.svm, instructions, &[liquidator], &liquidator.pubkey()) + send( + &mut self.svm, + instructions, + &[liquidator], + &liquidator.pubkey(), + ) } /// Send a lone `refresh_reserve` so accrued interest lands in the index. @@ -756,7 +807,13 @@ impl Env { .to_account_metas(None), data: lending::instruction::CollectProtocolFees {}.data(), }; - send(&mut self.svm, vec![refresh, collect], &[&owner], &owner.pubkey()).unwrap(); + send( + &mut self.svm, + vec![refresh, collect], + &[&owner], + &owner.pubkey(), + ) + .unwrap(); owner_liquidity } diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_borrow_repay.rs b/finance/lending/anchor-v1/programs/lending/tests/test_borrow_repay.rs index 9d829e4a..db241083 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_borrow_repay.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_borrow_repay.rs @@ -7,7 +7,13 @@ use solana_signer::Signer; /// One market with a collateral reserve and a separately-supplied borrow /// reserve, plus a borrower who has posted 1000 units of collateral (value /// $1000, so 75% LTV => $750 borrow power). Both tokens priced at $1, 6 decimals. -fn setup() -> (Env, ReserveHandle, ReserveHandle, Keypair, anchor_lang::prelude::Pubkey) { +fn setup() -> ( + Env, + ReserveHandle, + ReserveHandle, + Keypair, + anchor_lang::prelude::Pubkey, +) { let mut env = Env::new(); let collateral = env.add_reserve(6, dollars(1), default_config()); let borrow = env.add_reserve(6, dollars(1), default_config()); @@ -32,15 +38,29 @@ fn borrow_up_to_max_ltv_then_one_more_fails() { let (mut env, collateral, borrow, borrower, obligation) = setup(); // $750 of borrow power, borrowing a $1 token => 750 units exactly. - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 750_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 750_000_000, + ) + .unwrap(); assert_eq!( env.token_balance(ata(&borrower.pubkey(), &borrow.mint)), 750_000_000 ); // One more unit exceeds the allowed borrow value. - let result = env.try_borrow(&borrower, obligation, &[&collateral], &[&borrow], &borrow, 1); + let result = env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[&borrow], + &borrow, + 1, + ); assert!( result.unwrap_err().contains("BorrowTooLarge"), "borrowing past the LTV limit must be rejected" @@ -65,7 +85,14 @@ fn borrow_with_stale_price_feed_is_rejected() { let (mut env, collateral, borrow, borrower, obligation) = setup(); // Advance well past the staleness window without re-publishing prices. env.warp_slots(50); - let result = env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 100_000_000); + let result = env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 100_000_000, + ); assert!(result.unwrap_err().contains("StalePriceFeed")); } @@ -83,7 +110,14 @@ fn borrow_with_price_from_before_a_restart_is_rejected() { env.warp_slots(5); env.set_last_restart_slot(restart_slot); - let result = env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 100_000_000); + let result = env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 100_000_000, + ); assert!( result.unwrap_err().contains("PricePredatesRestart"), "a pre-restart price must be rejected even inside the staleness window" @@ -96,15 +130,29 @@ fn borrow_with_price_from_before_a_restart_is_rejected() { env.warp_slots(1); env.set_price(collateral.mint, dollars(1)); env.set_price(borrow.mint, dollars(1)); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 100_000_000) - .expect("a freshly published price must be accepted after a restart"); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 100_000_000, + ) + .expect("a freshly published price must be accepted after a restart"); } #[test] fn repay_reduces_debt_and_over_repay_clamps() { let (mut env, collateral, borrow, borrower, obligation) = setup(); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 500_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 500_000_000, + ) + .unwrap(); assert_eq!(env.reserve(&borrow).borrowed_principal > 0, true); env.repay(&borrower, obligation, &borrow, 200_000_000); @@ -120,8 +168,15 @@ fn repay_reduces_debt_and_over_repay_clamps() { #[test] fn withdraw_blocked_while_borrowed_then_allowed_after_repay() { let (mut env, collateral, borrow, borrower, obligation) = setup(); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 750_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 750_000_000, + ) + .unwrap(); // At the LTV limit, withdrawing any collateral would undercollateralize. let blocked = env.try_withdraw_collateral( diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_deposit_redeem.rs b/finance/lending/anchor-v1/programs/lending/tests/test_deposit_redeem.rs index c96d65c5..e92c4adc 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_deposit_redeem.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_deposit_redeem.rs @@ -52,8 +52,14 @@ fn raw_token_donation_does_not_inflate_exchange_rate() { // Attacker donates raw tokens straight into the reserve vault. available_liquidity // is the source of truth, so this must NOT change the share exchange rate. let owner = env.owner.insecure_clone(); - mint_tokens_to_token_account(&mut env.svm, &usdc.mint, &usdc.liquidity_vault, amount, &owner) - .unwrap(); + mint_tokens_to_token_account( + &mut env.svm, + &usdc.mint, + &usdc.liquidity_vault, + amount, + &owner, + ) + .unwrap(); let second = env.create_user(); env.fund(&second, usdc.mint, amount); @@ -95,7 +101,10 @@ fn sole_supplier_leaves_the_minimum_behind() { let shares = env.token_balance(share_account); env.try_redeem(&supplier, &usdc, shares).unwrap(); - assert_eq!(env.token_balance(liquidity_account), amount - MINIMUM_SHARES); + assert_eq!( + env.token_balance(liquidity_account), + amount - MINIMUM_SHARES + ); let reserve = env.reserve(&usdc); assert_eq!(reserve.share_mint_supply, 0); assert_eq!(reserve.available_liquidity, MINIMUM_SHARES); diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_interest.rs b/finance/lending/anchor-v1/programs/lending/tests/test_interest.rs index f802ed05..37e7fcb3 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_interest.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_interest.rs @@ -1,6 +1,6 @@ mod common; -use common::{default_config, dollars, ata, Env, TENTH_OF_A_YEAR}; +use common::{ata, default_config, dollars, Env, TENTH_OF_A_YEAR}; use lending::constants::FIXED_POINT_SCALE; use solana_signer::Signer; @@ -26,10 +26,20 @@ fn interest_accrues_on_borrows_over_time() { env.supply(&borrower, &collateral, 1_000_000_000); let obligation = env.initialize_obligation(&borrower); env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 500_000_000) - .unwrap(); - - assert_eq!(env.reserve(&borrow).borrow_accumulation_factor, FIXED_POINT_SCALE); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 500_000_000, + ) + .unwrap(); + + assert_eq!( + env.reserve(&borrow).borrow_accumulation_factor, + FIXED_POINT_SCALE + ); // Let a tenth of a year pass, then re-publish prices and refresh. env.warp_seconds(TENTH_OF_A_YEAR); @@ -80,8 +90,15 @@ fn protocol_fees_accrue_and_owner_can_collect() { env.supply(&borrower, &collateral, 1_000_000_000); let obligation = env.initialize_obligation(&borrower); env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 500_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 500_000_000, + ) + .unwrap(); // No interest has accrued yet, so no fees. assert_eq!(env.reserve(&borrow).accumulated_protocol_fees, 0); @@ -95,7 +112,7 @@ fn protocol_fees_accrue_and_owner_can_collect() { assert!(fees > 0, "protocol fees should accrue once interest does"); let total_interest = reserve.current_borrowed_amount().unwrap() - 500_000_000; let expected_fee = total_interest / 10; // 1000 bps = 10% - // Allow a 1-unit rounding tolerance from flooring. + // Allow a 1-unit rounding tolerance from flooring. assert!( fees.abs_diff(expected_fee) <= 1, "fees {fees} should be ~10% of interest {total_interest}" diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_liquidation.rs b/finance/lending/anchor-v1/programs/lending/tests/test_liquidation.rs index 2024369d..242561f8 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_liquidation.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_liquidation.rs @@ -28,8 +28,15 @@ fn setup() -> ( env.supply(&borrower, &collateral, 1_000_000_000); let obligation = env.initialize_obligation(&borrower); env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 700_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 700_000_000, + ) + .unwrap(); let liquidator = env.create_user(); env.fund(&liquidator, borrow.mint, 1_000_000_000); @@ -96,7 +103,10 @@ fn unhealthy_obligation_liquidated_with_bonus_capped_by_close_factor() { // The borrower's debt and collateral both dropped. let obligation_state = env.obligation(obligation); - assert_eq!(obligation_state.deposits[0].deposited_shares, 1_000_000_000 - 459_375_000); + assert_eq!( + obligation_state.deposits[0].deposited_shares, + 1_000_000_000 - 459_375_000 + ); } /// A repayment whose seizure would exceed the posted collateral is rejected @@ -134,5 +144,8 @@ fn over_seizing_liquidation_rejected_smaller_succeeds() { ) .unwrap(); let liquidator_collateral_account = ata(&liquidator.pubkey(), &collateral.share_mint); - assert_eq!(env.token_balance(liquidator_collateral_account), 525_000_000); + assert_eq!( + env.token_balance(liquidator_collateral_account), + 525_000_000 + ); } diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_reserve.rs b/finance/lending/anchor-v1/programs/lending/tests/test_reserve.rs index 4a7eabe4..b8786c17 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_reserve.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_reserve.rs @@ -1,8 +1,8 @@ mod common; use common::{default_config, Env}; -use lending::state::Reserve; use lending::constants::FIXED_POINT_SCALE; +use lending::state::Reserve; #[test] fn init_market_and_reserve() { @@ -76,8 +76,15 @@ fn half_borrowed_reserve(env: &mut Env) -> (common::ReserveHandle, common::Reser env.supply(&borrower, &collateral, 1_000_000_000); let obligation = env.initialize_obligation(&borrower); env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 500_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 500_000_000, + ) + .unwrap(); (collateral, borrow) } @@ -134,7 +141,10 @@ fn a_timestamp_behind_the_last_accrual_charges_nothing() { env.shift_timestamp(-600); env.refresh_reserve_only(&refresher, &borrow); let behind = env.reserve(&borrow); - assert_eq!(behind.borrow_accumulation_factor, before.borrow_accumulation_factor); + assert_eq!( + behind.borrow_accumulation_factor, + before.borrow_accumulation_factor + ); assert_eq!(behind.last_accrual_timestamp, before.last_accrual_timestamp); // 1,600 seconds forward from the shifted clock is 1,000 past the stamp. diff --git a/finance/lending/anchor-v1/programs/lending/tests/test_rounding.rs b/finance/lending/anchor-v1/programs/lending/tests/test_rounding.rs index 983be7d6..34aaf15c 100644 --- a/finance/lending/anchor-v1/programs/lending/tests/test_rounding.rs +++ b/finance/lending/anchor-v1/programs/lending/tests/test_rounding.rs @@ -22,13 +22,22 @@ fn deposit_that_would_mint_zero_shares_is_rejected() { env.supply(&borrower, &collateral, 1_000_000_000); let obligation = env.initialize_obligation(&borrower); env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 500_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 500_000_000, + ) + .unwrap(); // Accrue enough interest that total liquidity exceeds the share supply. env.warp_seconds(common::TENTH_OF_A_YEAR); env.refresh_reserve_only(&borrower, &borrow); - assert!(env.reserve(&borrow).borrow_accumulation_factor > lending::constants::FIXED_POINT_SCALE); + assert!( + env.reserve(&borrow).borrow_accumulation_factor > lending::constants::FIXED_POINT_SCALE + ); let dust_depositor = env.create_user(); env.fund(&dust_depositor, borrow.mint, 1); @@ -74,8 +83,15 @@ fn withdraw_at_health_boundary_then_one_more_unit_fails() { env.post_collateral(&borrower, obligation, &collateral, 1_000_000_000); // Borrow $600 against $1000 collateral (75% LTV => $750 power). - env.try_borrow(&borrower, obligation, &[&collateral], &[], &borrow, 600_000_000) - .unwrap(); + env.try_borrow( + &borrower, + obligation, + &[&collateral], + &[], + &borrow, + 600_000_000, + ) + .unwrap(); // Withdrawing $200 of collateral lands exactly on the limit: new power // $750 - 0.75*$200 = $600 == debt. This must pass.