You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rootstock上通过ethers.js聚合ERC20余额与授权查询请求?

在ethers.js中聚合多笔ERC20查询为单个JSON-RPC请求

当然可以通过两种主流方式实现请求聚合,大幅降低JSON-RPC调用频率:

方法一:ethers.js原生批量JSON-RPC请求

利用JSON-RPC的批量请求特性,通过ethers.js的provider.send方法一次性发送多个eth_call请求,每个请求对应一个ERC20的balanceOf或allowance调用。

代码示例

import { ethers } from "ethers";

// 初始化Rootstock Provider
const provider = new ethers.providers.JsonRpcProvider("https://rpc.rootstock.io/mainnet");

// ERC20核心ABI片段
const erc20Abi = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)"
];
const erc20Interface = new ethers.utils.Interface(erc20Abi);

// 定义查询参数
const userAddress = "0x..."; // 你的用户地址
const spenderAddress = "0x..."; // 授权的合约地址(比如DEX)
const tokenAddresses = [
  "0xToken1Address",
  "0xToken2Address"
];

// 构造批量请求数组
const batchRequests = [];
tokenAddresses.forEach(tokenAddr => {
  // 添加balanceOf查询
  batchRequests.push({
    jsonrpc: "2.0",
    id: batchRequests.length + 1,
    method: "eth_call",
    params: [
      {
        to: tokenAddr,
        data: erc20Interface.encodeFunctionData("balanceOf", [userAddress])
      },
      "latest"
    ]
  });
  // 添加allowance查询
  batchRequests.push({
    jsonrpc: "2.0",
    id: batchRequests.length + 1,
    method: "eth_call",
    params: [
      {
        to: tokenAddr,
        data: erc20Interface.encodeFunctionData("allowance", [userAddress, spenderAddress])
      },
      "latest"
    ]
  });
});

// 发送批量请求
const batchResults = await provider.send("eth_sendBatch", batchRequests);

// 解析结果
batchResults.forEach(result => {
  if (result.error) {
    console.error(`请求失败: ${result.error.message}`);
    return;
  }
  // 根据id或顺序解析对应的函数返回值
  const value = ethers.BigNumber.from(result.result);
  console.log(`查询结果: ${value.toString()}`);
});

方法二:使用Multicall合约(更推荐)

Multicall是一个标准合约,允许在单个eth_call中执行多个视图函数调用,并返回所有结果(包括每个调用的成功状态)。Rootstock网络支持部署或使用已有的Multicall合约,这种方式比原生批量请求更结构化,还能处理部分调用失败的场景。

代码示例

import { ethers } from "ethers";

const provider = new ethers.providers.JsonRpcProvider("https://rpc.rootstock.io/mainnet");

// Multicall合约ABI(核心方法)
const multicallAbi = [
  "function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)"
];
// 替换为Rootstock上的Multicall合约地址(若未部署可自行部署标准Multicall)
const multicallAddress = "0xMulticallAddressOnRootstock";
const multicallContract = new ethers.Contract(multicallAddress, multicallAbi, provider);

// ERC20接口和查询参数(同方法一)
const erc20Abi = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)"
];
const erc20Interface = new ethers.utils.Interface(erc20Abi);
const userAddress = "0x...";
const spenderAddress = "0x...";
const tokenAddresses = ["0xToken1", "0xToken2"];

// 构造Multicall调用数组
const calls = [];
tokenAddresses.forEach(tokenAddr => {
  calls.push([
    tokenAddr,
    erc20Interface.encodeFunctionData("balanceOf", [userAddress])
  ]);
  calls.push([
    tokenAddr,
    erc20Interface.encodeFunctionData("allowance", [userAddress, spenderAddress])
  ]);
});

// 执行Multicall查询
const [blockNumber, returnData] = await multicallContract.aggregate(calls);

// 解析每个结果
returnData.forEach((data, index) => {
  // 根据索引判断是balanceOf还是allowance
  const isBalance = index % 2 === 0;
  const value = ethers.BigNumber.from(data);
  const tokenAddr = tokenAddresses[Math.floor(index / 2)];
  console.log(`${tokenAddr} ${isBalance ? '余额' : '授权额度'}: ${value.toString()}`);
});

两种方式对比

  • 原生批量请求:无需依赖额外合约,直接利用JSON-RPC协议特性,适合快速实现。
  • Multicall合约:返回结果结构化,支持部分失败处理,且链上执行更高效,适合长期维护的DApp。

内容的提问来源于stack exchange,提问作者bguiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 21:50:39