Skip to content

Commit

Permalink
changing added price weight to be i64
Browse files Browse the repository at this point in the history
  • Loading branch information
0xripleys committed Dec 13, 2023
1 parent 6cd9140 commit 52e21c0
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 38 deletions.
79 changes: 57 additions & 22 deletions token-lending/program/tests/refresh_reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,33 +358,34 @@ async fn test_success_only_switchboard_reserve() {

#[tokio::test]
async fn test_use_price_weight() {
let (mut test, lending_market, reserves, _obligations, _users, _) = custom_scenario(
&[ReserveArgs {
mint: wsol_mint::id(),
config: ReserveConfig {
added_price_weight_bps: 5_000,
..test_reserve_config()
},
liquidity_amount: 100_000 * FRACTIONAL_TO_USDC,
price: PriceArgs {
price: 10,
conf: 0,
expo: 0,
ema_price: 10,
ema_conf: 0,
},
}],
&[],
)
.await;
let (mut test, lending_market, reserves, _obligations, _users, lending_market_owner) =
custom_scenario(
&[ReserveArgs {
mint: wsol_mint::id(),
config: ReserveConfig {
added_price_weight_bps: 2_000,
..test_reserve_config()
},
liquidity_amount: 100_000 * FRACTIONAL_TO_USDC,
price: PriceArgs {
price: 10,
conf: 0,
expo: 0,
ema_price: 10,
ema_conf: 0,
},
}],
&[],
)
.await;

test.set_price(
&wsol_mint::id(),
&PriceArgs {
price: 10,
conf: 0,
expo: 0,
ema_price: 12,
ema_price: 20,
ema_conf: 0,
},
)
Expand All @@ -400,10 +401,44 @@ async fn test_use_price_weight() {
let wsol_reserve = test.load_account::<Reserve>(reserves[0].pubkey).await;
assert_eq!(
wsol_reserve.account.liquidity.market_price,
Decimal::from(15u64)
Decimal::from(12u64)
);
assert_eq!(
wsol_reserve.account.liquidity.smoothed_market_price,
Decimal::from(24u64)
);

test.advance_clock_by_slots(1).await;

lending_market
.update_reserve_config(
&mut test,
&lending_market_owner,
&wsol_reserve,
ReserveConfig {
added_price_weight_bps: -2_000,
..wsol_reserve.account.config
},
wsol_reserve.account.rate_limiter.config,
None,
)
.await
.unwrap();

test.advance_clock_by_slots(1).await;

lending_market
.refresh_reserve(&mut test, &reserves[0])
.await
.unwrap();

let wsol_reserve = test.load_account::<Reserve>(reserves[0].pubkey).await;
assert_eq!(
wsol_reserve.account.liquidity.market_price,
Decimal::from(8u64)
);
assert_eq!(
wsol_reserve.account.liquidity.smoothed_market_price,
Decimal::from(18u64)
Decimal::from(16u64)
);
}
22 changes: 18 additions & 4 deletions token-lending/sdk/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ impl LendingInstruction {
let (asset_type, rest) = Self::unpack_u8(rest)?;
let (max_liquidation_bonus, rest) = Self::unpack_u8(rest)?;
let (max_liquidation_threshold, rest) = Self::unpack_u8(rest)?;
let (added_price_weight_bps, _rest) = Self::unpack_u64(rest)?;
let (added_price_weight_bps, _rest) = Self::unpack_i64(rest)?;
Self::InitReserve {
liquidity_amount,
config: ReserveConfig {
Expand Down Expand Up @@ -658,7 +658,7 @@ impl LendingInstruction {
let (asset_type, rest) = Self::unpack_u8(rest)?;
let (max_liquidation_bonus, rest) = Self::unpack_u8(rest)?;
let (max_liquidation_threshold, rest) = Self::unpack_u8(rest)?;
let (added_price_weight_bps, rest) = Self::unpack_u64(rest)?;
let (added_price_weight_bps, rest) = Self::unpack_i64(rest)?;
let (window_duration, rest) = Self::unpack_u64(rest)?;
let (max_outflow, _rest) = Self::unpack_u64(rest)?;

Expand Down Expand Up @@ -738,6 +738,20 @@ impl LendingInstruction {
Ok((value, rest))
}

fn unpack_i64(input: &[u8]) -> Result<(i64, &[u8]), ProgramError> {
if input.len() < 8 {
msg!("i64 cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
}
let (bytes, rest) = input.split_at(8);
let value = bytes
.get(..8)
.and_then(|slice| slice.try_into().ok())
.map(i64::from_le_bytes)
.ok_or(LendingError::InstructionUnpackError)?;
Ok((value, rest))
}

fn unpack_u8(input: &[u8]) -> Result<(u8, &[u8]), ProgramError> {
if input.is_empty() {
msg!("u8 cannot be unpacked");
Expand Down Expand Up @@ -1764,7 +1778,7 @@ mod test {
protocol_take_rate: rng.gen::<u8>(),
added_borrow_weight_bps: rng.gen::<u64>(),
reserve_type: ReserveType::from_u8(rng.gen::<u8>() % 2).unwrap(),
added_price_weight_bps: rng.gen::<u64>(),
added_price_weight_bps: rng.gen(),
},
};

Expand Down Expand Up @@ -1925,7 +1939,7 @@ mod test {
protocol_take_rate: rng.gen::<u8>(),
added_borrow_weight_bps: rng.gen::<u64>(),
reserve_type: ReserveType::from_u8(rng.gen::<u8>() % 2).unwrap(),
added_price_weight_bps: rng.gen::<u64>(),
added_price_weight_bps: rng.gen(),
},
rate_limiter_config: RateLimiterConfig {
window_duration: rng.gen::<u64>(),
Expand Down
51 changes: 39 additions & 12 deletions token-lending/sdk/src/state/reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ pub const MAX_BONUS_PCT: u8 = 25;
/// Maximum protocol liquidation fee in deca bps (1 deca bp = 10 bps)
pub const MAX_PROTOCOL_LIQUIDATION_FEE_DECA_BPS: u8 = 50;

/// Upper bound on price weight
pub const MAX_PRICE_WEIGHT_BPS: u64 = 10000;
/// Upper bound on added price weight
pub const MAX_ADDED_PRICE_WEIGHT_BPS: i64 = 2000;

/// Lower bound on added price weight
pub const MIN_ADDED_PRICE_WEIGHT_BPS: i64 = -2000;

/// Lending market reserve state
#[derive(Clone, Debug, Default, PartialEq)]
Expand Down Expand Up @@ -85,9 +88,16 @@ impl Reserve {

/// get price weight. Guaranteed to be greater than 1
pub fn price_weight(&self) -> Decimal {
Decimal::one()
.try_add(Decimal::from_bps(self.config.added_price_weight_bps))
.unwrap()
let added_price_weight_bps = min(
MAX_ADDED_PRICE_WEIGHT_BPS,
max(
MIN_ADDED_PRICE_WEIGHT_BPS,
self.config.added_price_weight_bps,
),
);

let price_weight_bps = 10_000 + added_price_weight_bps;
Decimal::from_bps(price_weight_bps as u64)
}

/// get loan to value ratio as a Rate
Expand Down Expand Up @@ -912,7 +922,7 @@ pub struct ReserveConfig {
pub reserve_type: ReserveType,
/// Added price weight in basis points. Exclusively used to calculate a more reliable asset price for
/// staked assets (mSOL, stETH).
pub added_price_weight_bps: u64,
pub added_price_weight_bps: i64,
}

/// validates reserve configs
Expand Down Expand Up @@ -1001,10 +1011,13 @@ pub fn validate_reserve_config(config: ReserveConfig) -> ProgramResult {
return Err(LendingError::InvalidConfig.into());
}

if config.added_price_weight_bps > MAX_PRICE_WEIGHT_BPS {
if config.added_price_weight_bps < MIN_ADDED_PRICE_WEIGHT_BPS
|| config.added_price_weight_bps > MAX_ADDED_PRICE_WEIGHT_BPS
{
msg!(
"Added price weight must be in range [0, {}]",
MAX_PRICE_WEIGHT_BPS
"Added price weight must be in range [{}, {}]",
MIN_ADDED_PRICE_WEIGHT_BPS,
MAX_ADDED_PRICE_WEIGHT_BPS
);
return Err(LendingError::InvalidConfig.into());
}
Expand Down Expand Up @@ -1489,7 +1502,7 @@ impl Pack for Reserve {
protocol_take_rate: u8::from_le_bytes(*config_protocol_take_rate),
added_borrow_weight_bps: u64::from_le_bytes(*config_added_borrow_weight_bps),
reserve_type: ReserveType::from_u8(config_asset_type[0]).unwrap(),
added_price_weight_bps: u64::from_le_bytes(*config_added_price_weight_bps),
added_price_weight_bps: i64::from_le_bytes(*config_added_price_weight_bps),
},
rate_limiter: RateLimiter::unpack_from_slice(rate_limiter)?,
})
Expand Down Expand Up @@ -2125,14 +2138,28 @@ mod test {
}),
Just(ReserveConfigTestCase {
config: ReserveConfig {
added_price_weight_bps: 10001,
added_price_weight_bps: 2001,
..ReserveConfig::default()
},
result: Err(LendingError::InvalidConfig.into()),
}),
Just(ReserveConfigTestCase {
config: ReserveConfig {
added_price_weight_bps: 1999,
..ReserveConfig::default()
},
result: Ok(())
}),
Just(ReserveConfigTestCase {
config: ReserveConfig {
added_price_weight_bps: -2001,
..ReserveConfig::default()
},
result: Err(LendingError::InvalidConfig.into()),
}),
Just(ReserveConfigTestCase {
config: ReserveConfig {
added_price_weight_bps: 9999,
added_price_weight_bps: -1999,
..ReserveConfig::default()
},
result: Ok(())
Expand Down

0 comments on commit 52e21c0

Please sign in to comment.