ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

web3.js 4.x ENS 模块迁移指南:从 web3.eth.ens 1.x 升级的破坏性变更与实战改造

2026/9/20 20:40:13 拓冰建站 浏览量
web3.js 4.x ENS 模块迁移指南:从 web3.eth.ens 1.x 升级的破坏性变更与实战改造 web3.js 4.x ENS 模块迁移指南从 web3.eth.ens 1.x 升级的破坏性变更与实战改造【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js本文档面向从 web3.js 1.x 升级到 4.x 的开发者系统梳理web3.eth.ens模块的全部破坏性变更Breaking Changes与已移除 API并结合仓库中web3-eth-ens包的源码实现、单元测试与集成测试给出可直接落地的迁移步骤、新 API 用法与常见陷阱。读完本文你将能够把旧版 ENS 相关代码完整迁移到 4.x并理解新架构中ENS、Registry、Resolver三个核心类的职责划分。迁移背景从web3.eth.ens到独立的web3-eth-ens包在 web3.js 1.x 中ENS 功能以内置模块web3.eth.ens的形式存在到了 4.xENS 能力被拆分为独立的web3-eth-ens包并作为web3.eth.ens命名空间挂在聚合包web3之下。这一拆分的直接证据在 packages/web3/src/eth.exports.tsexport * as ens from web3-eth-ens;也就是说web3.eth.ens与web3-eth-ens是同一份代码的两种入口。从 packages/web3-eth-ens/src/index.ts 的包级注释可以看出 4.x 的设计取向所有 API 级接口中 1.x 返回或接收的null一律改为undefined函数不再接受回调callback参数全部改为 Promise / PromiEvent 风格原接受可选TransactionConfig作为末参的函数现在接受可选的NonPayableCallOptions详见web3-eth-contract包移除了所有非只读set 系列方法——如果需要修改 resolver 或 registry官方建议改用 ENS 生态的其他专用工具。# 方式一使用聚合包通过 web3.eth.ens 访问 npm i web3 # 方式二按需安装独立包更适合轻量应用 npm i web3-eth-ens两种方式的典型用法如下示例取自 packages/web3-eth-ens/src/ens.ts 的类注释// 聚合包入口 import { Web3 } from web3; const web3 new Web3(https://127.0.0.1:4545); console.log(await web3.eth.ens.getAddress(ethereum.eth)); // 独立包入口 import { ENS } from web3-eth-ens; const ens new ENS(undefined, https://127.0.0.1:4545); console.log(await ens.getAddress(vitalik.eth));ENS类的构造签名见 ens.ts为new ENS(registryAddr?, provider?)registryAddr可指定自定义注册表地址provider可以是字符串、SupportedProviders或Web3ContextObject。两个参数都可选。破坏性变更逐项详解1.null统一改为undefined1.x 中返回或接受null的 API 接口在 4.x 一律使用undefined。这意味着诸如记录不存在解析器未设置等空值场景的判断逻辑需要从 null/! null改为 undefined/! undefined。该约定同样适用于web3-eth-ens包内的内部类型定义。2. 回调函数全部移除4.x 中所有函数都不再接受 callback统一返回 Promise读操作或 PromiEvent写操作。迁移时把回调写法改为await/.then()// 1.x web3.eth.ens.getAddress(ethereum.eth, (err, addr) { if (!err) console.log(addr); }); // 4.x const addr await web3.eth.ens.getAddress(ethereum.eth); console.log(addr);3.TransactionConfig变为NonPayableCallOptions1.x 中接受可选TransactionConfig作为最后一个参数的函数在 4.x 中改为接受可选的NonPayableCallOptions。类型定义与web3-eth-contract包对齐具体类型细节可查阅 packages/web3-eth-contract/src/types.ts。值得注意4.x 保留的唯一写方法setAddress使用的是PayableCallOptions见 ens.ts这是NonPayableCallOptions的付费变体携带from、gas、gasPrice、value等字段const receipt await ens.setAddress( web3js.eth, 0xe2597eb05cf9a87eb1309e86750c903ec38e527e, { from: 0xYourAccount }, );4.receipt对象的数值类型全部变为BigInt事件监听器收到的receipt对象中以下属性由number变为BigInt属性1.x 类型4.x 类型transactionIndexnumberBigIntblockNumbernumberBigIntcumulativeGasUsednumberBigIntgasUsednumberBigInteffectiveGasPricenumberBigIntstatusbooleanBigIntstatus从布尔值变成 BigInt 是最容易踩坑的点原来receipt.status true的判断需要改为receipt.status 1n且不能再把status直接当作 truthy 值使用。5.registryAddress默认值改为主网注册表地址1.x 中ens会尝试探测当前网络对应的注册表地址4.x 的默认值直接固定为主网 ENS 注册表地址。这一行为在 packages/web3-eth-ens/src/config.ts 中定义export const registryAddresses: { [T: string]: string } { main: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e, goerli: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e, };对应地ENS构造函数中this.registryAddress registryAddr ?? registryAddresses.main见 ens.ts。单元测试也验证了这一默认行为packages/web3-eth-ens/test/unit/ens.test.tsnew ENS()时provider为undefinedregistryAddress等于registryAddresses.main。迁移建议连接非主网/非 Goerli 的自定义网络时务必显式传入注册表地址例如new ENS(0x你的注册表地址, providerUrl)在未知链上如果不指定将直接使用主网注册表地址。6.registry功能直接暴露在ens类上1.x 中通过ens.registry获取 ENS 注册表对象4.x 移除了该访问器注册表相关的只读能力getOwner、getTTL、recordExists、getResolver、events直接暴露在ENS类上。从 ens.ts 可以看出ENS内部持有_registryRegistry实例与_resolverResolver实例对外统一转发。// 1.x const owner await web3.eth.ens.registry.getOwner(ethereum.eth); // 4.x const owner await web3.eth.ens.getOwner(ethereum.eth);7.resolver移除改用getResolverresolver在 1.x 后期版本中已被标记废弃4.x 中彻底移除统一使用getResolver(name)。getResolver会先通过注册表查询 namehash 对应的解析器地址再返回一个绑定PublicResolverAbi的合约实例见 packages/web3-eth-ens/src/registry.tsconst resolver await ens.getResolver(ethereum.eth); console.log(resolver.options.address); // 0x12345678901234567890123456789012345678908.setOwner签名修正文档曾漏掉address参数迁移文档特别指出1.x 文档中描述setOwner(name, txConfig, callback)是错误的真实签名多一个address参数应为setOwner(name: string, address: string, txConfig?: TransactionConfig, callback?: ...)。4.x 沿用了这一正确签名虽然该函数本身已在 4.x 的移除清单中。迁移时不要照抄旧文档的错误示例。9.getTTL返回bigint而非number4.x 中getTTL(name)返回bigint。集成测试packages/web3-eth-ens/test/integration/ens.test.ts明确断言expect(TTL).toBe(BigInt(0))说明返回类型确实是 BigIntconst ttl await web3.eth.ens.getTTL(ethereum.eth); console.log(ttl); // 例如 0n4.x 已移除的 API 清单getMultihash移除getMultihash在 4.x 的web3-eth-ens中不再支持原因是它已在 ENS 官方 Public Resolver 中被废弃请改用getContenthash。set 系列函数移除以下是 4.x 不再支持的函数官方迁移文档清单setResolver setSubnodeRecord setApprovalForAll isApprovedForAll setSubnodeOwner setTTL setOwner setRecord setAddress setPubkey setContenthash迁移策略如果业务确实需要修改 resolver 或 registry例如注册域名、设置记录、转移所有权建议将相关链上交互改用 ENS 生态专用工具如ensdomains/ensjs完成web3-eth-ens4.x 专注只读查询。值得注意的实现差异虽然迁移文档将setAddress列入移除清单但从当前仓库源码看ENS类仍保留了setAddress方法并转发给Resolver.setAddress见 ens.ts 与 packages/web3-eth-ens/src/resolver.ts内部会先通过 EIP-165supportsInterface检查解析器是否支持setAddr接口。文档与实现之间存在这一差异迁移时应以实际安装版本的源码为准。4.x 新架构ENS / Registry / Resolver 三层职责理解新架构有助于准确预判 API 行为ENSens.ts对外门面继承Web3Context持有 provider、registryAddress组合Registry与Resolver提供getAddress、getOwner、getTTL、getText、getName、getPubkey、getContenthash、supportsInterface、checkNetwork、recordExists、getResolver、setAddress、events等能力Registryregistry.ts包装ENSRegistryAbi合约负责owner、ttl、recordExists、resolver查询与注册表事件events所有查询都基于namehash(name)计算出的节点Resolverresolver.ts包装PublicResolverAbi负责地址/公钥/contenthash/文本记录解析与反向解析getName每次调用前通过checkInterfaceSupport按 EIP-165 校验解析器是否实现对应接口。其中namehash的实现位于 packages/web3-eth-ens/src/utils.ts使用adraffy/ens-normalize先做名称规范化ens_normalize再按 label 从右向左逐级sha3Raw计算节点哈希。常用只读 API 一览4.x方法功能默认/关键参数getAddress(name, coinType 60)解析名称对应地址coinType默认 60ETH支持多链币种getName(address)反向解析地址对应的 ENS 名称自动构造${addr}.addr.reverse节点getText(nameOrAddress, key)ERC-634 文本记录查询传入地址时自动先反向解析getOwner(name)查询名称所有者—getTTL(name)查询缓存 TTL返回bigintrecordExists(name)记录是否存在对旧版未迁移记录返回falsegetPubkey(name)查询公钥 X/Y 坐标—getContenthash(name)查询内容哈希IPFS/Swarm 等—supportsInterface(name, interfaceId)查询解析器是否支持某接口可传方法签名自动sha3后截取前 10 位checkNetwork()检测当前网络是否支持 ENS结果缓存 1 小时get events注册表事件集合NewOwner、NewResolver、Transfer、allEventsEIP-165 接口检测机制Resolver在调用具体方法前会先校验解析器实现resolver.ts。若方法名不在已知接口表内或解析器未实现对应接口会抛出ResolverMethodMissingError。接口 ID 定义在 packages/web3-eth-ens/src/config.tsexport const interfaceIds: { [T: string]: string } { addr: 0x3b3b57de, name: 0x691f3431, abi: 0x2203ab56, pubkey: 0xc8690233, text: 0x59d1d43c, contenthash: 0xbc1c58d1, };网络检测与错误处理4.x 的checkNetwork()见 ens.ts逻辑为检查节点是否同步调用isSyncing若节点仍在同步返回对象而非false抛出ENSNetworkNotSyncedError同步检查结果缓存 3600 秒通过getId获取当前网络 ID以十六进制格式映射到已知网络0x1→ main、0x5→ goerli见 config.ts在映射表中查不到对应注册表地址时抛出ENSNetworkNotSyncedError之外的ENSUnsupportedNetworkError。try { const addr await web3.eth.ens.checkNetwork(); console.log(addr); // 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e } catch (err) { // ENSUnsupportedNetworkError / ENSNetworkNotSyncedError console.error(err); }这两个错误类型分别对应ENSNetworkNotSyncedError与ENSUnsupportedNetworkError单元测试对节点未同步超过 1 小时缓存阈值后重新检测不支持的网络三种场景均有覆盖见 packages/web3-eth-ens/test/unit/ens.test.ts。典型迁移示例从 1.x 到 4.x下面是一个覆盖查询类 API 的完整迁移示例// 1.x const web3 new Web3(provider); web3.eth.ens.getAddress(ethereum.eth, (err, addr) { if (!err) console.log(addr); }); // 4.x import { Web3 } from web3; const web3 new Web3(provider); // 地址解析支持 coinType默认 ETH60 const addr await web3.eth.ens.getAddress(ethereum.eth); // 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359 // 所有者查询 const owner await web3.eth.ens.getOwner(ethereum.eth); // TTL 查询返回 bigint const ttl await web3.eth.ens.getTTL(ethereum.eth); // 记录存在性 const exists await web3.eth.ens.recordExists(ethereum.eth); // 文本记录ERC-634 const email await web3.eth.ens.getText(ethereum.eth, email); // 反向解析地址 → 名称 const name await web3.eth.ens.getName(0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359); // 公钥与内容哈希 const pubkey await web3.eth.ens.getPubkey(ethereum.eth); const contenthash await web3.eth.ens.getContenthash(ethereum.eth); // 接口能力探测 const supports await web3.eth.ens.supportsInterface(ethereum.eth, addr(bytes32)); // 注册表事件订阅 web3.eth.ens.events.NewOwner({ filter: {} }, (err, event) { console.log(event); });迁移检查清单所有null判断改为undefined判断删除所有回调参数改用await/ Promise 链receipt.status等字段的比较改为 BigInt 语义如 1n其余数值字段直接用 BigInt 运算需要修改 ENS 记录注册、转移、设置文本/地址等的代码改用 ENS 生态专用工具web3-eth-ens仅保留只读查询与setAddress连接非主网时显式传入注册表地址避免误用主网默认值resolver访问器改为getResolver()registry访问器改为ens类上的直接方法检查网络支持性优先调用checkNetwork()并捕获ENSNetworkNotSyncedError/ENSUnsupportedNetworkError。测试与验证web3-eth-ens包提供了完善的测试支撑迁移验证单元测试packages/web3-eth-ens/test/unit/ens.test.ts覆盖构造函数默认参数、getResolver/recordExists/getTTL/getOwner/getAddress/setAddress/getPubkey/getContenthash/supportsInterface的转发逻辑以及checkNetwork的错误分支单元测试packages/web3-eth-ens/test/unit/registry.test.ts、packages/web3-eth-ens/test/unit/resolver.test.ts分别验证注册表与解析器层集成测试packages/web3-eth-ens/test/integration/ens.test.ts在本地系统测试网络上部署真实的ENSRegistry、PublicResolver、NameWrapper合约ABI 与字节码位于 packages/web3-eth-ens/test/fixtures/ens随后验证getOwner、getResolver、getTTL断言 BigInt 返回值、recordExists等查询在真实合约上的表现事件测试packages/web3-eth-ens/test/integration/ens.events.test.ts与解析器集成测试packages/web3-eth-ens/test/integration/resolver.test.ts。迁移完成后建议对照上述测试用例逐项验证新代码在目标网络主网或测试网上的实际行为尤其是 BigInt 返回值与自定义注册表地址配置这两处最容易引入回归的改动点。【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考