_replaceScope() performs a wholesale replacement of the scope array: it clears the old entries, then fills in the new ones. Both operations loop over the full array with no upper bound on size. The clearing phase alone iterates the entire existing _scopeAccounts array and writes a false to each isAccountInScope mapping slot:
There is no MAX_SCOPE_SIZE constant anywhere in the contract. A sponsor who initializes a pool with a very large scope, or who calls setPoolScope() with a large array, can cause both the clearing and the fill loops to exceed block gas limits.
Likelihood:
A sponsor must deliberately or accidentally supply a very large accounts array. Normal usage with modest scope sizes (tens of accounts) is unaffected.
The risk increases if the protocol's agreement contracts regularly include hundreds of BattleChain accounts in scope.
Impact:
If the clearing loop exceeds the block gas limit, setPoolScope() permanently reverts, trapping the pool in its current scope with no on-chain fix path (scope updates are permanently disabled).
If the fill loop exceeds the gas limit during initialize(), pool creation fails entirely, blocking the factory from deploying pools for large-scope agreements.
The issue is demonstrated in two stages. First, a sponsor creates a pool with a large scope. Second, because the clearing loop now has to process all those entries, a subsequent scope update costs even more gas and may permanently fail, trapping the pool in an uneditable state.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.