Skip to content

Loops do not break when possible#

Low Risk

Looping through arrays can be expensive, that is why it is important to break the loop as soon as possible. There are multiple cases in the code base, where loops go through whole array even though it already has the information that it needs.

Examples#

Example 1#

verifyTraits in Create.sol goes through whole canvasTraits array, although the loop could be exited whenever valid is set to false.

bool valid = true;
for (uint256 i = 0; i < canvasTraits.length;) {
    if (canvasTraits[i].traitsChance > 10_000) valid = false;
    if (canvasTraits[i].values.length != canvasTraits[i].chancesOrQuantity.length) valid = false;
    unchecked { i++; }
}

if (!valid) revert InvalidTraits();

Solution 1#

uint256 len = canvasTraits.length;
for (uint256 i = 0; i < len;) {
    if(canvasTraits[i].traitsChance > 10_000 || canvasTraits[i].values.length != canvasTraits[i].chancesOrQuantity.length)
        revert InvalidTraits();
    unchecked { i++; }
}

Example 2#

setTokenRefs in Customize.sol goes through whole ds.allowedRefs[canvasId] array, although the loop could be exited when allowed is set to true.

bool allowed = false;
for (uint256 j = 0; j < ds.allowedRefs[canvasId].length;) {
    if (ds.allowedRefs[canvasId][j] == refs[i].tokenAddress) allowed = true;
    unchecked { j++; }
}
if (!allowed) revert InvalidReference();

Solution 2#

bool allowed = false;
uint256 len = ds.allowedRefs[canvasId].length;
for (uint256 j = 0; j < len) {
    if (ds.allowedRefs[canvasId][j] == refs[i].tokenAddress) {
        allowed = true;
        break;
    }
    unchecked { j++; }
}
if (!allowed) revert InvalidReference();