跳转到主要内容

Permit2 合约

Permit2 是共享的代币授权管理器。用户只需将代币授权给 Permit2 一次,然后可以向特定的授权对象授予限定范围的权限。 概念概述请参阅 Permit2 概念

核心函数

approve

授予授权对象通过 Permit2 代表调用者转移特定代币的权限。
function approve(
    address token,
    address spender,
    uint160 amount,
    uint48 expiration
) external;
参数类型描述
tokenaddress要授权的 ERC-20 代币
spenderaddress被授予权限的地址(例如 Universal Router)
amountuint160授权对象可转移的最大数量
expirationuint48权限过期的 Unix 时间戳
示例:
const permit2 = new ethers.Contract(PERMIT2_ADDRESS, PERMIT2_ABI, signer);

await permit2.approve(
  tokenAddress,
  UNIVERSAL_ROUTER,
  ethers.MaxUint160,                           // 最大数量
  Math.floor(Date.now() / 1000) + 365 * 86400  // 1 年有效期
);

allowance

查询给定的 owner-token-spender 三元组的当前授权信息。
function allowance(
    address owner,
    address token,
    address spender
) external view returns (
    uint160 amount,
    uint48 expiration,
    uint48 nonce
);
返回值类型描述
amountuint160剩余授权数量
expirationuint48过期的 Unix 时间戳
nonceuint48此授权的当前 nonce 值
示例:
const [amount, expiration, nonce] = await permit2.allowance(
  userAddress,
  tokenAddress,
  UNIVERSAL_ROUTER
);

const needsApproval = amount < requiredAmount || expiration < Math.floor(Date.now() / 1000);

ABI

[
  "function approve(address token, address spender, uint160 amount, uint48 expiration)",
  "function allowance(address owner, address token, address spender) view returns (uint160 amount, uint48 expiration, uint48 nonce)"
]

集成模式

async function ensurePermit2Approval(signer, tokenAddress, spender, requiredAmount) {
  const permit2 = new ethers.Contract(PERMIT2_ADDRESS, PERMIT2_ABI, signer);
  const owner = await signer.getAddress();

  // 1. 检查现有的 Permit2 子授权
  const [amount, expiration] = await permit2.allowance(owner, tokenAddress, spender);
  const now = Math.floor(Date.now() / 1000);

  if (amount >= requiredAmount && expiration > now) {
    return; // 已授权
  }

  // 2. 检查对 Permit2 的 ERC-20 授权
  const token = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
  const tokenAllowance = await token.allowance(owner, PERMIT2_ADDRESS);

  if (tokenAllowance < requiredAmount) {
    const tx = await token.approve(PERMIT2_ADDRESS, ethers.MaxUint256);
    await tx.wait();
  }

  // 3. 授予 Permit2 子授权
  const tx = await permit2.approve(
    tokenAddress,
    spender,
    ethers.MaxUint160,
    now + 365 * 86400
  );
  await tx.wait();
}