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) {
EnumerableMap.AddressToUintMap storage creditDeposits = self.creditDeposits;
uint256 creditDepositsLength = creditDeposits.length();
for (uint256 i; i < creditDepositsLength; i++) {
(address asset, uint256 value) = creditDeposits.at(i);
Collateral.Data storage collateral = Collateral.load(asset);
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) {
UD60x18 creditDepositsValueUsdX18;
if (block.timestamp <= self.lastCreditDepositsValueRehydration) {
creditDepositsValueUsdX18 = ud60x18(self.creditDepositsValueCacheUsd);
} else {
creditDepositsValueUsdX18 = getCreditDepositsValueUsd(self);
}
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) {
EnumerableMap.AddressToUintMap storage creditDeposits = self.creditDeposits;
uint256 creditDepositsLength = creditDeposits.length();
require(offset < creditDepositsLength, "Offset out of bounds");
uint256 end = Math.min(offset + limit, creditDepositsLength);
for (uint256 i = offset; i < end; i++) {
(address asset, uint256 value) = creditDeposits.at(i);
Collateral.Data storage collateral = Collateral.load(asset);
creditDepositsValueUsdX18 =
creditDepositsValueUsdX18.add((collateral.getAdjustedPrice().mul(ud60x18(value))));
}
}