Part 2

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

`rebalanceVaultsAssets` will revert due underflow of `depositedUsdc`

Summary

In the current implementation the `rebalanceVaultsAssets` is very likely to revert due to an underflow of depositedUsdc

Vulnerability Details

The function will first check if the credit vault has more credit then the debt:\

// if debt absolute value > credit, use credit value, else use debt value
SD59x18 depositAmountUsdX18 = inCreditVaultUnsettledRealizedDebtUsdX18.gt(
inDebtVaultUnsettledRealizedDebtUsdX18Abs
) ? inDebtVaultUnsettledRealizedDebtUsdX18Abs : inCreditVaultUnsettledRealizedDebtUsdX18;

If the debt is less than the credit then the whole debt will be used.
After that this amount is converted to the collateral token and swapped:

uint256 assetInputNative = IDexAdapter(ctx.dexAdapter).getExpectedOutput(
usdc,
ctx.inDebtVaultCollateralAsset,
// convert usdc input to native precision
Collateral.load(usdc).convertSd59x18ToTokenAmount(depositAmountUsdX18)
);
// prepare the data for executing the swap asset -> usdc
SwapExactInputSinglePayload memory swapCallData = SwapExactInputSinglePayload({
tokenIn: ctx.inDebtVaultCollateralAsset,
tokenOut: usdc,
amountIn: assetInputNative,
recipient: address(this) // deposit the usdc to the market making engine proxy
});
// approve the collateral token to the dex adapter and swap assets for USDC
IERC20(ctx.inDebtVaultCollateralAsset).approve(ctx.dexAdapter, assetInputNative);
dexSwapStrategy.executeSwapExactInputSingle(swapCallData);
// SD59x18 -> uint128 using zaros internal precision
>>> uint128 usdDelta = depositAmountUsdX18.intoUint256().toUint128();

After the swap is executed the following updates are performed:

// important considerations:
// 1) all subsequent storge updates must use zaros internal precision
// 2) code implicitly assumes that 1 USD = 1 USDC
//
// deposits the USDC to the in-credit vault
inCreditVault.depositedUsdc += usdDelta;
// increase the in-credit vault's share of the markets realized debt
// as it has received the USDC and needs to settle it in the future
inCreditVault.marketsRealizedDebtUsd += usdDelta.toInt256().toInt128();
// withdraws the USDC from the in-debt vault
inDebtVault.depositedUsdc -= usdDelta;
// decrease the in-debt vault's share of the markets realized debt
// as it has transferred USDC to the in-credit vault
inDebtVault.marketsRealizedDebtUsd -= usdDelta.toInt256().toInt128();

However the depositedUsdc is of uint type so it will revert whenever usdDelta is more than the depositedUsdc.

Impact

Some inDebt vaults cannot be rebalanced.

Tools Used

Manual Review

Recommendations

Updates

Lead Judging Commences

inallhonesty Lead Judge
5 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.