sherlock-audit / 2024-08-woofi-solana-deployment-judging

0 stars 0 forks source link

Fast Sand Millipede - Improper Decimal Scaling in Cross-Price Calculation #10

Open sherlock-admin3 opened 15 hours ago

sherlock-admin3 commented 15 hours ago

Fast Sand Millipede

High

Improper Decimal Scaling in Cross-Price Calculation

Summary

The original code for calculating the cross-price between the base and quote tokens improperly scales the base_price by the quote_decimal without accounting for the base_decimal.

This results in over-scaling and inaccurate cross-price calculations.

Vulnerability Detail

In the original code, the base_price is scaled by 10 ** quote_decimal, but the base decimals is not properly accounted for.

This leads to over-scaling of the base_price when both the base and quote tokens already have their own decimal precision. Additionally, the result is not adjusted for the base decimals after the division, leading to inflated or incorrect values.

    let base_price = pyth_result.price as u128;
    let quote_price = quote_price_result.price as u128;    

    let quote_decimal = quote_price_result.exponent.abs().try_into().unwrap();

    let clo_price = base_price
        .checked_mul(10_u128.pow(quote_decimal)) // Scales base_price by quote decimals
        .unwrap()
        .checked_div(quote_price)
        .unwrap();

Impact

The over-scaling of base_price leads to an incorrect cross-price calculation and potentially marking the price as out-of-bound in this check here:

    let wo_price_in_bound = clo_price != 0
        && ((clo_price * (ONE_E18_U128 - bound)) / ONE_E18_U128 <= wo_price
            && wo_price <= (clo_price * (ONE_E18_U128 + bound)) / ONE_E18_U128);

Code Snippet

https://github.com/sherlock-audit/2024-08-woofi-solana-deployment/blob/main/WOOFi_Solana/programs/woofi/src/instructions/get_price.rs#L64-L71

Tool used

Manual Review

Recommendation

To fix this issue, ensure that the base_price is properly scaled by the difference between base_decimal and quote_decimal and that the result is adjusted for base_decimal after the division. Here's one of the approaches:

let base_price = pyth_result.price as u128;
let quote_price = quote_price_result.price as u128;
let base_decimal = pyth_result.exponent.abs().try_into().unwrap();
let quote_decimal = quote_price_result.exponent.abs().try_into().unwrap();

// Normalize the base price to the precision of the quote price
let normalized_base_price = base_price.checked_mul(10_u128.pow(quote_decimal)).unwrap();

// Calculate the cross-price and adjust for base decimals
let clo_price = normalized_base_price
    .checked_div(quote_price)
    .unwrap()
    .checked_div(10_u128.pow(base_decimal)) // Adjust for base decimals
    .unwrap();
toprince commented 13 hours ago

Not valid for this one The meaning of this calc is to transit from BaseToken/USD to BaseToken/QuoteToken like SOL/USD to SOL/USDC if SOL's price is 150, decimal is 6, need give out 150000000, not 150.