Part 2

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

Missing prior credit capacity recalculation in `depositCreditForMarket()`

Summary

The depositCreditForMarket() function fails to call recalculateVaultsCreditCapacity() before accepting deposits, unlike other similar functions like withdrawUsdTokenFromMarket(). This omission can lead to deposits being accepted based on stale vault states.

Vulnerability Details

The recalculateVaultsCreditCapacity() function performs several critical state updates:

1.Debt Recalculation:

(
SD59x18 vaultTotalRealizedDebtChangeUsdX18,
SD59x18 vaultTotalUnrealizedDebtChangeUsdX18,
UD60x18 vaultTotalUsdcCreditChangeX18,
UD60x18 vaultTotalWethRewardChangeX18
) = _recalculateConnectedMarketsState(self, connectedMarketsIdsCache, true);
  • Updates realized and unrealized debt from connected markets

  • Recalculates USDC credit changes

  • Updates WETH reward distributions

2.Credit Delegation Updates:

(, SD59x18 vaultNewCreditCapacityUsdX18) = _updateCreditDelegations(
self,
updatedConnectedMarketsIdsCache,
false
);
  • Updates credit delegations to connected markets

  • Adjusts based on new credit capacity

The Problem in depositCreditForMarket()

Current implementation:

function depositCreditForMarket(
uint128 marketId,
address collateralAddr,
uint256 amount
) external onlyRegisteredEngine(marketId) {
Market.Data storage market = Market.loadLive(marketId);
if (market.getTotalDelegatedCreditUsd().isZero()) {
revert Errors.NoDelegatedCredit(marketId);
}
---SNIP---
// @audit-info Directly updates market state without recalculation
if (collateralAddr == usdToken) {
market.updateNetUsdTokenIssuance(unary(amountX18.intoSD59x18()));
} else {
if (collateralAddr == usdc) {
market.settleCreditDeposit(address(0), amountX18);
} else {
market.depositCredit(collateralAddr, amountX18);
}
}
}

The function proceeds with deposits without:

  • Recalculating current vault credit capacities

  • Updating debt distributions

  • Refreshing credit delegations

Impact

Stale debt values are used for critical calculations resulting in incorrect credit delegation amounts and misaligned reward distributions.

Tools Used

Manual Review

Recommendations

  1. Add credit capacity recalculation to depositCreditForMarket():

function depositCreditForMarket(
uint128 marketId,
address collateralAddr,
uint256 amount
) external onlyRegisteredEngine(marketId) {
Market.Data storage market = Market.loadLive(marketId);
+ // @audit Recalculate vault credit capacity
+ uint256[] memory connectedVaults = market.getConnectedVaultsIds();
+ Vault.recalculateVaultsCreditCapacity(connectedVaults);
if (market.getTotalDelegatedCreditUsd().isZero()) {
revert Errors.NoDelegatedCredit(marketId);
}
// Rest of the function...
}
Updates

Lead Judging Commences

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

Credit capacity calculation uses stale total assets in VaultRouterBranch::deposit by updating before the actual deposit, causing DOS in depositCreditForMarket

Support

FAQs

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