usdc-plus-exchange 0.1.8

USDC <-> USDC+ exchange library for the Reflect protocol.
Documentation
use anchor_lang::prelude::*;
use crate::drift::SafeMath;
use crate::errors::ReflectErrorCodes;
use spl_math::precise_number::PreciseNumber;

pub fn compute_base_token(    
    receipt: u64,
    deposited_vault: u64,
    receipt_token_supply: u64,
) -> Result<u64> {
    PreciseNumber::new(receipt as u128)
        .ok_or_else(|| {
            msg!("Failed to create PreciseNumber from receipt: {}", receipt);
            ReflectErrorCodes::MathOverflow
        })?
        .checked_mul(
            &PreciseNumber::new(deposited_vault as u128)
                .ok_or_else(|| {
                    msg!("Failed to create PreciseNumber from deposited_vault: {}", deposited_vault);
                    ReflectErrorCodes::MathOverflow
                })?
        )
        .ok_or_else(|| {
            msg!(
                "Multiplication overflow: receipt={} deposited_vault={}", 
                receipt, deposited_vault
            );
            ReflectErrorCodes::MathOverflow
        })?
        .checked_div(
            &PreciseNumber::new(receipt_token_supply as u128)
                .ok_or_else(|| {
                    msg!(
                        "Failed to create PreciseNumber from receipt_token_supply: {}", 
                        receipt_token_supply
                    );
                    ReflectErrorCodes::MathOverflow
                })?
        )
        .ok_or_else(|| {
            msg!(
                "Division overflow: numerator=receipt*deposited_vault denominator={}", 
                receipt_token_supply
            );
            ReflectErrorCodes::MathOverflow
        })?
        .to_imprecise()
        .ok_or_else(|| {
            msg!("Failed to convert PreciseNumber to imprecise (u128).");
            ReflectErrorCodes::MathOverflow
        })?
        .try_into()
        .map_err(|_| {
            msg!("Failed to cast final imprecise value into u64.");
            ReflectErrorCodes::MathOverflow.into()
        })
}

pub fn compute_receipt_token<'info>(    
    deposit: u64,
    deposited_vault: u64,
    receipt_token_supply: u64,
) -> Result<u64> {
    if receipt_token_supply == 0 { 
        msg!(
            "Receipt token supply is zero, returning deposit={} directly.", 
            deposit
        );
        return Ok(deposit); 
    };

    PreciseNumber::new(deposit as u128)
        .ok_or_else(|| {
            msg!("Failed to create PreciseNumber from deposit: {}", deposit);
            ReflectErrorCodes::MathOverflow
        })?
        .checked_mul(
            &PreciseNumber::new(receipt_token_supply as u128)
                .ok_or_else(|| {
                    msg!(
                        "Failed to create PreciseNumber from receipt_token_supply: {}", 
                        receipt_token_supply
                    );
                    ReflectErrorCodes::MathOverflow
                })?
        )
        .ok_or_else(|| {
            msg!(
                "Multiplication overflow: deposit={} receipt_token_supply={}", 
                deposit, receipt_token_supply
            );
            ReflectErrorCodes::MathOverflow
        })?
        .checked_div(
            &PreciseNumber::new(deposited_vault as u128)
                .ok_or_else(|| {
                    msg!("Failed to create PreciseNumber from deposited_vault: {}", deposited_vault);
                    ReflectErrorCodes::MathOverflow
                })?
        )
        .ok_or_else(|| {
            msg!(
                "Division overflow: numerator=deposit*receipt_token_supply denominator={}", 
                deposited_vault
            );
            ReflectErrorCodes::MathOverflow
        })?
        .to_imprecise()
        .ok_or_else(|| {
            msg!("Failed to convert PreciseNumber to imprecise (u128).");
            ReflectErrorCodes::MathOverflow
        })?
        .try_into()
        .map_err(|_| {
            msg!("Failed to cast final imprecise value into u64.");
            ReflectErrorCodes::MathOverflow.into()
        })
}




#[inline(never)]
pub fn calc_cut(total_amount: u64, cut: u16) -> Result<u64> {
    // Use integer arithmetic directly to avoid any rounding issues
    let numerator = (total_amount as u128) * (cut as u128);
    let result = numerator / 10_000u128;
    
    Ok(result as u64)
}

#[inline(never)]
pub fn calc_all_cuts(total_amount: u64, cuts: Vec<u16>) -> Result<Vec<u64>> {

    // Throw out illegal inputs.
    if cuts.is_empty() {        
        return Err(ReflectErrorCodes::MathError.into());
    }

    if cuts.iter().sum::<u16>() != 10_000 {        
        return Err(ReflectErrorCodes::MathError.into());
    }
    
    let mut amounts: Vec<u64> = vec![];
    let mut total_distributed: u64 = 0;

    // Process all cuts except the last one
    for i in 0..cuts.len()-1 {
        let cut_amount = calc_cut(total_amount, cuts[i])?;
        amounts.push(cut_amount);
        total_distributed = total_distributed.safe_add(cut_amount)?;
    }
    
    // Last recipient gets exactly what remains
    let final_amount = total_amount.safe_sub(total_distributed)?;
    amounts.push(final_amount);

    Ok(amounts)
}