Skip to content

docs(b20-asset): enumerate multiplier reverts, trim ERC-8056 natspec - #179

Open
stevieraykatz wants to merge 1 commit into
mainfrom
fix/erc8056-natspec-revert-enumeration
Open

docs(b20-asset): enumerate multiplier reverts, trim ERC-8056 natspec#179
stevieraykatz wants to merge 1 commit into
mainfrom
fix/erc8056-natspec-revert-enumeration

Conversation

@stevieraykatz

Copy link
Copy Markdown
Member

Summary

Follow-up NatSpec/doc cleanup on the ERC-8056 scaled-multiplier work (#173). No ABI, storage, or behavior changes — interfaces and docs only.

Three findings from a post-merge review:

  1. Revert enumeration regression (IB20Asset). The team convention is that every revert path — role gates included — gets its own @dev Reverts with ... line in execution order. The pre-feat(b20-asset): ERC-8056 scaled multiplier (scheduled updates + conformance) #173 updateMultiplier documented these; widening the surface to ERC-8056 dropped them and shipped setUIMultiplier / cancelScheduledMultiplier with none. Restored for all three:

    • setUIMultiplier: AccessControlUnauthorizedAccount, InvalidMultiplier, EffectiveAtInPast, EffectiveAtTooFar, ScheduleOverlap
    • cancelScheduledMultiplier: AccessControlUnauthorizedAccount, NoScheduledMultiplier
    • updateMultiplier: AccessControlUnauthorizedAccount, InvalidMultiplier
  2. Callsite natspec carrying design rationale (IScaledUIAmount). The core interface @dev explained why TransferWithUIAmount is omitted (the D9 decision). That rationale is concept-level and now lives in docs/B20/Asset.md; the interface keeps only the callsite fact plus a pointer.

  3. Overflow claim over-scoped (docs/B20/Asset.md). "scaled reads can never overflow" holds for balance-derived reads (bounded by the uint128 supply cap) but not for toScaledBalance(rawBalance), which takes an arbitrary input and still reverts on overflow — as its own test asserts. Scoped the guarantee accordingly.

Testing

forge build passes (no new warnings). No test changes — this is documentation-only.

@github-actions

Copy link
Copy Markdown

Interface Coverage

✅ All interface functions have test coverage.

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

📊 Forge Coverage (src/lib/)

🟡 ≥95% across all metrics — some metrics below 99%.

File Lines Stmts Branches Funcs
🔴 B20FactoryLib.sol 95.40% 96.00% 100.00% 90.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 100.00% 100.00% 100.00% 100.00%
Total 96.63% 97.27% 98.63% 96.33%

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

@stevieraykatz
stevieraykatz force-pushed the fix/erc8056-natspec-revert-enumeration branch from 5d99c0c to 5396db3 Compare July 28, 2026 18:33
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

⚠️ Fork tests: 66 failed, 646 passed

These failures indicate divergences where base/base needs to catch up to the base-std spec. This check is advisory and does not block merging.

Failing tests
  • test_childrenSlot_success_locatesChildArray(uint8): custom error 0x6fdd1491; counterexample: calldata=0x69fce776000000000000000000000000000000000000000000000000000000000000001a args=[26]
  • test_createCompositePolicy_revertOrder(uint8): custom error 0x6fdd1491; counterexample: calldata=0x5fafe4f70000000000000000000000000000000000000000000000000000000000000004 args=[4]
  • test_createCompositePolicy_revert_builtinChild(address,address,uint8): Error != expected error: custom error 0x6fdd1491 != InvalidChildPolicy(0); counterexample: calldata=0x87108a4b0000000000000000000000005fc77d564310e8c6890f2fd8ca09718ae082dcb400000000000000000000000058ce6c64876b708cf29209eb96e3223767bfd4400000000000000000000000000000000000000000000000000000000000000000 args=[0x5fC77d564310E8c6890f2Fd8CA09718ae082dcb4, 0x58Ce6c64876B708cF29209EB96e3223767Bfd440, 0]
  • test_createCompositePolicy_revert_childPoliciesOutsideOfRange(address,address,uint8,uint8): Error != expected error: custom error 0x6fdd1491 != ChildPoliciesOutsideOfRange(2, 4); counterexample: calldata=0xb8466436000000000000000000000000cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000e1 args=[0xCB00000000000000000000000000000000000000, 0x00000000000000000000000000000000000040E0, 3, 225]
  • test_createCompositePolicy_revert_incompatiblePolicyType(address,address,uint8): Error != expected error: custom error 0x6fdd1491 != IncompatiblePolicyType(); counterexample: calldata=0x9732692500000000000000000000000031d404509893774f19df09e265da85ab3efc30bc00000000000000000000000004ff5fd9d119b7fb018a178b19871d1ac9dc3a6b0000000000000000000000000000000000000000000000000000000000000000 args=[0x31d404509893774f19Df09e265DA85ab3eFC30BC, 0x04fF5Fd9D119b7fB018A178b19871d1Ac9dc3a6b, 0]
  • test_createCompositePolicy_revert_invalidChildPolicy(address,address,uint8): custom error 0x6fdd1491; counterexample: calldata=0x7416f45900000000000000000000000010ce341807f0b2fb697e812934dfb338804a38c200000000000000000000000024f35d3796bde197e1fb1e363f2c410f2e3730e5000000000000000000000000000000000000000000000000000000000000002d args=[0x10CE341807f0b2Fb697E812934DFb338804A38c2, 0x24f35D3796bde197E1fb1E363F2C410f2E3730E5, 45]
  • test_createCompositePolicy_revert_policyNotFound(address,address,uint8,uint64): Error != expected error: custom error 0x6fdd1491 != PolicyNotFound(); counterexample: calldata=0x1803f605000000000000000000000000081f9de7a10c1768d391b50c7be2a116a24fad38000000000000000000000000f862332223d9361dfc0dbecad8a45a04fedbfa05000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000031c46b43caa18a3b args=[0x081F9dE7A10c1768d391B50C7be2a116A24Fad38, 0xF862332223D9361dFc0DBeCAD8a45a04fEdbfa05, 1, 3586109142200322619 [3.586e18]]
  • test_createCompositePolicy_revert_zeroAdmin(address,uint8): Error != expected error: custom error 0x6fdd1491 != ZeroAddress(); counterexample: calldata=0xb18b5cb100000000000000000000000000000000000000000000000000000000000013340000000000000000000000000000000000000000000000000000000000000097 args=[0x0000000000000000000000000000000000001334, 151]
  • test_createCompositePolicy_success_advancesNextPolicyId(address,uint8,uint8): custom error 0x6fdd1491; counterexample: calldata=0xf9a1ca77000000000000000000000000ca9faacf6e116636049ac822b477fe29536dd35300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 args=[0xCA9fAAcF6e116636049aC822B477FE29536dD353, 0, 3]
  • test_createCompositePolicy_success_atMaxChildren(address,address,uint8): custom error 0x6fdd1491; counterexample: calldata=0x296e3341000000000000000000000000ee2a4fe9797cd8c64a4c1abdb637fe4ba5aa2b180000000000000000000000008ce620138ff7efb38572984ed3b3fdd76663422b0000000000000000000000000000000000000000000000000000000000000002 args=[0xEE2a4Fe9797CD8c64A4c1AbdB637fE4bA5Aa2b18, 0x8ce620138ff7efb38572984Ed3b3fdD76663422b, 2]
  • test_createCompositePolicy_success_emitsCompositePolicyUpdated(address,address,uint8): log != expected log; counterexample: calldata=0x1694cfe00000000000000000000000007c5a542b916bbe32a8ac6e6d7e15a02f72580b040000000000000000000000001296a44b78b743423de9a0f534e13c8e3179fee90000000000000000000000000000000000000000000000000000000000000008 args=[0x7C5A542B916BbE32a8AC6e6D7e15a02F72580b04, 0x1296a44B78B743423De9A0f534E13c8E3179Fee9, 8]
  • test_createCompositePolicy_success_emitsInitialPolicyAdminUpdated(address,address,uint8): log != expected log; counterexample: calldata=0xd6a6c2b200000000000000000000000000000000000000000000000000000000000013fd000000000000000000000000000000000000000000000000000000000000094e00000000000000000000000000000000000000000000000000000000000000a8 args=[0x00000000000000000000000000000000000013FD, 0x000000000000000000000000000000000000094e, 168]
  • test_createCompositePolicy_success_emitsPolicyCreated(address,address,uint8): log != expected log; counterexample: calldata=0x89031165000000000000000000000000d3901c7f2829eab2b744f010f52ad1c799f4366b000000000000000000000000ee6d7e23bbaaf1aa91bd3d5c136fc98cf41f1fa40000000000000000000000000000000000000000000000000000000000000061 args=[0xd3901C7f2829EAb2B744F010f52aD1c799f4366b, 0xeE6d7e23BbaAf1AA91Bd3d5C136FC98Cf41F1fa4, 97]
  • test_createCompositePolicy_success_intersect(address,address): custom error 0x6fdd1491; counterexample: calldata=0xccbe0bd4000000000000000000000000000000000000000000000000000000000000042f000000000000000000000000b20f000000000000000000000000000000000000 args=[0x000000000000000000000000000000000000042f, 0xB20f000000000000000000000000000000000000]
  • test_createCompositePolicy_success_union(address,address): custom error 0x6fdd1491; counterexample: calldata=0xd748b1fe00000000000000000000000045894571a48ab8acaa503647ec5e4ee8146ac9c30000000000000000000000006e91629c94913671bd5d4d84ab1be70554676286 args=[0x45894571A48Ab8AcAa503647EC5E4Ee8146Ac9c3, 0x6e91629c94913671bD5d4D84aB1BE70554676286]
  • test_isAuthorized_success_composite_mixedChildTypes(address): custom error 0x6fdd1491; counterexample: calldata=0xca56e88d00000000000000000000000076289caf485edd49e33fd74f3f11ce0c1170a00c args=[0x76289CAF485EdD49E33fD74F3f11cE0C1170a00C]
  • test_isAuthorized_success_composite_reflectsChildMembershipChange(address): custom error 0x6fdd1491; counterexample: calldata=0x9154ecaf0000000000000000000000000000000000000000000000000000000000002cf6 args=[0x0000000000000000000000000000000000002cf6]
  • test_isAuthorized_success_intersect_allChildrenAuthorize(address): custom error 0x6fdd1491; counterexample: calldata=0x12f37cef000000000000000000000000615aaeacce418d9b4c695ce723bd44207e863572 args=[0x615aAeacCE418d9B4C695CE723BD44207E863572]
  • test_isAuthorized_success_intersect_oneChildDenies(address): custom error 0x6fdd1491; counterexample: calldata=0x70fa07e60000000000000000000000004c1c802d0c0311c709e5bff850e2c2e23d122421 args=[0x4C1C802d0c0311C709e5bfF850E2c2E23D122421]
  • test_isAuthorized_success_union_anyChildAuthorizes(address): custom error 0x6fdd1491; counterexample: calldata=0x1ab5411300000000000000000000000068002bc47755d0338ab5d3e78d986c2853a05c50 args=[0x68002Bc47755D0338AB5D3e78D986c2853A05c50]
  • test_isAuthorized_success_union_noChildAuthorizes(address): custom error 0x6fdd1491; counterexample: calldata=0x18ea2b8700000000000000000000000086e8d145dc7d6219515ca2047c05c30587de4d98 args=[0x86E8d145dC7D6219515Ca2047C05c30587de4D98]
  • test_updateComposite_revertOrder(uint8): custom error 0x6fdd1491; counterexample: calldata=0x46b240f90000000000000000000000000000000000000000000000000000000000000003 args=[3]
  • test_updateComposite_revert_builtinChild(uint8): custom error 0x6fdd1491; counterexample: calldata=0x44e9729e0000000000000000000000000000000000000000000000000000000000000001 args=[1]
  • test_updateComposite_revert_childPoliciesOutsideOfRange(uint8,uint8): custom error 0x6fdd1491; counterexample: calldata=0x25c44760000000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000003d args=[47, 61]
  • test_updateComposite_revert_incompatiblePolicyType(uint8): Error != expected error: custom error 0xbfe142c0 != IncompatiblePolicyType(); counterexample: calldata=0xbe9d9a40000000000000000000000000000000000000000000000000000000000000005f args=[95]
  • test_updateComposite_revert_invalidChildPolicy(uint8): custom error 0x6fdd1491; counterexample: calldata=0xfc6d02c60000000000000000000000000000000000000000000000000000000000000078 args=[120]
  • test_updateComposite_revert_policyNotFound(address,uint64): Error != expected error: custom error 0xbfe142c0 != PolicyNotFound(); counterexample: calldata=0xbc492f7a000000000000000000000000b981810eb72a69098c94ffe8d72a46742b727a70000000000000000000000000000000000000000000000000000000000005dbe0 args=[0xb981810eb72A69098C94Ffe8d72a46742B727A70, 383968 [3.839e5]]
  • test_updateComposite_revert_policyNotFoundChild(uint8,uint64): custom error 0x6fdd1491; counterexample: calldata=0x5d96e02c00000000000000000000000000000000000000000000000000000000000000b700000000000000000000000000000000000000000000000000000000000f4240 args=[183, 1000000 [1e6]]
  • test_updateComposite_revert_renouncedComposite(uint8): custom error 0x6fdd1491; counterexample: calldata=0x9c795a4200000000000000000000000000000000000000000000000000000000000000c9 args=[201]
  • test_updateComposite_revert_unauthorized(address,uint8): custom error 0x6fdd1491; counterexample: calldata=0x13f7deab000000000000000000000000d92c4240bfd1d7c8a9580a394aaf93dc0158f5420000000000000000000000000000000000000000000000000000000000000003 args=[0xd92c4240BFd1D7c8a9580a394AAf93dC0158F542, 3]
  • test_updateComposite_success_atMaxChildren(uint8): custom error 0x6fdd1491; counterexample: calldata=0x9b8e06050000000000000000000000000000000000000000000000000000000000000001 args=[1]
  • test_updateComposite_success_emitsCompositePolicyUpdated(uint8): custom error 0x6fdd1491; counterexample: calldata=0xc975d54c0000000000000000000000000000000000000000000000000000000000000000 args=[0]
  • test_updateComposite_success_replacesChildSet(address): custom error 0x6fdd1491; counterexample: calldata=0xbb14993300000000000000000000000000000000000000000000000000000000667f9d71 args=[0x00000000000000000000000000000000667f9D71]

Restore the revert enumeration on the scheduled-multiplier interface that
the ERC-8056 change dropped, and tighten two doc claims.

- IB20Asset: add per-revert @dev lines (in execution order) for
  setUIMultiplier, cancelScheduledMultiplier, and updateMultiplier, per
  the team natspec convention that every revert path (role gates included)
  is enumerated. updateMultiplier previously documented these; the widening
  to the ERC-8056 surface removed them.
- IScaledUIAmount: move the TransferWithUIAmount-omission rationale out of
  callsite natspec into docs/B20/Asset.md; keep only the callsite fact.
- docs/B20/Asset.md: scope the no-overflow guarantee to balance-derived
  reads (toScaledBalance takes arbitrary input and can still overflow), and
  carry the TransferWithUIAmount rationale the interface now points to.
@stevieraykatz
stevieraykatz force-pushed the fix/erc8056-natspec-revert-enumeration branch from 5396db3 to c8ae772 Compare July 28, 2026 19:00
@stevieraykatz
stevieraykatz marked this pull request as ready for review July 28, 2026 19:17
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.

1 participant