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
);
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---
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
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...
}