如何使用Web3.py检测BSC地址是否持有除BNB外的代币
Python Web3环境下查询BSC地址非BNB代币持有方案
web3.eth.getTransactionCount(address)只能返回地址发起过的原生链上交易计数,无法识别从未发起过BNB交易、仅持有BEP20代币的地址,你提到的示例地址0x7DBbA1e788b169139F5602CCb734137F45a59aa9就属于这类场景:地址本身从未发起过交易,nonce值为0,但有其他地址转入的BEP20代币。
纯web3.py链上实现方案(无第三方依赖)
BEP20代币的转账都会触发标准Transfer(address,address,uint256)事件,只要查询目标地址作为接收方的Transfer事件,再验证对应代币的余额大于0,就能判断地址是否持有非BNB资产。
- 初始化BSC连接
from web3 import Web3 # 替换为你可用的BSC RPC节点地址 web3 = Web3(Web3.HTTPProvider("https://bsc-dataseed.binance.org/")) target_addr = Web3.to_checksum_address("0x7DBbA1e788b169139F5602CCb734137F45a59aa9") # 计算Transfer事件的topic哈希 transfer_topic = web3.keccak(text="Transfer(address,address,uint256)").hex() # 目标地址作为转账接收方的topic编码(补零到32字节格式) receiver_topic = "0x" + target_addr.lower().zfill(66)[2:]
- 拉取目标地址相关的Transfer事件
# 可根据需要调整查询的区块范围,公开RPC单次查询建议不超过10000个区块,避免被限流 latest_block = web3.eth.block_number event_logs = web3.eth.get_logs({ "fromBlock": latest_block - 10000, "toBlock": "latest", "topics": [transfer_topic, None, receiver_topic] }) # 提取涉及的代币合约地址,去重 hit_contracts = {log["address"] for log in event_logs}
- 验证代币实际余额,排除转入后又转出的情况
# 仅需要BEP20标准的balanceOf方法ABI即可完成查询 bep20_minimal_abi = [ { "constant": True, "inputs": [{"name": "_owner", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "balance", "type": "uint256"}], "type": "function" } ] hold_non_bnb = False for contract_addr in hit_contracts: checksum_contract = Web3.to_checksum_address(contract_addr) token_contract = web3.eth.contract(address=checksum_contract, abi=bep20_minimal_abi) try: bal = token_contract.functions.balanceOf(target_addr).call() if bal > 0: hold_non_bnb = True break except Exception as e: # 跳过不符合BEP20标准的异常合约 continue print(f"地址是否持有非BNB代币: {hold_non_bnb}")
注意事项
- 单次查询区块范围过大可能触发RPC节点返回限制,需要查询全历史数据的话可以按10000区块为步长分批遍历
- 只要地址收到过BEP20代币,就一定会在对应代币合约的Transfer事件中留下记录,不存在完全无事件记录的BEP20持仓
- 地址nonce为0仅代表地址从未主动发起过链上交易,和地址是否有资产没有必然联系
内容的提问来源于stack exchange,提问作者rbutrnz
相关产品推荐
相关产品推荐

