Permit 存款、Gas 与赞助商 Relayer

  • 曲弯
  • 发布于 6天前
  • 阅读 117

permitDeposit、EIP-2612链下签名`、无ETH场景、赞助商代付Gas。1.背景与合约角色XZXToken:OpenZeppelinERC20+ERC20Permit,名称与EIP-712域一致(如"xzx")。TokenBankV2:deposi

permitDeposit、EIP-2612 链下签名`、无 ETH 场景、赞助商代付 Gas。


1. 背景与合约角色

  • XZXToken:OpenZeppelin ERC20 + ERC20Permit,名称与 EIP-712 域一致(如 "xzx")。
  • TokenBankV2deposit / withdraw / permitDeposit 中的 amount 均为最小单位(与标准 ERC20 一致)。
  • permitDeposit:在一笔对 Bank 的调用内,依次执行代币的 permittransferFrom(owner, Bank, amount),并更新 deposits[owner]

2. 为什么需要 Permit + permitDeposit

  • 常规路径:用户先 approve(Bank),再 deposit —— 通常需要用户自己发链上交易并付 Gas。
  • EIP-2612:用户离线签名,授权某个 spender(此处为 Bank 地址)在一定 value 内动用代币;第三方可把签名提交上链执行 permit,再 transferFrom
  • permitDeposit 的价值:把「授权 + 从用户划币进 Bank + 记账」串成 一次对 Bank 的调用;用户侧可只做 签名,不必自己发 approve 交易。

3. 链上:permitDeposit 在做什么(逐步)

对应实现逻辑(概念与代码一致):

  1. 校验 amount > 0owner != address(0)
  2. 预检 token.balanceOf(owner) >= amount(避免 permit 成功后转账失败)。
  3. IERC20Permit(token).permit(owner, address(Bank), amount, deadline, v, r, s)
    • 验签、nonce、deadline、写入 allowance(owner, Bank) 都在 代币合约 内完成。
  4. token.transferFrom(owner, address(Bank), amount)
    • 调用方是 Bank,故从 用户 扣 XZX 到 Bank
  5. deposits[owner] += amount,首存写入 depositorsemit Deposit

重要澄清:验签不在 Bank
Bank 只转发调用;EIP-2612 签名验证在 Token 的 permit 中完成


4. 链下:EIP-712 签名如何构造(与 OZ ERC20Permit 一致)

4.1 Permit 类型(类型哈希固定)

Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)

PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")

4.2 字段含义(必须与链上调用一致)

字段 说明
owner 持币用户地址(签名私钥对应地址)
spender 必须为 TokenBankV2 部署地址
value 最小单位,且必须等于 permitDepositamount
nonce 链上读取 token.nonces(owner)(每笔成功 permit 后递增,防重放)
deadline Unix 秒;过期则 permit 失败

4.3 哈希与签名

  • structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))
  • DOMAIN_SEPARATOR:链上 IERC20Permit(token).DOMAIN_SEPARATOR()(与代币合约地址、链 ID、name/version 绑定)
  • digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash))
  • owner 私钥digestsecp256k1 签名,得到 (v, r, s)

4.4 链上提交

任意账户可调:

bank.permitDeposit(owner, amount, deadline, v, r, s)

其中 owner, amount, deadline 必须与签名时一致


5. 谁支付 Gas?(易错点)

  • 在以太坊(及常见 L2)上:谁广播这笔链上交易、谁作为付款账户,谁就支付该笔交易的 Gas(原生币:主网 ETH 等)。
  • Bank 部署者不会自动替所有用户付 Gas;仅当部署者本人去发那笔交易时才由他付。
  • permitDeposit 不能让用户用 XZX 直接当 Gas:ERC-20 不是原生 Gas 币;合约也无法从用户钱包里「自动扣 ETH」。
  • Permit 解决的是:用户可不做链上 approve,常配合 Relayer 由别人代发 permitDeposit 交易。

验签位置 vs Gas:

项目 说明
验签发生在哪里 代币合约 permit
Gas 谁付 发送 permitDeposit 交易的外部账户(或 AA/Paymaster 体系下的赞助方)

6. 用户只有 XZX Token、没有 ETH 怎么办?

  • 纯 EOA:没有原生 Gas 币就不能自己把交易送上链。
  • 用户仍能 离线签 Permit(不耗 Gas)。
  • 要上链完成存款,需要 别人代发 调用 permitDeposit 的交易(见下节 赞助商 D),或 账户抽象 + Paymaster 等方案,或给用户少量入门 ETH。

7. 引入赞助商 D 代付 Gas(Relayer 模式,与现有合约兼容)

7.1 角色

  • 用户 A:只有 XZX Token;完成 链下 Permit 签名
  • 赞助商 D:持有 ETH(或该链原生 Gas 币);可运行 Relayer,代发交易。

7.2 流程(推荐理解顺序)

  1. A 在 dApp 确定 amount(最小单位)、deadline,读取 nonces(A) 等。
  2. A 对 Permit(owner=A, spender=Bank, value=amount, nonce, deadline)签名,得到 (v,r,s)
  3. A 将 {owner, amount, deadline, v, r, s} 交给 dApp / 后端(HTTPS 等,不必上链)。
  4. D 用自有 EOA 广播交易
    • to = Bank
    • data = permitDeposit(A, amount, deadline, v, r, s)
    • Gas 从 D 账户扣除
  5. 链上:Token permit 验证 A 的签名transferFromA 扣 XZX 到 Bank;Bank 记 deposits[A]

7.3 资金流向小结

  • Gas:链上由 D(或 Relayer 账户)原生币 支付。
  • XZX:从 A 进入 Bank不是从 D 扣 XZX Token(除非另外设计给 D 的手续费)。
  • D 如何回本:链下订阅、活动补贴、链下用 XZX Token 结算等——属产品与合规范畴,不由 permitDeposit 单独保证。

7.4 安全提示

  • 签名在 deadline 前可被任何知道参数的人提交;deadline 不宜过长
  • nonce 用过后旧签名失效;参数被篡改则 permit 验签失败

7.5 其他形态:ERC-4337 + Paymaster

  • 智能合约钱包 + Paymaster 由 D 垫付 Gas,细节依赖 Bundler、EntryPoint、Paymaster 合约,工程量比单纯 Relayer 大。
  • 可实现「用户用 ERC-20 向 D 结算」等,但需单独设计,非仅 Bank 合约即可完成。

8. 与 deposit 的对比

项目 deposit前需链上 approve permitDeposit
用户链上操作 通常需用户自己 approve(付 Gas) 用户只需链下签 Permit;上链可由 Relayer 代发
amount 含义(当前项目) 最小单位 最小单位(= Permit 的 value

9. 一句话备忘

链下:用户 A 对 Permit 签名。
链上:Relayer / 赞助商 D 付 Gas 调 permitDeposit验签在 Token;扣 XZX Token 从 A;Bank 只编排调用与记账。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
曲弯
曲弯
0xb51E...CADb
Don't give up if you love it. If you don't, then that's not good either, because one shouldn't do things they don't enjoy.