Page cover image

FV-SOL-9 Unbounded Loops

TLDR

Overly verbose iterations can result in failed transactions, denial of service, and reduced contract usability

Code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract UnboundedLoopExample {
    address public owner;
    address[] public recipients;
    uint256 public rewardAmount = 1 ether;

    constructor() {
        owner = msg.sender;
    }

    // Adds a recipient to the list (for testing)
    function addRecipient(address _recipient) external {
        recipients.push(_recipient);
    }

    // Distributes rewards to all recipients in the array
    function distributeRewards() external {
        require(msg.sender == owner, "Only owner can distribute rewards");

        // Unbounded loop over dynamic array "recipients"
        for (uint256 i = 0; i < recipients.length; i++) {
            // For demonstration, we assume "transfer" sends the reward.
            // In practice, we might call an ERC20 transfer or similar function.
            (bool success, ) = recipients[i].call{value: rewardAmount}("");
            require(success, "Transfer failed");
        }
    }

    // Receive Ether to fund the contract
    receive() external payable {}
}

Classifications

Mitigation Patterns

Batch Processing (FV-SOL-9-M1)

Break down large loops into smaller batches, allowing users to process data over multiple transactions rather than a single on

Gas Hard Limit (FV-SOL-9-M2)

Set a gas threshold or limit for loop processing and exit the loop once it approaches that threshold

Avoid Dynamic Data in Loops (FV-SOL-9-M3)

Limit loop iterations to fixed-sized arrays or arrays with capped sizes. Avoid using user-input data or dynamic arrays in loop conditions

Events Instead of Iteration (FV-SOL-9-M4)

In cases where a function needs to notify many users or accounts, consider emitting events instead of looping through recipients, allowing users to handle their own state separately

Actual Occurrences

Content

Last updated

Was this helpful?