Part 2

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

Arithmetic and Fee Calculation Issues

Summary

https://github.com/Cyfrin/2025-01-zaros-part-2/blob/39e33b2f6b3890573bb1affc41a7e520277ceb2c/src/market-making/branches/StabilityBranch.sol#L97

Arithmetic and fee calculation issues in the StabilityBranch contract arise from potential division by zero, precision loss during conversions, and rounding errors. These vulnerabilities can lead to unintended behavior, including reverts, inaccurate fee computations, and exploitation by attackers to repeatedly extract minor financial advantages.

Vulnerability Details

In the getAmountOfAssetOut function, usdAmountInX18 is divided by indexPriceX18. If indexPriceX18 equals zero, the operation reverts, causing potential disruptions in swap functionality.

Similar risks are present in getFeesForAssetsAmountOut and getFeesForUsdTokenAmountIn, where division operations may involve variables that could unexpectedly equal zero.

Precision Loss and Rounding Errors:

Conversions between different precisions (e.g., 18-decimal USD tokens and asset tokens with varying decimal places) can introduce rounding errors.

Attackers could exploit these rounding errors by repeatedly executing small transactions designed to manipulate rounding outcomes in their favor.

Cascading Effects on Fees:

Incorrect fee calculations due to precision loss or division errors might lead to either overcharging or undercharging users. Overcharged fees might harm user trust, while undercharged fees could result in financial losses for the protocol.

function getAmountOfAssetOut(
uint128 vaultId,
UD60x18 usdAmountInX18,
UD60x18 indexPriceX18
)
public
view
returns (UD60x18 amountOutX18)
{
// fetch the vault's storage pointer
Vault.Data storage vault = Vault.load(vaultId);
// fetch the vault's total assets in USD; if the vault is empty
// revert here to prevent panic from subsequent divide by zero
UD60x18 vaultAssetsUsdX18 = ud60x18(IERC4626(vault.indexToken).totalAssets()).mul(indexPriceX18);
if (vaultAssetsUsdX18.isZero()) revert Errors.InsufficientVaultBalance(vaultId, 0, 0);
// we use the vault's net sum of all debt types coming from its connected markets to determine the swap rate
SD59x18 vaultDebtUsdX18 = vault.getTotalDebt();
// calculate the premium or discount that may be applied to the vault asset's index price
// note: if no premium or discount needs to be applied, the premiumDiscountFactorX18 will be
// 1e18 (UD60x18 one value)
UD60x18 premiumDiscountFactorX18 =
UsdTokenSwapConfig.load().getPremiumDiscountFactor(vaultAssetsUsdX18, vaultDebtUsdX18);
// get amounts out taking into consideration the CL price and the premium/discount
amountOutX18 = usdAmountInX18.div(indexPriceX18).mul(premiumDiscountFactorX18);
}

Impact

Division by zero errors could render critical functions (e.g., initiateSwap, fulfillSwap) unusable, causing a DoS (Denial of Service) scenario.

Financial Losses:

Exploitation of rounding errors or precision loss could enable attackers to drain protocol funds incrementally, resulting in long-term financial damage.

Reputation Damage:

Incorrect fee calculations or transaction failures could erode user trust in the platform, affecting adoption and usage.

Tools Used

Manual Review

Recommendations

Add checks to ensure indexPriceX18 and similar variables are non-zero before performing division. For example:

require(indexPriceX18 > 0, "Index price cannot be zero");
Updates

Lead Judging Commences

inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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