Part 2

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

Incorrect Conversion Prevents Proper Vault Asset Transfers

Summary

A misconfiguration in the calculateSwapAmount function within settleVaultsDebt leads to incorrect asset conversion, preventing the vault from receiving the correct amount of assets.

Vulnerability Details

In settleVaultsDebt, the assetIn and assetOut parameters in calculateSwapAmount are incorrectly assigned:

/2025-01-zaros-part-2/src/market-making/branches/CreditDelegationBranch.sol:491
491: ctx.usdcIn = calculateSwapAmount(
492: dexSwapStrategy.dexAdapter,
493: ctx.vaultAsset, // <--should be ctx.usdc
494: ctx.usdc, // <--should be ctx.vaultAsset
495: usdcCollateralConfig.convertSd59x18ToTokenAmount(ctx.vaultUnsettledRealizedDebtUsdX18.abs()) // 0.5e30
496: );

The code checks if the ctx.usdcIn is less then the vault Balance then use ctx.usdcIn otherwise use ctx.vaultUsdcBalance.

/2025-01-zaros-part-2/src/market-making/branches/CreditDelegationBranch.sol:491
502: // if the vault doesn't have enough usdc use whatever amount it has
503: // make sure we compare native precision values together and output native precision
504: ctx.usdcIn = (ctx.usdcIn <= ctx.vaultUsdcBalance) ? ctx.usdcIn : ctx.vaultUsdcBalance;

Due to the incorrect parameter order, this check fails to properly assess the vault’s balance, resulting in an incorrect amount being passed to _convertUsdcToAssets.

/2025-01-zaros-part-2/src/market-making/branches/CreditDelegationBranch.sol:491
505:
506: // swaps the vault's usdc balance to more vault assets and
507: // send them to the ZLP Vault contract (index token address)
508: // both input and output in native precision
509: ctx.assetOutAmount = _convertUsdcToAssets(
510: vault.swapStrategy.assetDexSwapStrategyId,
511: ctx.vaultAsset,
512: ctx.usdcIn,
513: vault.swapStrategy.assetDexSwapPath,
514: vault.indexToken,
515: ctx.usdc
516: );
517: console.log("ctx.usdcIn",ctx.usdcIn);

This results in an incorrect ctx.assetOutAmount, leading to insufficient asset transfers.

Consider the following Proof Of Code:

POC

/test/integration/market-making/credit-delegation-branch/settleVaultsDebt/settleVaultsDebt.t.sol:120
120: function test_calculateSwapAmount_poc() //@audit POC
121: external
122: whenVaultIdIsValid
123: {
124: // fuzz args 12373 [1.237e4], 541, 3407112312 [3.407e9], 13379 [1.337e4])
125: uint256 vaultId = 12373;
126: uint256 marketId = 541;
127: uint128 adapterIndex = 13379;
128:
129: uint128 debtAmount = 200_000e18;
130:
131: uint128 depositedUsdc = 100_000e18; // vaultUnsettledDebtUsdAbs
132:
133: VaultConfig memory fuzzVaultConfig = getFuzzVaultConfig(vaultId);
134: PerpMarketCreditConfig memory fuzzMarketConfig = getFuzzPerpMarketCreditConfig(marketId);
135:
136: uint256[] memory marketIds = new uint256[](1);
137: marketIds[0] = fuzzMarketConfig.marketId;
138:
139: uint256[] memory vaultIds = new uint256[](1);
140: vaultIds[0] = fuzzVaultConfig.vaultId;
141:
142: changePrank({ msgSender: users.owner.account });
143: marketMakingEngine.connectVaultsAndMarkets(vaultIds, marketIds);
144:
145: deal({ token: address(fuzzVaultConfig.asset), to: fuzzVaultConfig.indexToken, give: 1e18 });
146:
147: marketMakingEngine.workaround_updateMarketTotalDelegatedCreditUsd(fuzzMarketConfig.marketId, 1e10);
148: marketMakingEngine.workaround_Vault_setTotalCreditDelegationWeight(fuzzVaultConfig.vaultId, 1e9);
149:
150: IDexAdapter adapter = getFuzzDexAdapter(adapterIndex);
151:
152:
153:
154: deal({ token: address(fuzzVaultConfig.asset), to: address(marketMakingEngine), give: type(uint128).max });
155: deal({ token: address(usdc), to: address(marketMakingEngine), give: type(uint128).max });
156:
157: marketMakingEngine.workaround_setVaultDebt(fuzzVaultConfig.vaultId, int128(debtAmount));
158: marketMakingEngine.workaround_setVaultDepositedUsdc(fuzzVaultConfig.vaultId, depositedUsdc);
159:
160: marketMakingEngine.updateVaultSwapStrategy(
161: fuzzVaultConfig.vaultId, "", "", adapter.STRATEGY_ID(), adapter.STRATEGY_ID()
162: );
163:
164: changePrank({ msgSender: address(perpsEngine) });
165: marketMakingEngine.settleVaultsDebt(vaultIds);
166:
167: }

output

ctx.usdcIn 200
ctx.vaultUsdcBalance 100000000000
ctx.usdcIn 200

Impact

The vault fails to receive the correct asset amount, disrupting debt settlement. Insufficient funding for vault operations, leading to potential liquidity issues.

Tools Used

Manual Review, Unit Testing

Recommendations

Swap the parameters in calculateSwapAmount:

after fixing the code:

491: ctx.usdcIn = calculateSwapAmount(
492: dexSwapStrategy.dexAdapter,
493: ctx.usdc,
494: ctx.vaultAsset,
495: usdcCollateralConfig.convertSd59x18ToTokenAmount(ctx.vaultUnsettledRealizedDebtUsdX18.abs())
496: );

output

ctx.usdcIn 50000000000000000000
ctx.vaultUsdcBalance 100000000000
ctx.usdcIn 100000000000

ctx.usdcIn now reflects the correct conversion, ensuring proper asset transfers to the vault.

Updates

Lead Judging Commences

inallhonesty Lead Judge
4 months ago
inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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