Skip to content

Commit

Permalink
[Maths] Use new maths functions in utilities (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
crypto-vincent authored Oct 23, 2023
1 parent e63c4e3 commit a6c9e5c
Show file tree
Hide file tree
Showing 17 changed files with 146 additions and 142 deletions.
5 changes: 2 additions & 3 deletions programs/uxd/src/mercurial_utils/calculate_lp_tokens_value.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::UxdError;
use crate::utils::checked_as_u64;
use anchor_lang::{
prelude::{Account, Clock, SolanaSysvar},
Result,
Expand All @@ -10,9 +11,7 @@ pub fn calculate_lp_tokens_value(
mercurial_vault_lp_mint_supply: u64,
lp_token_amount: u64,
) -> Result<u64> {
let current_time = u64::try_from(Clock::get()?.unix_timestamp)
.ok()
.ok_or(UxdError::MathOverflow)?;
let current_time = checked_as_u64(Clock::get()?.unix_timestamp)?;

Ok(mercurial_vault
.get_amount_by_share(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{error::UxdError, utils::compute_value_for_single_share_ceil};
use crate::error::UxdError;
use crate::utils::checked_as_u64;
use crate::utils::compute_value_for_single_share_ceil;
use anchor_lang::{
prelude::{Account, Clock, SolanaSysvar},
Result,
Expand All @@ -11,9 +13,7 @@ pub fn calculate_possible_lp_token_precision_loss_collateral_value(
mercurial_vault: &Account<Vault>,
mercurial_vault_lp_mint_supply: u64,
) -> Result<u64> {
let current_time = u64::try_from(Clock::get()?.unix_timestamp)
.ok()
.ok_or(UxdError::MathOverflow)?;
let current_time = checked_as_u64(Clock::get()?.unix_timestamp)?;

// Calculate the price of 1 native LP token
// Do not use mercurial_vault.get_amount_by_share because it does not handle precision loss
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use anchor_lang::require;
use crate::error::UxdError;
use crate::utils::calculate_depositories_sum_value;
use crate::utils::checked_as_u64;
use crate::utils::checked_sub;
use crate::ROUTER_DEPOSITORIES_COUNT;

use super::compute_amount_less_fraction_floor;
Expand Down Expand Up @@ -36,10 +37,10 @@ pub fn calculate_depositories_mint_collateral_amount(
{
return Ok(0);
}
Ok(depository
.target_redeemable_amount
.checked_sub(depository_redeemable_amount_under_management)
.ok_or(UxdError::MathOverflow)?)
checked_sub(
depository.target_redeemable_amount,
depository_redeemable_amount_under_management,
)
})
.collect::<Result<Vec<u64>>>()?;

Expand All @@ -65,10 +66,10 @@ pub fn calculate_depositories_mint_collateral_amount(
let depositories_mint_collateral_amount = depositories_maximum_mintable_collateral_amount
.iter()
.map(|depository_mintable_collateral_amount| {
let other_depositories_maximum_mintable_collateral_amount =
total_maximum_mintable_collateral_amount
.checked_sub(*depository_mintable_collateral_amount)
.ok_or(UxdError::MathOverflow)?;
let other_depositories_maximum_mintable_collateral_amount = checked_sub(
total_maximum_mintable_collateral_amount,
*depository_mintable_collateral_amount,
)?;
compute_amount_less_fraction_floor(
requested_mint_collateral_amount,
other_depositories_maximum_mintable_collateral_amount,
Expand Down
69 changes: 36 additions & 33 deletions programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use anchor_lang::require;

use crate::error::UxdError;
use crate::utils::calculate_depositories_sum_value;
use crate::utils::checked_add;
use crate::utils::checked_as_u64;
use crate::utils::checked_sub;
use crate::ROUTER_DEPOSITORIES_COUNT;

use super::compute_amount_less_fraction_floor;
Expand Down Expand Up @@ -42,9 +44,10 @@ pub fn calculate_depositories_redeemable_amount(
{
return Ok(0);
}
Ok(depository_redeemable_amount_under_management
.checked_sub(depository.target_redeemable_amount)
.ok_or(UxdError::MathOverflow)?)
checked_sub(
depository_redeemable_amount_under_management,
depository.target_redeemable_amount,
)
})
.collect::<Result<Vec<u64>>>()?;

Expand Down Expand Up @@ -82,9 +85,10 @@ pub fn calculate_depositories_redeemable_amount(
// -- to be able to fullfill the user's redeemable requested amount
// ---------------------------------------------------------------------

let total_overall_redeemable_amount = total_over_target_redeemable_amount
.checked_add(total_under_target_redeemable_amount)
.ok_or(UxdError::MathOverflow)?;
let total_overall_redeemable_amount = checked_add(
total_over_target_redeemable_amount,
total_under_target_redeemable_amount,
)?;
require!(
total_overall_redeemable_amount >= requested_redeemable_amount,
UxdError::InvalidRedeemableAmount
Expand All @@ -109,15 +113,16 @@ pub fn calculate_depositories_redeemable_amount(
requested_redeemable_amount,
total_over_target_redeemable_amount,
);
let requested_second_redeemable_amount = requested_redeemable_amount
.checked_sub(requested_first_redeemable_amount)
.ok_or(UxdError::MathOverflow)?;
let requested_second_redeemable_amount = checked_sub(
requested_redeemable_amount,
requested_first_redeemable_amount,
)?;
// First step, try to use the over_target amounts, weighted for each depository
let depository_first_redeemable_amount = if total_over_target_redeemable_amount > 0 {
let other_depositories_over_target_redeemable_amount =
total_over_target_redeemable_amount
.checked_sub(*depository_over_target_redeemable_amount)
.ok_or(UxdError::MathOverflow)?;
let other_depositories_over_target_redeemable_amount = checked_sub(
total_over_target_redeemable_amount,
*depository_over_target_redeemable_amount,
)?;
compute_amount_less_fraction_floor(
requested_first_redeemable_amount,
other_depositories_over_target_redeemable_amount,
Expand All @@ -128,10 +133,10 @@ pub fn calculate_depositories_redeemable_amount(
};
// Second step, anything under_target must be taken as backup
let depository_second_redeemable_amount = if total_under_target_redeemable_amount > 0 {
let other_depositories_under_target_redeemable_amount =
total_under_target_redeemable_amount
.checked_sub(*depository_under_target_redeemable_amount)
.ok_or(UxdError::MathOverflow)?;
let other_depositories_under_target_redeemable_amount = checked_sub(
total_under_target_redeemable_amount,
*depository_under_target_redeemable_amount,
)?;
compute_amount_less_fraction_floor(
requested_second_redeemable_amount,
other_depositories_under_target_redeemable_amount,
Expand All @@ -141,9 +146,10 @@ pub fn calculate_depositories_redeemable_amount(
0
};
// The combo of the two gives our depository amount
Ok(depository_first_redeemable_amount
.checked_add(depository_second_redeemable_amount)
.ok_or(UxdError::MathOverflow)?)
checked_add(
depository_first_redeemable_amount,
depository_second_redeemable_amount,
)
},
)
.collect::<Result<Vec<u64>>>()?;
Expand All @@ -158,27 +164,24 @@ pub fn calculate_depositories_redeemable_amount(
let total_redeemable_amount =
calculate_depositories_sum_value(&depositories_redeemable_amount)?;

let mut rounding_errors = requested_redeemable_amount
.checked_sub(total_redeemable_amount)
.ok_or(UxdError::MathOverflow)?;
let mut rounding_errors = checked_sub(requested_redeemable_amount, total_redeemable_amount)?;

for i in 0..depositories_info.len() {
let depository = &depositories_info[i];
if !depository.is_liquid {
continue;
}
let depository_remaining_after_redeem =
checked_as_u64(depository.redeemable_amount_under_management)?
.checked_sub(depositories_redeemable_amount[i])
.ok_or(UxdError::MathOverflow)?;
let depository_remaining_after_redeem = checked_sub(
checked_as_u64(depository.redeemable_amount_under_management)?,
depositories_redeemable_amount[i],
)?;
let depository_rounding_correction =
std::cmp::min(depository_remaining_after_redeem, rounding_errors);
depositories_redeemable_amount[i] = depositories_redeemable_amount[i]
.checked_add(depository_rounding_correction)
.ok_or(UxdError::MathOverflow)?;
rounding_errors = rounding_errors
.checked_sub(depository_rounding_correction)
.ok_or(UxdError::MathOverflow)?;
depositories_redeemable_amount[i] = checked_add(
depositories_redeemable_amount[i],
depository_rounding_correction,
)?;
rounding_errors = checked_sub(rounding_errors, depository_rounding_correction)?;
}

// Done
Expand Down
5 changes: 2 additions & 3 deletions programs/uxd/src/utils/calculate_depositories_sum_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anchor_lang::prelude::Result;
use anchor_lang::require;

use crate::error::UxdError;
use crate::utils::checked_add;
use crate::ROUTER_DEPOSITORIES_COUNT;

/**
Expand All @@ -15,9 +16,7 @@ pub fn calculate_depositories_sum_value(depositories_values: &Vec<u64>) -> Resul
let sum = depositories_values
.iter()
.try_fold(0u64, |accumulator: u64, value: &u64| {
accumulator
.checked_add(*value)
.ok_or(UxdError::MathOverflow)
checked_add(accumulator, *value)
})?;
Ok(sum)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use anchor_lang::require;

use crate::error::UxdError;
use crate::utils::calculate_depositories_sum_value;
use crate::utils::checked_add;
use crate::utils::checked_as_u64;
use crate::utils::checked_sub;
use crate::BPS_POWER;
use crate::ROUTER_DEPOSITORIES_COUNT;

Expand Down Expand Up @@ -76,9 +78,10 @@ pub fn calculate_depositories_target_redeemable_amount(
if depository_raw_target_redeemable_amount <= depository_hard_cap_amount {
return Ok(0);
}
Ok(depository_raw_target_redeemable_amount
.checked_sub(*depository_hard_cap_amount)
.ok_or(UxdError::MathOverflow)?)
checked_sub(
*depository_raw_target_redeemable_amount,
*depository_hard_cap_amount,
)
},
)
.collect::<Result<Vec<u64>>>()?;
Expand All @@ -93,9 +96,10 @@ pub fn calculate_depositories_target_redeemable_amount(
if depository_raw_target_redeemable_amount >= depository_hard_cap_amount {
return Ok(0);
}
Ok(depository_hard_cap_amount
.checked_sub(*depository_raw_target_redeemable_amount)
.ok_or(UxdError::MathOverflow)?)
checked_sub(
*depository_hard_cap_amount,
*depository_raw_target_redeemable_amount,
)
},
)
.collect::<Result<Vec<u64>>>()?;
Expand Down Expand Up @@ -150,11 +154,13 @@ pub fn calculate_depositories_target_redeemable_amount(
} else {
0
};
let final_target = depository_raw_target_redeemable_amount
.checked_add(overflow_amount_reallocated_from_other_depositories)
.ok_or(UxdError::MathOverflow)?
.checked_sub(*depository_overflow_amount)
.ok_or(UxdError::MathOverflow)?;
let final_target = checked_sub(
checked_add(
*depository_raw_target_redeemable_amount,
overflow_amount_reallocated_from_other_depositories,
)?,
*depository_overflow_amount,
)?;
Ok(final_target)
},
)
Expand Down
25 changes: 8 additions & 17 deletions programs/uxd/src/utils/math/checked_add_u128_and_i128.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
use crate::error::UxdError;
use crate::utils::checked_add;
use crate::utils::checked_as_u128;
use crate::utils::checked_sub;
use anchor_lang::prelude::*;

pub fn checked_add_u128_and_i128(value_before: u128, change_delta: i128) -> Result<u128> {
// In case of a simple positive change (increase), add the two positive values
if change_delta >= 0 {
let increase: u128 = u128::try_from(change_delta)
.ok()
.ok_or(UxdError::MathOverflow)?;
return Ok(value_before
.checked_add(increase)
.ok_or(UxdError::MathOverflow)?);
let increase: u128 = checked_as_u128(change_delta)?;
return checked_add(value_before, increase);
}
// In case of a negative change, substract the absolute value of the delta (decrease)
let decrease: u128 = if change_delta == i128::MIN {
// special case: i128::MIN does not have an i128 absolute value
u128::try_from(i128::MAX)
.ok()
.ok_or(UxdError::MathOverflow)?
.checked_add(1)
.ok_or(UxdError::MathOverflow)?
checked_add(checked_as_u128(i128::MAX)?, 1)?
} else {
u128::try_from(change_delta.checked_abs().ok_or(UxdError::MathOverflow)?)
.ok()
.ok_or(UxdError::MathOverflow)?
checked_as_u128(change_delta.checked_abs().ok_or(UxdError::MathOverflow)?)?
};
Ok(value_before
.checked_sub(decrease)
.ok_or(UxdError::MathOverflow)?)
checked_sub(value_before, decrease)
}
23 changes: 8 additions & 15 deletions programs/uxd/src/utils/math/compute_amount_fraction_ceil.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::error::UxdError;
use crate::utils::checked_as_u64;
use crate::utils::checked_ceil_div;
use crate::utils::checked_mul;
use anchor_lang::prelude::*;

// Rounding error may increase the returned amount.
Expand All @@ -12,19 +15,9 @@ pub fn compute_amount_fraction_ceil(
if fraction_numerator == 0 || amount == 0 {
return Ok(0);
}
let amount: u128 = amount.into();
let fraction_numerator: u128 = fraction_numerator.into();
let fraction_denominator: u128 = fraction_denominator.into();
let amount_fraction_ceil: u128 = amount
.checked_mul(fraction_numerator)
.ok_or(UxdError::MathOverflow)?
.checked_sub(1)
.ok_or(UxdError::MathOverflow)?
.checked_div(fraction_denominator)
.ok_or(UxdError::MathOverflow)?
.checked_add(1)
.ok_or(UxdError::MathOverflow)?;
Ok(u64::try_from(amount_fraction_ceil)
.ok()
.ok_or(UxdError::MathOverflow)?)
let amount_fraction_ceil: u128 = checked_ceil_div::<u128>(
checked_mul::<u128>(u128::from(amount), u128::from(fraction_numerator))?,
u128::from(fraction_denominator),
)?;
checked_as_u64(amount_fraction_ceil)
}
34 changes: 19 additions & 15 deletions programs/uxd/src/utils/math/compute_amount_less_fraction_floor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::error::UxdError;
use crate::utils::checked_as_u64;
use crate::utils::checked_div;
use crate::utils::checked_mul;
use crate::utils::checked_sub;
use anchor_lang::prelude::*;

// Precision loss may lower the returned amount.
Expand All @@ -9,19 +13,19 @@ pub fn compute_amount_less_fraction_floor(
fraction_denominator: u64,
) -> Result<u64> {
require!(fraction_denominator > 0, UxdError::MathOverflow);
let amount: u128 = amount.into();
let fraction_numerator: u128 = fraction_numerator.into();
let fraction_denominator: u128 = fraction_denominator.into();
let amount_less_fraction: u128 = amount
.checked_mul(
fraction_denominator
.checked_sub(fraction_numerator)
.ok_or(UxdError::MathOverflow)?,
)
.ok_or(UxdError::MathOverflow)?
.checked_div(fraction_denominator)
.ok_or(UxdError::MathOverflow)?;
Ok(u64::try_from(amount_less_fraction)
.ok()
.ok_or(UxdError::MathOverflow)?)
require!(
fraction_denominator >= fraction_numerator,
UxdError::MathOverflow
);
let amount_less_fraction: u128 = checked_div::<u128>(
checked_mul::<u128>(
u128::from(amount),
checked_sub::<u128>(
u128::from(fraction_denominator),
u128::from(fraction_numerator),
)?,
)?,
u128::from(fraction_denominator),
)?;
checked_as_u64(amount_less_fraction)
}
Loading

0 comments on commit a6c9e5c

Please sign in to comment.