最近在整理钱包授权相关的功能,之前用 DApp 的时候经常点「授权」,但对授权之后到底发生了什么,其实一直没仔细想过。这里把查到的东西和做功能时遇到的几个点记一下。
授权和转账
ERC-20 的 approve(spender, amount) 可以理解为:允许某个地址,在额度内使用我的 Token。之后可以用 allowance(owner, spender) 查看当前还剩多少额度。
比如我给一个合约授权 100 个 Token,不代表这 100 个已经转出去了。但在额度范围内,spender 可以通过 transferFrom 使用它们。所以有些 DApp 申请很大额度时,还是得看看这个合约是否可信,以及自己还需不需要继续使用。
怎么查一个地址的授权
在 WalletOps 里做扫描时,我用的思路是:先拿到地址当前有余额的 Token,再把它们和已知的 spender 组合起来,逐个查询 allowance。
这里的查询只是读取链上数据,知道地址就可以查,不需要连接对方的钱包。连接钱包主要是在后面需要用户自己发起交易的时候。
Token 和 spender 一多,查询次数也会跟着增加。这里用了 viem 的 multicall 做批量读取,再加上 allowFailure: true,这样其中一个 Token 调用失败时,还能处理其他成功的结果:
1 | const results = await publicClient.multicall({ |
当然,allowFailure 也不是说请求一定会成功,整批 RPC 请求还是可能报错。还有一点是,失败的那项不能当成零授权,不然页面看起来就像已经查过了一样。
查到的额度需要按 Token 的 decimals 格式化,大整数也不要直接拿普通浮点数做金额计算。
撤销授权
常见的撤销方式是让 owner 钱包发起 approve(spender, 0)。这是写交易,需要用户连接自己的钱包、确认网络并签名,也通常需要 Gas。
前端拿到交易 hash 后,只能说明交易已经提交,还要等 receipt,看看最终执行成功还是失败。
最后还有个扫描范围的问题:上面这种做法只查了当前有余额的 Token 和已经配置的 spender。未知 spender、零余额 Token,以及超出扫描范围的内容,都可能漏掉。所以页面没有查到结果,也不能直接说这个地址没有任何授权。