如何无需初始化Moralis查询钱包中的代币总数量?
不依赖Moralis查询钱包代币余额的方案
要绕过Moralis的初始化流程,直接查询钱包里的代币余额,你可以直接连接区块链节点,用原生JSON-RPC调用或者轻量级库(比如ethers.js)实现,完全不需要依赖Moralis这类第三方API,速度会快很多。
方法一:用ethers.js实现(推荐,代码简洁易维护)
- 先安装依赖:
npm install ethers
- 完整代码示例:
const { ethers } = require('ethers'); const runApp = async () => { // 连接Goerli测试网节点,这里用Infura,也可以换Alchemy或本地节点 const provider = new ethers.JsonRpcProvider('https://goerli.infura.io/v3/你的Infura密钥'); const walletAddress = '0xbf820316675F3F96beb7a47Cec34c5aEdf07BD0e'; // 获取ETH余额 const ethBalance = await provider.getBalance(walletAddress); console.log(`ETH余额: ${ethers.formatEther(ethBalance)} ETH`); // 示例:查询单个已知ERC20代币的余额(Goerli USDC) const erc20BasicAbi = [ 'function balanceOf(address owner) view returns (uint256)', 'function decimals() view returns (uint8)' ]; const usdcContractAddr = '0x07865c6E87B9F70255377e024ace6630C1Eaa37F'; const usdcContract = new ethers.Contract(usdcContractAddr, erc20BasicAbi, provider); const usdcBalance = await usdcContract.balanceOf(walletAddress); const usdcDecimals = await usdcContract.decimals(); console.log(`USDC余额: ${ethers.formatUnits(usdcBalance, usdcDecimals)} USDC`); // 自动扫描钱包所有持有的ERC20代币(通过Transfer事件日志) console.log('\n钱包持有所有ERC20代币余额:'); const transferEventTopic = ethers.id('Transfer(address,address,uint256)'); const logs = await provider.getLogs({ to: walletAddress, topics: [transferEventTopic] }); // 去重代币合约地址 const uniqueTokenContracts = [...new Set(logs.map(log => log.address))]; for (const contractAddr of uniqueTokenContracts) { try { const tokenContract = new ethers.Contract(contractAddr, erc20BasicAbi, provider); const balance = await tokenContract.balanceOf(walletAddress); const decimals = await tokenContract.decimals(); console.log(`${contractAddr}: ${ethers.formatUnits(balance, decimals)}`); } catch (err) { console.log(`${contractAddr}: 非标准ERC20合约,跳过查询`); } } }; runApp();
方法二:原生JSON-RPC调用(不依赖任何第三方库)
如果不想用任何库,可以直接发HTTP请求到节点的JSON-RPC接口:
const fetch = require('node-fetch'); const runApp = async () => { const rpcUrl = 'https://goerli.infura.io/v3/你的Infura密钥'; const walletAddress = '0xbf820316675F3F96beb7a47Cec34c5aEdf07BD0e'; // 查询ETH余额 const ethRes = await fetch(rpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_getBalance', params: [walletAddress, 'latest'], id: 1 }) }); const ethResult = await ethRes.json(); const ethBalance = parseInt(ethResult.result, 16) / 1e18; console.log(`ETH余额: ${ethBalance} ETH`); // 查询USDC余额(Goerli测试网) const usdcContract = '0x07865c6E87B9F70255377e024ace6630C1Eaa37F'; // 构造balanceOf的调用数据:方法签名+钱包地址补全64位 const balanceOfData = '0x70a08231' + walletAddress.slice(2).padStart(64, '0'); const tokenRes = await fetch(rpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_call', params: [{ to: usdcContract, data: balanceOfData }, 'latest'], id: 2 }) }); const tokenResult = await tokenRes.json(); const usdcBalance = parseInt(tokenResult.result, 16) / 1e6; console.log(`USDC余额: ${usdcBalance} USDC`); }; runApp();
注意事项
- 节点可以选择Infura、Alchemy等免费公共节点,也可以自己搭建本地节点(如Geth),后者速度更快但需要同步区块。
- 自动扫描所有代币的方式需要遍历Transfer事件日志,首次查询可能较慢,但后续可以缓存代币列表优化性能。
- 所有操作直接和区块链节点交互,完全去中心化,不需要依赖第三方API的初始化和调用流程。
内容的提问来源于stack exchange,提问作者Dev shaheer
相关产品推荐
相关产品推荐

