feat(b20): cap supply cap at uint128.max#164
Merged
Merged
Conversation
Interface Coverage✅ All interface functions have test coverage. |
📊 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 | 100.00% | 100.00% | 100.00% | 100.00% |
| Total | 96.69% | 97.23% | 98.39% | 96.89% |
Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).
69fe3be to
fc9da12
Compare
|
fc9da12 to
f16f362
Compare
Introduce an upper bound on the B-20 supply cap: it may never be set
above type(uint128).max. Because mint rejects any totalSupply above the
cap, this also bounds totalSupply to type(uint128).max.
- B20Constants: add MAX_SUPPLY_CAP = type(uint128).max as the canonical
ceiling (and unbounded sentinel), alongside the existing MAX_* limits.
- IB20: document the ceiling on supplyCap() / updateSupplyCap(), with
uint128.max now the unbounded ("no cap") sentinel. InvalidSupplyCap is
reused for the above-maximum case (its notice now covers both
out-of-range directions); no new error.
- MockB20: mirror MAX_SUPPLY_CAP from B20Constants and reject
newSupplyCap < currentSupply || newSupplyCap > MAX_SUPPLY_CAP with
InvalidSupplyCap.
- MockB20Factory: write the default bootstrap cap as
B20Constants.MAX_SUPPLY_CAP.
Tests: add the above-maximum revert (InvalidSupplyCap), the inclusive
at-maximum boundary, and a factory-creation test asserting a fresh
token's supplyCap is seeded to MAX_SUPPLY_CAP (surface + slot, fuzzed
caller/salt) so fork mode catches a precompile that misses it. Bound
minted amounts to B20Constants.MAX_SUPPLY_CAP across the
mint/transfer/burn/memo/storage suites (replacing hardcoded
type(uint128).max) so the ceiling is referenced via a single constant.
Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
f16f362 to
f44597c
Compare
refcell
approved these changes
Jun 11, 2026
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
Introduces an upper bound on the B-20 supply cap: it may never be set above
type(uint128).max. Becausemintalready rejects anytotalSupplyabove the cap, this also guaranteestotalSupplycan never exceedtype(uint128).max.type(uint128).maxbecomes the new unbounded ("no cap") sentinel, replacingtype(uint256).max.No new error: the existing
InvalidSupplyCapis reused for the above-maximum case (its scope now covers both out-of-range directions — below current supply and above the maximum).Changes
B20Constants: addedMAX_SUPPLY_CAP = type(uint128).maxas the canonical ceiling / unbounded sentinel, alongside the existingMAX_*limits.IB20:InvalidSupplyCapnotice broadened to cover both out-of-range directions;supplyCap()/updateSupplyCap()natspec updated for theuint128.maxceiling.MockB20: mirrorsMAX_SUPPLY_CAPfromB20Constants;updateSupplyCaprevertsInvalidSupplyCapwhennewSupplyCap < currentSupply || newSupplyCap > MAX_SUPPLY_CAP.MockB20Factory: writes the default bootstrap cap asB20Constants.MAX_SUPPLY_CAP.Tests
test_updateSupplyCap_revert_aboveMaximum(expectsInvalidSupplyCap) andtest_updateSupplyCap_success_atMaximum(inclusive boundary).test_createB20_success_assetSupplyCapDefaultsToMax: asserts a factory-created token'ssupplyCap()is seeded toMAX_SUPPLY_CAPat creation (paired surface + slot, fuzzed caller/salt). The surface assertion runs against the real precompile underLIVE_PRECOMPILES, so fork mode catches a precompile that fails to seed the cap at creation.B20Constants.MAX_SUPPLY_CAP(replacing hardcodedtype(uint128).max) across the mint / transfer / transferFrom / burn / burnBlocked / memo / storage suites, so the ceiling is referenced through a single named constant.Result: 625 pass / 0 fail / 4 skipped (pre-existing
LIVE_PRECOMPILES-gated).forge fmtclean.MockB20.sol100% coverage; overall branch coverage 100%.Note on Rust parity
base-std mirrors the Rust precompile. This adds a
uint128.maxsupply-cap ceiling that should be confirmed against the Rust implementation before merge — if Rust does not enforce the same ceiling, the fork tests will diverge.