Wagmi Chains 指南:从wagmi/chains入口到自定义 Chain 定义
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
导读
在 Wagmi(Reactive primitives for Ethereum apps)中,Chain 对象是连接应用与具体区块链网络的基石:它描述了链 ID、原生货币、RPC 端点、区块浏览器与预部署合约地址,决定了createConfig中传输层如何建立、查询与交易落在哪条链上。本文将围绕 site/react/api/chains.md 展开,讲解如何通过wagmi/chains入口导入 Viem 内置的数百条链定义、如何自定义 Chain 对象并接入 Wagmi 配置,同时结合仓库源码说明其底层转发与类型约束机制,帮助你写出可直接运行、类型安全的链配置。
从wagmi/chains导入内置链
Wagmi 本身不重复维护一份链数据,而是将viem/chains中定义的所有链对象整体转发出来。官方文档明确说明:
Import via the
'wagmi/chains'entrypoint (proxies all chains from'viem/chains').
实际使用方式极其简单:
import { mainnet } from 'wagmi/chains'这一声明的底层实现在 packages/react/src/exports/chains.ts 中只有一行:
export * from 'viem/chains'core 包的 packages/core/src/exports/chains.ts 也是如此。也就是说,wagmi/chains是一个纯粹的全量转发入口(barrel re-export),所有从viem/chains导出的链对象(mainnet、sepolia、optimism、arbitrum、polygon、celo、base等数百条)都会原样可用。
在 packages/react/package.json 中可以看到,"./chains"被显式声明在exports字段中,并指向./dist/types/exports/chains.d.ts与./dist/esm/exports/chains.js,同时typesVersions中也有对应映射,保证子路径导入在 ESM 与 TypeScript 场景下都能正确解析。仓库当前的 Viem 版本为viem@2.55.7(见根目录 package.json),因此wagmi/chains提供的链集合以该 Viem 版本为准;若需要使用更新版本的链定义,应升级 Viem 依赖。
内置链速查:SearchChains 组件
文档中嵌入了一个可交互的<SearchChains />组件用于浏览可用链。其实现位于 site/components/SearchChains.vue:它直接import * as allChains from 'viem/chains',将每个导出的链对象展开为{ ...chain, import: key }并按链 ID 升序排序,随后提供按chain.id、import名称、chain.name与nativeCurrency.symbol四类字段的模糊过滤。这从侧面印证了两点事实:
- 链的可用列表完全来自 Viem,Wagmi 文档站点只是动态聚合展示;
- 每条链至少具备
id、name、nativeCurrency(含symbol)等核心字段,这些字段正是后续自定义 Chain 时的必填项。
由于该组件运行时动态渲染,本文不再罗列静态链清单——在官方文档站点的 Chains 页面中,你可以直接搜索 "Ethereum Mainnet"(ID1)、"Sepolia"(ID11155111)或 "Polygon"(ID137)等名称来确认导入标识。
在 Wagmi 配置中使用 Chain
导入链后,最常见的用法是将其传入createConfig。以仓库脚手架模板 packages/create-wagmi/templates/next/src/wagmi.ts 为例:
import { cookieStorage, createConfig, createStorage, http } from 'wagmi' import { mainnet, sepolia } from 'wagmi/chains' export function getConfig() { return createConfig({ chains: [mainnet, sepolia], storage: createStorage({ storage: cookieStorage, }), ssr: true, transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, }) } declare module 'wagmi' { interface Register { config: ReturnType<typeof getConfig> } }这里的模式非常关键:
chains数组是非空元组(readonly [Chain, ...Chain[]]),保证至少配置一条链;transports的键由chains[number]['id']约束,也就是说每条链都必须提供对应 ID 的传输层,类型系统会在编译期强制你写全,避免漏配导致运行时缺传输的隐患;- 配置完成后,
useChains、useChainId、useSwitchChain、getChainId、getClient等 API 都会基于这套链集合工作。
上述约束可以在 packages/core/src/createConfig.ts 的泛型签名中直接看到:chains extends readonly [Chain, ...Chain[]]、transports extends Record<chains[number]['id'], Transport>(packages/core/src/createConfig.ts),并且内部通过createStore(() => rest.chains)将链集合存入 store,客户端缓存clients也以chains[number]['id']作为 Map 键(packages/core/src/createConfig.ts)。
自定义 Chain:两种受支持的写法
当内置链不满足需求(例如接入本地开发链、企业私有链或尚未收录的新网络)时,需要自行定义 Chain 对象。文档给出的标准做法有两种,核心是让对象满足 Viem 的Chain类型约束:
方式一:as const satisfies Chain
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 Chainas const让所有字段(尤其是id、address等字面量)保持最精确的 readonly 字面量类型,satisfies Chain则在不改变推断类型的前提下校验结构是否满足Chain接口——写错字段名或漏掉必填项时会得到类型错误。
方式二: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是 Viem 提供的工厂函数,会做额外的类型归一化(如补全formatters、serializers等可选字段的默认值),适合希望获得标准 Chain 结构、避免手写细节字段的场景。
两种方式在 IDE 中都会先报类型错误,提示你补齐必填属性;文档中提示"Add the missing required properties to the object until the error goes away",即借助类型系统引导完成定义。
Chain 字段详解
文档逐项说明了各字段的含义与取值来源,这里结合仓库证据整理如下(数据均可在 Viem 的viem/chains与社区 ethereum-lists/chains 数据集中查证,官方文档引用其eip155-56.json等文件作为参考来源):
| 字段 | 说明 | 示例 |
|---|---|---|
id | 网络链 ID(Chain ID),可在 ChainList 等站点按网络名查询 | Ethereum Mainnet 为1 |
name | 链的可读名称 | 'Ethereum' |
nativeCurrency | 链的原生货币,含name/symbol/decimals | { name: 'Ether', symbol: 'ETH', decimals: 18 } |
rpcUrls | 至少一个公开、可信的 RPC URL,default.http为数组 | { default: { http: ['https://eth.merkle.io'] } } |
blockExplorers | 链对应的区块浏览器集合,default含name与url | { default: { name: 'Etherscan', url: 'https://etherscan.io' } } |
contracts | 链上已部署的合约地址集合(均可选) | 见下文 |
sourceId | 源链 ID(例如 L2 对应的 L1 链 ID) | 例如 OP Stack 链指向主网1 |
testnet | 是否为测试网 | true/false |
contracts 子字段要点
multicall3:可选但强烈建议。Wagmi 的批量读取与多合约调用依赖 Multicall3 合约,其地址在绝大多数链上都是0xca11bde05977b3631167028862be2a173976ca11,部署区块号(blockCreated)可在区块浏览器上查到。若你的链上自行部署了 Multicall3,请确保合约已开源验证。ensRegistry:可选,并非所有链都有 ENS 注册表。ensUniversalResolver:可选,并非所有链都有 ENS Universal Resolver。
文档同时强调:给 Chain 对象补充的属性越多,它与 Wagmi 配合使用的效果就越好——完整的 RPC、区块浏览器与合约地址会让http()传输、getBlockNumber、readContracts(Multicall3)、ENS 相关 actions 等开箱即用。
从源码看 Chain 的使用闭环
- 入口转发:packages/react/src/exports/chains.ts 与 packages/core/src/exports/chains.ts 均为
export * from 'viem/chains',这是wagmi/chains子路径在 React 与 core 两个包中共用的实现方式。 - 配置约束:packages/core/src/createConfig.ts 中
chains为非空元组、transports以chains[number]['id']为键,从类型层面保证链与传输一一对应;运行时chains存入 store,客户端以链 ID 为键缓存。 - 测试与脚手架佐证:仓库测试广泛使用
chains: [mainnet]或chains: [mainnet, celo]的组合(例如 packages/core/src/actions/connect.test-d.ts),脚手架模板 packages/create-wagmi/templates/next/src/wagmi.ts 则演示了mainnet+sepolia搭配http()的标准写法,均可作为实际项目配置的参考范本。
小结
围绕wagmi/chains,你可以总结出三层使用心法:
- 优先复用:绝大多数场景直接用
import { mainnet } from 'wagmi/chains'即可,链集合与 Viem 版本同步,无需维护本地数据; - 按需自定义:接入非内置链时,用
as const satisfies Chain或defineChain定义对象,并尽量补全rpcUrls、blockExplorers、contracts.multicall3等字段; - 接入配置:将链对象传入
createConfig({ chains, transports }),保证transports覆盖每条链的 ID,即可获得完整的类型安全链管理能力。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考