viem 批量读合约:固定区块,保留每项 success 与 failure
链小知 · 进阶 · 核验 · 依官方文档整理
从单次 readContract 扩展为 multicall,检查 ABI、历史部署、calldata 字节和逐项失败,避免部分结果缺失被合计为零。
开始前准备
- 准备已有viem项目的锁定版本、获准RPC、期望chainId、同链合约地址/ABI、查询函数与args;若排查旧结果,带原blockNumber或blockHash。
- 任务仅Public Client与view/pure读取,不使用Wallet Client或私钥。固定源码6501d059…用于解释当前官方分支,不代替项目安装版本;查询会向RPC披露地址/参数并可能计费。
1. 建立 Public Client 并读取端点实际身份
在既有项目用 createPublicClient({ chain: chosenChain, transport: http(rpcUrl) });chosenChain是预期链配置,不能作为RPC实际链的证明。使用client.getChainId()把返回number与期望十进制chainId比较,保存脱敏端点、项目版本和读取时点。
官方http()不传URL会回落publicRPC,不能据此承诺可用性或不限额。网络不匹配、认证失败、限流时先处理端点,不进入余额合计,也不改成连接钱包。
检查结果:Public Client配置与实际chainId一致,访问/费用边界已记录。
2. 单次 readContract 验证 ABI 与原返回
以既有ABI as const保留类型,传address、abi、functionName:'balanceOf'、args:[publicAddress]读取目标方法;decimals/totalSupply单独选正确view/pure函数,不按图标或symbol合并合约。
返回类型按ABI推导,uint256通常bigint;保存raw.toString()。需要展示时用formatUnits(raw, knownDecimals),例如420000000000n与精度9显示'420';未知decimals保留整数不补18。编码错误、空返回或revert均保留原错。
检查结果:先有一项可解释的ABI结果或明确失败,再决定是否聚合。
3. 把所有读请求固定在相同块范围
将单次和后续multicall的blockNumber设为同一个bigint,如已有块15121123对应15121123n。网页Type:number与n示例冲突,固定CallParameters源码为bigint;实际项目按对应版本类型校验,不做浮点转换。
blockNumber、blockTag、blockHash选择一类;requireCanonical仅和blockHash配合。默认call标签受client.experimental_blockTag影响,未配置时latest;因此不要把多次latest当同一快照。历史状态、safe/finalized或EIP1898未受节点支持时留错误,不回落最新后仍标旧块。
检查结果:每一项输入的区块选择相同,兼容/历史状态缺口明确。
4. 建立有顺序的 multicall 列表并核部署
将contracts数组按确定顺序列出,每项保留address/abi/functionName/args,在client.multicall({ contracts, blockNumber, allowFailure:true })中使用同一块。另存输入索引,不能按返回显示name猜原合约。
默认使用chain.contracts.multicall3;该地址须在所读历史块已部署。缺地址/部署条件、RPC calldata上限或历史状态问题都可能影响整个批次。deployless或自定义multicallAddress是另一路径,不在错误时自动开启来掩盖配置缺口,也不能当链上部署证明。
检查结果:输入顺序、块范围和Multicall3来源/限制清楚;不是盲目拆分重试。
5. 逐项检查状态,保留文档字段差异
当前页面示例与固定源码是{status:'success',result}或{status:'failure',error,result:undefined};网页Return Value却写data/reverted,不能混用。核项目实际版本/原对象,按对应分支处理并保留原响应。
allowFailure默认true,外层完成不表示全部成功;按原索引逐项归档。合约revert、解码错或整批RPC失败都可成为failure,undefined不是0。allowFailure:false遇错抛出,成功是直接值数组,不能再按包装对象读取;只有成功项可进入数量汇总。
检查结果:输入与返回项一一对应,失败不被吞掉或计为零。
6. 按字节控制批次并交付有限快照
batchSize默认1024是编码calldata字节,不是1024次调用;0取消该尺寸分割不等于RPC无上限。Public Client的batch.multicall默认false,Promise.all不会自动证明开启聚合;启用后wait/cache也需记录,不能据优化文档推实际账单。
输出项目版本/chainId、块选择、输入索引、原整数/精度、逐项status与原error。聚合成功只说明该读取范围,不能证明代币安全、实时余额或交易完成;cacheTime毫秒与CCIP offchain查找也影响请求来源/新鲜度,诊断记录应带配置。
检查结果:形成同范围读取表与失败清单,额度/缓存和未覆盖方法单列。
怎样确认完成
- 得到可复核的同块输入索引—返回状态—原整数/错误对照。
- 缺失项、节点服务范围和版本差异保留;未签名或发送交易。
常见错误与边界
- Multicall3的调用环境与普通单次call并非可无条件互换,sender相关方法要核合约实际逻辑。
- 官方返回表与示例存在冲突;固定main代码不是已安装npm版本验收。
- RPC收费/认证/历史部署未实测;没有通过批量调用证明整个链或全部资产覆盖。