Skip to content

Commit

Permalink
Release v1.7.4 (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
oeble authored Dec 23, 2024
1 parent 68adbcd commit f449cd4
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 26 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ anchor-spl = { version = "0.29.0", features = ["dex", "token"] }
# Solana
solana-program = "~1.17.18"
solana-sdk = "~1.17.18"
solana-program-test = "=1.17.18"
solana-banks-client = "~1.17.18"
solana-banks-interface = "~1.17.18"
solana-address-lookup-table-program = "~1.17.18"
Expand Down
4 changes: 4 additions & 0 deletions programs/klend/src/utils/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ pub const MIN_NET_VALUE_IN_OBLIGATION: Fraction = fraction!(0.000001);

pub const DUST_LAMPORT_THRESHOLD: u64 = 1;

pub const MAX_PRICE_DECIMALS_U256: u32 = 36;

pub const TARGET_PRICE_DECIMALS: u32 = MAX_PRICE_DECIMALS_U256 / 2;

pub fn ten_pow(x: usize) -> u64 {
const POWERS_OF_TEN: [u64; 20] = [
1,
Expand Down
48 changes: 28 additions & 20 deletions programs/klend/src/utils/prices/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::{
};
use crate::{
dbg_msg,
utils::{prices::Price, NULL_PUBKEY, U128},
utils::{prices::Price, MAX_PRICE_DECIMALS_U256, NULL_PUBKEY, TARGET_PRICE_DECIMALS, U256},
LendingError, Result, ScopeConfiguration,
};

Expand Down Expand Up @@ -83,40 +83,48 @@ fn get_price_usd(
return err!(LendingError::NoPriceFound);
}

let price_chain = &price_chain_raw[..chain_len];

if chain_len == 1 {
let price = price_chain[0].unwrap();
let price = price_chain_raw[0].unwrap();
let price_load = Box::new(move || Ok(price_to_fraction(price.0)));
return Ok(TimestampedPrice {
price_load,
timestamp: price.1,
});
}

let oldest_timestamp = price_chain.iter().flatten().map(|x| x.1).min().unwrap();

let oldest_timestamp = price_chain_raw
.iter()
.take(chain_len)
.flatten()
.map(|x| x.1)
.min()
.unwrap();

let init_price: Price<U256> = Price {
value: U256::from(1_u64),
exp: 0,
};
let price_load = Box::new(move || {
let price_chain = &price_chain_raw[..chain_len];
let total_decimals: u32 = price_chain
.iter()
.flatten()
.try_fold(0u32, |acc, price| acc.checked_add(price.0.exp))
.ok_or_else(|| dbg_msg!(LendingError::MathOverflow))?;

let product = price_chain
let base_price = price_chain
.iter()
.flatten()
.try_fold(U128::from(1u128), |acc, price| {
acc.checked_mul(price.0.value.into())
.map(|x| x.0.size_up::<U256>())
.try_fold(init_price, |acc, x| {
let (current_price, next_price) = if acc.exp + x.exp > MAX_PRICE_DECIMALS_U256 {
(
acc.reduce_exp_lossy(TARGET_PRICE_DECIMALS)?,
x.reduce_exp_lossy(TARGET_PRICE_DECIMALS)?,
)
} else {
(acc, x)
};
let value = current_price.value.checked_mul(next_price.value)?;
let exp = current_price.exp + next_price.exp;
Some(Price { value, exp })
})
.ok_or_else(|| dbg_msg!(LendingError::MathOverflow))?;

let base_price = Price {
value: product,
exp: total_decimals,
};

Ok(price_to_fraction(base_price))
});

Expand Down
58 changes: 56 additions & 2 deletions programs/klend/src/utils/prices/types.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,71 @@
use anchor_lang::prelude::*;

use crate::utils::{Fraction, U128};
use super::utils::ten_pow;
use crate::utils::{Fraction, U256};

#[derive(Clone, Copy, Debug, AnchorDeserialize, AnchorSerialize, Default)]
pub(crate) struct Price<T>
where
T: Into<U128>,
T: Into<U256>,
{
pub value: T,

pub exp: u32,
}

impl<T> Price<T>
where
T: Into<U256> + Copy + TryFrom<U256>,
{
pub fn to_adjusted_exp(self, target_exp: u32) -> Option<Price<T>> {
if target_exp == self.exp {
return Some(self);
}
let value: U256 = self.value.into();
let exp = self.exp;

let value_256 = if exp > target_exp {
let diff = exp - target_exp;
let factor = ten_pow(diff).into();
value.checked_div(factor)
} else {
let diff = target_exp - exp;
let factor = ten_pow(diff).into();
value.checked_mul(factor)
};

value_256.and_then(|value| {
Some(Price {
value: T::try_from(value).ok()?,
exp: target_exp,
})
})
}

pub fn reduce_exp_lossy(self, target_exp: u32) -> Option<Price<T>> {
if self.exp <= target_exp {
return Some(self);
}
self.to_adjusted_exp(target_exp)
}
}

impl<T> Price<T>
where
T: Into<U256> + Copy,
{
pub fn size_up<U>(self) -> Price<U>
where
U: From<T> + Into<U256>,
{
let Price { value, exp } = self;
Price {
value: U::from(value),
exp,
}
}
}

pub(super) struct TimestampedPrice {
pub price_load: Box<dyn FnOnce() -> Result<Fraction>>,
pub timestamp: u64,
Expand Down
12 changes: 9 additions & 3 deletions programs/klend/src/utils/prices/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use crate::{

pub(crate) fn price_to_fraction<T>(price: Price<T>) -> Fraction
where
T: Into<U128> + Copy,
T: Into<U256> + Copy,
{
let Price { value, exp } = price;
let value: U256 = value.into().into();
let value: U256 = value.into();
let decimal = ten_pow(exp);

let value_bf = BigFraction::from_num(value);
Expand All @@ -19,8 +19,14 @@ where
.expect("Failed to convert Price stored on BigFraction to Fraction")
}

fn ten_pow(exponent: u32) -> U128 {
pub(super) fn ten_pow(exponent: u32) -> U128 {
let value: u128 = match exponent {
36 => 1_000_000_000_000_000_000_000_000_000_000_000_000,
35 => 100_000_000_000_000_000_000_000_000_000_000_000,
34 => 10_000_000_000_000_000_000_000_000_000_000_000,
33 => 1_000_000_000_000_000_000_000_000_000_000_000,
32 => 100_000_000_000_000_000_000_000_000_000_000,
31 => 10_000_000_000_000_000_000_000_000_000_000,
30 => 1_000_000_000_000_000_000_000_000_000_000,
29 => 100_000_000_000_000_000_000_000_000_000,
28 => 10_000_000_000_000_000_000_000_000_000,
Expand Down

0 comments on commit f449cd4

Please sign in to comment.