Skip to content

feat: add ApprovalRevocationEnforcer#177

Open
jeffsmale90 wants to merge 6 commits intomainfrom
feat/erc20-allowance-revocation-enforcer
Open

feat: add ApprovalRevocationEnforcer#177
jeffsmale90 wants to merge 6 commits intomainfrom
feat/erc20-allowance-revocation-enforcer

Conversation

@jeffsmale90
Copy link
Copy Markdown
Contributor

@jeffsmale90 jeffsmale90 commented Apr 22, 2026

What?

This enforcer grants the authority to revoke allowances granted by either:

  • ERC20 approve(spender,amount)
  • ERC721 approve(to,tokenId)
  • ERC721 setApprovalForAll(operator,approved)

This covers approvals set for ERC20, ERC721 and ERC1155 tokens.

Why?

The enforcer now verifies that the target implements the expected token standard, by first invoking the standard-specific function to check the allowance being revoked.

Advanced Permissions currently has an erc20-token-revocation permission that grants the authority to revoke only ERC20 approvals. NFT approvals are also required.

By combining these revocations into a single enforcer, we get a number of benefits:

  • user must sign only a single permission to revoke all allowances across multiple token types
  • reduced gas cost to invoke a revocation (single caveat, rather than composition of multiple caveats)

How?

The enforcer accepts terms of exactly 1 byte, interpreted as a bitmask of the following values:

  • Bit 0 (0x01) - ERC-20 approve(spender, 0) (spender non-zero, amount zero)
  • Bit 1 (0x02) - ERC-721 per-token approve(address(0), tokenId)
  • Bit 2 (0x04) - ERC-721 / ERC-1155 setApprovalForAll(operator, false)

Indicating which revocation primitives the delegation authorizes. Terms must be non-zero, and the reserved upper bits must not be set.

The beforeHook only runs in single call type and default execution mode. It first performs general verification - no native value is sent (no additional value limiting caveat is required), and execution calldata is the expected length - then dispatches by selector.

setApprovalForAll and approve are distinguished by selector. The two approve signatures share a selector and are distinguished by the spender / to (first) parameter — if it is the zero address, the call is treated as the ERC-721 approve(to, tokenId) form; otherwise it is treated as the ERC-20 approve(spender, amount) form. Any other selector is rejected.

Each branch then performs a check against the delegator's current approval state on the target, ensuring the revocation is to an existing approval - ensuring that the contract implementation is a valid target for the invocation.


Note

Medium Risk
Introduces a new enforcer that gates execution based on calldata parsing and external token-interface calls; while it only enables approval reductions, incorrect routing/standard assumptions could cause unexpected reverts or missed revocations across tokens and redelegation chains.

Overview
Adds ApprovalRevocationEnforcer, a new CaveatEnforcer that allows delegates to only clear existing token approvals (ERC-20 approve(spender,0), ERC-721 approve(address(0),tokenId), and ERC-721/1155 setApprovalForAll(operator,false)) gated by a 1-byte terms bitmask, restricted to single-call + default execution mode, zero native value, and fixed calldata length, with pre-checks against current on-chain approval state.

Updates docs (CaveatEnforcers.md) with usage/terms and redelegation semantics caveats, wires the enforcer into the deploy script and verification list, and adds a comprehensive test suite covering term validation, selector/flag routing, failure modes on non-token targets, integration revocation flows, and redelegation edge cases.

Reviewed by Cursor Bugbot for commit 3f7906f. Bugbot is set up for automated code reviews on this repo. Configure here.

@jeffsmale90 jeffsmale90 requested a review from a team as a code owner April 22, 2026 03:02
@MoMannn MoMannn changed the title feat: add AllowanceRevocationEnforcer feat: add ApprovalRevocationEnforcer Apr 22, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 84896cd. Configure here.

Comment thread script/verification/verify-enforcer-contracts.sh
Copy link
Copy Markdown
Contributor Author

@jeffsmale90 jeffsmale90 left a comment

Choose a reason for hiding this comment

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

Looks good to me!

Minor comment regarding using the term permission to refer to the allowed revocation mechanism.

Comment thread src/enforcers/ApprovalRevocationEnforcer.sol Outdated
Comment thread src/enforcers/ApprovalRevocationEnforcer.sol Outdated
@MoMannn MoMannn self-requested a review April 28, 2026 06:59
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.

2 participants