Skip to content

Commit

Permalink
Add instruction to update the LTV of a reserve
Browse files Browse the repository at this point in the history
  • Loading branch information
DaSichuan committed Jul 15, 2021
1 parent b7f7207 commit bdcdbc1
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
32 changes: 32 additions & 0 deletions token-lending/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,22 @@ pub enum LendingInstruction {
/// liquidity_amount is the amount of collateral tokens to withdraw
collateral_amount: u64,
},

// 16
/// Updates a reserve config parameter
///
/// Accounts expected by this instruction:
///
/// 1. `[writable]` Reserve account - refreshed
/// 2 `[]` Lending market account.
/// 3 `[]` Derived lending market authority.
/// 4 `[signer]` Lending market owner.
UpdateReserveConfig {
/// Specifies which config to change
config_enum: u8,
/// New value for the config
new_value: u8,
},
}

impl LendingInstruction {
Expand Down Expand Up @@ -456,6 +472,14 @@ impl LendingInstruction {
let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
Self::WithdrawObligationCollateralAndRedeemReserveCollateral { collateral_amount }
}
16 => {
let (config_enum, _rest) = Self::unpack_u8(rest)?;
let (new_value, _rest) = Self::unpack_u8(_rest)?;
Self::UpdateReserveConfig {
config_enum,
new_value,
}
}
_ => {
msg!("Instruction cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
Expand Down Expand Up @@ -612,6 +636,14 @@ impl LendingInstruction {
buf.push(15);
buf.extend_from_slice(&collateral_amount.to_le_bytes());
}
Self::UpdateReserveConfig {
config_enum,
new_value,
} => {
buf.push(16);
buf.extend_from_slice(&config_enum.to_le_bytes());
buf.extend_from_slice(&new_value.to_le_bytes());
}
}
buf
}
Expand Down
78 changes: 76 additions & 2 deletions token-lending/program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
CalculateBorrowResult, CalculateLiquidationResult, CalculateRepayResult,
InitLendingMarketParams, InitObligationParams, InitReserveParams, LendingMarket,
NewReserveCollateralParams, NewReserveLiquidityParams, Obligation, Reserve,
ReserveCollateral, ReserveConfig, ReserveLiquidity,
ReserveCollateral, ReserveConfig, ReserveConfigKey, ReserveLiquidity,
},
};
use num_traits::FromPrimitive;
Expand Down Expand Up @@ -114,13 +114,25 @@ pub fn process_instruction(
LendingInstruction::WithdrawObligationCollateralAndRedeemReserveCollateral {
collateral_amount,
} => {
msg!("Instruction: Withdraw Obligation Collateral and Redeem Reserve Collateral ");
msg!("Instruction: Withdraw Obligation Collateral and Redeem Reserve Collateral");
process_withdraw_obligation_collateral_and_redeem_reserve_liquidity(
program_id,
collateral_amount,
accounts,
)
}
LendingInstruction::UpdateReserveConfig {
config_enum,
new_value,
} => {
msg!("Instruction: UpdateReserveConfig");
process_update_reserve_config(
program_id,
ReserveConfigKey::from_u8(config_enum)?,
new_value,
accounts,
)
}
}
}

Expand Down Expand Up @@ -1994,6 +2006,68 @@ fn process_withdraw_obligation_collateral_and_redeem_reserve_liquidity(
)
}

#[inline(never)] // avoid stack frame limit
fn process_update_reserve_config(
program_id: &Pubkey,
config_enum: ReserveConfigKey,
new_value: u8,
accounts: &[AccountInfo],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter().peekable();
let reserve_info = next_account_info(account_info_iter)?;
let lending_market_info = next_account_info(account_info_iter)?;
let lending_market_authority_info = next_account_info(account_info_iter)?;
let lending_market_owner_info = next_account_info(account_info_iter)?;

let mut reserve = assert_uninitialized::<Reserve>(reserve_info)?;
if reserve_info.owner != program_id {
msg!(
"Reserve provided is not owned by the lending program {} != {}",
&reserve_info.owner.to_string(),
&program_id.to_string(),
);
return Err(LendingError::InvalidAccountOwner.into());
}

let lending_market = LendingMarket::unpack(&lending_market_info.data.borrow())?;
if lending_market_info.owner != program_id {
msg!(
"Lending market provided is not owned by the lending program {} != {}",
&lending_market_info.owner.to_string(),
&program_id.to_string(),
);
return Err(LendingError::InvalidAccountOwner.into());
}
if &lending_market.owner != lending_market_owner_info.key {
msg!("Lending market owner does not match the lending market owner provided");
return Err(LendingError::InvalidMarketOwner.into());
}
if !lending_market_owner_info.is_signer {
msg!("Lending market owner provided must be a signer");
return Err(LendingError::InvalidSigner.into());
}

let authority_signer_seeds = &[
lending_market_info.key.as_ref(),
&[lending_market.bump_seed],
];
let lending_market_authority_pubkey =
Pubkey::create_program_address(authority_signer_seeds, program_id)?;
if &lending_market_authority_pubkey != lending_market_authority_info.key {
msg!(
"Derived lending market authority does not match the lending market authority provided"
);
return Err(LendingError::InvalidMarketAuthority.into());
}
match config_enum {
ReserveConfigKey::LoanToValueRatio => {
reserve.config.loan_to_value_ratio = new_value;
}
};
Reserve::pack(reserve, &mut reserve_info.data.borrow_mut())?;
Ok(())
}

fn assert_rent_exempt(rent: &Rent, account_info: &AccountInfo) -> ProgramResult {
if !rent.is_exempt(account_info.lamports(), account_info.data_len()) {
msg!(
Expand Down
17 changes: 17 additions & 0 deletions token-lending/program/src/state/reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,23 @@ pub struct ReserveConfig {
pub fees: ReserveFees,
}

/// ReserveConfig configurable values
#[repr(u8)]
pub enum ReserveConfigKey {
/// Enum to specify LoanToValueRatio
LoanToValueRatio = 0,
}

impl ReserveConfigKey {
/// returns the ReserveConfigKey corresponding to the integer
pub fn from_u8(value: u8) -> Result<ReserveConfigKey, ProgramError> {
match value {
0 => Ok(ReserveConfigKey::LoanToValueRatio),
_ => Err(LendingError::InvalidConfig.into()),
}
}
}

/// Additional fee information on a reserve
///
/// These exist separately from interest accrual fees, and are specifically for the program owner
Expand Down

0 comments on commit bdcdbc1

Please sign in to comment.