如何用web3.py获取单个钱包地址的所有ENS域名?
问题原因
ns.name(address) 是ENS的反向解析方法,仅当钱包地址主动设置了反向解析(将地址映射到某个ENS域名)时才会返回对应域名。而多个ENS域名指向同一个地址属于正向解析(域名→地址),两者是独立的系统:
- 正向解析:任意数量的ENS域名都可以绑定到同一个地址
- 反向解析:一个地址只能设置一个主域名作为反向解析结果
你的代码中ns.name()返回None,说明该钱包地址没有设置反向解析,或者反向解析的域名不是你预期的seeds.eth。
解决方案
方案1:设置反向解析(获取单个主域名)
如果你控制该钱包地址,可以通过web3.py设置反向解析,让ns.name()返回指定的域名(比如seeds.eth):
from web3 import Web3, HTTPProvider from ens import ENS infura_endpoint = f'https://mainnet.infura.io/v3/{infura_api_key}' w3 = Web3(HTTPProvider(infura_endpoint)) ns = ENS.fromWeb3(w3) target_address = '0xC99c2bdA0BEaA0B4c9774B48B81307C00e19CAde' private_key = '你的钱包私钥' # 仅当你控制该钱包时使用 account = w3.eth.account.from_key(private_key) # 构造反向解析域名(格式为 地址去掉0x后的字符串.addr.reverse) reverse_domain = f"{target_address[2:]}.addr.reverse" resolver = ns.resolver(reverse_domain) # 发送交易设置反向解析到seeds.eth tx_hash = resolver.set_name('seeds.eth', transact={'from': account.address, 'gas': 150000}) w3.eth.wait_for_transaction_receipt(tx_hash) # 再次查询反向解析 print(ns.name(target_address)) # 此时会返回'seeds.eth'
方案2:获取所有绑定到地址的ENS域名(无需反向解析)
如果需要获取所有正向绑定到该地址的ENS域名,可以通过查询ENS Registry合约的事件实现。ENS主网Registry合约地址为0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e,我们可以遍历NewResolver事件,检查每个域名的解析器是否指向目标地址:
from web3 import Web3, HTTPProvider from ens import ENS infura_endpoint = f'https://mainnet.infura.io/v3/{infura_api_key}' w3 = Web3(HTTPProvider(infura_endpoint)) ns = ENS.fromWeb3(w3) target_address = '0xC99c2bdA0BEaA0B4c9774B48B81307C00e19CAde' # ENS Registry合约ABI(仅包含所需事件和方法) registry_abi = [ { "anonymous": False, "inputs": [ {"indexed": True, "internalType": "bytes32", "name": "node", "type": "bytes32"}, {"indexed": False, "internalType": "address", "name": "owner", "type": "address"}, {"indexed": False, "internalType": "address", "name": "resolver", "type": "address"} ], "name": "NewResolver", "type": "event" } ] resolver_addr_abi = [ { "constant": True, "inputs": [{"internalType": "bytes32", "name": "node", "type": "bytes32"}], "name": "addr", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": False, "stateMutability": "view", "type": "function" } ] registry_contract = w3.eth.contract( address="0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abi=registry_abi ) # 查询最近100000个区块的事件(可以根据需要调整区块范围) events = registry_contract.events.NewResolver.get_logs(fromBlock='latest'-100000, toBlock='latest') matching_domains = set() for event in events: node = event['args']['node'] resolver_addr = event['args']['resolver'] try: resolver_contract = w3.eth.contract(address=resolver_addr, abi=resolver_addr_abi) resolved_addr = resolver_contract.functions.addr(node).call() if resolved_addr.lower() == target_address.lower(): # 将ENS节点哈希转换为域名 domain = ns.name_at(node) matching_domains.add(domain) except Exception as e: continue print(f"绑定到该地址的所有ENS域名:{list(matching_domains)}")
注意事项
- 方案2的事件查询可能较慢,建议限制区块范围(比如只查询最近N个区块),避免遍历全量区块。
- 部分旧域名可能没有触发
NewResolver事件,这种情况下需要额外处理,但大部分活跃域名会覆盖到。
内容的提问来源于stack exchange,提问作者Pablo Uboldi
相关产品推荐
相关产品推荐

