Part 2

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

Wrong amount in calcaulation when performing a swap from vault asset to usdc

Summary

During settling vault debt we call the settlevaultdebt and when the contract has some credit we swap usdc for Vault assets but the vault asset amount used is not correctly calculated leading to some issues like the failure to actually settle the vault debt as expected.

Vulnerability Details

The amount taken in as the Vault asset amount is totally wrong and is in usdc value instead of vault asset value.

function settleVaultsDebt(uint256[] calldata vaultsIds) external onlyRegisteredSystemKeepers {
// first, we need to update the credit capacity of the vaults
Vault.recalculateVaultsCreditCapacity(vaultsIds);
// working data, cache usdc address
SettleVaultDebtContext memory ctx;
ctx.usdc = MarketMakingEngineConfiguration.load().usdc;
// load the usdc collateral data storage pointer
@audit>> Collateral.Data storage usdcCollateralConfig = Collateral.load(ctx.usdc);
// get swap amount; both input and output in native precision
@audit>> ctx.usdcIn = calculateSwapAmount(
dexSwapStrategy.dexAdapter,
ctx.vaultAsset,
ctx.usdc,
@audit>> usdc amount passed for vault asset >> usdcCollateralConfig.convertSd59x18ToTokenAmount(ctx.vaultUnsettledRealizedDebtUsdX18.abs()) //BUG use token in asset amount not usdc.
);
// get deposited USDC balance of the vault, convert to native precision
@audit>> ctx.vaultUsdcBalance = usdcCollateralConfig.convertUd60x18ToTokenAmount(ud60x18(vault.depositedUsdc));
// if the vault doesn't have enough usdc use whatever amount it has
// make sure we compare native precision values together and output native precision
@audit>> Good control but lessser values will not be accurate >> ctx.usdcIn = (ctx.usdcIn <= ctx.vaultUsdcBalance) ? ctx.usdcIn : ctx.vaultUsdcBalance; // this catches the error if the amount is above but a smaller returned value for some tokens will cause issues BUG

Instead of passing the Value of the vault asset we use usdc amount without ever converting it

function calculateSwapAmount(
address dexAdapter,
address assetIn,
address assetOut,
@audit>> uint256 vaultUnsettledDebtUsdAbs
)
public
view
returns (uint256 amount)
{
// calculate expected asset amount needed to cover the debt
@audit>> amount = IDexAdapter(dexAdapter).getExpectedOutput(assetIn, assetOut, @audit >> vaultUnsettledDebtUsdAbs);
}

The amount in passed is the usdc amount in value and not the vault token amount in actually required .

Wrong equation will lead to = (usdcamount * collateral price) / usdc price

instead of = (collateral amount * collateral price) /usdc price

/// @notice Get the expected output amount
/// @param tokenIn The token in address
/// @param tokenOut The token out address
/// @param amountIn The input amount in native precision of tokenIn
/// @return expectedAmountOut The expected amount out in native precision of tokenOut
function getExpectedOutput(
address tokenIn,
address tokenOut,
@audit>> uint256 amountIn
)
public
view
returns (uint256 expectedAmountOut)
{
// fail fast for zero input
if (amountIn == 0) revert Errors.ZeroExpectedSwapOutput();
// get token prices
UD60x18 priceTokenInX18 = IPriceAdapter(swapAssetConfigData[tokenIn].priceAdapter).getPrice();
UD60x18 priceTokenOutX18 = IPriceAdapter(swapAssetConfigData[tokenOut].priceAdapter).getPrice();
// convert input amount from native to internal zaros precision
@audit>> UD60x18 amountInX18 = Math.convertTokenAmountToUd60x18(swapAssetConfigData[tokenIn].decimals, amountIn);
// calculate the expected amount out in native precision of output token
@audit>> expectedAmountOut = Math.convertUd60x18ToTokenAmount(
@audit>> swapAssetConfigData[tokenOut].decimals, amountInX18.mul(priceTokenInX18).div(priceTokenOutX18)
);
// revert when calculated expected output is zero; must revert here
// otherwise the subsequent slippage bps calculation will also
// return a minimum swap output of zero giving away the input tokens
if (expectedAmountOut == 0) revert Errors.ZeroExpectedSwapOutput();
}

Impact

Incorrect accounting and inability to settle the vaults debt for some vaults,or over settlement as total balance can be used when it shouldn't.

Tools Used

Manual review

Recommendations

Convert the usdc amount straight to collateral amount first and then pass it into the function to calculate usdc in.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

CreditDelegationBranch::settleVaultsDebt uses dex output expected token amount as input incorrectly, leading to failed debt settlements

Support

FAQs

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