Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lone Fossilized Lemur - Critical Position Size Inflation Due to Scaling Error in Liquidation Mechanism in BorrowingLiquidation::liquidationType2 #1048

Open
sherlock-admin3 opened this issue Dec 30, 2024 · 0 comments

Comments

@sherlock-admin3
Copy link
Contributor

Lone Fossilized Lemur

High

Critical Position Size Inflation Due to Scaling Error in Liquidation Mechanism in BorrowingLiquidation::liquidationType2

Summary

A severe computational error has been discovered in the BorrowingLiquidation::liquidationType2 function's sizeDelta parameter calculation. This error results in grossly inflated position sizes being transmitted to the Synthetix PerpsV2 system, potentially destabilizing the entire liquidation process.

Root Cause

The sizeDelta calculation:

-int((uint(margin * 1 ether * 1e16) / currentEthPrice))

incorrectly multiplies the margin by both 1 ether ((1e18)) and an additional scaling factor 1e16, leading to a drastically inflated result. This excessive scaling inflates the sizeDelta by a factor of (1e16).

Internal pre-conditions

  1. The BorrowingLiquidation::liquidationType2 function is invoked with:
    • A valid amount (e.g., (1e18) for 1 Ether).
    • A currentEthPrice value representing the ETH/USD price (e.g., (1000e2) for $1000 with 2 decimal places).
  2. The synthetixPerpsV2 contract is deployed and accessible.
  3. Sufficient funds are available in the system to process the margin transfer.

External pre-conditions

No response

Attack Path

  1. Initial Trigger:

    • When liquidation is initiated, the function processes inputs through flawed calculation
    • The scaling error compounds through multiplication operations
  2. System Response:

    • The contract forwards an extremely oversized position to Synthetix
    • No safeguards catch the mathematical error before execution
  3. Cascading Effects:

    • Position sizes become unreasonably large
    • System parameters deviate from intended ranges

Impact

  1. Protocol Stability:
    • Risk of system-wide imbalances
    • Potential cascade of failed liquidations
  2. Economic Consequences:
    • Severe miscalculation of position values
    • Possible exploitation of price differences
  3. Operational Risks:
    • Disruption of normal liquidation processes
    • Increased complexity in position management

PoC

function liquidationType2(
        address user,
        uint64 index,
        uint64 currentEthPrice
    ) internal {
        //...



        // Calculate the margin
        int256 margin = int256((amount * currentEthPrice) / 100);
        // Transfer the margin to synthetix
        synthetixPerpsV2.transferMargin(margin);

        // Submit an offchain delayed order in synthetix for short position with 1X leverage
        synthetixPerpsV2.submitOffchainDelayedOrder(
            -int((uint(margin * 1 ether * 1e16) / currentEthPrice)),
            currentEthPrice * 1e16
        );
    }

Margin Calculation

The margin is calculated using the formula:

$$ \text{margin} = \frac{\text{amount} \times \text{currentEthPrice}}{100} $$

Substituting the given values:
amount = 1e18

currentEthPrice = 1000e2

We compute:

$$ \text{margin} = \frac{1 \times 10^{18} \times 1000e2}{100} = \frac{10^{18} \times 10^5}{10^2} = 10^{21} $$

Thus,

$$ \text{margin} = 1000e18 $$

Position Sizing with Leverage

For a 1x leverage short position, the sizeDelta is calculated as:

$$ \text{sizeDelta} = -\text{int}\left(\frac{\text{margin} \times 1e18 \times 1e16}{\text{currentEthPrice}}\right) $$

Substituting the values:
margin = 1000e18
currentEthPrice = 1000e2

Numerator:

$$ \text{Numerator} = \text{margin} \times 1e18 \times 1e16 = 1,000 \times 10^{18} \times 10^{18} \times 10^{16} = 10^{52} $$

Denominator:

$$ \text{Denominator} = \text{currentEthPrice} = 100,000 = 10^5 $$

Final Calculation:

$$ \text{sizeDelta} = -\text{int}\left(\frac{10^{52}}{10^5}\right) = -\text{int}(10^{47}) $$

Thus,

$$ \text{sizeDelta} = -10^{47} $$


Expected Value

Given that the margin is 1000e18, the expected position size should be approximately -1e18, representing a short position of 1 ETH. However, the computed value -10^47 is astronomically large and incorrect.

Simply code to test the inflated value
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MathCalculation {
    function calculateSizeDelta(uint256 amount, uint256 currentEthPrice) external pure returns (int256) {
        int256 margin = int256((amount * currentEthPrice) / 100);
        int256 sizeDelta = -int256(uint256(margin * 1 ether * 1e16) / currentEthPrice);
        return sizeDelta;
    }
}

Mitigation

  1. Update the sizeDelta in BorrowingLiquidation::liquidationType2 the calculation to avoid unnecessary scaling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant