wagmi 中的 Chains:从内置链导入到自定义链的完整实践指南
wagmi 中的 Chains从内置链导入到自定义链的完整实践指南【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi本文以 wagmi 官方文档 site/core/api/chains.md 为骨架系统讲解在 wagmi 应用中如何导入内置链、如何定位可用链列表以及如何通过as const satisfies Chain或defineChain两种方式自定义链并接入createConfig。读完本文你将掌握链对象的核心字段id、name、nativeCurrency、rpcUrls、blockExplorers、contracts、sourceId、testnet的实际用法并能结合仓库源码理解链在 wagmi 配置与运行时中的底层作用。为什么需要理解 wagmi 的 Chains链Chain是 EVM 应用中一切交互的基础交易需要知道目标链的 chain IDRPC 请求需要知道节点的 URL余额与区块查询需要依赖链的元数据。wagmi 本身并不维护一套独立的链定义而是直接代理 Viem 的链集合只要通过专用入口导入即可获得 Viem 中维护的完整链列表无需自行收集或重复定义。在配置层链通过createConfig传入 wagmi 的Config成为客户端创建、交易签名、网络切换等行为的依据在运行时层getChains等 action 可以从配置中读取已注册的链。因此理解链从哪里来、如何定义、如何接入是掌握 wagmi 的第一步。从 wagmi/core/chains 入口导入内置链wagmi 提供了专用入口wagmi/core/chains它完整代理 Viem 的viem/chains中的所有链定义import { mainnet } from wagmi/core/chains该入口的实现在 packages/core/src/exports/chains.ts 中核心只有一行export * from viem/chains这意味着你能导入的链与 Viem 同步例如mainnet、sepolia、base、celo、zkSync等各框架包React 的wagmi/chains、Vue、Solid 等同样采用这一代理模式例如 packages/react/src/exports/chains.ts 也是export * from viem/chains这些链对象同时携带 Viem 的 formatters/serializers 等链专属能力是类型安全的。版本说明当前仓库的根 package.json 锁定viem2.55.7因此文档中Available Chains一节所展示的链定义以该版本为准。若需要更新的链列表应以viemlatest的链索引为准对应文档原文指向 Viem 仓库的链索引文件本文不展开外部链接。如何查看可用的链文档中的 Available Chains 一节通过一个交互式搜索组件site/components/SearchChains.vue动态列出所有可用链其数据来源同样是viem/chains。从该组件的源码可以看到它做了什么通过import * as allChains from viem/chains收集全部链以链的id升序排序支持按链名name、导入名import、链 IDid以及原生币符号nativeCurrency.symbol进行过滤。组件渲染出每个链的name、导入标识符如mainnet、id和nativeCurrency.symbol。这意味着想要按网络名如 Ethereum Mainnet查找链 → 看name想要按导入名如mainnet查找 → 看代码块中的标识符想要按数字 ID如1查找 → 看id。你可以在本地站点site/目录中打开该页面直接搜索也可以在node_modules/viem/chains中按名称查找对应定义。自定义链两种官方推荐写法当内置链集合无法覆盖你的网络私有链、测试网、L2 等时文档提供两种等价的创建方式。方式一as const satisfies Chain从 Viem 导入Chain类型用as const断言字面量类型再用satisfies让对象接受Chain结构的编译期校验import { type Chain } from viem export const mainnet {} as const satisfies Chain此时 TypeScript 会报错提示缺少必需字段。补齐所需属性后即为合法链对象import { type Chain } from viem export const mainnet { id: 1, name: Ethereum, nativeCurrency: { name: Ether, symbol: ETH, decimals: 18 }, rpcUrls: { default: { http: [https://eth.merkle.io] }, }, blockExplorers: { default: { name: Etherscan, url: https://etherscan.io }, }, contracts: { ensRegistry: { address: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e, }, ensUniversalResolver: { address: 0xE4Acdd618deED4e6d2f03b9bf62dc6118FC9A4da, blockCreated: 16773775, }, multicall3: { address: 0xca11bde05977b3631167028862be2a173976ca11, blockCreated: 14353601, }, }, } as const satisfies Chain方式二defineChain使用 Viem 提供的defineChain辅助函数同样的字段以普通对象传入即可import { defineChain } from viem export const mainnet defineChain({ id: 1, name: Ethereum, nativeCurrency: { name: Ether, symbol: ETH, decimals: 18 }, rpcUrls: { default: { http: [https://eth.merkle.io] }, }, blockExplorers: { default: { name: Etherscan, url: https://etherscan.io }, }, contracts: { ensRegistry: { address: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e, }, ensUniversalResolver: { address: 0xE4Acdd618deED4e6d2f03b9bf62dc6118FC9A4da, blockCreated: 16773775, }, multicall3: { address: 0xca11bde05977b3631167028862be2a173976ca11, blockCreated: 14353601, }, }, })两种写法最终得到语义相同的链对象defineChain省去类型断言样板as const satisfies Chain则在未使用辅助函数时保证严格类型检查。链对象字段详解文档明确属性补充得越完整该链在 wagmi 中的可用性越好。以下字段来自文档并结合 Viem 的Chain类型结构展开。字段含义说明id网络的 chain ID例如 Ethereum Mainnet 的 Chain ID 为1可在 ChainList 等渠道确认。id是链的唯一标识也是 transports 映射的键name人类可读的链名称例如Ethereum MainnetnativeCurrency链的原生币含name如Ether、symbol如ETH、decimals通常为18rpcUrls至少一个公开、可信的 RPC URL通常给出default下的http数组wagmi 的http()transport 会据此发起请求blockExplorers区块浏览器集合例如default: { name: Etherscan, url: https://etherscan.io }contracts链上已部署的合约集合见下方子项说明sourceId源链 ID例如 L2 对应的 L1 链 ID用于表达链的层级关系如 OP Stack 类 L2 的sourceId指向其 L1testnet是否为测试网布尔值帮助区分主网与测试环境contracts子字段的选填策略contracts是可选字段但文档与官方示例都推荐尽量补齐multicall3可选但强烈建议地址几乎总是0xca11bde05977b3631167028862be2a173976ca11部署区块号可从区块浏览器查得。wagmi 的多合约批量读取multicall依赖它缺失时相关能力会退化ensRegistry可选并非所有链都有 ENS Registry只有部署了 ENS 的链才需要ensUniversalResolver可选同理仅存在 ENS Universal Resolver 的链需要配置。字段来源参考文档指出上述大多数字段可在社区维护的ethereum-lists/chains数据仓库中找到id/name对应链条目nativeCurrency、rpcUrls、blockExplorers均有对应 JSON 段落文档示例以 eip155-56 链数据为参照。接入真实网络时优先从这类可信数据源复制避免使用不可靠或临时的 RPC。将自定义链接入 wagmi 配置定义好链对象后通过createConfig的chains与transports接入应用import { createConfig, http } from wagmi/core import { mainnet, sepolia } from wagmi/core/chains const config createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(https://mainnet.example.com), [sepolia.id]: http(https://sepolia.example.com), }, })chains要求类型为readonly [Chain, ...Chain[]]即至少一个链transports要求以链 ID 为键、Transport为值因此每一条链都必须有一个对应的 transport若希望精细控制内部 ViemClient的创建可改用client({ chain })函数方式返回自定义createClient但chains仍是必填项。对应仓库中的真实配置示例见 site/snippets/core/config-chain-properties.ts其中同时注册了base、celo、mainnet三条链并为各自id配置了http()transport。从源码看链在运行时的作用createConfig中的链管理链在 wagmi 配置中的底层行为可从 packages/core/src/createConfig.ts 窥见第 41-42 行泛型约束chains extends readonly [Chain, ...Chain[]]与transports extends Recordchains[number][id], Transport在类型层面把链 ID 与 transport 强绑定第 66 行const chains createStore(() rest.chains)链集合被放入内部 store可被读取与更新第 127-155 行getClient按chainId在chains中查找链对象并创建对应 ViemClient默认回退到第一条链第 201 行chains.getState()[0].id第 423-424 行暴露get chains()供getChains等 action 读取。也就是说你传入chains的每个链对象直接决定了内部 Viem Client 的chain配置、默认链选择以及 transport 的映射关系。链字段如rpcUrls、contracts.multicall3会进一步传导到 RPC 请求与批量读取行为。getChains读取已配置的链wagmi 提供getChainsaction 用于读取配置中的链文档见 site/core/api/actions/getChains.md实现见 packages/core/src/actions/getChains.tsimport { getChains } from wagmi/core import { config } from ./config const chains getChains(config)实现要点返回类型GetChainsReturnTypeconfig即config[chains]类型上保持为readonly [Chain, ...Chain[]]函数内部读取config.chains并通过deepEqual做记忆化缓存第 15-16 行链集合未变化时返回上一次的引用避免无意义的新引用引发下游重渲染或重计算。进阶链专属属性的类型收窄部分链如 Celo、zkSync、OP Stack 系支持额外属性这由 Viem 的 formatters/serializers 驱动详见 site/core/guides/chain-properties.md。在 wagmi 中通过类型收窄即可类型安全地使用这些属性。按chainId收窄参数当配置了多条支持额外属性的链时自动补全可能被塞满可显式传入chainId限定单链import { parseEther } from viem import { simulateContract } from wagmi/core import { celo } from wagmi/chains const result await simulateContract({ to: 0xd2135CfB216b74109775236E36d4b433F1DF507B, value: parseEther(0.01), chainId: celo.id, // 收窄到 Celo feeCurrency: 0x…, // 此时 feeCurrency 才会出现在类型中 })收窄返回类型返回结果同样可能携带链专属字段两种方式可取显式传入chainId如waitForTransactionReceipt({ chainId: zkSync.id, hash })返回值自动带上ZkSyncLog[]等类型利用 wagmi 在返回类型上附加的chainId数据属性配合类型守卫做收窄const result await waitForTransactionReceipt({ hash }) if (result.chainId zkSync.id) { result.logs // 类型收窄为 ZkSyncLog[] | undefined }这一机制依赖于链对象本身携带的 formatters/serializers 信息再次印证了链定义越完整、类型体验越好的设计理念。实践清单与注意事项优先复用内置链通过wagmi/core/chains或框架包的wagmi/chains导入与 Viem 保持同步且开箱即用自定义链务必补全核心字段id、name、nativeCurrency、rpcUrls是基本盘blockExplorers、contracts.multicall3强烈建议补齐能显著提升 wagmi 可用性RPC URL 选择可信来源参照社区维护的链数据仓库文档指向ethereum-lists/chains获取公开可信的端点避免失效或伪造的 RPC保证链条与 transport 一一对应createConfig中chains的每个链 ID 都必须在transports中有对应条目否则运行时会缺客户端利用getChains读取链集合获取配置链时使用该 action 而非自行持有副本可获得类型安全与引用缓存的双重收益处理链专属属性时显式chainId多链场景下通过chainId收窄参数与返回类型保持类型推断精确可控。通过以上内容你可以像使用内置链一样顺畅地使用自定义链并在 wagmi 的类型系统与运行时中获得一致的体验。若想进一步了解链在配置中的完整角色可继续阅读 site/shared/createConfig.md 中chains、transports、client参数的说明。【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考