Streamlines full-stack Wagmi development for web3 applications.
Install
mkdir -p .claude/skills/wagmi-development && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/4453" && unzip -o skill.zip -d .claude/skills/wagmi-development && rm skill.zipInstalls to .claude/skills/wagmi-development
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Creates Wagmi features across all layers - core actions, query options, framework bindings. Use when adding new actions, hooks, or working across packages/core, packages/react, packages/vue.Key capabilities
- →Create core actions wrapping Viem
- →Implement TanStack Query options
- →Develop React and Vue framework bindings
- →Generate type tests and benchmarks
- →Configure wallet action testing
How it works
The skill provides patterns for wrapping Viem actions into Wagmi core actions, query options, and framework-specific hooks. It enforces strict type inference and testing standards across core, React, and Vue packages.
Inputs & outputs
When to use wagmi-development
- →Create new blockchain interaction hooks
- →Implement TanStack Query options for web3
- →Build framework-specific actions for Wagmi
About this skill
Wagmi Development
Full-stack patterns for adding Wagmi features. This skill covers Viem-based actions only (not Wagmi config actions).
Layer Overview
- Core Action (
packages/core/src/actions/) - Base functionality wrapping Viem - Query Options (
packages/core/src/query/) - TanStack Query integration - Framework Bindings - React (
packages/react/src/hooks/), Vue (packages/vue/src/composables/)
1. Core Action
Structure
import {
type MyActionErrorType as viem_MyActionErrorType,
type MyActionParameters as viem_MyActionParameters,
type MyActionReturnType as viem_MyActionReturnType,
myAction as viem_myAction,
} from 'viem/actions'
import type { Config } from '../createConfig.js'
import type { ChainIdParameter, ConnectorParameter } from '../types/properties.js'
import type { Compute } from '../types/utils.js'
import { getAction } from '../utils/getAction.js'
export type MyActionParameters<config extends Config = Config> = Compute<
ChainIdParameter<config> & viem_MyActionParameters
>
export type MyActionReturnType = viem_MyActionReturnType
export type MyActionErrorType = viem_MyActionErrorType
/** https://wagmi.sh/core/api/actions/myAction */
export async function myAction<config extends Config>(
config: config,
parameters: MyActionParameters<config>,
): Promise<MyActionReturnType> {
const { chainId, ...rest } = parameters
const client = config.getClient({ chainId })
const action = getAction(client, viem_myAction, 'myAction')
return action(rest)
}
Key Rules
- Viem imports: Prefix with
viem_(e.g.,viem_getBalance) - Client access:
- Read-only:
config.getClient({ chainId }) - Wallet:
await getConnectorClient(config, { chainId, connector, account }) - Mixed: Use
getConnectorClientfor account,getClientfor action (seeestimateGas.ts)
- Read-only:
- Parameters: Add
ChainIdParameter<config>always. AddConnectorParameterfor wallet actions. - Type params: Mirror Viem's type params for inference. Use
constmodifier for literal inference (abi, args). - Spread: Omit wagmi-specific props (
chainId,connector) when calling Viem action.
Testing
Runtime tests (action.test.ts):
import { abi, address, config } from '@wagmi/test'
import { expect, test } from 'vitest'
import { myAction } from './myAction.js'
test('default', async () => {
await expect(myAction(config, { /* required params */ })).resolves.toMatchInlineSnapshot(`...`)
})
test('parameters: chainId', async () => { /* test chainId param */ })
test('behavior: error case', async () => { /* test error handling */ })
Type tests (action.test-d.ts) - only if action has type inference:
import { config } from '@wagmi/test'
import { expectTypeOf, test } from 'vitest'
import { myAction } from './myAction.js'
test('default', async () => {
const result = await myAction(config, { /* params */ })
expectTypeOf(result).toEqualTypeOf<ExpectedType>()
})
Type benchmarks (action.bench-d.ts) - only if action has type inference:
import { attest } from '@ark/attest'
import { test } from 'vitest'
import type { MyActionParameters } from './myAction.js'
test('default', () => {
type Result = MyActionParameters<typeof abi.erc20, 'balanceOf'>
const res = {} as Result
attest.instantiations([12345, 'instantiations'])
attest(res.args).type.toString.snap(`readonly [account: \`0x\${string}\`]`)
})
Wallet action tests: Connect before, disconnect after:
test('default', async () => {
await connect(config, { connector })
await expect(myAction(config, { /* params */ })).resolves.toMatchInlineSnapshot(`...`)
await disconnect(config, { connector })
})
2. Query Options
Query (read-only) or Mutation (wallet) options for TanStack Query.
Query Structure
import {
type MyActionErrorType,
type MyActionParameters,
type MyActionReturnType,
myAction,
} from '../actions/myAction.js'
import type { Config } from '../createConfig.js'
import type { ScopeKeyParameter } from '../types/properties.js'
import type { QueryOptions, QueryParameter } from '../types/query.js'
import type { Compute, ExactPartial } from '../types/utils.js'
import { filterQueryOptions, structuralSharing } from './utils.js'
export type MyActionOptions<
config extends Config,
selectData = MyActionData,
> = Compute<ExactPartial<MyActionParameters<config>> & ScopeKeyParameter> &
QueryParameter<MyActionQueryFnData, MyActionErrorType, selectData, MyActionQueryKey<config>>
export function myActionQueryOptions<
config extends Config,
selectData = MyActionData,
>(
config: config,
options: MyActionOptions<config, selectData> = {},
): MyActionQueryOptions<config, selectData> {
return {
...options.query,
enabled: Boolean(options.requiredParam && (options.query?.enabled ?? true)),
queryFn: async (context) => {
const [, { scopeKey: _, ...parameters }] = context.queryKey
if (!parameters.requiredParam) throw new Error('requiredParam is required')
const result = await myAction(config, {
...(parameters as MyActionParameters),
requiredParam: parameters.requiredParam,
})
return result ?? null
},
queryKey: myActionQueryKey(options),
structuralSharing, // include when returning complex objects/arrays
}
}
export type MyActionQueryFnData = Compute<MyActionReturnType>
export type MyActionData = MyActionQueryFnData
export function myActionQueryKey<config extends Config>(
options: Compute<ExactPartial<MyActionParameters<config>> & ScopeKeyParameter> = {},
) {
return ['myAction', filterQueryOptions(options)] as const
}
export type MyActionQueryKey<config extends Config> = ReturnType<typeof myActionQueryKey<config>>
export type MyActionQueryOptions<
config extends Config,
selectData = MyActionData,
> = QueryOptions<MyActionQueryFnData, MyActionErrorType, selectData, MyActionQueryKey<config>>
Mutation Structure
import type { MutationOptions, MutationParameter } from '../types/query.js'
export type MyActionOptions<config extends Config, context = unknown> = MutationParameter<
MyActionData,
MyActionErrorType,
MyActionVariables<config>,
context
>
export function myActionMutationOptions<config extends Config, context>(
config: config,
options: MyActionOptions<config, context> = {},
): MyActionMutationOptions<config> {
return {
...options.mutation,
mutationFn: async (variables) => {
return myAction(config, variables)
},
mutationKey: ['myAction'],
}
}
export type MyActionMutationOptions<config extends Config> = MutationOptions<
MyActionData,
MyActionErrorType,
MyActionVariables<config>
>
Key Rules
- ExactPartial vs UnionExactPartial: Use
ExactPartialfor simple types,UnionExactPartialfor complex unions (contract actions) - enabled: Based on required params being truthy
- structuralSharing: Include when action returns objects/arrays
- filterQueryOptions: Filters common non-serializable props. Skip props like
onReplacedmanually in query key. - Query key: Always
['actionName', filterQueryOptions(options)]
Testing
import { config } from '@wagmi/test'
import { expect, test } from 'vitest'
import { myActionQueryOptions } from './myAction.js'
test('default', () => {
expect(myActionQueryOptions(config, {})).toMatchInlineSnapshot(`
{
"enabled": false,
"queryFn": [Function],
"queryKey": ["myAction", {}],
}
`)
})
test('enabled', () => {
expect(myActionQueryOptions(config, { requiredParam: 'value' }).enabled).toBe(true)
})
test('queryFn: calls query fn', async () => {
const options = myActionQueryOptions(config, { requiredParam: 'value' })
const result = await options.queryFn({ queryKey: options.queryKey } as any)
expect(result).toMatchInlineSnapshot(`...`)
})
3. Framework Bindings
React Query Hook
'use client'
import type { Config, MyActionErrorType, ResolvedRegister } from '@wagmi/core'
import type { Compute } from '@wagmi/core/internal'
import {
type MyActionData,
type MyActionOptions,
myActionQueryOptions,
} from '@wagmi/core/query'
import type { ConfigParameter } from '../types/properties.js'
import { type UseQueryReturnType, useQuery } from '../utils/query.js'
import { useChainId } from './useChainId.js'
import { useConfig } from './useConfig.js'
export type UseMyActionParameters<
config extends Config = Config,
selectData = MyActionData,
> = Compute<MyActionOptions<config, selectData> & ConfigParameter<config>>
export type UseMyActionReturnType<selectData = MyActionData> =
UseQueryReturnType<selectData, MyActionErrorType>
/** https://wagmi.sh/react/api/hooks/useMyAction */
export function useMyAction<
config extends Config = ResolvedRegister['config'],
selectData = MyActionData,
>(
parameters: UseMyActionParameters<config, selectData> = {},
): UseMyActionReturnType<selectData> {
const config = useConfig(parameters)
const chainId = useChainId({ config })
const options = myActionQueryOptions(config, {
...parameters,
chainId: parameters.chainId ?? chainId,
query: parameters.query,
})
return useQuery(options)
}
React Mutation Hook
'use client'
import { useMutation } from '@tanstack/react-query'
import type { Config, ResolvedRegister, MyActionErrorType } from '@wagmi/core'
import {
type MyActionData,
type MyActionMutate,
type MyActionMutateAsync,
type MyActionOptions,
type MyActionVariables,
myActionMutationOptions,
} from '@wagmi/core/query'
import type { ConfigParameter } from '../types/properties.js'
import type { UseMutationReturnType } from '../utils/query.js'
import { useConfig } from './useConfig.js'
export type UseMyActionParameters<config extends Config = Config, context = unknown> =
MyActionOptions<config, context> & ConfigParameter<config>
export type UseMyActionReturnType<config extends Con
---
*Content truncated.*
When not to use it
- →Implementing Wagmi config actions
- →Non-Viem based blockchain actions
Prerequisites
Limitations
- →Covers Viem-based actions only
- →Requires manual setup for complex type inference
How it compares
Unlike manual implementation, this provides standardized patterns for type inference, client access, and framework-specific reactivity.
Compared to similar skills
wagmi-development side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| wagmi-development (this skill) | 1 | 6mo | Review | Advanced |
| ai-model-web | 1 | 2mo | Review | Intermediate |
| convex-realtime | 1 | 6mo | No flags | Intermediate |
| query-layer | 1 | 2mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
ai-model-web
TencentCloudBase
Use this skill when developing browser/Web applications (React/Vue/Angular, static websites, SPAs) that need AI capabilities. Features text generation (generateText) and streaming (streamText) via @cloudbase/js-sdk. Built-in models include Hunyuan (hunyuan-2.0-instruct-20251111 recommended) and DeepSeek (deepseek-v3.2 recommended). NOT for Node.js backend (use ai-model-nodejs), WeChat Mini Program (use ai-model-wechat), or image generation (Node SDK only).
convex-realtime
waynesutton
Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading
query-layer
EpicenterHQ
Query layer patterns for consuming services with TanStack Query, error transformation, and runtime dependency injection. Use when implementing queries/mutations, transforming service errors for UI, or adding reactive data management.
rdc-setup
reactive
Install and set up @data-client/react or @data-client/vue in a project. Detects project type (NextJS, Expo, React Native, Vue, plain React) and protocol (REST, GraphQL, custom), then hands off to protocol-specific setup skills.
lifi-dev
mashharuki
>
create-react-component
OpenCTI-Platform
Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query