_replaceScope Causes Permanent DoS on Scope Updates Due to zkSync L1 Pubdata Limit on BattleChainThe ConfidencePool contract allows the sponsor (pool owner) to define and update a list of BattleChain accounts (the "scope") that the pool commits to insuring. Per DESIGN.md §8, the sponsor can update this scope freely via setPoolScope() while the registry is in pre-attack staging (NOT_DEPLOYED / NEW_DEPLOYMENT). The scope is replaced atomically through the internal _replaceScope() function, which performs a wholesale clear-and-rewrite of the entire scope list in a single transaction.
BattleChain is a confirmed zkSync-based L2 (per lib/battlechain-safe-harbor-contracts/docs/deploy-considerations.md), which enforces a hard L1 pubdata limit of ~100,000 bytes per transaction. Because _replaceScope() performs unbounded storage writes with no upper bound on scope size, a sponsor who initializes a pool with ~520+ accounts will permanently lose the ability to update the scope — the replacement transaction will always revert due to exceeding the pubdata limit. There is no batch or incremental alternative; the wholesale atomic replacement is the only code path available.
Each scope replacement of N accounts requires 3N storage writes (N clears + N mapping writes + N array pushes). On zkSync, each storage write produces ~64 bytes of L1 pubdata (32B key + 32B value). The pubdata cost scales linearly with no cap:
Setting this equal to zkSync's ~100,000 byte limit: $192N = 100{,}000 \implies N \approx 520$. Any scope replacement involving more than ~520 accounts will permanently revert.
Likelihood: Medium
Protocols with large contract deployments (DEXes, lending platforms, multi-contract DeFi systems) routinely maintain hundreds of deployed contracts across their ecosystem. A sponsor protecting such a protocol will naturally initialize scope with 500+ accounts — crossing the pubdata threshold on the confirmed zkSync-based target chain.
The contract enforces no upper bound on scope size and provides no warning or documentation about this chain-specific limitation. Sponsors have no way to know they are entering an irreversible state until the first setPoolScope() call reverts.
Impact: Low
The stated design guarantee in DESIGN.md §8 — that sponsors can "update scope freely" pre-lock — is violated. Once scope size exceeds ~520 accounts, the sponsor permanently loses the ability to correct errors (typos, wrong addresses), reflect protocol upgrades (new contract deployments), or remove deprecated/vulnerable contracts from the scope list.
The on-chain scope list, which serves as the binding transparency mechanism and audit trail for stakers to evaluate their risk exposure and for the moderator to justify resolution decisions, becomes permanently stale. Stakers can no longer verify that the published scope reflects the sponsor's actual intent, degrading the trust and accountability properties the protocol relies on.
Note: No direct fund loss occurs. The on-chain scope is not read by any payout-determining code path —
flagOutcomerelies on the moderator's off-chain judgment, and theclaimExpiredauto-resolution is explicitly scope-blind (line 533: "Scope-blind by design").
Place in test/unit/ConfidencePool.scopeDoS.t.sol and run with:
Test Output (measured):
| Scope Size | Gas Used | Est. Pubdata | Gas/Account | Within zkSync Limit? |
|---|---|---|---|---|
| 10 | 486,076 | 1,920 B | 48,607 | ✅ Yes |
| 100 | 4,542,779 | 19,200 B | 45,427 | ✅ Yes |
| 300 | 13,576,036 | 57,600 B | 45,253 | ✅ Yes |
| 500 | 22,617,889 | 96,000 B | 45,235 | ⚠️ Borderline |
| 700 | 31,662,501 | 134,400 B | 45,232 | ❌ Exceeds by 34,400 B |
Add an upper bound on scope size that respects BattleChain's pubdata constraints:
Alternatively, implement an incremental scope update pattern (e.g., addToScope() / removeFromScope()) that avoids the wholesale clear-and-rewrite, allowing large scopes to be modified in multiple transactions.
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.