本文作者:翻译小组[1]
前几天,Uniswap Labs 发布了两个新的智能合约 Permit2 和 Universal Router :
Uniswap 最初构思 Permit2 和 Universal Router 是为了改进 Uniswap 自己的产品,优化 Gas 成本,简化用户交易流程,并加强安全性。在构思的过程中,Unswap 觉得其他应用可以从整合这些合约中大大受益。Uniswap 本身致力于建设公共基础设施,因此设计了这些合约,提供整个开发者生态系统使用,包括广泛的文档、SDK。
Permit2[4]是一个代币授权合约,可以在不同的智能合约中安全地共享和管理代币授权。随着越来越多的项目与 Permit2 集成,可以在所有应用程序中对代币授权进行标准化。反过来,Permit2 将通过降低交易成本来改善用户体验,同时提高智能合约的安全性。
以下是EIP-20[5]中定义的典型代币授权(Approve)方法图示:
approve()
,向一个合约授予支出授权。transferFrom()
,转账她的代币。显然,这种模式是可行的(它无处不在),并且最终可以相当灵活,因为协议通常会最终不间断地长期访问用户的代币。但它有两个众所周知的现实世界的问题。
EIP-2612[6] 对代币的授权进行了迭代。用户可以通过在他们的交易中附加一个授权签名(Permit)信息来与应用合约交互,而不需要事先授权。
让我们看看 ERC20 的 EIP-2612 扩展所启用的方法,它通常是这样的:
transferFrom()
,转账由 Alice 持有的代币。这解决了典型 ERC20 授权方法的两个问题:
approve()
交易。虽然 EIP-2612 使代币授权更加安全,但在 EIP-2612 之前推出的代币并不支持签名授权功能,而且并非所有较新的代币都采用该功能,这就是悲催的现实。因此大多数时候,这种方法不可行。
关于 EIP-2612, 我那个登链社区上还有一些文章探讨,可参考这里[7]
最后,让我们深入探讨 Permit2 的方法,Permit2[8] 结合了这两种模式,将 EIP-2612 的用户体验和安全优势扩展到也涵盖了普通的 ERC20 代币!
为了说明 Permit2 的革命性,在一个常见的场景中,协议需要转账 Alice 持有的代币。
approve()
,典型的方式为的 Permit2 合约授予一个无限的授权。permit2
消息,该消息表明协议合约被允许代表她转账代币。permitTransferFrom()
,而 Permit2 合约又使用其授权(在 1 中授予)在 ERC20 合约上调用 "transferFrom()",转账 Alice 持有的代币。要求用户首先授予一个明确的授权交易,这似乎是一种倒退。但是,用户不是直接授予协议,而是将其授予规范的 Permit2 合约。这意味着,如果用户之前已经这样做了,比如说与另一个集成了 Permit2 的协议进行交互,那么其他每一个协议都可以跳过这个步骤。
这太棒了。
协议不会直接调用 ERC20 代币上的transferFrom()
来执行转账,而是调用规范的 Permit2 合约上的permitTransferFrom()
。Permit2 位于协议和 ERC20 代币之间,跟踪和验证 permit2 消息,然后最终使用其授权直接在 ERC20 上执行transferFrom()
调用。这种间接性使得 Permit2 可以将类似于 EIP-2612 的好处扩展到每一个现有的 ERC20 代币上。🎉
同时,像 EIP-2612 签名授权信息一样,Permit2 信息也会过期,以限制漏洞的攻击窗口。
对于集成 Permit2 的前端来说,它需要获取一个用户签名,并将其传递到交易中。这些签名签署的 Permit2 消息结构(PermitTransferFrom
)必须符合EIP-712[9]标准(社区有一些相关文章[10]),使用这里[11]和这里[12]定义的 Permit2 域和类型散列。请注意,EIP-712 Permit2 对象的 spender
字段需要被设置为将要消费它的合约地址。
智能合约的整合实际上是相当容易的! 任何需要转账用户持有的代币的函数只需要接受任何的许可信息细节和相应的 EIP-712 用户签名。为了实际转账代币,我们将在规范的 Permit2 合约上调用permitTransferFrom()
。该函数的声明为:
function permitTransferFrom(
PermitTransferFrom calldata permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
这个函数的参数是:
permit
- permit2 消息的详情, 有下面的信息。token
- 要转账的代币的地址。amount
- 此签名信息可转移的最大金额。permitted
一个TokenPermissions
结构,有以下字段:nonce
- 一个独特的数字,用来防止重用签名许可。一旦签名许可被使用,任何使用该 nonce 的其他签名许可将无效。deadline
- 该签名许可有效的截止时间。transferDetails
- 一个包含转账接收人和转账金额的结构,可以小于用户签名的金额。owner
- 签署许可的人,也是持有代币。通常,在简单的使用场景中,调用者和用户是同一个人,这应该被设置为调用者(msg.sender
)。但在更奇特的集成中,你可能需要更复杂的检查[13]。signature
- permit2 信息对应的 EIP-712 签名,由owner
签名。如果从签名验证中还原的地址与 owner
不一致,调用将失败。注意,
PermitTransferFrom
结构不包括签名信息 EIP-712 typehash 定义[14]中的spender
字段。在处理过程中,它将被填入我们的合约地址(permitTransferFrom()
的直接调用者)。这就是为什么用户签署的 EIP-712 对象的spender
字段必须是这个合约的地址。
前面涵盖了 Permit2 提供的基本功能,但你还可以用它做更多的事情!
这里提供的示例代码[21]是一个简单的金库,用户可以使用 Permit2 将 ERC20 代币存入其中,随后可以提取。因为它是多用户的,它需要启动转账,以便可靠地记入哪个账户拥有哪个余额。通常情况下,这需要给金库合约授予授权,然后让金库对代币本身执行transferFrom()
,但 Permit2 让我们跳过了这个麻烦!
Test 用例[22]部署了一个本地的、字节码的主网 Permit2 合约的分叉,以测试金库的一个实例。EIP-712 Hash 和签名生成也是用 solidity/foundry 编写的,但通常应该在链外用你选择的语言在前端或后端执行。
[1]
翻译小组: https://learnblockchain.cn/people/412
[2]
Permit2 : https://github.com/Uniswap/permit2
[3]
Universal Router: https://github.com/Uniswap/universal-router
[4]
Permit2: https://github.com/Uniswap/permit2
[5]
EIP-20: https://eips.ethereum.org/EIPS/eip-20
[6]
EIP-2612: https://eips.ethereum.org/EIPS/eip-2612
[7]
参考这里: https://learnblockchain.cn/tags/EIP2612
[8]
Permit2: https://github.com/Uniswap/permit2
[9]
EIP-712: https://eips.ethereum.org/EIPS/eip-712
[10]
相关文章: https://learnblockchain.cn/tags/EIP712
[11]
这里: https://github.com/Uniswap/permit2/blob/main/src/EIP712.sol
[12]
这里: https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol
[13]
你可能需要更复杂的检查: https://docs.uniswap.org/contracts/permit2/reference/signature-transfer#security-considerations
[14]
签名信息 EIP-712 typehash 定义: https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol#L21
[15]
自定义见证数据: https://docs.uniswap.org/contracts/permit2/reference/signature-transfer#single-permitwitnesstransferfrom
[16]
批量转账: https://docs.uniswap.org/contracts/permit2/reference/signature-transfer#batched-permittransferfrom
[17]
Smart Nonces: https://docs.uniswap.org/contracts/permit2/reference/signature-transfer#nonce-schema
[18]
回调签名: https://github.com/Uniswap/permit2/blob/main/src/libraries/SignatureVerification.sol#L43
[19]
EIP-1271: https://eips.ethereum.org/EIPS/eip-1271
[20]
Permit2 Allowances: https://docs.uniswap.org/contracts/permit2/reference/allowance-transfer
[21]
示例代码: https://github.com/dragonfly-xyz/useful-solidity-patterns/blob/main/patterns/permit2/Permit2Vault.sol
[22]
Test用例: https://github.com/dragonfly-xyz/useful-solidity-patterns/blob/main/test/Permit2Vault.t.sol
[23]
Permit2公告: https://uniswap.org/blog/permit2-and-universal-router
[24]
Permit2 Repo: https://github.com/Uniswap/permit2
[25]
Permit2 SignatureTransfer
文档: https://docs.uniswap.org/contracts/permit2/reference/signature-transfer
[26]
Permit2 解释: https://github.com/dragonfly-xyz/useful-solidity-patterns/tree/main/patterns/permit2
Twitter : https://twitter.com/NUpchain Discord : https://discord.gg/pZxy3CU8mh
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有