Safe Harbor agreements can include child-contract coverage through ChildContractScope. A child contract can be legally covered by a parent account's Binding Agreement even when the child itself is not a top-level BattleChain account.
Confidence Pool scope is only a flat address[] of accounts. _replaceScope() validates each address with IAgreement(agreement).isContractInScope(account), and the Safe Harbor implementation's isContractInScope() only checks the top-level BattleChain scope cache. As a result, a child contract covered only through a parent cannot be added directly to a pool scope. A pool can include the parent, but pool.isAccountInScope(child) remains false and the pool has no field to represent ChildContractScope.All, ExistingOnly, FutureOnly, or the cutoff time.
The underlying issue is that the pool's on-chain scope functionality cannot faithfully represent a valid Safe Harbor child-coverage commitment.
The upstream scope model includes child coverage in AgreementTypes.sol#L41-L58:
The Safe Harbor binding rules describe child-contract resolution in seal-agreement-modified.md#L345-L350:
The pool scope replacement path validates only the flat account list in ConfidencePool.sol::_replaceScope:
The current agreement scope predicate checks only the top-level cache in Agreement.sol::isContractInScope:
The pool accepts only the top-level cache address. It cannot encode that a non-top-level child is legally covered by the parent account's child-contract setting.
Likelihood: Low
A Safe Harbor agreement uses parent-account child coverage such as All, ExistingOnly, or FutureOnly.
A sponsor wants a Confidence Pool to cover a specific child contract or wants the pool's scope API to expose that child coverage.
Integrations or users inspect getScopeAccounts() or isAccountInScope(child) to understand the pool's advertised coverage.
Impact: Low
A legally covered child contract cannot be added directly to the Confidence Pool scope.
A pool scoped to the parent does not expose child membership through isAccountInScope(child).
The on-chain pool scope cannot represent the child coverage mode or cutoff semantics that define the Safe Harbor Binding Agreement for child contracts.
The PoC file included with this report is:
To run it in a fresh contest checkout:
Copy ChildContractScopeNotRepresentablePoC.t.sol into the repository's test/ directory.
Run:
Expected result:
The PoC demonstrates:
A mock agreement has parent P in top-level scope with ChildContractScope.All.
Child C is legally included by the Safe Harbor-style child resolver.
agreement.isContractInScope(C) returns false because C is not in the top-level BattleChain cache.
Initializing a pool directly scoped to C reverts with AccountNotInAgreementScope.
Initializing a pool scoped to P succeeds, but pool.isAccountInScope(C) remains false.
Inline PoC source (ChildContractScopeNotRepresentablePoC.t.sol):
If Confidence Pools intend to support Safe Harbor child coverage, extend pool scope to represent child-contract semantics explicitly, or add a binding-aware resolver query for child contracts.
One direction is to store richer scope entries instead of a flat account list:
If child coverage is intentionally unsupported, the factory and pool documentation should state that pool scope only covers top-level BattleChain accounts and that isAccountInScope(child) is not a Safe Harbor child-coverage resolver.
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.