Skip to content

docs(b20): document factory bootstrap policy asymmetry (MintReceiver always enforced)#150

Merged
stevieraykatz merged 1 commit into
mainfrom
stevekatzman/bop-332-psrc-23-factory-bootstrap-bypasses-transfer-policies-but
Jun 10, 2026
Merged

docs(b20): document factory bootstrap policy asymmetry (MintReceiver always enforced)#150
stevieraykatz merged 1 commit into
mainfrom
stevekatzman/bop-332-psrc-23-factory-bootstrap-bypasses-transfer-policies-but

Conversation

@stevieraykatz

Copy link
Copy Markdown
Member

Summary

Resolves the comment mismatch flagged in BOP-332 / PSRC #23. The IB20Factory.createB20 natspec stated that the creation (bootstrap) window bypasses the token's "role / policy / pause" authorization gates for factory-originated calls. That overstated the bypass on two counts:

  • MINT_RECEIVER_POLICY is always enforced, even for privileged (factory) mints — new supply is never issued to a policy-denied recipient, even at creation.
  • Pause is never bypassed — it defaults to nothing-paused and must be opted into via initCalls.

Only the role gates and the transfer-side policies (TRANSFER_SENDER_POLICY, TRANSFER_RECEIVER_POLICY, TRANSFER_EXECUTOR_POLICY) are actually bypassed during the window. This matches the implemented MockB20 reference semantics and the production Rust precompile.

Per the team discussion, base-std natspec is the source of truth, so the intent is pinned here rather than in implementation comments.

Changes

  • src/interfaces/IB20Factory.sol — rewrite the createB20 bootstrap-window @dev to spell out the asymmetry (role + transfer-side policies bypassed; MINT_RECEIVER_POLICY always enforced; pause never bypassed; token invariants never bypassed).
  • src/interfaces/IB20.sol — add cross-referencing @dev notes to the four policy-type getters.
  • docs/B20/Factory.md — document the asymmetry in the initCalls section.
  • test/unit/B20/supply/mint.t.sol — add test_mint_revert_privilegedStillEnforcesReceiverPolicy, which pins (via a genuine factory bootstrap, no vm.store cheat) that a privileged mint to a denied MINT_RECEIVER recipient reverts PolicyForbids. The transfer-bypass side is already covered by test_transfer_success_privilegedBypasses{Sender,Receiver}Policy in transfer.t.sol.

Testing

forge test — 620 tests passing (619 prior + 1 new). forge fmt --check clean.

…always enforced)

The `IB20Factory.createB20` natspec claimed the creation (bootstrap) window
bypasses the token's "role / policy / pause" gates for factory-originated
calls. That overstated the bypass on two counts (BOP-332 / PSRC #23):

- `MINT_RECEIVER_POLICY` is always enforced, even for privileged mints, so
  new supply is never issued to a policy-denied recipient at creation.
- Pause is never bypassed; it defaults to nothing-paused and must be opted
  into via initCalls.

Only role gates and the transfer-side policies (sender / receiver / executor)
are actually bypassed. base-std natspec is the source of truth, so pin the
intent there rather than in implementation comments:

- Rewrite the `createB20` bootstrap-window natspec to spell out the asymmetry.
- Add cross-referencing notes to the IB20 policy-type getters.
- Document the asymmetry in docs/B20/Factory.md.
- Add a unit test pinning that a privileged bootstrap mint to a denied
  MINT_RECEIVER recipient reverts (the transfer-bypass side is already
  covered in transfer.t.sol).

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@linear

linear Bot commented Jun 9, 2026

Copy link
Copy Markdown

BOP-332

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Interface Coverage

✅ All interface functions have test coverage.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

📊 Forge Coverage (src/lib/)

🟢 ≥99% across all metrics.

File Lines Stmts Branches Funcs
🟢 B20FactoryLib.sol 100.00% 100.00% 100.00% 100.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.95% 99.08% 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 100.00% 100.00% 100.00% 100.00%
Total 99.86% 99.88% 100.00% 100.00%

Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

✅ Fork tests: all 609 passed

base/base is fully in sync with the base-std spec.

@stevieraykatz stevieraykatz merged commit daf5eed into main Jun 10, 2026
10 checks passed
@stevieraykatz stevieraykatz deleted the stevekatzman/bop-332-psrc-23-factory-bootstrap-bypasses-transfer-policies-but branch June 10, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants