code-423n4 / 2024-06-panoptic-validation

0 stars 0 forks source link

Division by Zero in _computeSpread Function Leads to Potential Runtime Errors and Incorrect Collateral Calculations #48

Open c4-bot-1 opened 5 months ago

c4-bot-1 commented 5 months ago

Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/main/contracts/CollateralTracker.sol#L1516

Vulnerability details

Impact

The _computeSpread function in the CollateralTracker contract contains a calculation that may result in a division by zero error if either notional or notionalP is zero. This issue can lead to runtime errors, causing the contract to terminate unexpectedly. Such errors can disrupt the collateral tracking process, potentially leading to incorrect collateral calculations and vulnerabilities in the contract.

Proof of Concept

Line of Code:

spreadRequirement = (notional < notionalP)
    ? Math.unsafeDivRoundingUp((notionalP - notional) * contracts, notional)
    : Math.unsafeDivRoundingUp((notional - notionalP) * contracts, notionalP);

If either notional or notionalP is zero, the division in the Math.unsafeDivRoundingUp function will result in a division by zero error, causing the contract execution to fail. This can be demonstrated by setting notional or notionalP to zero and observing the contract's behavior during execution.

Tools Used

Manual

Recommended Mitigation Steps

Check for zero values before performing the division.

function _computeSpread(
    TokenId tokenId,
    uint128 positionSize,
    uint256 index,
    uint256 partnerIndex,
    uint128 poolUtilization
) internal view returns (uint256 spreadRequirement) {
    // Compute the total amount of funds moved for the position's current leg
    LeftRightUnsigned amountsMoved = PanopticMath.getAmountsMoved(tokenId, positionSize, index);

    // Compute the total amount of funds moved for the position's partner leg
    LeftRightUnsigned amountsMovedPartner = PanopticMath.getAmountsMoved(
        tokenId,
        positionSize,
        partnerIndex
    );

    // Amount moved is right slot if tokenType=0, left slot otherwise
    uint128 movedRight = amountsMoved.rightSlot();
    uint128 movedLeft = amountsMoved.leftSlot();

    // Amounts moved for partner
    uint128 movedPartnerRight = amountsMovedPartner.rightSlot();
    uint128 movedPartnerLeft = amountsMovedPartner.leftSlot();

    uint256 tokenType = tokenId.tokenType(index);

    // Compute the max loss of the spread
    uint256 notional;
    uint256 notionalP;
    uint128 contracts;

    if (tokenType == 1) {
        notional = movedRight;
        notionalP = movedPartnerRight;
        contracts = movedLeft;
    } else {
        notional = movedLeft;
        notionalP = movedPartnerLeft;
        contracts = movedRight;
    }

    // Check for zero values to prevent division by zero
    if (notional == 0 || notionalP == 0) {
        spreadRequirement = 0;
    } else {
        spreadRequirement = (notional < notionalP)
            ? Math.unsafeDivRoundingUp((notionalP - notional) * contracts, notional)
            : Math.unsafeDivRoundingUp((notional - notionalP) * contracts, notionalP);
    }
}

Assessed type

Math