From d102e926af36a58cbe4df6e05635f89a09f36ca7 Mon Sep 17 00:00:00 2001 From: uxd-vincent <106254129+uxd-vincent@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:35:36 +0100 Subject: [PATCH 1/4] [Audit] I-4 - Remove useless checked_as_u64 (#324) --- programs/uxd/src/instructions/redeem.rs | 2 +- .../src/utils/calculate_depositories_redeemable_amount.rs | 3 +-- .../calculate_depositories_target_redeemable_amount.rs | 7 ++----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/programs/uxd/src/instructions/redeem.rs b/programs/uxd/src/instructions/redeem.rs index 78b6b4a4a..479cc1478 100644 --- a/programs/uxd/src/instructions/redeem.rs +++ b/programs/uxd/src/instructions/redeem.rs @@ -177,7 +177,7 @@ pub(crate) fn handler(ctx: Context, redeemable_amount: u64) -> Result<() let new_epoch_outflow_amount = { // How long ago was the last outflow let last_outflow_elapsed_slots = std::cmp::min( - checked_as_u64(checked_sub(current_slot, controller.last_outflow_slot)?)?, + checked_sub(current_slot, controller.last_outflow_slot)?, controller.slots_per_epoch, ); // How much was unlocked by waiting since last redeem diff --git a/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs b/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs index 5aeef4a2e..a7dab3cf5 100644 --- a/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs +++ b/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs @@ -4,7 +4,6 @@ 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; @@ -167,7 +166,7 @@ pub fn calculate_depositories_redeemable_amount( continue; } let depository_remaining_after_redeem = checked_sub( - checked_as_u64(depository.redeemable_amount_under_management)?, + depository.redeemable_amount_under_management, depositories_redeemable_amount[i], )?; let depository_rounding_correction = diff --git a/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs b/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs index 868ef49ef..1fb887126 100644 --- a/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs +++ b/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs @@ -4,7 +4,6 @@ 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; @@ -26,8 +25,6 @@ pub fn calculate_depositories_target_redeemable_amount( UxdError::InvalidDepositoriesVector ); - let redeemable_circulating_supply = checked_as_u64(redeemable_circulating_supply)?; - // Double check that the weights adds up to 100% let depositories_weights_bps = depositories_info .iter() @@ -66,8 +63,8 @@ pub fn calculate_depositories_target_redeemable_amount( // Read the minting caps of each depository let depositories_hard_cap_amount = depositories_info .iter() - .map(|depository| checked_as_u64(depository.redeemable_amount_under_management_cap)) - .collect::>>()?; + .map(|depository| depository.redeemable_amount_under_management_cap) + .collect::>(); // Compute the depository_overflow amount of raw target that doesn't fit within the cap of each depository let depositories_overflow_amount = std::iter::zip( From 6d7895d7708dbdc297d923769d454c200b33cc0d Mon Sep 17 00:00:00 2001 From: uxd-vincent <106254129+uxd-vincent@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:37:48 +0100 Subject: [PATCH 2/4] [Audit] Q-3 - Usage of saturating_sub vs checked_sub (#321) --- ...collect_profits_of_credix_lp_depository.rs | 28 +++++++---------- ...hdraw_request_from_credix_lp_depository.rs | 13 ++------ ...hdraw_request_from_credix_lp_depository.rs | 16 +++------- ...t_profits_of_mercurial_vault_depository.rs | 4 +-- ...ate_depositories_mint_collateral_amount.rs | 31 ++++++------------- ...alculate_depositories_redeemable_amount.rs | 23 ++++++-------- ...e_depositories_target_redeemable_amount.rs | 20 +++--------- 7 files changed, 42 insertions(+), 93 deletions(-) diff --git a/programs/uxd/src/instructions/credix_lp/collect_profits_of_credix_lp_depository.rs b/programs/uxd/src/instructions/credix_lp/collect_profits_of_credix_lp_depository.rs index 85a722b2a..0d182473f 100644 --- a/programs/uxd/src/instructions/credix_lp/collect_profits_of_credix_lp_depository.rs +++ b/programs/uxd/src/instructions/credix_lp/collect_profits_of_credix_lp_depository.rs @@ -10,6 +10,7 @@ use crate::error::UxdError; use crate::events::CollectProfitsOfCredixLpDepositoryEvent; use crate::state::controller::Controller; use crate::state::credix_lp_depository::CredixLpDepository; +use crate::utils::checked_as_u64; use crate::utils::compute_decrease; use crate::utils::compute_increase; use crate::utils::compute_shares_amount_for_value_floor; @@ -178,37 +179,30 @@ pub(crate) fn handler(ctx: Context) -> Resul )?; // How much collateral can we withdraw as profits - let profits_value: u128 = { + let profits_value = { // Compute the set of liabilities owed to the users - let liabilities_value: u128 = ctx - .accounts - .depository - .load()? - .redeemable_amount_under_management; + let liabilities_value = checked_as_u64( + ctx.accounts + .depository + .load()? + .redeemable_amount_under_management, + )?; msg!( "[collect_profits_of_credix_lp_depository:liabilities_value:{}]", liabilities_value ); // Compute the set of assets owned in the LP - let assets_value: u128 = owned_shares_value_before.into(); + let assets_value = owned_shares_value_before; msg!( "[collect_profits_of_credix_lp_depository:assets_value:{}]", assets_value ); // Compute the amount of profits that we can safely withdraw - assets_value - .checked_sub(liabilities_value) - .ok_or(UxdError::MathOverflow)? + assets_value.saturating_sub(liabilities_value) }; - msg!( - "[collect_profits_of_credix_lp_depository:profits_value:{}]", - profits_value - ); // Assumes and enforce a collateral/redeemable 1:1 relationship on purpose - let collateral_amount_before_precision_loss: u64 = u64::try_from(profits_value) - .ok() - .ok_or(UxdError::MathOverflow)?; + let collateral_amount_before_precision_loss: u64 = profits_value; msg!( "[collect_profits_of_credix_lp_depository:collateral_amount_before_precision_loss:{}]", collateral_amount_before_precision_loss diff --git a/programs/uxd/src/instructions/credix_lp/rebalance_create_withdraw_request_from_credix_lp_depository.rs b/programs/uxd/src/instructions/credix_lp/rebalance_create_withdraw_request_from_credix_lp_depository.rs index b24cfbe40..572736dfe 100644 --- a/programs/uxd/src/instructions/credix_lp/rebalance_create_withdraw_request_from_credix_lp_depository.rs +++ b/programs/uxd/src/instructions/credix_lp/rebalance_create_withdraw_request_from_credix_lp_depository.rs @@ -12,7 +12,6 @@ use crate::state::mercurial_vault_depository::MercurialVaultDepository; use crate::utils::calculate_router_depositories_target_redeemable_amount; use crate::utils::checked_add; use crate::utils::checked_as_u64; -use crate::utils::checked_sub; use crate::utils::compute_value_for_shares_amount_floor; use crate::validate_is_program_frozen; use crate::CONTROLLER_NAMESPACE; @@ -183,7 +182,7 @@ pub(crate) fn handler( total_shares_supply, total_shares_value, )?; - checked_sub(owned_shares_value, redeemable_amount_under_management)? + owned_shares_value.saturating_sub(redeemable_amount_under_management) }; let overflow_value = { @@ -196,14 +195,8 @@ pub(crate) fn handler( &ctx.accounts.alloyx_vault_depository, )? .credix_lp_depository_target_redeemable_amount; - if redeemable_amount_under_management < redeemable_amount_under_management_target_amount { - 0 - } else { - checked_sub( - redeemable_amount_under_management, - redeemable_amount_under_management_target_amount, - )? - } + redeemable_amount_under_management + .saturating_sub(redeemable_amount_under_management_target_amount) }; // --------------------------------------------------------------------- diff --git a/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs b/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs index 31a5de66c..7c5ec20d7 100644 --- a/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs +++ b/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs @@ -264,10 +264,8 @@ pub(crate) fn handler( .redeemable_amount_under_management, )?; - let profits_collateral_amount = checked_sub( - owned_shares_value_before, - redeemable_amount_under_management, - )?; + let profits_collateral_amount = + owned_shares_value_before.saturating_sub(redeemable_amount_under_management); msg!( "[rebalance_redeem_withdraw_request_from_credix_lp_depository:profits_collateral_amount:{}]", profits_collateral_amount @@ -283,14 +281,8 @@ pub(crate) fn handler( &ctx.accounts.alloyx_vault_depository, )? .credix_lp_depository_target_redeemable_amount; - if redeemable_amount_under_management < redeemable_amount_under_management_target_amount { - 0 - } else { - checked_sub( - redeemable_amount_under_management, - redeemable_amount_under_management_target_amount, - )? - } + redeemable_amount_under_management + .saturating_sub(redeemable_amount_under_management_target_amount) }; msg!( "[rebalance_redeem_withdraw_request_from_credix_lp_depository:overflow_value:{}]", diff --git a/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs b/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs index a436fd52c..eb60e82fa 100644 --- a/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs +++ b/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs @@ -251,9 +251,7 @@ impl<'info> CollectProfitsOfMercurialVaultDepository<'info> { .ok() .ok_or(UxdError::MathOverflow)?; - Ok(owned_lp_tokens_value - .checked_sub(redeemable_amount_under_management) - .ok_or(UxdError::MathOverflow)?) + Ok(owned_lp_tokens_value.saturating_sub(redeemable_amount_under_management)) } } diff --git a/programs/uxd/src/utils/calculate_depositories_mint_collateral_amount.rs b/programs/uxd/src/utils/calculate_depositories_mint_collateral_amount.rs index c4e412b19..9a597adf9 100644 --- a/programs/uxd/src/utils/calculate_depositories_mint_collateral_amount.rs +++ b/programs/uxd/src/utils/calculate_depositories_mint_collateral_amount.rs @@ -35,18 +35,13 @@ pub fn calculate_depositories_mint_collateral_amount( .iter() .map(|depository| { if !depository.directly_mintable { - return Ok(0); + return 0; } - if depository.target_redeemable_amount <= depository.redeemable_amount_under_management - { - return Ok(0); - } - checked_sub( - depository.target_redeemable_amount, - depository.redeemable_amount_under_management, - ) + depository + .target_redeemable_amount + .saturating_sub(depository.redeemable_amount_under_management) }) - .collect::>>()?; + .collect::>(); let total_under_target_redeemable_amount = calculate_depositories_sum_value(&depositories_under_target_redeemable_amount)?; @@ -63,23 +58,17 @@ pub fn calculate_depositories_mint_collateral_amount( .iter() .map(|depository| { if !depository.directly_mintable { - return Ok(0); + return 0; } let depository_after_target_redeemable_amount = std::cmp::max( depository.redeemable_amount_under_management, depository.target_redeemable_amount, ); - if depository.redeemable_amount_under_management_cap - <= depository_after_target_redeemable_amount - { - return Ok(0); - } - checked_sub( - depository.redeemable_amount_under_management_cap, - depository_after_target_redeemable_amount, - ) + depository + .redeemable_amount_under_management_cap + .saturating_sub(depository_after_target_redeemable_amount) }) - .collect::>>()?; + .collect::>(); let total_under_cap_redeemable_amount = calculate_depositories_sum_value(&depositories_under_cap_redeemable_amount)?; diff --git a/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs b/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs index a7dab3cf5..aea777a8f 100644 --- a/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs +++ b/programs/uxd/src/utils/calculate_depositories_redeemable_amount.rs @@ -35,18 +35,13 @@ pub fn calculate_depositories_redeemable_amount( .iter() .map(|depository| { if !depository.directly_redeemable { - return Ok(0); + return 0; } - if depository.redeemable_amount_under_management <= depository.target_redeemable_amount - { - return Ok(0); - } - checked_sub( - depository.redeemable_amount_under_management, - depository.target_redeemable_amount, - ) + depository + .redeemable_amount_under_management + .saturating_sub(depository.target_redeemable_amount) }) - .collect::>>()?; + .collect::>(); let total_over_target_redeemable_amount = calculate_depositories_sum_value(&depositories_over_target_redeemable_amount)?; @@ -62,14 +57,14 @@ pub fn calculate_depositories_redeemable_amount( .iter() .map(|depository| { if !depository.directly_redeemable { - return Ok(0); + return 0; } - Ok(std::cmp::min( + std::cmp::min( depository.redeemable_amount_under_management, depository.target_redeemable_amount, - )) + ) }) - .collect::>>()?; + .collect::>(); let total_under_target_redeemable_amount = calculate_depositories_sum_value(&depositories_under_target_redeemable_amount)?; diff --git a/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs b/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs index 1fb887126..f91b7e6d9 100644 --- a/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs +++ b/programs/uxd/src/utils/calculate_depositories_target_redeemable_amount.rs @@ -73,16 +73,10 @@ pub fn calculate_depositories_target_redeemable_amount( ) .map( |(depository_raw_target_redeemable_amount, depository_hard_cap_amount)| { - if depository_raw_target_redeemable_amount <= depository_hard_cap_amount { - return Ok(0); - } - checked_sub( - *depository_raw_target_redeemable_amount, - *depository_hard_cap_amount, - ) + depository_raw_target_redeemable_amount.saturating_sub(*depository_hard_cap_amount) }, ) - .collect::>>()?; + .collect::>(); // Compute the amount of space available under the cap in each depository let depositories_available_amount = std::iter::zip( @@ -91,16 +85,10 @@ pub fn calculate_depositories_target_redeemable_amount( ) .map( |(depository_raw_target_redeemable_amount, depository_hard_cap_amount)| { - if depository_raw_target_redeemable_amount >= depository_hard_cap_amount { - return Ok(0); - } - checked_sub( - *depository_hard_cap_amount, - *depository_raw_target_redeemable_amount, - ) + depository_hard_cap_amount.saturating_sub(*depository_raw_target_redeemable_amount) }, ) - .collect::>>()?; + .collect::>(); // --------------------------------------------------------------------- // -- Phase 3 From 6bc0400771d2c47f7f12684cb6c803fc3158b21e Mon Sep 17 00:00:00 2001 From: uxd-vincent <106254129+uxd-vincent@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:40:55 +0100 Subject: [PATCH 3/4] [Audit] I-6 - Alloyx to early return when rebalancing zero --- .../uxd/src/instructions/rebalance_alloyx_vault_depository.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs b/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs index 1a27e6740..f5556af33 100644 --- a/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs +++ b/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs @@ -292,9 +292,9 @@ pub(crate) fn handler(ctx: Context, vault_id: &s alloyx_vault_depository.redeemable_amount_under_management, deposited_underflow_collateral, )?; - // If we deposited, we can stop here - return Ok(()); } + // If we deposited, we can stop here (no need to withdraw) + return Ok(()); } // --------------------------------------------------------------------- From 14eba90566dc0283c78a845ad5f095972d30d621 Mon Sep 17 00:00:00 2001 From: uxd-vincent <106254129+uxd-vincent@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:41:19 +0100 Subject: [PATCH 4/4] [Audit] I-8 - Avoid unecessary CPIs when amounts=0 (#322) --- ...hdraw_request_from_credix_lp_depository.rs | 38 ++++++++++--------- ...t_profits_of_mercurial_vault_depository.rs | 18 +++++---- .../redeem_from_mercurial_vault_depository.rs | 18 +++++---- .../rebalance_alloyx_vault_depository.rs | 24 +++++++----- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs b/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs index 7c5ec20d7..be35aa882 100644 --- a/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs +++ b/programs/uxd/src/instructions/credix_lp/rebalance_redeem_withdraw_request_from_credix_lp_depository.rs @@ -342,11 +342,6 @@ pub(crate) fn handler( total_shares_value_before, )?; - if withdrawal_total_shares_amount == 0 { - msg!("[rebalance_redeem_withdraw_request_from_credix_lp_depository:no_withdrawable_liquidity]",); - return Ok(()); - } - let withdrawal_total_collateral_amount_after_precision_loss = compute_value_for_shares_amount_floor( withdrawal_total_shares_amount, @@ -354,6 +349,11 @@ pub(crate) fn handler( total_shares_value_before, )?; + if withdrawal_total_collateral_amount_after_precision_loss == 0 { + msg!("[rebalance_redeem_withdraw_request_from_credix_lp_depository:no_withdrawable_liquidity]",); + return Ok(()); + } + // Precision loss should be taken from the profits, not the overflow // Otherwise this means that the precision loss would take out of the backing value let withdrawal_overflow_value_after_precision_loss = withdrawal_overflow_value; @@ -382,23 +382,27 @@ pub(crate) fn handler( "[rebalance_redeem_withdraw_request_from_credix_lp_depository:profits_beneficiary_collateral_transfer:{}]", withdrawal_profits_collateral_amount_after_precision_loss ); - token::transfer( - ctx.accounts - .into_transfer_depository_collateral_to_profits_beneficiary_collateral_context() - .with_signer(depository_pda_signer), - withdrawal_profits_collateral_amount_after_precision_loss, - )?; + if withdrawal_profits_collateral_amount_after_precision_loss > 0 { + token::transfer( + ctx.accounts + .into_transfer_depository_collateral_to_profits_beneficiary_collateral_context() + .with_signer(depository_pda_signer), + withdrawal_profits_collateral_amount_after_precision_loss, + )?; + } msg!( "[rebalance_redeem_withdraw_request_from_credix_lp_depository:identity_depository_collateral_transfer:{}]", withdrawal_overflow_value_after_precision_loss ); - token::transfer( - ctx.accounts - .into_transfer_depository_collateral_to_identity_depository_collateral_context() - .with_signer(depository_pda_signer), - withdrawal_overflow_value_after_precision_loss, - )?; + if withdrawal_overflow_value_after_precision_loss > 0 { + token::transfer( + ctx.accounts + .into_transfer_depository_collateral_to_identity_depository_collateral_context() + .with_signer(depository_pda_signer), + withdrawal_overflow_value_after_precision_loss, + )?; + } // Refresh account states after withdrawal { diff --git a/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs b/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs index eb60e82fa..112160d42 100644 --- a/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs +++ b/programs/uxd/src/instructions/mercurial/collect_profits_of_mercurial_vault_depository.rs @@ -120,14 +120,16 @@ pub(crate) fn handler(ctx: Context) -> ]]; // 5 - withdraw collateral from mercurial vault for LP tokens - mercurial_vault::cpi::withdraw( - ctx.accounts - .into_withdraw_collateral_from_mercurial_vault_context() - .with_signer(depository_signer_seed), - lp_token_amount_to_match_collectable_profits_value, - // Do not check slippage here - 0, - )?; + if lp_token_amount_to_match_collectable_profits_value > 0 { + mercurial_vault::cpi::withdraw( + ctx.accounts + .into_withdraw_collateral_from_mercurial_vault_context() + .with_signer(depository_signer_seed), + lp_token_amount_to_match_collectable_profits_value, + // Do not check slippage here + 0, + )?; + } // 6 - Reload accounts impacted by the withdraw (We need updated numbers for further calculation) ctx.accounts.depository_lp_token_vault.reload()?; diff --git a/programs/uxd/src/instructions/mercurial/redeem_from_mercurial_vault_depository.rs b/programs/uxd/src/instructions/mercurial/redeem_from_mercurial_vault_depository.rs index 744187d8c..32ba80b08 100644 --- a/programs/uxd/src/instructions/mercurial/redeem_from_mercurial_vault_depository.rs +++ b/programs/uxd/src/instructions/mercurial/redeem_from_mercurial_vault_depository.rs @@ -166,14 +166,16 @@ pub(crate) fn handler( )?; // 3 - Redeem collateral from mercurial vault for lp tokens - mercurial_vault::cpi::withdraw( - ctx.accounts - .into_withdraw_collateral_from_mercurial_vault_context() - .with_signer(depository_signer_seed), - lp_token_amount_to_match_collateral_amount_less_fees, - // Do not check slippage here - 0, - )?; + if lp_token_amount_to_match_collateral_amount_less_fees > 0 { + mercurial_vault::cpi::withdraw( + ctx.accounts + .into_withdraw_collateral_from_mercurial_vault_context() + .with_signer(depository_signer_seed), + lp_token_amount_to_match_collateral_amount_less_fees, + // Do not check slippage here + 0, + )?; + } // 4 - Reload accounts impacted by the withdraw (We need updated numbers for further calculation) ctx.accounts.depository_lp_token_vault.reload()?; diff --git a/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs b/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs index f5556af33..4cd6242cf 100644 --- a/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs +++ b/programs/uxd/src/instructions/rebalance_alloyx_vault_depository.rs @@ -406,15 +406,18 @@ impl<'info> RebalanceAlloyxVaultDepository<'info> { collateral_mint.as_ref(), &[self.alloyx_vault_depository.load()?.bump], ]]; + token::transfer( self.into_transfer_identity_depository_collateral_to_alloyx_vault_depository_collateral_context() .with_signer(identity_depository_pda_signer), collateral_amount_after_precision_loss, - )?; - token::transfer( - self.into_transfer_payer_collateral_to_alloyx_vault_depository_collateral_context(), - collateral_amount_delta_precision_loss, - )?; + )?; + if collateral_amount_delta_precision_loss > 0 { + token::transfer( + self.into_transfer_payer_collateral_to_alloyx_vault_depository_collateral_context(), + collateral_amount_delta_precision_loss, + )?; + } alloyx_cpi::cpi::deposit( self.into_deposit_alloyx_vault_depository_to_alloyx_vault_context() .with_signer(alloyx_vault_depository_pda_signer), @@ -580,16 +583,19 @@ impl<'info> RebalanceAlloyxVaultDepository<'info> { collateral_mint.as_ref(), &[self.alloyx_vault_depository.load()?.bump], ]]; + alloyx_cpi::cpi::withdraw( self.into_withdraw_from_alloyx_vault_to_alloyx_vault_depository_collateral_context() .with_signer(alloyx_vault_depository_pda_signer), vault_id.to_owned(), shares_amount, )?; - token::transfer( - self.into_transfer_payer_collateral_to_identity_depository_collateral_context(), - collateral_amount_delta_precision_loss, - )?; + if collateral_amount_delta_precision_loss > 0 { + token::transfer( + self.into_transfer_payer_collateral_to_identity_depository_collateral_context(), + collateral_amount_delta_precision_loss, + )?; + } token::transfer( self.into_transfer_alloyx_vault_depository_collateral_to_identity_depository_collateral_context() .with_signer(alloyx_vault_depository_pda_signer),