-
Notifications
You must be signed in to change notification settings - Fork 2
refactor(asset): remove batchBurn and BURN_FROM_ROLE (BOP-250) #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -141,13 +141,19 @@ contract B20Test is B20FactoryTest { | |
| return B20Constants.MINT_RECEIVER_POLICY; | ||
| } | ||
|
|
||
| /// @notice True iff `policyType` is one of the four base-token | ||
| /// supported policy types. Used by tests that fuzz arbitrary | ||
| /// `bytes32` and need to filter to the supported / unsupported | ||
| /// partition. | ||
| /// @notice True iff `policyType` is supported by the deployed token. | ||
| /// Used by tests that fuzz arbitrary `bytes32` and need to filter | ||
| /// to the supported / unsupported partition. Includes the four | ||
| /// base-token policy types AND the security variant's own | ||
| /// `REDEEM_SENDER_POLICY`, because `_deployToken()` returns a | ||
| /// security-variant token (see contract-level natspec) — fuzzing | ||
| /// a `bytes32` that happens to equal `keccak256("REDEEM_SENDER_POLICY")` | ||
| /// would otherwise fall through to the variant's `_readPolicyId` | ||
| /// override and not revert as `UnsupportedPolicyType`. | ||
| function _isKnownPolicyType(bytes32 policyType) internal pure returns (bool) { | ||
| return policyType == B20Constants.TRANSFER_SENDER_POLICY || policyType == B20Constants.TRANSFER_RECEIVER_POLICY | ||
| || policyType == B20Constants.TRANSFER_EXECUTOR_POLICY || policyType == B20Constants.MINT_RECEIVER_POLICY; | ||
| || policyType == B20Constants.TRANSFER_EXECUTOR_POLICY || policyType == B20Constants.MINT_RECEIVER_POLICY | ||
| || policyType == keccak256("REDEEM_SENDER_POLICY"); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are we adding this? Can we keep out as we are removing REDEEM_SENDER_POLICY in #119
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keeping it in: without this line, this PR's CI breaks. The fuzz tests in question (test_policyId_revert_unsupportedPolicyType / test_updatePolicy_revert_unsupportedPolicyType) call vm.assume(!_isKnownPolicyType(x)) and then expect UnsupportedPolicyType. Because B20Test._deployToken() returns a security-variant token, REDEEM_SENDER_POLICY is actually a supported slot at runtime (via MockB20Security._readPolicyId override at test/lib/mocks/MockB20Security.sol:222) — when the fuzz seed hits keccak256("REDEEM_SENDER_POLICY") the call doesn't revert. This was a latent bug that the seed shift from the batchBurn removal happened to surface (see commit 91f1342). You're right that it becomes dead the moment #119 lands — both the override and the constant go away — so removing this line is a trivial part of that PR's cleanup. Happy to leave a TODO here pointing at #119 if you'd like. |
||
| } | ||
|
|
||
| /// @notice Pauses a single `PausableFeature`, lazily granting `PAUSE_ROLE` | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,13 +59,12 @@ import {MockB20RedeemStorage} from "test/lib/mocks/MockB20Storage.sol"; | |
| /// `_isPrivileged()` so the factory can stage initial | ||
| /// announcements, batched issuance, ratios, identifiers, and | ||
| /// minimum-redeemable values during the bootstrap window | ||
| /// without first granting itself roles. The two paths that | ||
| /// the factory will never legitimately call during bootstrap | ||
| /// (`redeem` / `redeemWithMemo`, which are holder-initiated, | ||
| /// and `batchBurn`, which is a corporate-actions clawback | ||
| /// against existing balances) deliberately do NOT bypass | ||
| /// their authorization checks: there is no init-time use case | ||
| /// for them, so the bypass would be dead code that widens the | ||
| /// without first granting itself roles. `redeem` / | ||
| /// `redeemWithMemo` are the only paths the factory will never | ||
| /// legitimately call during bootstrap (they are | ||
| /// holder-initiated) and deliberately do NOT bypass their | ||
| /// authorization checks: there is no init-time use case for | ||
| /// them, so the bypass would be dead code that widens the | ||
| /// attack surface without buying anything. Token invariants | ||
| /// (supply-cap math, balance accounting, share-amount floor | ||
| /// on `redeem`) are NOT bypassed anywhere. | ||
|
|
@@ -75,7 +74,6 @@ contract MockB20Security is MockB20, IB20Security { | |
| // ============================================================ | ||
|
|
||
| bytes32 public constant SECURITY_OPERATOR_ROLE = keccak256("SECURITY_OPERATOR_ROLE"); | ||
| bytes32 public constant BURN_FROM_ROLE = keccak256("BURN_FROM_ROLE"); | ||
|
|
||
| bytes32 public constant REDEEM_SENDER_POLICY = keccak256("REDEEM_SENDER_POLICY"); | ||
|
|
||
|
|
@@ -96,25 +94,6 @@ contract MockB20Security is MockB20, IB20Security { | |
| return 6; | ||
| } | ||
|
|
||
| // ============================================================ | ||
| // MODIFIERS | ||
| // ============================================================ | ||
|
|
||
| /// @dev Like the base `onlyRole` but without the factory bootstrap | ||
| /// bypass: the role check is unconditional, even for the | ||
| /// factory in the init window. Reserved for variant paths | ||
| /// that deliberately reject the bypass — currently just | ||
| /// `batchBurn`, the corporate-actions clawback that has no | ||
| /// init-time use case (see this contract's natspec). Lives | ||
| /// here, not on the base, because no base function needs the | ||
| /// stricter gate. | ||
| modifier onlyRoleStrict(bytes32 role) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are we deleting this?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dead code after batchBurn removal: |
||
| if (!hasRole(role, msg.sender)) { | ||
| revert AccessControlUnauthorizedAccount(msg.sender, role); | ||
| } | ||
| _; | ||
| } | ||
|
|
||
| // ============================================================ | ||
| // ANNOUNCEMENTS | ||
| // ============================================================ | ||
|
|
@@ -170,7 +149,7 @@ contract MockB20Security is MockB20, IB20Security { | |
| } | ||
|
|
||
| // ============================================================ | ||
| // BATCHED ISSUANCE / CLAWBACK | ||
| // BATCHED ISSUANCE | ||
| // ============================================================ | ||
|
|
||
| /// @dev Pause + role enforced ONCE for the entire batch via the | ||
|
|
@@ -190,28 +169,6 @@ contract MockB20Security is MockB20, IB20Security { | |
| } | ||
| } | ||
|
|
||
| /// @dev `onlyRoleStrict` (not `onlyRole`): the factory bootstrap | ||
| /// bypass is deliberately NOT honored here, per the contract | ||
| /// natspec — clawback against existing balances has no init-time | ||
| /// use case, so granting the factory a bypass would only widen | ||
| /// the attack surface. | ||
| function batchBurn(address[] calldata accounts, uint256[] calldata amounts) | ||
| external | ||
| whenNotPaused(PausableFeature.BURN) | ||
| onlyRoleStrict(BURN_FROM_ROLE) | ||
| { | ||
| if (accounts.length != amounts.length) { | ||
| revert LengthMismatch(accounts.length, amounts.length); | ||
| } | ||
| if (accounts.length == 0) revert EmptyBatch(); | ||
| for (uint256 i = 0; i < accounts.length; i++) { | ||
| // Zero amounts are allowed per ERC-20 conventions (`transfer(0)` is valid); | ||
| // `_burnRaw` is a no-op for amount == 0 and emits `Transfer(account, 0, 0)`. | ||
| // Callers that want all-non-zero semantics can validate upstream. | ||
| _burnRaw(accounts[i], amounts[i]); | ||
| } | ||
| } | ||
|
|
||
| // ============================================================ | ||
| // REDEMPTION | ||
| // ============================================================ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignore docs for now, will get big rewrite
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you link to where we're tracking this? seems like we'll need to take a fine-toothed anti-Security comb to the whole repo