使用 @wagmi/vue 的 useBytecode:在 Vue 应用中获取链上合约字节码的完整指南
2026/9/18 14:53:28 网站建设 项目流程

使用 @wagmi/vue 的 useBytecode:在 Vue 应用中获取链上合约字节码的完整指南

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

useBytecode@wagmi/vue提供的一个响应式组合式函数(Composable),用于在 Vue 应用中查询指定地址上的合约字节码(Bytecode)。本文以 site/vue/api/composables/useBytecode.md 为核心,结合仓库中@wagmi/vue@wagmi/core的源码实现与测试用例,系统讲解useBytecode的导入方式、基础用法、全部参数(addressblockNumberblockTagchainIdconfigscopeKey)、TanStack Query 扩展选项、返回值结构以及底层调用链,帮助你快速判断一个地址是否为已部署合约、校验合约部署状态,或排查链上合约是否存在。

一、useBytecode 是什么

useBytecode是一个 Vue 组合式函数(Composable),封装了对链上地址字节码的查询逻辑。它基于@wagmi/coregetBytecodeaction 与 TanStack Query(@tanstack/vue-query)构建,返回响应式的查询状态(dataerrorstatus等),当链 ID、地址或区块参数发生变化时,查询结果会自动失效并重新获取。

在真实业务中,useBytecode常见的应用场景包括:

  • 判断某个地址是否部署了合约(无合约的地址返回空字节码0x);
  • 校验合约部署结果,例如在部署交易确认后确认链上已存在代码;
  • 结合blockNumber/blockTag回溯历史区块,检查某区块高度时合约是否存在;
  • 配合chainId在多链应用中按指定链查询。

二、导入方式

在 Vue 项目中,从@wagmi/vue包中导入useBytecode

import { useBytecode } from '@wagmi/vue'

该组合式函数的类型定义位于仓库源码 packages/vue/src/composables/useBytecode.ts:

export type UseBytecodeParameters< config extends Config = Config, selectData = GetBytecodeData, > = Compute< DeepMaybeRef<GetBytecodeOptions<config, selectData> & ConfigParameter<config>> > export type UseBytecodeReturnType<selectData = GetBytecodeData> = UseQueryReturnType<selectData, GetBytecodeErrorType>

可见它的参数类型UseBytecodeParametersGetBytecodeOptionsConfigParameter的组合,并支持DeepMaybeRef——这意味着所有参数都可以是 Vue 的ref/reactive响应式值,这在动态切换查询目标时非常有用。

三、基础用法

useBytecode最基本的使用方式是指定一个合约地址,返回的data即为该地址的字节码(0x开头的十六进制字符串):

<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', }) </script> <template> Byte Code: {{ byteCode }} </template>

在调用前需要先创建并注入 Wagmi 配置。仓库中的配置示例(site/snippets/vue/config.ts)如下:

import { createConfig, http } from '@wagmi/vue' import { mainnet, sepolia } from '@wagmi/vue/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })

然后在应用入口通过WagmiPlugin(Vue 包中对应 React 的WagmiProvider)注入该配置,useBytecode便会从最近的插件上下文中自动获取config。关于配置的详细说明可参考 site/vue/api/createConfig.md 与 site/vue/api/WagmiPlugin.md。

四、参数详解

useBytecode接收一个对象参数,类型为UseBytecodeParameters。以下是文档与源码确认的全部参数。

1.address

  • 类型:Address | undefined
  • 说明:要查询字节码的合约地址。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', }) </script> <template> Byte Code: {{ byteCode }} </template>

值得注意的是,address必填项。从 packages/core/src/query/getBytecode.ts 的源码可以看到,查询的启用条件与校验都依赖于它:

enabled: Boolean(options.address && (options.query?.enabled ?? true)), queryFn: async (context) => { const [, { scopeKey: _, ...parameters }] = context.queryKey if (!parameters.address) throw new Error('address is required') ... }

也就是说:未提供address时查询不会执行(enabledfalse);即使强制执行,queryFn也会抛出'address is required'错误。

2.blockNumber

  • 类型:bigint | undefined
  • 说明:指定在哪个区块高度上查询字节码,可用于回溯历史状态。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', blockNumber: 16280770n, }) </script> <template> Byte Code: {{ byteCode }} </template>

3.blockTag

  • 类型:'latest' | 'earliest' | 'pending' | 'safe' | 'finalized' | undefined
  • 说明:指定在哪个区块标签上查询字节码。其中safefinalized通常用于 Layer 2(如 OP Stack)链,表示已安全确认或已最终确定的区块。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', blockTag: 'safe', }) </script> <template> Byte Code: {{ byteCode }} </template>

注意:blockNumberblockTag是互斥的区块定位参数,二选一使用。

4.chainId

  • 类型:config['chains'][number]['id'] | undefined
  • 说明:指定在哪个链上查询。未传入时,默认使用当前激活的链 ID(由useChainId提供)。这使多链应用可以针对不同链分别查询同一地址的字节码。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' import { mainnet } from '@wagmi/vue/chains' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', chainId: mainnet.id, }) </script> <template> Byte Code: {{ byteCode }} </template>

5.config

  • 类型:Config | undefined
  • 说明:显式指定要使用的[Config](https://link.gitcode.com/i/5ca64b4729193ab1f573ebad3e7e5953)实例,而不是从最近的WagmiPlugin上下文中获取。适合在测试或需要绕过全局上下文注入的场景中使用。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' import { config } from './config' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', config, }) </script> <template> Byte Code: {{ byteCode }} </template>

6.scopeKey

  • 类型:string | undefined
  • 说明:将查询缓存限定到指定上下文。具有相同scopeKey与相同其他参数的组合式函数会共享同一份缓存,从而避免不同业务场景之间互相污染查询状态。
<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' import { config } from './config' const { data: byteCode } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', scopeKey: 'foo', }) </script> <template> Byte Code: {{ byteCode }} </template>

7.query(TanStack Query 扩展参数)

除上述业务参数外,useBytecode还支持通过query子对象透传 TanStack Query 的选项(详见 site/shared/query-options.md)。常用选项包括:

参数类型说明与默认值
enabledboolean \| undefined设为false可禁用查询自动执行,常用于依赖查询(Dependent Queries)
gcTimenumber \| Infinity \| undefined未使用/非活跃缓存数据的保留时间,默认5 * 60 * 1000(5 分钟),SSR 期间为Infinity
initialDataGetBytecodeData \| (() => GetBytecodeData) \| undefined初始缓存数据;初始数据默认视为过期(除非设置了staleTime
staleTimenumber \| Infinity \| undefined数据被视为过期的毫秒数,默认0;设为Infinity则永不过期
refetchIntervalnumber \| false \| function \| undefined轮询刷新频率(毫秒),可用于监控合约部署状态
retryboolean \| number \| function \| undefined失败重试次数,客户端默认3,服务端默认0
networkMode'online' \| 'always' \| 'offlineFirst' \| undefined网络模式,默认'online'
select((data: GetBytecodeData) => unknown) \| undefined对返回数据做变换,仅影响返回的data,不影响缓存内容

一个组合示例:仅在地址存在且组件挂载后才发起查询,并对结果做长度判断:

<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' import { ref } from 'vue' const address = ref<`0x${string}` | undefined>() const { data: byteCode, isLoading, isError } = useBytecode({ address, query: { enabled: () => Boolean(address.value), }, }) </script>

说明:Wagmi 内部使用queryFnqueryKey来驱动查询,因此这两个 TanStack Query 参数不支持用户覆盖。

五、返回值

useBytecode的返回值类型为UseBytecodeReturnType(即UseQueryReturnType<GetBytecodeData, GetBytecodeErrorType>),本质上是 TanStack Query 的观察者结果(详见 site/shared/query-result.md),主要包括:

  • dataGetBytecodeData,最后一次成功解析的数据(字节码,0x开头的十六进制字符串;若地址无合约,datanull——见下文源码说明),默认为undefined
  • errornull | GetBytecodeErrorType,查询失败时的错误对象,默认为null
  • status'error' | 'pending' | 'success',查询状态;
  • fetchStatus'fetching' | 'idle' | 'paused',是否正在抓取;
  • 派生布尔值isErrorisPendingisSuccessisLoadingisFetchingisRefetchingisStale等;
  • refetch:手动重新执行查询的函数;
  • failureCount/failureReason:失败次数与失败原因;
  • dataUpdatedAt/errorUpdatedAt:数据与错误最近一次更新的时间戳。

在模板中常用的组合方式是:

<script setup lang="ts"> import { useBytecode } from '@wagmi/vue' const { data: byteCode, isLoading, isError } = useBytecode({ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', }) </script> <template> <div v-if="isLoading">Loading…</div> <div v-else-if="isError">Failed to load bytecode</div> <div v-else> {{ byteCode ? `Contract deployed (${byteCode.length} hex chars)` : 'No contract at address' }} </div> </template>

六、源码原理:从 composable 到链上 RPC

useBytecode的调用链清晰且分层明确,理解它有助于排查问题和进行二次封装。

1. Vue 组合式函数层

源码 packages/vue/src/composables/useBytecode.ts 的核心逻辑如下:

export function useBytecode< config extends Config = ResolvedRegister['config'], selectData = GetBytecodeData, >( parameters: UseBytecodeParameters<config, selectData> = {}, ): UseBytecodeReturnType<selectData> { const params = computed(() => deepUnref(parameters)) const config = useConfig(params) const chainId = useChainId({ config }) const options = computed(() => getBytecodeQueryOptions(config as any, { ...params.value, chainId: params.value.chainId ?? chainId.value, }), ) return useQuery(options as any) as any }

它依次完成四件事:

  1. deepUnrefref/reactive形式的参数深度解包为普通值,并包装为computed,保证参数变化时自动重建查询;
  2. 通过useConfig获取配置(优先取显式传入的config,否则取插件上下文中的全局配置);
  3. 通过useChainId获取当前链 ID,并在未显式传入chainId时作为默认值;
  4. 调用getBytecodeQueryOptions生成查询选项,交由useQuery(对@tanstack/vue-query的封装,见 packages/vue/src/utils/query.ts)执行。

2. 查询选项层(query key / enabled / queryFn)

packages/core/src/query/getBytecode.ts 负责构建查询:

export function getBytecodeQueryOptions< config extends Config, selectData = GetBytecodeData, >(config: config, options: GetBytecodeOptions<config, selectData> = {}) { return { ...options.query, enabled: Boolean(options.address && (options.query?.enabled ?? true)), queryFn: async (context) => { const [, { scopeKey: _, ...parameters }] = context.queryKey if (!parameters.address) throw new Error('address is required') const bytecode = await getBytecode(config, { ...(parameters as any), address: parameters.address, }) return (bytecode ?? null) as any }, queryKey: getBytecodeQueryKey(options), } } export function getBytecodeQueryKey<config extends Config>(options = {}) { return ['getBytecode', filterQueryOptions(options)] as const }

要点:

  • 缓存键(queryKey)['getBytecode', { address, chainId, blockNumber, blockTag, scopeKey }]。只要这些参数变化,就会产生新的缓存条目,并在chainId等变化时自动重新查询;
  • enabled逻辑address存在且用户未显式禁用时才执行查询;
  • 空字节码处理:底层若返回undefined(如 EOA 地址或不存在合约的地址),会统一归一化为null,方便在模板中做v-if判断。

3. 底层 action 层

最终请求由 core 层的getBytecodeaction 发出(packages/core/src/actions/getBytecode.ts):

export async function getBytecode<config extends Config>( config: config, parameters: GetBytecodeParameters<config>, ): Promise<GetBytecodeReturnType> { const { chainId, ...rest } = parameters const client = config.getClient({ chainId }) const action = getAction(client, viem_getBytecode, 'getBytecode') return action(rest) }

它从config中按chainId取出对应的 viem Client,并通过getAction调用 viem 的getBytecode方法,最终走 RPC 的eth_getCode。这与 site/core/api/actions/getBytecode.md 中记录的 core action 一一对应。

七、测试验证:查询选项与 action 的行为契约

仓库为getBytecode提供了完整的单元测试,可用于验证上述行为:

  • packages/core/src/query/getBytecode.test.ts 验证了查询选项的构建:默认情况下enabledtrue,且queryKey会精确反映addresschainIdblockNumberblockTag等参数(例如传入chainId: 456时,queryKey 中出现"chainId": 456;传入blockNumber: 1234567890n时以bigint形式出现在 queryKey 中);
  • packages/core/src/actions/getBytecode.test.ts 则覆盖了 action 层的defaultblockNumberblockTagchainId四类调用场景,确认这些参数都会正确透传给底层 viem action。

八、注意事项与最佳实践

  1. address为必填:未提供时查询不会执行,且queryFn会抛错,因此建议配合响应式ref在地址确定后再渲染组件或再启用查询。
  2. 空地址/EOA 的处理:地址上不存在合约时,datanull,可用v-else分支提示"该地址无合约",而不要用!data简单判断。
  3. 区块定位参数互斥blockNumberblockTag二选一,同时传入可能导致不符合预期的查询。
  4. 多链场景显式传chainId:虽然默认会跟随当前激活链,但在多链 UI 中建议显式传入目标chainId,避免用户切换网络时数据发生跳变。
  5. 善用query扩展项:如需轮询合约部署进度,可设置refetchInterval;如需与其他查询联动,可使用enabled实现依赖查询。
  6. 类型导入:相关的GetBytecodeDataGetBytecodeOptionsGetBytecodeQueryKeygetBytecodeQueryOptionsgetBytecodeQueryKey等类型与工具函数定义于@wagmi/core/query(Vue 侧通过@wagmi/vue暴露),在编写自定义查询或测试时可从@wagmi/vue/query导入。

总结

useBytecode@wagmi/vue中一个"小而精"的查询组合式函数:参数层覆盖了地址、区块定位、链选择、配置注入与缓存隔离;查询层由 TanStack Query 提供缓存、重试、轮询等能力;底层则由@wagmi/coregetBytecodeaction 与 viem 的eth_getCode支撑。通过本文的参数表、可运行示例与源码调用链分析,你可以直接在 Vue 应用中接入合约字节码查询,用于合约存在性校验、部署状态监控与历史区块回溯等场景。

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询