test(BOP-486): add seize smoke journey (+ fix stablecoin burnBlocked binding) - #187
Merged
stephancill merged 5 commits intoJul 31, 2026
Merged
Conversation
New `seize` smoke journey exercising the Cobalt `seizeWithMemo` surface against a live node: SEIZE_HOLDER_POLICY membership gate + SEIZE_ROLE, the happy-path seizeWithMemo (Transfer -> Memo -> Seized, supply-preserving), the reject gates (AccountNotSeizable, role, InvalidReceiver, ContractPaused), the admin-op decoupling from the receiver policy on `to`, and the independent SEIZE pause vector. Fork-gated: probes the SEIZE_HOLDER_POLICY() getter and skips cleanly on a pre-Cobalt chain, mirroring the multiplier journey. Adds SEIZE_ROLE / SEIZE_HOLDER_POLICY / FEATURE_SEIZE constants to config, registers the journey in the CLI (run order + `all`), and documents it in the README. Complements the stablecoin journey's legacy burn-based burnBlocked path. Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
stephancill
requested review from
amiecorso,
eric-ships,
ilikesymmetry,
rayyan224 and
stevieraykatz
as code owners
July 31, 2026 19:47
Interface Coverage✅ All interface functions have test coverage. |
Match the feature/surface name (seizeWithMemo) and the CLI key. The epic is titled Transfer Blocked; the operation is seize. Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
📊 Forge Coverage (
|
| 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% | 99.54% | 97.67% | 100.00% |
| 🟢 MockPolicyRegistryStorage.sol | 100.00% | 100.00% | 100.00% | 100.00% |
| Total | 96.75% | 97.26% | 98.09% | 96.46% |
Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).
✅ Fork tests: all 703 passedbase/base is fully in sync with the base-std spec. |
…ring Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
…rney base-std #186 removed burnBlocked from the IB20 interface, so it is absent from STABLECOIN_ABI and web3 raised ABIFunctionNotFound. The selector still dispatches on the precompile (retained for back-compat), so bind it via an explicit fragment to keep exercising the legacy burn-based freeze-and-seize path. Full smoke suite now green (7/7) against a local Cobalt node. Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
robriks
approved these changes
Jul 31, 2026
stevieraykatz
approved these changes
Jul 31, 2026
stephancill
deleted the
stephancilliers/bop-486-transfer-blocked-smoke-tests
branch
July 31, 2026 20:11
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
Adds a
seizesmoke journey exercising the CobaltseizeWithMemosurface against a live node, closing out BOP-486. Complements thestablecoinjourney, which covers the legacy burn-basedburnBlockedpath.The journey (
script/smoke/journeys/seize.py, CLI keyseize) walks:SEIZE_HOLDER_POLICY()/SEIZE_ROLE()match the keccak constants.seizeWithMemo(from, to, amount, memo)reassigns a seizable holder's balance; assertsTransfer→Memo→Seizedlog order,Seizedevent args, and thattotalSupplyis unchanged (seize is a transfer, not a burn).AccountNotSeizable, role (AccessControlUnauthorizedAccount),InvalidReceiver(zeroto), andContractPausedunder a pausedSEIZE.toonTRANSFER_RECEIVER_POLICY(a normal transfer revertsPolicyForbids) and shows seize still lands, since it's an admin op that doesn't consult the receiver policy.SEIZEblocks seize but leaves transfers working; unpause restores.Fork-gated: probes the
SEIZE_HOLDER_POLICY()getter and cleanly skips on a pre-Cobalt chain (where the seize selectors don't exist), the same stance as themultiplierjourney.Also adds
SEIZE_ROLE/SEIZE_HOLDER_POLICY/FEATURE_SEIZEtoconfig, registers the journey in the CLI (run order +all), and documents it in the README.Also: stablecoin journey fix
Fixes a regression from #186 (which removed
burnBlockedfrom theIB20interface): thestablecoinjourney calledburnBlockedthrough the interface ABI and now failed withABIFunctionNotFound. The selector still dispatches on the precompile (retained for back-compat), so the journey now binds it via an explicit ABI fragment to keep exercising the legacy burn-based freeze-and-seize path. (This regression is live onmaintoday; base-std has no gating smoke CI, so it wasn't caught at #186 merge.)Testing
Ran the full suite against a local Cobalt node (patched
anvil+forgefrom the base-anvil fork built against this base/base seize surface):seizepasses every assertion;stablecoingreen after the fix;invariants13/13. Statically:forge buildexposesseizeWithMemo/SEIZE_HOLDER_POLICY/SEIZE_ROLE/Seized/AccountNotSeizable; config keccak ids match the Rust precompile constants; all referenced error names resolve from the ABI.