亚洲财经

☰ 搜索

代币授权与许可签名: allowance 真正授权的内容

ERC-20 授权与 Permit 签名:深度解析

ERC-20 授权允许指定的spender(花费者)提取特定数量的代币,但这并不授权提取其他代币,也不会自动转移资金。ERC-2612 标准允许使用签名消息来建立链上授权,其字段包括所有者(owner)、花费者(spender)、金额(value)、非ces(nonce)和截止时间(deadline),这些字段共同定义了授权范围。Permit 的截止时间仅限制签名被接受的时间窗口;一旦授权建立,它将保持活跃状态,直到被消耗、替换或根据代币规则以其他方式撤销。

本文将深入探讨代币批准和 Permit 签名实际授权的范畴、ERC-20 授权的工作机制,以及为何 Permit 截止时间不会自动导致支出权限过期。


1. ERC-20 授权究竟批准了什么?

ERC-20 授权属于代币合约内的特定关系:所有者、花费者以及剩余可用额度。标准中的 `approve` 函数用于设置额度,而 `allowance` 函数则报告花费者仍被允许提取的金额。再次调用 `approve` 会替换现有值,而不是在原有基础上累加。该授权可以覆盖多次提款,只要累计金额不超过授权额度即可。

相应的 `transferFrom` 函数在授权机制下将代币从一个地址转移到另一个地址。在常规的授权模型中,花费者通过该函数行使所有者的权限。批准和转账是两个独立的操作:建立授权本身并不会转移代币,也不会预留所有者余额的一部分。

考虑一个示例:所有者拥有 100 个代币,给某个花费者设定的有限授权为 60。如果普通的授权消耗实现处理了一次 25 的提款,所有者的余额变为 75,剩余授权变为 35。另一次提款可以使用剩余的权限,而无需新的批准。此示例假设是一个没有转账费或其他自定义余额行为的普通代币。

授权记录并不包含交易背后的商业目的。ERC-20 的批准字段不指定购买行为、目标地址、汇率、最低产出或特定的应用程序动作。虽然花费者合约可以在其代码中施加此类限制,但这些是基本授权之外的额外规则。因此,可识别的应用程序标签并不能解释底层授权的全部范围。

此外,授权也是针对特定代币的。由一个代币合约记录的权限,仅凭 ERC-20 标准本身,并不能授权另一个代币或账户的原生 ETH。然而,在已批准的代币内部,授权并不绑定于批准时刻的余额。如果权限仍然存在且所有者的余额后来增加,那么新收到的代币也可能在该权限下可转移,具体取决于代币的实际执行规则。这源于标准中余额和授权记录的分离。


2. Permit 如何成为链上授权?

ERC-2612 改变了授权的方式。代币合约不再仅仅从 `approve` 的调用者推导所有者,而是验证结构化 permit 消息上的所有者签名。该扩展在 ERC-20 接口中增加了 `permit`、`nonces` 和 `DOMAIN_SEPARATOR`。

该机制分为三个 distinct 阶段:

  • 签署消息:签名将 permit 的字段绑定到所有者的签名权和合约的签名域。仅签署消息不会更新代币合约的授权。
  • 在链上展示签名:调用者向代币合约提供 permit 和签名。ERC-2612 并不限制调用者必须是所有者或指定的花费者。中继者(relayer)或其他地址也可以提交它。
  • 合约验证并更新状态:成功的 permit 操作会将所有者的指定花费者授权设置为签名中的值,将所有者的 permit nonce 增加 1,并触发 Approval 事件。签名必须有效,所有者地址不能为零,nonce 必须匹配,且当前区块时间戳不得超过截止时间。否则,标准要求调用回滚。

Permit 操作本身改变的是授权,而非代币所有权。应用程序可能在同一笔交易中执行 permit 和随后的代币转账,但那是额外的操作。这就是为什么在提供签名后不久资金可能会被转移,尽管 permit 的直接效果仅是授权更新。

同样的区别也适用于“免 Gas 批准”这一说法。所有者可以生成签名而不发送批准交易,而由其他人提交链上调用。执行仍然发生在链上;ERC-2612 并未使其免费,也不保证中继者一定会提交它。该标准明确指出中继者可以扣留 permit。


3. 签名字段实际控制什么?

签名的 permit 结构包含所有者、花费者、金额、nonce 和截止时间。其解释还取决于验证代币合约使用的 EIP-712 域。每个元素回答不同的授权问题。

  • 所有者(Owner):谁的代币受权限约束?这是更改授权且必须验证签名的账户。仅提交交易的个人或地址不会仅因出示 permit 而成为所有者。
  • 花费者(Spender):哪个地址获得权限?这是被批准的花费者,可能与交易提交者、网站运营商和最终代币接收者不同。ERC-2612 不将提交绑定到特定的中继者。
  • 金额(Value):将记录多少授权?该值是新的授权额度,而非保证的转账金额,也不是对现有授权的增量。代币数量使用整数单位。ERC-20 的可选 decimals 元数据解释了这些单位如何显示;如果没有相关面值,无法准确解释表观金额。
  • Nonce:哪些授权状态必须仍然有效?ERC-2612 在代币合约中为每个所有者跟踪一个 nonce。成功的 permit 会通过增加 nonce 来消耗当前的 nonce。仅创建签名不会消耗它。如果对相同的当前 nonce 签署了两个 permit,接受其中一个会使另一个无法满足该 nonce 检查。计数器并非跨所有代币或链的全局序列。
  • 截止时间(Deadline):合约在何时之前可以接受此 permit?检查使用区块时间戳,允许相等。它在 permit 执行时应用,而不是在所有者签署时开始倒计时。
  • 域(Domain):在此签名应在哪个合约和链上下文中生效?ERC-2612 要求使用 EIP-712 域分隔符,并指出它应区分合约和链。其常见示例包括 name、version、chainId 和 verifyingContract。这四个字段是常见的构造方式,并非强制所有实现都使用完全相同的字段列表。EIP-712 定义了一个通用的域框架;ERC-2612 添加了特定的 permit 语义和 nonce 机制。

结构化签名使内容具有可解释性,但字段名称本身并不能确立花费者的可信度或已部署合约的正确性。EIP-712 本身明确不提供重放保护。在 ERC-2612 中,保护依赖于 permit 规则、nonce 检查、域构造及其实现的协同工作。


4. 为何 Permit 截止时间不会使授权过期?

考虑一个假设的例子:2026 年 11 月 15 日,东部标准时间(EST, GMT-05:00)。一个 permit 授权 100 个代币的额度,截止时间为中午 12:00 EST。如果合约在上午 11:59 EST 接受了它,授权被设置为 100。在中午 12:01 EST,过期的截止时间并不会消除该授权。截止时间管理的是对签名消息的接受;普通的 ERC-20 授权状态没有过期字段。

如果 permit 未被接受,且当前区块时间戳晚于中午 12:00 EST 的截止时间,它将无法再通过 ERC-2612 的截止时间检查。这是两种不同的结果:未使用的授权可能变得不可接受,而由此创建的授权则仍然有效。

有限的授权随后可能被消费或被另一个授权更新所替换。其持久性或金额不能仅从原始截止时间推断。同样,完成激励批准的活动也不会自动移除任何剩余的授权。应用程序或代币可以实现额外的过期规则,但这些必须单独建立。

标准本身记录了这种区别的重要性。其兼容性讨论描述了一种不同的 permit 实现,该实现使转账依赖于过期时间戳。这种行为与 ERC-2612 规定的机制形成对比,而非 permit 签名的普遍属性。


5. 顺序和未使用的签名如何影响局面?

授权是可变的狀態,因此调用的执行顺序至关重要。将 100 的授权替换为 20,并不意味着在整个过渡期间只能花费 20 个代币。如果花费者在替换处理之前使用了旧授权,后续更新仍可建立 20 的新授权。ERC-20 警告存在这种批准竞态条件,ERC-2612 明确表示这也适用于 permit。

另一个时机问题涉及未使用的签名:当前的授权和一个未使用的 permit 签名是不同的事物。在基本标准中,使用 `approve` 更改授权并不规定要推进 ERC-2612 的 nonce。因此,一个仍然有效但未消耗的 permit 稍后可能会替换该授权,只要其条件得到满足。因此,特定区块的零授权本身并不能证明不存在可能建立新授权的未决签名。代币可能会添加其他无效行为,但这需要单独验证。

交易提交者也对 permit 签名没有独占权。另一个地址可以先提交相同的有效 permit。指定的授权效果仍然绑定于签名的所有者、花费者和金额,但时机可能会影响预期自行提交 permit 的更广泛的应用程序工作流。ERC-2612 承认这种抢先交易的可能性;它不保证周围应用程序操作的每一步都能成功。

这些时机区别解释了为何“已签名”、“已提交”、“已接受”和“已花费”描述的是不同的事实。签名不是包含的证明,Approval 事件不是转账的证明,转账也不是花费者没有剩余权限的证明。


6. 实现差异在哪里?

ERC-20 并不要求每个代币都支持 ERC-2612。此外,名为 `permit` 的函数并不表明它使用 ERC-2612 的确切消息或语义。标准的兼容部分描述了一种 DAI 风格的变体,它使用布尔型 `allowed` 字段代替数值,并具有不同命名的过期字段。这种差异会影响签名消息,不能被视为表面修饰。

授权会计也有实现惯例。OpenZeppelin Contracts 5.x 文档指出,其 ERC20 实现在 `transferFrom` 执行时,不会减少设置为最大 uint256 值的授权。它将该值视为无限授权。这是一种需要验证的特定于实现的行为,而不是假设每个代币都以相同方式处理每个大额授权的理由。

额外的代币规则可能会影响原本授权的转账是否成功。充足的授权并不能确立所有者有足够的余额,也不能确保实际的代币和花费者实现将允许请求的操作。即使可见界面看起来很熟悉,扩展和自定义逻辑仍然相关。

域处理也有其自身的局限性。ERC-2612 警告称,如果在部署时缓存包含链 ID 的域分隔符,如果后来的链分叉改变了相关上下文,可能会产生重放风险。因此,熟悉的域字段只是表明意图绑定,而不是关于每个部署行为的全面保证。


7. 现有证据能确立什么?

不同的证据回答不同的问题。签名消息标识了提议的授权。成功的 permit 执行确立了合约在当时接受了该授权。在指定区块读取的授权识别了当时的剩余权限。结合代币转账读取的交易执行调用,可以确立该授权是否被行使。

事件有助于重建活动,但它们不能与当前状态互换。ERC-20 要求成功的 `approve` 产生 Approval 事件,ERC-2612 要求成功的 `permit` 产生 Approval 事件。这两条规则并不意味着每次后续的授权更改都必须产生相同的事件。例如,OpenZeppelin 的 ERC20 实施文档指出,它在 `transferFrom` 期间的授权消耗中省略了 Approval 事件。

授权读取也无法揭示链下可能存在的所有签名。在没有特定的代币部署、链、签名负载和执行历史的情况下,仅凭标准无法确立特定的授权当前是否可用,也不适用哪些额外的应用程序规则。

有用的模型是追踪权限的各个阶段:签名提出精确范围的授权更新;成功验证将其记录;后续执行可能会消耗它。Permit 截止时间限制了第一个转换。它并没有关闭该转换创建的支出权限。