Part 2

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

Unbounded Loops in _recalculateConnectedMarketsState

Summary

The _recalculateConnectedMarketsState function contains nested loops that iterate over connectedMarketsIdsCache, potentially leading to gas exhaustion when processing a large number of connected markets. This issue can cause transactions to fail due to excessive gas consumption, making the contract inefficient and unreliable. To mitigate this, implementing pagination or batch processing is recommended.


Vulnerability Details

  • Location: _recalculateConnectedMarketsState function

  • Severity: High

  • Type: Gas Optimization

  • Issue: The function contains unbounded nested loops that iterate over connectedMarketsIdsCache. If the array grows too large, executing this function in a transaction could exceed the block gas limit, causing transaction failure and potential denial of service.

  • Reproducibility: High


Root Cause

The function does not impose a limit on the number of iterations when processing connectedMarketsIdsCache. As a result, when the number of connected markets is large, the computation required becomes excessive, leading to gas exhaustion.


Impact

  • Transactions may fail due to excessive gas consumption.

  • The function could make certain operations unusable in production environments where the dataset grows significantly.

  • Users interacting with the function may experience higher transaction fees.

  • Potential denial of service if critical functions depend on this logic.


Tools Used

  • Hardhat

  • Foundry

  • Slither (for static analysis)

  • Gas Reporter (for gas cost estimation)


Proof of Concept

To validate this issue, i simulate a scenario where connectedMarketsIdsCache contains a large number of entries, causing gas exhaustion. Below is a Hardhat test to demonstrate this:

Hardhat Test to Simulate Gas Exhaustion

const { expect } = require("chai");
describe("Unbounded Loops in _recalculateConnectedMarketsState", function () {
let contract;
let owner;
beforeEach(async function () {
const Contract = await ethers.getContractFactory("YourContract");
contract = await Contract.deploy();
await contract.deployed();
[owner] = await ethers.getSigners();
});
it("Should fail due to excessive gas usage when processing a large connectedMarketsIdsCache", async function () {
// Simulate adding a large number of connected market IDs
let largeArray = [];
for (let i = 0; i < 10000; i++) {
largeArray.push(i);
}
// Manually set the connectedMarketsIdsCache (if possible)
await contract.setConnectedMarketsIdsCache(largeArray);
// Try calling the function
await expect(contract.recalculateConnectedMarketsState())
.to.be.revertedWith("out of gas");
});
});

This test populates connectedMarketsIdsCache with a large dataset and attempts to execute _recalculateConnectedMarketsState(), expecting a gas exhaustion failure.


Mitigation

To resolve this issue, consider the following fixes:

  1. Batch Processing: Process the connectedMarketsIdsCache in smaller chunks rather than iterating over all entries in a single transaction.

    uint256 public batchSize = 100;
    function recalculateConnectedMarketsState(uint256 startIndex, uint256 endIndex) external {
    require(endIndex <= connectedMarketsIdsCache.length, "Invalid range");
    for (uint256 i = startIndex; i < endIndex; i++) {
    // Process batch logic here
    }
    }
  2. Pagination: Allow users to process connectedMarketsIdsCache incrementally across multiple transactions instead of doing it all at once.

  3. Gas Limit Check: Implement logic to halt execution when the function is approaching the block gas limit.

These changes prevent excessive gas consumption, making the function more efficient and scalable.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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.