用中獲取鏈上合約字節(jié)碼的完整指南)
使用 wagmi/vue 的 useBytecode在 Vue 應(yīng)用中獲取鏈上合約字節(jié)碼的完整指南【免費(fèi)下載鏈接】wagmiReactive primitives for Ethereum apps項(xiàng)目地址: https://gitcode.com/GitHub_Trending/wa/wagmiuseBytecode是wagmi/vue提供的一個(gè)響應(yīng)式組合式函數(shù)Composable用于在 Vue 應(yīng)用中查詢指定地址上的合約字節(jié)碼Bytecode。本文以 site/vue/api/composables/useBytecode.md 為核心結(jié)合倉庫中wagmi/vue、wagmi/core的源碼實(shí)現(xiàn)與測(cè)試用例系統(tǒng)講解useBytecode的導(dǎo)入方式、基礎(chǔ)用法、全部參數(shù)address、blockNumber、blockTag、chainId、config、scopeKey、TanStack Query 擴(kuò)展選項(xiàng)、返回值結(jié)構(gòu)以及底層調(diào)用鏈幫助你快速判斷一個(gè)地址是否為已部署合約、校驗(yàn)合約部署狀態(tài)或排查鏈上合約是否存在。一、useBytecode 是什么useBytecode是一個(gè) Vue 組合式函數(shù)Composable封裝了對(duì)鏈上地址字節(jié)碼的查詢邏輯。它基于wagmi/core的getBytecodeaction 與 TanStack Querytanstack/vue-query構(gòu)建返回響應(yīng)式的查詢狀態(tài)data、error、status等當(dāng)鏈 ID、地址或區(qū)塊參數(shù)發(fā)生變化時(shí)查詢結(jié)果會(huì)自動(dòng)失效并重新獲取。在真實(shí)業(yè)務(wù)中useBytecode常見的應(yīng)用場(chǎng)景包括判斷某個(gè)地址是否部署了合約無合約的地址返回空字節(jié)碼0x校驗(yàn)合約部署結(jié)果例如在部署交易確認(rèn)后確認(rèn)鏈上已存在代碼結(jié)合blockNumber/blockTag回溯歷史區(qū)塊檢查某區(qū)塊高度時(shí)合約是否存在配合chainId在多鏈應(yīng)用中按指定鏈查詢。二、導(dǎo)入方式在 Vue 項(xiàng)目中從wagmi/vue包中導(dǎo)入useBytecodeimport { useBytecode } from wagmi/vue該組合式函數(shù)的類型定義位于倉庫源碼 packages/vue/src/composables/useBytecode.tsexport type UseBytecodeParameters config extends Config Config, selectData GetBytecodeData, Compute DeepMaybeRefGetBytecodeOptionsconfig, selectData ConfigParameterconfig export type UseBytecodeReturnTypeselectData GetBytecodeData UseQueryReturnTypeselectData, GetBytecodeErrorType可見它的參數(shù)類型UseBytecodeParameters是GetBytecodeOptions與ConfigParameter的組合并支持DeepMaybeRef——這意味著所有參數(shù)都可以是 Vue 的ref/reactive響應(yīng)式值這在動(dòng)態(tài)切換查詢目標(biāo)時(shí)非常有用。三、基礎(chǔ)用法useBytecode最基本的使用方式是指定一個(gè)合約地址返回的data即為該地址的字節(jié)碼0x開頭的十六進(jìn)制字符串script setup langts import { useBytecode } from wagmi/vue const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, }) /script template Byte Code: {{ byteCode }} /template在調(diào)用前需要先創(chuàng)建并注入 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(), }, })然后在應(yīng)用入口通過WagmiPluginVue 包中對(duì)應(yīng) React 的WagmiProvider注入該配置useBytecode便會(huì)從最近的插件上下文中自動(dòng)獲取config。關(guān)于配置的詳細(xì)說明可參考 site/vue/api/createConfig.md 與 site/vue/api/WagmiPlugin.md。四、參數(shù)詳解useBytecode接收一個(gè)對(duì)象參數(shù)類型為UseBytecodeParameters。以下是文檔與源碼確認(rèn)的全部參數(shù)。1.address類型Address | undefined說明要查詢字節(jié)碼的合約地址。script setup langts import { useBytecode } from wagmi/vue const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, }) /script template Byte Code: {{ byteCode }} /template值得注意的是address是必填項(xiàng)。從 packages/core/src/query/getBytecode.ts 的源碼可以看到查詢的啟用條件與校驗(yàn)都依賴于它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時(shí)查詢不會(huì)執(zhí)行enabled為false即使強(qiáng)制執(zhí)行queryFn也會(huì)拋出address is required錯(cuò)誤。2.blockNumber類型bigint | undefined說明指定在哪個(gè)區(qū)塊高度上查詢字節(jié)碼可用于回溯歷史狀態(tài)。script setup langts import { useBytecode } from wagmi/vue const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, blockNumber: 16280770n, }) /script template Byte Code: {{ byteCode }} /template3.blockTag類型latest | earliest | pending | safe | finalized | undefined說明指定在哪個(gè)區(qū)塊標(biāo)簽上查詢字節(jié)碼。其中safe與finalized通常用于 Layer 2如 OP Stack鏈表示已安全確認(rèn)或已最終確定的區(qū)塊。script setup langts import { useBytecode } from wagmi/vue const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, blockTag: safe, }) /script template Byte Code: {{ byteCode }} /template注意blockNumber與blockTag是互斥的區(qū)塊定位參數(shù)二選一使用。4.chainId類型config[chains][number][id] | undefined說明指定在哪個(gè)鏈上查詢。未傳入時(shí)默認(rèn)使用當(dāng)前激活的鏈 ID由useChainId提供。這使多鏈應(yīng)用可以針對(duì)不同鏈分別查詢同一地址的字節(jié)碼。script setup langts 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 }} /template5.config類型Config | undefined說明顯式指定要使用的[Config](https://link.gitcode.com/i/5ca64b4729193ab1f573ebad3e7e5953)實(shí)例而不是從最近的WagmiPlugin上下文中獲取。適合在測(cè)試或需要繞過全局上下文注入的場(chǎng)景中使用。script setup langts import { useBytecode } from wagmi/vue import { config } from ./config const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, config, }) /script template Byte Code: {{ byteCode }} /template6.scopeKey類型string | undefined說明將查詢緩存限定到指定上下文。具有相同scopeKey與相同其他參數(shù)的組合式函數(shù)會(huì)共享同一份緩存從而避免不同業(yè)務(wù)場(chǎng)景之間互相污染查詢狀態(tài)。script setup langts import { useBytecode } from wagmi/vue import { config } from ./config const { data: byteCode } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, scopeKey: foo, }) /script template Byte Code: {{ byteCode }} /template7.queryTanStack Query 擴(kuò)展參數(shù)除上述業(yè)務(wù)參數(shù)外useBytecode還支持通過query子對(duì)象透?jìng)?TanStack Query 的選項(xiàng)詳見 site/shared/query-options.md。常用選項(xiàng)包括參數(shù)類型說明與默認(rèn)值enabledboolean \| undefined設(shè)為false可禁用查詢自動(dòng)執(zhí)行常用于依賴查詢Dependent QueriesgcTimenumber \| Infinity \| undefined未使用/非活躍緩存數(shù)據(jù)的保留時(shí)間默認(rèn)5 * 60 * 10005 分鐘SSR 期間為InfinityinitialDataGetBytecodeData \| (() GetBytecodeData) \| undefined初始緩存數(shù)據(jù)初始數(shù)據(jù)默認(rèn)視為過期除非設(shè)置了staleTimestaleTimenumber \| Infinity \| undefined數(shù)據(jù)被視為過期的毫秒數(shù)默認(rèn)0設(shè)為Infinity則永不過期refetchIntervalnumber \| false \| function \| undefined輪詢刷新頻率毫秒可用于監(jiān)控合約部署狀態(tài)retryboolean \| number \| function \| undefined失敗重試次數(shù)客戶端默認(rèn)3服務(wù)端默認(rèn)0networkModeonline \| always \| offlineFirst \| undefined網(wǎng)絡(luò)模式默認(rèn)onlineselect((data: GetBytecodeData) unknown) \| undefined對(duì)返回?cái)?shù)據(jù)做變換僅影響返回的data不影響緩存內(nèi)容一個(gè)組合示例僅在地址存在且組件掛載后才發(fā)起查詢并對(duì)結(jié)果做長(zhǎng)度判斷script setup langts import { useBytecode } from wagmi/vue import { ref } from vue const address ref0x${string} | undefined() const { data: byteCode, isLoading, isError } useBytecode({ address, query: { enabled: () Boolean(address.value), }, }) /script說明Wagmi 內(nèi)部使用queryFn與queryKey來驅(qū)動(dòng)查詢因此這兩個(gè) TanStack Query 參數(shù)不支持用戶覆蓋。五、返回值useBytecode的返回值類型為UseBytecodeReturnType即UseQueryReturnTypeGetBytecodeData, GetBytecodeErrorType本質(zhì)上是 TanStack Query 的觀察者結(jié)果詳見 site/shared/query-result.md主要包括dataGetBytecodeData最后一次成功解析的數(shù)據(jù)字節(jié)碼0x開頭的十六進(jìn)制字符串若地址無合約data為null——見下文源碼說明默認(rèn)為undefinederrornull | GetBytecodeErrorType查詢失敗時(shí)的錯(cuò)誤對(duì)象默認(rèn)為nullstatuserror | pending | success查詢狀態(tài)fetchStatusfetching | idle | paused是否正在抓取派生布爾值isError、isPending、isSuccess、isLoading、isFetching、isRefetching、isStale等refetch手動(dòng)重新執(zhí)行查詢的函數(shù)failureCount/failureReason失敗次數(shù)與失敗原因dataUpdatedAt/errorUpdatedAt數(shù)據(jù)與錯(cuò)誤最近一次更新的時(shí)間戳。在模板中常用的組合方式是script setup langts import { useBytecode } from wagmi/vue const { data: byteCode, isLoading, isError } useBytecode({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, }) /script template div v-ifisLoadingLoading…/div div v-else-ifisErrorFailed to load bytecode/div div v-else {{ byteCode ? Contract deployed (${byteCode.length} hex chars) : No contract at address }} /div /template六、源碼原理從 composable 到鏈上 RPCuseBytecode的調(diào)用鏈清晰且分層明確理解它有助于排查問題和進(jìn)行二次封裝。1. Vue 組合式函數(shù)層源碼 packages/vue/src/composables/useBytecode.ts 的核心邏輯如下export function useBytecode config extends Config ResolvedRegister[config], selectData GetBytecodeData, ( parameters: UseBytecodeParametersconfig, selectData {}, ): UseBytecodeReturnTypeselectData { 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 }它依次完成四件事用deepUnref將ref/reactive形式的參數(shù)深度解包為普通值并包裝為computed保證參數(shù)變化時(shí)自動(dòng)重建查詢通過useConfig獲取配置優(yōu)先取顯式傳入的config否則取插件上下文中的全局配置通過useChainId獲取當(dāng)前鏈 ID并在未顯式傳入chainId時(shí)作為默認(rèn)值調(diào)用getBytecodeQueryOptions生成查詢選項(xiàng)交由useQuery對(duì)tanstack/vue-query的封裝見 packages/vue/src/utils/query.ts執(zhí)行。2. 查詢選項(xiàng)層query key / enabled / queryFnpackages/core/src/query/getBytecode.ts 負(fù)責(zé)構(gòu)建查詢export function getBytecodeQueryOptions config extends Config, selectData GetBytecodeData, (config: config, options: GetBytecodeOptionsconfig, 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 getBytecodeQueryKeyconfig extends Config(options {}) { return [getBytecode, filterQueryOptions(options)] as const }要點(diǎn)緩存鍵queryKey為[getBytecode, { address, chainId, blockNumber, blockTag, scopeKey }]。只要這些參數(shù)變化就會(huì)產(chǎn)生新的緩存條目并在chainId等變化時(shí)自動(dòng)重新查詢enabled邏輯address存在且用戶未顯式禁用時(shí)才執(zhí)行查詢空字節(jié)碼處理底層若返回undefined如 EOA 地址或不存在合約的地址會(huì)統(tǒng)一歸一化為null方便在模板中做v-if判斷。3. 底層 action 層最終請(qǐng)求由 core 層的getBytecodeaction 發(fā)出packages/core/src/actions/getBytecode.tsexport async function getBytecodeconfig extends Config( config: config, parameters: GetBytecodeParametersconfig, ): PromiseGetBytecodeReturnType { const { chainId, ...rest } parameters const client config.getClient({ chainId }) const action getAction(client, viem_getBytecode, getBytecode) return action(rest) }它從config中按chainId取出對(duì)應(yīng)的 viem Client并通過getAction調(diào)用 viem 的getBytecode方法最終走 RPC 的eth_getCode。這與 site/core/api/actions/getBytecode.md 中記錄的 core action 一一對(duì)應(yīng)。七、測(cè)試驗(yàn)證查詢選項(xiàng)與 action 的行為契約倉庫為getBytecode提供了完整的單元測(cè)試可用于驗(yàn)證上述行為packages/core/src/query/getBytecode.test.ts 驗(yàn)證了查詢選項(xiàng)的構(gòu)建默認(rèn)情況下enabled為true且queryKey會(huì)精確反映address、chainId、blockNumber、blockTag等參數(shù)例如傳入chainId: 456時(shí)queryKey 中出現(xiàn)chainId: 456傳入blockNumber: 1234567890n時(shí)以bigint形式出現(xiàn)在 queryKey 中packages/core/src/actions/getBytecode.test.ts 則覆蓋了 action 層的default、blockNumber、blockTag、chainId四類調(diào)用場(chǎng)景確認(rèn)這些參數(shù)都會(huì)正確透?jìng)鹘o底層 viem action。八、注意事項(xiàng)與最佳實(shí)踐address為必填未提供時(shí)查詢不會(huì)執(zhí)行且queryFn會(huì)拋錯(cuò)因此建議配合響應(yīng)式ref在地址確定后再渲染組件或再啟用查詢。空地址/EOA 的處理地址上不存在合約時(shí)data為null可用v-else分支提示該地址無合約而不要用!data簡(jiǎn)單判斷。區(qū)塊定位參數(shù)互斥blockNumber與blockTag二選一同時(shí)傳入可能導(dǎo)致不符合預(yù)期的查詢。多鏈場(chǎng)景顯式傳chainId雖然默認(rèn)會(huì)跟隨當(dāng)前激活鏈但在多鏈 UI 中建議顯式傳入目標(biāo)chainId避免用戶切換網(wǎng)絡(luò)時(shí)數(shù)據(jù)發(fā)生跳變。善用query擴(kuò)展項(xiàng)如需輪詢合約部署進(jìn)度可設(shè)置refetchInterval如需與其他查詢聯(lián)動(dòng)可使用enabled實(shí)現(xiàn)依賴查詢。類型導(dǎo)入相關(guān)的GetBytecodeData、GetBytecodeOptions、GetBytecodeQueryKey、getBytecodeQueryOptions、getBytecodeQueryKey等類型與工具函數(shù)定義于wagmi/core/queryVue 側(cè)通過wagmi/vue暴露在編寫自定義查詢或測(cè)試時(shí)可從wagmi/vue/query導(dǎo)入??偨Y(jié)useBytecode是wagmi/vue中一個(gè)小而精的查詢組合式函數(shù)參數(shù)層覆蓋了地址、區(qū)塊定位、鏈選擇、配置注入與緩存隔離查詢層由 TanStack Query 提供緩存、重試、輪詢等能力底層則由wagmi/core的getBytecodeaction 與 viem 的eth_getCode支撐。通過本文的參數(shù)表、可運(yùn)行示例與源碼調(diào)用鏈分析你可以直接在 Vue 應(yīng)用中接入合約字節(jié)碼查詢用于合約存在性校驗(yàn)、部署狀態(tài)監(jiān)控與歷史區(qū)塊回溯等場(chǎng)景?!久赓M(fèi)下載鏈接】wagmiReactive primitives for Ethereum apps項(xiàng)目地址: https://gitcode.com/GitHub_Trending/wa/wagmi創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考