Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

授权机制进阶:兼容调用与撤销范围

基础篇展示了旧额度和新额度都被消费的排序。这里区分三件事:更新代币 allowance 的兼容方式、许可签名的使用方式,以及撤销是否覆盖未来提交的签名。

1. 无限授权的信任边界

approve(spender, type(uint256).max) 给 Spender 长期代扣权限。若路由可升级、存在允许任意 from 的入口,或其管理权被攻破,历史额度都可能被利用。不可升级也不等于没有逻辑漏洞。

按需额度可以限制一次性暴露,但不能追回已经消费的资产。清理旧路由授权时还要识别真实 Token 和 Spender,不能仅凭前端展示名称判断。

2. forceApprove 做了什么?

某些代币拒绝从非零额度直接改成另一个非零额度。以 OpenZeppelin Contracts 5.2.0 为准,SafeERC20.forceApprove 先尝试目标值;若该尝试的返回行为不被接受,再尝试归零并设置目标值。源码

它不是“先读取 allowance,再决定归零”。它解决调用兼容性,不改变 approve 的覆盖语义,也不是用户历史授权的防抢跑证明。

// 位于业务合约内部;这设置的是该合约自身的 allowance。
using SafeERC20 for IERC20;
IERC20(token).forceApprove(spender, amount);

业务合约调用该方法时,Token 看到的 Owner 是业务合约,不是提交交易的用户。不能用它直接修改用户已经给其他 Spender 的额度。

示例工程中的 testForceApproveZeroFirstCompatibilityAndCallerScope 实际验证了先归零代币的更新路径,同时确认业务合约的授权变化不会修改 Alice 自己的 allowance。

forge test --match-test testForceApprove -vv

3. EIP-2612:许可与业务意图分开

permit 签入 Owner、Spender、Value、Nonce 和 Deadline。它授权 Spender 使用额度,没有签入实际 transferFrom 的收款人、swap 路径或最低输出。

所以“许可来源地址一致”只是必要的身份关联,不足以证明调用者可以把钱转给自己。支持 Relayer 的路由还需要业务签名或其他明确授权。自助存款可绑定 from = msg.sender 并给同一地址记账,详见可运行 permit 示例。

允许捕获 permit 失败也可以是正确设计:抢先提交已建立额度时,合法业务应仍能使用它。实际转账失败必须回滚;不能将异常容忍扩大为任意人可使用任意 Owner 的历史授权。

4. Permit2 的两层权限

层或模块保存什么权限典型失效方式
原始 ERC-20 → Permit2ERC-20 allowance在原始 Token 上撤销或消耗
AllowanceTransferToken/Spender 的额度、expiration、顺序 nonce修改额度、到期、推进许可 nonce
SignatureTransfer一次性签名转账的无序 nonce bitmap消费或显式失效对应 nonce 位

AllowanceTransfer.lockdown 针对传入的 Token/Spender 列表把额度设为零;不是一键撤销所有协议,也不负责清除原始 Token 对 Permit2 的基础额度。实现

清零当前额度不等于使所有离线许可失效。若仍有未消费、未到签名 deadline 的 permit,可以被提交以重新建立额度;需要按目标模块失效 nonce。AllowanceTransfer 的额度 expiration 与 permit 提交的 sigDeadline 也不同。

SignatureTransfer 按无序 nonce 消费一次性签名,不维护相同的持久 Spender allowance。其接收参数并非都自动受普通 permit 消息保护;路由要绑定调用上下文,必要时通过 Witness 签入业务条件。官方集成边界

5. 撤销前后的检查

撤销时分别确认:基础 ERC-20 额度、Permit2 内部额度,以及尚未提交的许可签名。等待相关交易确认后再查询状态;撤销交易被抢先排序前,旧权限仍可能被使用。

本篇 Permit2 部分按官方接口和实现核对,未运行链上部署或完整 Permit2 流程。仓库中的测试覆盖 ERC-20 排序、EIP-2612 与业务身份绑定,不应作为 Permit2 实现验证结果。

参考资料