Permit2 Link to heading
问题 Link to heading
- 有没有办法让为所有的 Token 合约实现离线授权?
Permit2交互流程: Link to heading
-
Alice在一个ERC20上调用 approve ,无限的授权给 Permit2 合约 (在各个链上有相同的地址)
-
Alice签署链下消息:表明协议合约被允许代表她转账代币
-
协议合约上调用一个交互函数,将签署的 permit2 消息作为参数传入
-
Permit2合约上调用 permitTransferFrom, Permit2 按照消息指示转移 Token 到协议
流程图 Link to heading
example Link to heading
合约 Link to heading
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.0;
import "./myToken.sol";
import "./interfaces/IPermit2.sol";
contract TokenBank {
// 记录每个地址在银行中的余额
mapping(address => uint256) public balances;
// ERC20代币合约地址
MyToken public token;
// Permit2 合约实例
IPermit2 public permit2;
// 委托授权结构体
struct DelegateAuthorization {
address owner; // 代币所有者
address delegate; // 被委托人
uint256 amount; // 授权金额
uint256 deadline; // 授权截止时间
bool used; // 是否已使用
}
// 委托授权映射:授权哈希 => 授权信息
mapping(bytes32 => DelegateAuthorization) public delegateAuthorizations;
// 事件
event Deposit(address indexed user, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
event DelegateAuthorizationCreated(address indexed owner, address indexed delegate, uint256 amount, uint256 deadline, bytes32 authHash);
event DelegateDepositExecuted(address indexed owner, address indexed delegate, uint256 amount, bytes32 authHash);
// 构造函数,设置要管理的ERC20代币
constructor(address _tokenAddress, address _permit2Address) {
token = MyToken(_tokenAddress);
permit2 = IPermit2(_permit2Address);
}
// 存款函数
function deposit(uint256 _amount) external {
require(_amount > 0, "Amount must be greater than 0");
require(token.balanceOf(msg.sender) >= _amount, "Insufficient token balance");
// 从用户账户转移代币到合约
require(token.transferFrom(msg.sender, address(this), _amount), "Transfer failed");
// 更新用户在银行的余额
balances[msg.sender] += _amount;
emit Deposit(msg.sender, _amount);
}
// 取款函数
function withdraw(uint256 _amount) external {
require(_amount > 0, "Amount must be greater than 0");
require(balances[msg.sender] >= _amount, "Insufficient bank balance");
// 更新用户在银行的余额
balances[msg.sender] -= _amount;
// 从合约转移代币到用户账户
require(token.transfer(msg.sender, _amount), "Transfer failed");
emit Withdraw(msg.sender, _amount);
}
// 使用 Permit2 进行签名授权存款
function depositWithPermit2(
PermitTransferFrom memory permitData,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external {
require(permitData.permitted.amount > 0, "Amount must be greater than 0");
require(transferDetails.to == address(this), "Transfer must be to TokenBank");
require(transferDetails.requestedAmount > 0, "Requested amount must be greater than 0");
require(transferDetails.requestedAmount <= permitData.permitted.amount, "Requested amount exceeds permitted amount");
require(block.timestamp <= permitData.deadline, "Permit expired");
// 使用 Permit2 执行签名转账
permit2.permitTransferFrom(
permitData,
transferDetails,
owner,
signature
);
// 更新用户在银行的存款余额
balances[owner] += transferDetails.requestedAmount;
emit Deposit(owner, transferDetails.requestedAmount);
}
}