Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: low
Invalid

Potential overflow in CreditDelegation.updateVaultLastDistributedValues()

Summary

The CreditDelegation.updateVaultLastDistributedValues() function updates the state of a credit delegation by converting values from SD59x18 and UD60x18 types to int128 and uint128. However, this conversion does not include explicit checks to ensure that the values fit within the target type's range. If the values exceed the range of int128 or uint128, it could cause an overflow, leading to incorrect state updates and potential accounting discrepancies.


Vulnerability Details

Code Analysis

The updateVaultLastDistributedValues() function is defined as follows:

function updateVaultLastDistributedValues(
Data storage self,
SD59x18 vaultDistributedRealizedDebtUsdPerShareX18,
SD59x18 vaultDistributedUnrealizedDebtUsdPerShareX18,
UD60x18 vaultDistributedUsdcCreditPerShareX18,
UD60x18 vaultDistributedWethRewardPerShareX18
) internal {
// Updates the credit delegation state
self.lastVaultDistributedRealizedDebtUsdPerShare =
vaultDistributedRealizedDebtUsdPerShareX18.intoInt256().toInt128();
self.lastVaultDistributedUnrealizedDebtUsdPerShare =
vaultDistributedUnrealizedDebtUsdPerShareX18.intoInt256().toInt128();
self.lastVaultDistributedUsdcCreditPerShare = vaultDistributedUsdcCreditPerShareX18.intoUint128();
self.lastVaultDistributedWethRewardPerShare = vaultDistributedWethRewardPerShareX18.intoUint128();
}

Key Observations:

  1. Type Conversion :

    • The function converts SD59x18 values (vaultDistributedRealizedDebtUsdPerShareX18 and vaultDistributedUnrealizedDebtUsdPerShareX18) to int128 using .intoInt256().toInt128().

    • Similarly, UD60x18 values (vaultDistributedUsdcCreditPerShareX18 and vaultDistributedWethRewardPerShareX18) are converted to uint128 using .intoUint128().

  2. Overflow Risk :

    • SD59x18 and UD60x18 are high-precision fixed-point types with a much larger range than int128 and uint128.

    • If the input values exceed the range of int128 (-2^127 to 2^127 - 1) or uint128 (0 to 2^128 - 1), the conversion will result in an overflow.

  3. Impact on State :

    • An overflow during conversion could lead to incorrect state updates, causing discrepancies in debt and reward accounting.

Attack Scenario

  1. An attacker or malicious market manipulates the inputs to updateVaultLastDistributedValues() such that one or more values exceed the range of int128 or uint128.

  2. For example:

    • A vaultDistributedRealizedDebtUsdPerShareX18 value greater than 2^127 - 1 causes an overflow when converted to int128.

    • A vaultDistributedUsdcCreditPerShareX18 value greater than 2^128 - 1 causes an overflow when converted to uint128.

  3. The overflow results in incorrect state updates, leading to improper accounting of debt and rewards.

  4. Users relying on these values may experience financial losses due to incorrect calculations.


Impact

  • Incorrect Accounting : Overflow during type conversion leads to incorrect state updates, affecting debt and reward distributions.

  • Financial Losses : Users may receive incorrect amounts of debt or rewards, leading to financial losses.

  • System Integrity : Persistent accounting discrepancies could undermine trust in the system and disrupt its functionality.


Tools Used

  1. Manual Code Review : Analyzed the type conversions in updateVaultLastDistributedValues() and identified potential overflow risks.

  2. Slither : Static analysis tool used to detect unsafe type conversions and potential overflow vulnerabilities.

  3. MythX : Security analysis platform used to verify the impact of overflow risks on the smart contract.


Recommendations

Short-Term Fix

Add explicit checks to ensure that the input values fit within the range of the target types before performing the conversion. For example:

require(
vaultDistributedRealizedDebtUsdPerShareX18 <= SD59x18.wrap(int256(type(int128).max)) &&
vaultDistributedRealizedDebtUsdPerShareX18 >= SD59x18.wrap(int256(type(int128).min)),
"Value out of range for int128"
);
require(
vaultDistributedUsdcCreditPerShareX18 <= UD60x18.wrap(uint256(type(uint128).max)),
"Value out of range for uint128"
);

Long-Term Fix

  1. Use SafeMath Libraries : Replace direct type conversions with safe math libraries that include built-in overflow checks.

  2. Input Validation : Validate all inputs to ensure they adhere to expected ranges before performing any operations.

  3. Event Logging : Emit events whenever the function is called to provide transparency and enable monitoring.

    event VaultDistributedValuesUpdated(
    uint128 vaultId,
    uint128 marketId,
    int128 realizedDebt,
    int128 unrealizedDebt,
    uint128 usdcCredit,
    uint128 wethReward
    );
    function updateVaultLastDistributedValues(...) internal {
    require(...); // Add range checks
    emit VaultDistributedValuesUpdated(
    self.vaultId,
    self.marketId,
    vaultDistributedRealizedDebtUsdPerShareX18.intoInt256().toInt128(),
    vaultDistributedUnrealizedDebtUsdPerShareX18.intoInt256().toInt128(),
    vaultDistributedUsdcCreditPerShareX18.intoUint128(),
    vaultDistributedWethRewardPerShareX18.intoUint128()
    );
    // Update state
    }
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!