如何通过钱包地址查询其持有的全部代币合约列表
BSC链地址持有的BEP20代币列表查询实现方案
你要的功能本质是筛选出所有和目标地址有转账交互、且当前余额大于0的BEP20合约,有三类常见实现路径:
- 路径1:链上事件扫描(不需要依赖第三方接口,兼容性最好)
所有符合BEP20标准的代币都会在转账时触发Transfer(address,address,uint256)事件,你只需要从区块高度0到当前最新高度,过滤所有to或者from为目标地址的Transfer事件,就能拿到所有和该地址交互过的BEP20合约地址。去重后遍历每个合约,调用balanceOf(目标地址)方法,返回值大于0的就是该地址当前持有的代币合约。
注意点:如果地址交易量大,全量扫块耗时会比较长,可以按需设置起始扫描高度降低耗时。 - 路径2:节点增强接口调用(效率最高,适合中小批量查询)
大部分商用BSC RPC节点都提供了定制化的代币余额批量查询接口,不需要自己扫块解析事件,直接传入目标地址即可一次性返回所有持有的BEP20合约地址和对应余额,单次请求即可拿到结果。 - 路径3:自建链上索引服务(适合高频、大规模查询场景)
如果你的业务需要频繁查询大量地址的代币持有情况,可以自己部署索引服务,提前全量索引BSC链上所有BEP20的Transfer事件,后续查询直接读索引数据库即可,响应速度可以做到毫秒级。
简易实现代码示例(web3.js版)
const Web3 = require('web3'); // 填入你的BSC RPC节点地址 const web3 = new Web3('你的BSC RPC节点URL'); const targetAddress = '要查询的目标钱包地址'; // BEP20标准ABI片段,只需要Transfer事件和balanceOf方法 const bep20Abi = [ {"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}, {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"} ]; async function getHolderTokens(address) { // 1. 获取所有和目标地址相关的Transfer事件 const transferEvents = await web3.eth.getPastLogs({ fromBlock: 0, // 可以换成你需要的起始高度 toBlock: 'latest', topics: [ web3.utils.keccak256('Transfer(address,address,uint256)'), null, web3.utils.padLeft(address, 64) // 匹配to为目标地址的事件,需要的话可以再加一个from的匹配 ] }); // 2. 去重得到所有交互过的合约地址 const contractAddresses = [...new Set(transferEvents.map(e => e.address))]; // 3. 遍历查询余额,筛选大于0的 const holdTokens = []; for (const contractAddr of contractAddresses) { const contract = new web3.eth.Contract(bep20Abi, contractAddr); const balance = await contract.methods.balanceOf(address).call(); if (BigInt(balance) > 0n) { holdTokens.push(contractAddr); } } return holdTokens; }
内容的提问来源于stack exchange,提问作者Nomad
相关产品推荐
相关产品推荐

