MEDIUM severity: Curve gauges with 7+ extra reward tokens cannot be integrated. When the PoolFactory creates new reward distributors, we begin by manually adding CRV and SDT as reward tokens. We then iterate through the Curve gauge's reward tokens and add each of those to the StakeDAO reward distributor.

StakeDAO's reward distributor is a fork of Curve's gauges. Both...

Vulnerable code:
/// @notice Add extra reward tokens to the reward distributor.
/// @param _gauge Address of the liquidity gauge.
function _addExtraRewards(address _gauge) internal virtual {
    /// Check if the gauge supports extra rewards.
    /// This function is not supported on all gauges, depending on when they were deployed.
    bytes memory data = abi.encodeWithSignature("reward_tokens(uint256)", 0);

    /// Hence the call to the function is wrapped in a try catch.
    (bool success,) = _gauge.call(data);
    if (!success) {
        /// If it fails, we set the LGtype to 1 to indicate that the gauge doesn't support extra rewards.
        /// So the harvest would skip the extra rewards.
        strategy.setLGtype(_gauge, 1);

        return;
    }

    /// Loop through the extra reward tokens.
    /// 8 is the maximum number of extra reward tokens supported by the gauges.
    for (uint8 i = 0; i < 8;) {
        /// Get the extra reward token address.
        address _extraRewardToken = ISDLiquidityGauge(_gauge).reward_tokens(i);

        /// If the address is 0, it means there are no more extra reward tokens.
        if (_extraRewardToken == address(0)) break;

        /// Performs checks on the extra reward token.
        /// Checks like if the token is also an lp token that can be staked in the locker, these tokens are not supported.
        if (_isValidToken(_extraRewardToken)) {
            /// Then we add the extra reward token to the reward distributor through the strategy.
            strategy.addRewardToken(_gauge, _extraRewardToken);
        }

        unchecked {
            ++i;
        }
    }
}

contract GaugeWithMaxRewardTokens {
    function lp_token() external view returns (address) {
        return 0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2;
    }

    function reward_tokens(uint256 i) external view returns (address) {
        if (i == 0) {
            return 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
        } else if (i == 1) {
            return 0xdAC17F958D2ee523a2206206994597C13D831ec7;
        } else if (i == 2) {
            return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
        } else if (i == 3) {
            return 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984;
        } else if (i == 4) {
            return 0x514910771AF9Ca656af840dff83E8264EcF986CA;
        } else if (i == 5) {
            return 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
        } else if (i == 6) {
            return 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
        } else if (i == 7) {
            return 0xF17A3fE536F8F7847F1385ec1bC967b2Ca9caE8D;
        } else {
            revert("NOT POSSILBE");
        }
    }
}

function testZach__gauge_with_max_fails() public {
    address gauge_to_test = 0x7ca5b0a2910B33e9759DC7dDB0413949071D7575;
    address gauge_with_max = address(new GaugeWithMaxRewardTokens());
    vm.etch(gauge_to_test, gauge_with_max.code);
    (address x, address y) = poolFactory.create(gauge_to_test);
}