Part 2

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

Denial of Service (DoS) in getCreditDepositsValueUsd Function

Summary

The getCreditDepositsValueUsd function in the Market.sol contract is vulnerable to a potential Denial of Service (DoS) attack due to its unbounded loop over the creditDeposits map. This can lead to excessive gas consumption and transaction failures, especially when the number of credit deposits is large.

Vulnerability Details

The issue is located in the following code snippet:

function getCreditDepositsValueUsd(Data storage self) internal view returns (UD60x18 creditDepositsValueUsdX18) {
// load the map of credit deposits and cache length
EnumerableMap.AddressToUintMap storage creditDeposits = self.creditDeposits;
uint256 creditDepositsLength = creditDeposits.length(); //@audit DoS possible, add offset, limit, from - to params
for (uint256 i; i < creditDepositsLength; i++) {
// load each credit deposit data & associated collateral
(address asset, uint256 value) = creditDeposits.at(i);
Collateral.Data storage collateral = Collateral.load(asset);
// update the total credit deposits value
creditDepositsValueUsdX18 =
creditDepositsValueUsdX18.add((collateral.getAdjustedPrice().mul(ud60x18(value))));
}
}

The function iterates over all entries in the creditDeposits map without any bounds, which can lead to excessive gas consumption and potential transaction failures if the number of entries is large.

The getCreditDepositsValueUsd function is used in the getRealizedDebtUsd function in the Market.sol contract:

function getRealizedDebtUsd(Data storage self) internal view returns (SD59x18 realizedDebtUsdX18) {
// prepare the credit deposits usd value variable;
UD60x18 creditDepositsValueUsdX18;
// if the credit deposits usd value cache is up to date, return the stored value
if (block.timestamp <= self.lastCreditDepositsValueRehydration) {
creditDepositsValueUsdX18 = ud60x18(self.creditDepositsValueCacheUsd);
} else {
// otherwise, we'll need to loop over credit deposits to calculate it
creditDepositsValueUsdX18 = getCreditDepositsValueUsd(self);
}
// finally after determining the market's latest credit deposits usd value, sum it with the stored net usd
// token issuance to return the net realized debt usd value
realizedDebtUsdX18 = creditDepositsValueUsdX18.intoSD59x18().add(sd59x18(self.netUsdTokenIssuance));
}

Impact

The impact of this issue is that it can lead to excessive gas consumption and transaction failures, potentially causing a Denial of Service (DoS) for users interacting with the contract. This can prevent users from performing essential operations such as calculating realized debt.

Tools Used

Manual code review

Recommendations

To mitigate this issue, it is recommended to add offset and limit parameters to the getCreditDepositsValueUsd function to allow for bounded iteration over the creditDeposits map. This can be achieved by implementing the following changes:

Add offset and limit parameters to the function signature.
Modify the loop to iterate only within the specified range.
Example:

function getCreditDepositsValueUsd(Data storage self, uint256 offset, uint256 limit) internal view returns (UD60x18 creditDepositsValueUsdX18) {
// load the map of credit deposits and cache length
EnumerableMap.AddressToUintMap storage creditDeposits = self.creditDeposits;
uint256 creditDepositsLength = creditDeposits.length();
// ensure offset and limit are within bounds
require(offset < creditDepositsLength, "Offset out of bounds");
uint256 end = Math.min(offset + limit, creditDepositsLength);
for (uint256 i = offset; i < end; i++) {
// load each credit deposit data & associated collateral
(address asset, uint256 value) = creditDeposits.at(i);
Collateral.Data storage collateral = Collateral.load(asset);
// update the total credit deposits value
creditDepositsValueUsdX18 =
creditDepositsValueUsdX18.add((collateral.getAdjustedPrice().mul(ud60x18(value))));
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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