本篇聚焦移除流动性流程中的授权细节,解释为何 Router 需要代用户持有 LP 代币并执行 _safeTransferFrom,以及在生产环境下如何通过 approve 与 permit(EIP-2612)降低交互成本并提升安全性。内容基于仓库现有的 Solidity 0.8.30 实现与 Fo
本篇聚焦移除流动性流程中的授权细节,解释为何 Router 需要代用户持有 LP 代币并执行 _safeTransferFrom
,以及在生产环境下如何通过 approve
与 permit
(EIP-2612)降低交互成本并提升安全性。内容基于仓库现有的 Solidity 0.8.30 实现与 Foundry 测试。
pairContract
调用 approve(address(router), liquidity)
?burn
,因此需要获得足额 allowance
。UniswapV2Router.removeLiquidity
。_safeTransferFrom(pair, msg.sender, pair, liquidity)
将 LP 代币转移回 Pair。IUniswapV2Pair(pair).burn(to)
,按照储备比例返还两种资产。amountA/amountB
是否满足滑点下限,否则回退。removeLiquidity
中的 _safeTransferFrom
需要 Router 转移用户持有的 LP 份额。由于 LP 是一种 ERC20 代币(Pair 继承 ERC20Permit
),transferFrom
必须预先获得 allowance
。因此即便在测试环境,仍需执行:
UniswapV2Pair pairContract = UniswapV2Pair(pair);
pairContract.approve(address(router), liquidity);
没有授权时 _safeTransferFrom
会因 TransferFromFailed()
自定义错误而回滚,导致移除流动性失败。
理论上用户可以自行将 LP 代币 transfer
到 Pair,再直接调用 burn
,但这会绕开 Router:
因此生产环境仍应遵循“先授权、再调用 Router”这一主流程。
approve
permit
(EIP-2612)免交易授权ERC20Permit
,支持链下签名授予额度;permit
结构体,钱包离线签名(无 gas 消耗);removeLiquidityWithPermit
的包装函数,在同一笔交易中:
permit(token, owner, router, value, deadline, v, r, s)
获取授权;_safeTransferFrom
与 burn
;Permit2
或 Session Key 等机制延伸设计,但需额外审计。permit
实战接入步骤DOMAIN_SEPARATOR
、nonces(owner)
、name
等参数,按照 EIP-2612 规范生成待签名结构体。(v, r, s)
;可设置合理的 deadline
防止长期生效的签名被滥用。removeLiquidityWithPermit
,先调用 permit
写入授权,再执行标准 removeLiquidity
流程。nonces
会自动递增);permit
,仍需传入 amountAMin/amountBMin
,避免在高波动时期遭受损失。Transfer
、Burn
、Sync
事件,便于追踪授权使用情况。permit
场景测试,验证 Router 在缺少授权时会正确回退。https://github.com/RyanWeb31110/uniswapv2_tech
欢迎克隆仓库,根据本文指导实现 removeLiquidityWithPermit
等扩展能力,并在实际部署前结合审计建议完善授权策略。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!