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,
494: ctx.usdc,
495: usdcCollateralConfig.convertSd59x18ToTokenAmount(ctx.vaultUnsettledRealizedDebtUsdX18.abs())
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:
503:
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:
507:
508:
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()
121: external
122: whenVaultIdIsValid
123: {
124:
125: uint256 vaultId = 12373;
126: uint256 marketId = 541;
127: uint128 adapterIndex = 13379;
128:
129: uint128 debtAmount = 200_000e18;
130:
131: uint128 depositedUsdc = 100_000e18;
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.