feat: composite-policy support in MockPolicyRegistry#175
Merged
rayyan224 merged 5 commits intoJul 24, 2026
Conversation
Add tests asserting createCompositePolicy and updateComposite revert InvalidChildPolicy when a child is a built-in sentinel (ALWAYS_ALLOW_ID / ALWAYS_BLOCK_ID), and align the IPolicyRegistry natspec accordingly. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
rayyan224
requested review from
amiecorso,
eric-ships,
ilikesymmetry and
stevieraykatz
as code owners
July 24, 2026 17:04
Interface Coverage❌ Interface functions with no test coverage found. |
📊 Forge Coverage (
|
| File | Lines | Stmts | Branches | Funcs |
|---|---|---|---|---|
| 🟢 B20FactoryLib.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🔴 test/lib/ForceFeeder.sol | 0.00% | 0.00% | 100.00% | 0.00% |
| 🔴 test/lib/PrecompileProbe.sol | 0.00% | 0.00% | 0.00% | 0.00% |
| 🟢 MockActivationRegistry.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟢 MockActivationRegistryStorage.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟢 MockB20.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟢 MockB20Asset.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟡 MockB20Factory.sol | 98.96% | 99.10% | 100.00% | 100.00% |
| 🟢 MockB20Stablecoin.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟢 MockB20Storage.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🟢 MockPolicyRegistry.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| 🔴 MockPolicyRegistryStorage.sol | 90.62% | 88.89% | 100.00% | 88.89% |
| Total | 96.51% | 97.04% | 98.53% | 96.06% |
Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).
|
Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
…ange Collapse the TooFewChildPolicies (< 2) and BatchSizeTooLarge(4) (> 4) composite child-count checks into a single ChildPoliciesOutsideOfRange(min, max) error reverting with (2, 4). Remove the now-unused TooFewChildPolicies error; BatchSizeTooLarge is retained for account-membership batches. Add MIN_CHILD_POLICIES and update the composite tests + revert-order walks accordingly. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
rayyan224
merged commit Jul 24, 2026
09a8792
into
composite-policy-interface-proposal
6 of 7 checks passed
rayyan224
added a commit
that referenced
this pull request
Jul 24, 2026
…ts (#174) * Propose composite policy interface (UNION/INTERSECT) Interface-only proposal for composite policies on IPolicyRegistry: - Extend PolicyType with UNION and INTERSECT (append-only; leaf discriminants 0/1 unchanged, gate rides the policy ID top byte). - Add createCompositePolicy(admin, gate, operands) and updateCompositeOperands(policyId, operands). Update is a full-set overwrite (replace-all), re-validated as at creation. - Add CompositePolicyCreated and CompositeOperandsUpdated events, and EmptyOperandSet / InvalidOperand errors. - Note on createPolicy/createPolicyWithAccounts that composite gates revert IncompatiblePolicyType. Operands are flat-only (leaf ALLOWLIST/BLOCKLIST), capped at the composite operand limit, and the set may not be empty. This changes only the interface; MockPolicyRegistry and the Rust precompile implementation follow in a separate PR, so the mock will not compile against this interface until then. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * Tighten composite NatSpec wording Drop the "not an incremental edit" binary contrast and the "silently" adverb; make the flat-only note active. Wording only, no signature or behavior change. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * Apply suggestion from @ilikesymmetry Co-authored-by: Conner Swenberg <conner.swenberg@coinbase.com> * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * Apply suggestion from @ilikesymmetry Co-authored-by: Conner Swenberg <conner.swenberg@coinbase.com> * feat: poloicy registry * feaet: more clean up * chore: clean up * feat: rename to simple * chore: clean up * chore: update error types * feat: update policy registry * refactor: remove CompositePolicyCreated event Use the canonical PolicyCreated event for every policy type and surface composite child policies via CompositePolicyUpdated (now emitted on both creation and update). Gives indexers one creation path and one per-field update path. Addresses PR #174 review. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * chore: update dev docs * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * Apply suggestion from @stevieraykatz Co-authored-by: katzman <steve.katzman@coinbase.com> * feat: policy registry * chore: clean up * feat: composite-policy support in MockPolicyRegistry (#175) * feat: create composite polocies * feat: create mock polocy * test: reject built-in sentinels as composite children Add tests asserting createCompositePolicy and updateComposite revert InvalidChildPolicy when a child is a built-in sentinel (ALWAYS_ALLOW_ID / ALWAYS_BLOCK_ID), and align the IPolicyRegistry natspec accordingly. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * style: forge fmt Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * refactor: replace composite count errors with ChildPoliciesOutsideOfRange Collapse the TooFewChildPolicies (< 2) and BatchSizeTooLarge(4) (> 4) composite child-count checks into a single ChildPoliciesOutsideOfRange(min, max) error reverting with (2, 4). Remove the now-unused TooFewChildPolicies error; BatchSizeTooLarge is retained for account-membership batches. Add MIN_CHILD_POLICIES and update the composite tests + revert-order walks accordingly. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * test: cover childrenSlot storage helper The Interface Coverage CI check flags any test/lib/mocks function with zero test hits. childrenSlot / childrenBaseSlot were added for the composite child set but never exercised. Add a slot-helper test that reads a composite's child array via childrenSlot, matching the existing slot-helper test pattern. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: katzman <steve.katzman@coinbase.com> Co-authored-by: Conner Swenberg <conner.swenberg@coinbase.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements composite-policy support in the
MockPolicyRegistryreference mock, filling the gap whereIPolicyRegistryalready declared composites (createCompositePolicy,updateComposite,CompositePolicyUpdated,TooFewChildPolicies,InvalidChildPolicy) but the mock only handled simple BLOCKLIST/ALLOWLIST policies.Storage (
MockPolicyRegistryStorage.sol)childrenmapping (uint64 => uint64[]) toLayoutat offset 4 (offsets 0–3 unchanged).CHILDREN_OFFSET,childrenBaseSlot(), and a documentedchildrenSlot(policyId)helper for slot-math parity with the Rust precompile.Implementation (
MockPolicyRegistry.sol)MAX_CHILD_POLICIES = 4.createCompositePolicy— canonical precedence:ZeroAddress→IncompatiblePolicyType→TooFewChildPolicies→BatchSizeTooLarge(4)→ child validation → create + store children +CompositePolicyUpdated.updateComposite— precedence:PolicyNotFound→IncompatiblePolicyType→Unauthorized→ count/size → child validation → full child-set replacement +CompositePolicyUpdated.isAuthorizedextended with live composite evaluation, split into_isAuthorizedUnion(OR, empty → false) and_isAuthorizedIntersect(AND, empty → true)._requireCreatedSimplePolicies— two-pass child validation: existence first (PolicyNotFound), then rejects built-in sentinels and composites (InvalidChildPolicy). Built-in sentinels (ALWAYS_ALLOW_ID/ALWAYS_BLOCK_ID) may not be composed.Tests
isAuthorizedUNION/INTERSECT/mixed/live-membership cases).test_createCompositePolicy_revert_builtinChildandtest_updateComposite_revert_builtinChildcovering the built-in-sentinel rejection.Testing
forge test→ 660 passed, 0 failed, 4 skipped (the 4 skipped are the mock-only counter-overflow tests guarded byvm.skip(livePrecompiles)).forge fmt --checkclean.