Skip to content

refactor(BOP-440): rename seize surface (seizeWithMemo/SEIZE_ROLE/SEIZE_HOLDER_POLICY); drop burnBlocked changes - #186

Merged
stephancill merged 5 commits into
mainfrom
stephancilliers/bop-440-seize-rename
Jul 31, 2026
Merged

refactor(BOP-440): rename seize surface (seizeWithMemo/SEIZE_ROLE/SEIZE_HOLDER_POLICY); drop burnBlocked changes#186
stephancill merged 5 commits into
mainfrom
stephancilliers/bop-440-seize-rename

Conversation

@stephancill

@stephancill stephancill commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Finalizes the base-std seize surface per the updated BOP-439 decisions, superseding the design merged in #177.

  • Rename the seize surface across the IB20 interface, the reference impl (MockB20), and tests:
    • transferFromSeizableWithMemoseizeWithMemo
    • TRANSFER_FROM_SEIZABLE_ROLESEIZE_ROLE
    • SEIZABLE_ACCOUNT_POLICYSEIZE_HOLDER_POLICY
    • event TransferredFromSeizableSeized
    • (role/policy keccak strings change accordingly)
  • Drop burnBlockedWithMemo entirely (no burn-with-memo variant).
  • Revert burnBlocked to its pre-feat(BOP-440): add transferFromSeizableWithMemo and burnBlockedWithMemo seize surface #177 behavior: blocked check on TRANSFER_SENDER_POLICY and the BURN pause vector. It is no longer part of the seize operation class; behavior is otherwise unchanged.
  • Remove burnBlocked from the IB20 interface as a deprecation signal. The reference impl keeps the selector working for back-compat; formal deprecation/removal is announced for the Denim hardfork. Retained burnBlocked reference tests call it via a concrete MockB20 cast.

The SEIZE pause vector now governs only seizeWithMemo. The dedicated seize storage slot (offset 14) is unchanged, so deployed layouts are undisturbed.

Testing

  • forge build OK
  • forge test — 712 passed, 0 failed, 4 skipped
  • forge fmt --check clean

Seize suites: seizeWithMemo (9), seizeWithMemo_revertOrder (5). burnBlocked suites reverted to BURN + TRANSFER_SENDER_POLICY: burnBlocked (7), burnBlocked_revertOrder (6).

Comparison vs pre-seize baseline

Diffed against main as of the commit right before the seize work (#177) landed, to confirm the net effect is purely the additive seize surface with burnBlocked untouched. Only #177 plus this branch's commits ever touched the core seize files, so the isolation is clean.

  • burnBlocked effectively untouched: implementation body is byte-identical to baseline (same BURN pause, TRANSFER_SENDER_POLICY check, AccountNotBlocked, BurnedBlocked). Tests are identical except the call-site cast token.burnBlocked(...)MockB20(address(token)).burnBlocked(...), forced only because burnBlocked was removed from the IB20 type. Only other addition is a deprecation comment.
  • Storage layout safe: seize slot added at offset 14; the mock-only initialized flag moved 14→15. Offsets 0–13 (every real token-state field) are unchanged, so deployed layouts are undisturbed. initialized doesn't exist in the Rust precompile, so its relocation is a no-op there. Offset-pin test updated accordingly.
  • Net new surface (additive/intended): SEIZE_ROLE, SEIZE_HOLDER_POLICY, Seized event, AccountNotSeizable error, seizeWithMemo + getters, _requireSeizable, and the behavior-preserving _moveBalance extraction. burnBlocked removed from the interface (intended deprecation), impl retained. burnBlockedWithMemo nets to zero vs baseline.
  • One intentional cross-cutting change: PausableFeature gains SEIZE (index 3), bumping ALL_FEATURES_PAUSED 7→15 (pinned by the removals regression). This is the shared/unversioned enum member that trips the frozen-V1 isPaused(3) gotcha on the base/base side.

No unexpected changes.

…anges

Finalizes the seize surface naming and decouples burnBlocked, per the
updated BOP-439 decisions (supersedes the #177 design):

- Rename across interface + reference impl + tests:
  - transferFromSeizableWithMemo -> seizeWithMemo
  - TRANSFER_FROM_SEIZABLE_ROLE  -> SEIZE_ROLE
  - SEIZABLE_ACCOUNT_POLICY      -> SEIZE_HOLDER_POLICY
  - event TransferredFromSeizable -> Seized
  (role/policy keccak strings change accordingly.)
- Drop burnBlockedWithMemo entirely (no burn-with-memo variant).
- Revert burnBlocked to its pre-#177 behavior: blocked check on
  TRANSFER_SENDER_POLICY and the BURN pause vector (no longer part of the
  seize class). Behavior is otherwise unchanged.
- Remove burnBlocked from the IB20 interface as a deprecation signal; the
  reference impl keeps the selector working for back-compat. Formal
  deprecation/removal is announced for the Denim hardfork. Retained
  burnBlocked reference tests call it via a concrete MockB20 cast.

SEIZE pause vector now governs only seizeWithMemo. The dedicated seize
storage slot (offset 14) is unchanged. All unit tests pass; fmt clean.

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@linear

linear Bot commented Jul 31, 2026

Copy link
Copy Markdown

BOP-440

@github-actions

Copy link
Copy Markdown

Interface Coverage

✅ All interface functions have test coverage.

@github-actions

github-actions Bot commented Jul 31, 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% 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).

…locked for burnBlocked

Splits the shared error so each gate has an accurate name:
- seizeWithMemo now reverts AccountNotSeizable(from) (gate: SEIZE_HOLDER_POLICY)
- deprecated burnBlocked keeps AccountNotBlocked(from) (gate: TRANSFER_SENDER_POLICY)

Membership in SEIZE_HOLDER_POLICY marks who CAN be seized from, so "not
blocked" was semantically wrong for the seize path.

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

⚠️ Fork tests: 46 failed, 680 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_policyId_success_reflectsUpdatePolicy(uint8,uint64): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0xa21d943e0000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000000e args=[88, 14]
  • test_policyId_success_zeroByDefault(uint8): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x11a5c8f400000000000000000000000000000000000000000000000000000000000000fd args=[253]
  • test_seizeWithMemo_revertOrder_blocked_beats_balance(address,address): Error != expected error: custom error 0xf916d81b != AccountNotSeizable(0x76D14Cd0Ae31781b69F101C0C78de192df691795); counterexample: calldata=0x8dcc06c200000000000000000000000076d14cd0ae31781b69f101c0c78de192df6917950000000000000000000000006eb9b82f8960121dcc846ea5fb7ab996909b0118 args=[0x76D14Cd0Ae31781b69F101C0C78de192df691795, 0x6EB9B82F8960121DcC846eA5Fb7AB996909b0118]
  • test_seizeWithMemo_revertOrder_pause_beats_blocked(address,address): custom error 0xa290249c: type check failed for "(uint8[])" with data: 0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003; counterexample: calldata=0xd8656555000000000000000000000000f65cd284a67f3f77887062f4055c1f595eec60b1000000000000000000000000ee0e6835ef89bb81bd61f1d27877c0109f2d23ed args=[0xF65cD284A67F3f77887062f4055C1f595eec60B1, 0xEe0e6835ef89Bb81bd61F1d27877C0109f2d23ed]
  • test_seizeWithMemo_revertOrder_pause_beats_role(address,address,address): custom error 0xa290249c: type check failed for "(uint8[])" with data: 0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003; counterexample: calldata=0xadeb3963000000000000000000000000b9a48f93a3ce86eb289f2d9286c3d1e4ae7ff85d00000000000000000000000009e1fc874724535da5db24957e0a93c7640906ff0000000000000000000000002adfbcf9704588cfe489d2b5420c5ee68600d6b1 args=[0xb9A48F93a3CE86EB289F2D9286c3D1E4Ae7FF85D, 0x09e1FC874724535Da5DB24957E0A93c7640906FF, 0x2aDfBcF9704588cfe489d2b5420C5ee68600d6b1]
  • test_seizeWithMemo_revertOrder_role_beats_zeroActors(address,address): Error != expected error: custom error 0xf916d81b != AccessControlUnauthorizedAccount(0xe7196954BC58A328837dDBE11CdBb20915DA63F8, 0x3469b8b0d89e9604f8510ed143f74a8336d22955d4f83e23bf53d9414e27f432); counterexample: calldata=0x36c308ae000000000000000000000000e7196954bc58a328837ddbe11cdbb20915da63f80000000000000000000000007416c34aec2d603dcf87452ad216b69f27a0cba3 args=[0xe7196954BC58A328837dDBE11CdBb20915DA63F8, 0x7416c34Aec2D603dCf87452AD216B69F27A0cBa3]
  • test_seizeWithMemo_revertOrder_zeroActors_beats_blocked(address): Error != expected error: custom error 0xf916d81b != InvalidReceiver(0x0000000000000000000000000000000000000000); counterexample: calldata=0x02c145c5000000000000000000000000b2000000000000000000009e871a2184b5afacd0 args=[0xB2000000000000000000009E871a2184B5AFaCd0]
  • test_seizeWithMemo_revert_accountNotBlocked(address,address,uint256): Error != expected error: custom error 0xf916d81b != AccountNotSeizable(0x7B70Ec16CEEFb12f632791CFf291ef6eD528d575); counterexample: calldata=0x41754db20000000000000000000000007b70ec16ceefb12f632791cff291ef6ed528d575000000000000000000000000d13f061ab0f9f31e26f8aa6533c9a2c8cf8bb49d00000000000000000000000000000000000000000000000e976cb733655e09cd args=[0x7B70Ec16CEEFb12f632791CFf291ef6eD528d575, 0xD13f061Ab0F9F31E26F8Aa6533c9a2C8Cf8Bb49d, 269165714460517468621 [2.691e20]]
  • test_seizeWithMemo_revert_insufficientBalance(address,address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x033c500500000000000000000000000048d6967671cee00dc4772d02ba00d543271a74db00000000000000000000000075837d74414859db4f2a18db2987b0ca896b595c0000000000000000000000000000000000000000000000000000000000000002 args=[0x48D6967671CEe00dC4772d02ba00d543271a74DB, 0x75837D74414859Db4F2A18Db2987b0CA896B595c, 2]
  • test_seizeWithMemo_revert_invalidReceiver(address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x92e9b38800000000000000000000000059151cba48f5d7276274170c15f292aff07374ed000000000000000000000000000058502b5f7119e6f62a3ef83a672cc1815320 args=[0x59151cBA48f5D7276274170C15F292afF07374Ed, 7693161403714561562594139576964027795985184 [7.693e42]]
  • test_seizeWithMemo_revert_unauthorized(address,address,address,uint256): Error != expected error: custom error 0xf916d81b != AccessControlUnauthorizedAccount(0x00000000000000000000ffffffFFFFFfFFFFfffE, 0x3469b8b0d89e9604f8510ed143f74a8336d22955d4f83e23bf53d9414e27f432); counterexample: calldata=0x0334937c00000000000000000000000000000000000000000000fffffffffffffffffffe0000000000000000000000000000000000000000000000000000000000000309000000000000000000000000845300000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000104c13ec args=[0x00000000000000000000ffffffFFFFFfFFFFfffE, 0x0000000000000000000000000000000000000309, 0x8453000000000000000000000000000000000002, 273421292 [2.734e8]]
  • test_seizeWithMemo_revert_whenSeizePaused(address,address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x83c47ba40000000000000000000000000ab2fe62d9afa38add2a3ebbdb0ec65c4f43c4dc0000000000000000000000009a71de900a936e2983f83c012ab6c51f3d7ca5830000048b43b04b1156d34be0dd3d6581cf3cf53bcac26e8059f70baa428c12f1 args=[0x0aB2fe62D9afa38adD2A3ebbdB0ec65c4F43c4Dc, 0x9A71De900a936E2983F83C012ab6c51F3D7CA583, 31361546420267702546736845602977235181058782940999042475711525513073393 [3.136e70]]
  • test_seizeWithMemo_success_emitsEvents(address,address,uint256,bytes32): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x984936cb0000000000000000000000000000000000000000000000000000000000002b550000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000d4f0000000000000000000000000000000000000000000000000000000000001145 args=[0x0000000000000000000000000000000000002b55, 0x0000000000000000000000000de0b6B3a7640000, 3407, 0x0000000000000000000000000000000000000000000000000000000000001145]
  • test_seizeWithMemo_success_ignoresReceiverPolicy(address,address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x6358be6c0000000000000000000000000000000000000000000000000000000093d328910000000000000000000000000000000000000000000000000000000000001e6f0000000000000000000000000000000000000000000000000000000000001b20 args=[0x0000000000000000000000000000000093d32891, 0x0000000000000000000000000000000000001E6F, 6944]
  • test_seizeWithMemo_success_movesBalance(address,address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0xc4ab022a000000000000000000000000bad3f46fa42206c2d3538caf427ce9ffa788183a000000000000000000000000ad7e96c7ef9601a6e5d74db6f503f82ede50d6270000000000000000000000000000000000000000000000000000000000000002 args=[0xBAd3F46fA42206C2d3538CAF427ce9ffa788183A, 0xad7e96C7eF9601A6E5d74Db6F503F82Ede50d627, 2]
  • test_seizeWithMemo_success_noAllowanceRequired(address,address,uint256): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0xdc26e1f50000000000000000000000000000000000000000000000000000000000000c2400000000000000000000000000000000000000000000000000000000000012b80000000000000000000000000000000000000000000000000000000004f04c9a args=[0x0000000000000000000000000000000000000c24, 0x00000000000000000000000000000000000012b8, 82857114 [8.285e7]]
  • test_updatePolicy_revert_policyNotFound(uint8,uint64): Error != expected error: UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2) != PolicyNotFound(216172782113783810 [2.161e17]); counterexample: calldata=0x74fd7f3900000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003 args=[3, 3]
  • test_updatePolicy_success_builtinAllow(uint8): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0xde997e8b0000000000000000000000000000000000000000000000000000000000000008 args=[8]
  • test_updatePolicy_success_builtinReject(uint8): UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2); counterexample: calldata=0x56f5b9080000000000000000000000000000000000000000000000000000000000000021 args=[33]
  • test_updatePolicy_success_emitsPolicyUpdated(uint8,uint64): log != expected log; counterexample: calldata=0x59afa2fa000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000521ff609 args=[128, 1377826313 [1.377e9]]
    [FAIL: UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2)] test_b20Layout_success_populatedSnapshotMatchesAllSlots() (gas: 569463)
    [FAIL: UnsupportedPolicyType(0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2)] test_seizePolicyIdsSlot_success_decodesSeizableLane() (gas: 12560)
    [FAIL: isPaused must still accept enum index 3 (SEIZE)] test_isPaused_revert_noFifthFeature() (gas: 9532)

Comment thread test/lib/mocks/MockB20.sol Outdated
Comment on lines +311 to +315
// Deprecated: `burnBlocked` is retained unchanged for back-compat but is no
// longer part of the IB20 interface. Its blocked check reads
// `TRANSFER_SENDER_POLICY` and it gates on the `BURN` pause vector — it is NOT
// part of the seize operation class (that is `seizeWithMemo`). Formal removal
// is announced for the Denim hardfork.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need to mention that it is not part of the seize operation class. we should however state that the recommended path is now seize to self and then burn

…then-burn)

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
Comment thread test/lib/mocks/MockB20.sol Outdated
// longer part of the IB20 interface. Its blocked check reads
// `TRANSFER_SENDER_POLICY` and it gates on the `BURN` pause vector. The
// recommended path is now `seizeWithMemo` to a treasury/self address followed
// by a normal `burn`. Formal removal is announced for the Denim hardfork.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to commit in a comment here what code will land in Denim?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment thread test/lib/mocks/MockB20.sol Outdated
emit Memo(msg.sender, memo);
}

// Deprecated: `burnBlocked` is retained unchanged for back-compat but is no

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe all caps DEPRECATED with a @notice?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI: Done — converted to a @notice DEPRECATED natspec, with the guard rationale moved to @dev.

Comment thread test/lib/mocks/MockB20.sol Outdated
Comment on lines +321 to +327
// The point of burnBlocked is to seize from policy-blocked
// accounts. Read the transfer-sender policy ID out of the
// transfer-side packed slot and reject if the target is
// currently authorized. Enforced unconditionally — including
// for factory-originated calls during the bootstrap window —
// matching the Rust precompile, which carves no `privileged`
// exception for this guard.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a weird place for this verbosity. We do one-line comments in impls generally unless something is very complicated. This seems more like natspec body content to me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI: Moved the rationale out of the impl body into @dev natspec; the function body no longer carries the block comment.

Comment thread test/lib/mocks/MockB20Storage.sol
…mitment

Addresses review: use all-caps DEPRECATED @notice natspec, move the guard
rationale into @dev instead of an inline impl block, and remove the
comment stating what will land in Denim.

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@robriks
robriks self-requested a review July 31, 2026 18:04

@robriks robriks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aligned with these renames

Comment thread src/interfaces/IB20.sol Outdated
Comment on lines +109 to +110
/// `SEIZE_HOLDER_POLICY` (i.e. not a member of the seize-holder set, so not eligible to be
/// seized from).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// `SEIZE_HOLDER_POLICY` (i.e. not a member of the seize-holder set, so not eligible to be
/// seized from).
/// `SEIZE_HOLDER_POLICY` (i.e. not a member of the seize-holder set).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI: Applied.

Comment thread src/interfaces/IB20.sol Outdated

/// @notice Required to call `burnBlocked` and `burnBlockedWithMemo`.
/// @notice Required to call the deprecated `burnBlocked` (no longer part of this interface; retained for
/// the back-compat impl, with formal removal announced for Denim).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

denim called out here too. must have missed first time through

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI: Removed the Denim mention on the BURN_BLOCKED_ROLE getter too. Grep-confirmed there are no remaining Denim references in the .sol files.

… BURN_BLOCKED_ROLE

Addresses review: apply the suggested shorter AccountNotSeizable wording,
and remove the remaining Denim commitment from the BURN_BLOCKED_ROLE getter.

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@stephancill
stephancill merged commit 96e9687 into main Jul 31, 2026
10 checks passed
@stephancill
stephancill deleted the stephancilliers/bop-440-seize-rename branch July 31, 2026 18:38
stephancill added a commit that referenced this pull request Jul 31, 2026
…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>
stephancill added a commit that referenced this pull request Jul 31, 2026
…binding) (#187)

* test(BOP-486): add transfer-blocked (seize) smoke journey

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>

* test(BOP-486): drop burnBlocked note from PausableFeature comment

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>

* test(BOP-486): rename journey module transfer_blocked -> seize

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>

* test(BOP-486): drop transfer-blocked wording from seize journey docstring

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>

* test(BOP-486): bind deprecated burnBlocked selector in stablecoin journey

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>

---------

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
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.

3 participants