Uniswap Labs发布了两个新的智能合约Permit2和UniversalRouter, Permit2 确实可以让链上交易体验上一层楼, 推荐各大协议接入。
前几天,Uniswap Labs发布了两个新的智能合约 Permit2 和 Universal Router :
Uniswap最初构思Permit2和Universal Router是为了改进Uniswap自己的产品,优化Gas成本,简化用户交易流程,并加强安全性。在构思的过程中,Unswap觉得其他应用可以从整合这些合约中大大受益。Uniswap 本身致力于建设公共基础设施,因此设计了这些合约,提供整个开发者生态系统使用,包括广泛的文档、SDK。
Permit2是一个代币授权合约,可以在不同的智能合约中安全地共享和管理代币授权。随着越来越多的项目与Permit2集成,可以在所有应用程序中对代币授权进行标准化。反过来,Permit2将通过降低交易成本来改善用户体验,同时提高智能合约的安全性。
以下是EIP-20中定义的典型代币授权(Approve)方法图示:
Alice在一个ERC20上调用approve()
,向一个合约授予支出授权。
Alice在合约上调用一个交互函数,该函数又在ERC20代币合约上调用transferFrom()
,转账她的代币。
显然,这种模式是可行的(它无处不在),并且最终可以相当灵活,因为协议通常会最终不间断地长期访问用户的代币。但它有两个众所周知的现实世界的问题。
EIP-2612 对代币的授权进行了迭代。用户可以通过在他们的交易中附加一个授权签名(Permit)信息来与应用合约交互,而不需要事先授权。
让我们看看ERC20的EIP-2612扩展所启用的方法,它通常是这样的:
transferFrom()
,转账由Alice持有的代币。这解决了典型ERC20 授权方法的两个问题:
approve()
交易。虽然EIP-2612使代币授权更加安全,但在EIP-2612之前推出的代币并不支持签名授权功能,而且并非所有较新的代币都采用该功能,这就是悲催的现实。因此大多数时候,这种方法不可行。
关于EIP-2612, 我那个登链社区上还有一些文章探讨,可参考这里
最后,让我们深入探讨Permit2的方法,Permit2 结合了这两种模式,将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标准(社区有一些相关文章),使用这里和这里定义的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 消息的详情, 有下面的信息。
permitted
一个TokenPermissions
结构,有以下字段:
token
- 要转账的代币的地址。
amount
- 此签名信息可转移的最大金额。
nonce
- 一个独特的数字,用来防止重用签名许可。一旦签名许可被使用,任何使用该nonce的其他签名许可将无效。
deadline
- 该签名许可有效的截止时间。
transferDetails
- 一个包含转账接收人和转账金额的结构,可以小于用户签名的金额。
owner
- 签署许可的人,也是持有代币。通常,在简单的使用场景中,调用者和用户是同一个人,这应该被设置为调用者(msg.sender
)。但在更奇特的集成中,你可能需要更复杂的检查。
signature
- permit2信息对应的EIP-712签名,由owner
签名。如果从签名验证中还原的地址与 owner
不一致,调用将失败。
注意,
PermitTransferFrom
结构不包括签名信息 EIP-712 typehash 定义中的spender
字段。在处理过程中,它将被填入我们的合约地址(permitTransferFrom()
的直接调用者)。这就是为什么用户签署的EIP-712对象的spender
字段必须是这个合约的地址。
前面涵盖了 Permit2 提供的基本功能,但你还可以用它做更多的事情!
这里提供的示例代码是一个简单的金库,用户可以使用Permit2将ERC20代币存入其中,随后可以提取。因为它是多用户的,它需要启动转账,以便可靠地记入哪个账户拥有哪个余额。通常情况下,这需要给金库合约授予授权,然后让金库对代币本身执行transferFrom()
,但Permit2让我们跳过了这个麻烦!
Test用例部署了一个本地的、字节码的主网Permit2合约的分叉,以测试金库的一个实例。EIP-712 Hash 和签名生成也是用solidity/foundry编写的,但通常应该在链外用你选择的语言在前端或后端执行。
SignatureTransfer
文档 - 由Uniswap提供的Permit2官方文档如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!