Add PolicyRegistry implementation#20
Open
eric-ships wants to merge 10 commits into
Open
Conversation
Implements IPolicyRegistry following the simplified interface on main: ALLOWLIST/BLOCKLIST only (no COMPOUND), batch membership updates, spec naming (updateAllowlist/Blocklist, stageUpdateAdmin, finalizeUpdateAdmin, renounceAdmin), and built-in IDs 0 (always-allow) and type(uint64).max (always-reject). Storage layout: each policy is a single packed uint256 with the admin address in bits [167:8] and the PolicyType discriminator in bits [7:0]. Existence is checked by _policies[id] == 0 (safe because createPolicy requires a non-zero admin).
…built-in IDs, overflow comment
- ALWAYS_BLOCK_ID changes from type(uint64).max to 1 - Global counter (_nextCounter) starts at 2, typed uint56 - nextPolicyId(PolicyType) returns full top-byte-encoded ID - Type is derived from ID top byte via _typeFromId; not stored in packed slot - policyType() returns ALWAYS_ALLOW/ALWAYS_BLOCK for built-ins instead of reverting - Remove AlwaysAllowPolicy/AlwaysRejectPolicy (not in interface) - _requireCustom simplified: just checks CREATED_BIT, built-ins fall through to PolicyNotFound
9e51de3 to
6fd0607
Compare
Replaces the skeleton MockPolicyRegistry with the full reference implementation following the MockB20/MockActivationRegistry pattern: written as Solidity-as-if-Rust, etched at the precompile address via vm.etch. Removes src/impls/PolicyRegistry.sol. Also fixes stale test stubs and BaseTest comment that still referenced type(uint64).max as the always-reject sentinel (now built-in ID 1), and rewrites nextPolicyId stubs to reflect the global counter design (shared counter, both types advance together).
Fills in all 13 test stubs across createPolicy, createPolicyWithAccounts, stageUpdateAdmin, finalizeUpdateAdmin, renounceAdmin, updateAllowlist, updateBlocklist, isAuthorized, nextPolicyId, policyExists, policyType, policyAdmin, and pendingPolicyAdmin. Also fixes _nextCounter initialization: vm.etch does not run the constructor so storage state variable initializers are not applied. Counter starts at 0; the discriminator byte (0x02/0x03) ensures custom IDs can never equal built-in IDs 0 or 1.
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.
Motivation
IPolicyRegistrywas merged to main but had no implementation. This PR providesPolicyRegistry.sol, a reference implementation of the simplified v1 interface: ALLOWLIST/BLOCKLIST policies only, batch membership updates, the spec naming conventions (updateAllowlist,updateBlocklist,stageUpdateAdmin,finalizeUpdateAdmin,renounceAdmin), and the built-in sentinel IDs (0= always-allow,type(uint64).max= always-reject).What changed
src/impls/PolicyRegistry.sol: new file, full implementation ofIPolicyRegistryStorage design
Each policy is stored as a single packed
uint256:Existence check:
_policies[id] == 0means never created. This works becausecreatePolicyrequires a non-zero admin, so any valid packed value is non-zero. Built-in IDs (0andtype(uint64).max) are handled as constants with no storage access.A second mapping
_members[policyId][account]stores set membership (true = on the list, regardless of type). A third mapping_pendingAdmins[policyId]holds the staged pending admin for in-flight two-step transfers.What was tried / considered
Separate
PolicySlotlibrary (previous PR #7): The old implementation used a library to pack compound policy data into a single slot with four 62-bit constituent fields. That complexity is no longer needed since COMPOUND policies are out of scope for v1. Inlining the two encode/decode helpers directly into the contract is simpler and equally readable.ID counter overflow guard: The counter
_nextIdincrements withunchecked. It will never reachtype(uint64).maxin practice (that sentinel is reserved for always-reject), so no explicit overflow revert is added.