# JAW Wagmi Integration
> Wagmi connector and React hooks for integrating JAW smart accounts into React/Next.js applications.
**This file is self-contained.** You have everything needed to help with this topic. Do NOT fetch other llms-*.txt files unless the user explicitly asks about a different topic.
## Key Info
- **Package:** `@jaw.id/wagmi`
- **Install:** `npm install @jaw.id/wagmi wagmi @tanstack/react-query`
- **Dashboard:** https://dashboard.jaw.id
- **Docs:** https://docs.jaw.id
## Quick Example
```typescript
import { jaw } from '@jaw.id/wagmi';
import { createConfig, http } from 'wagmi';
import { base } from 'wagmi/chains';
const config = createConfig({
chains: [base],
connectors: [
jaw({
apiKey: 'YOUR_API_KEY',
appName: 'My App',
}),
],
transports: { [base.id]: http() },
});
```
---
## Wagmi Integration
Source: https://docs.jaw.id/wagmi/index
## Wagmi Integration
The `@jaw.id/wagmi` package provides a Wagmi-compatible connector and React hooks for integrating JAW smart accounts into your dApp.
### Installation
:::code-group
```bash [npm]
npm install @jaw.id/wagmi wagmi @tanstack/react-query
```
```bash [pnpm]
pnpm add @jaw.id/wagmi wagmi @tanstack/react-query
```
```bash [yarn]
yarn add @jaw.id/wagmi wagmi @tanstack/react-query
```
```bash [bun]
bun add @jaw.id/wagmi wagmi @tanstack/react-query
```
:::
### Quick Start
#### 1. Configure the Connector
```typescript
import { createConfig, http } from 'wagmi';
import { mainnet, base, baseSepolia } from 'wagmi/chains';
import { jaw } from '@jaw.id/wagmi';
export const config = createConfig({
chains: [mainnet, base, baseSepolia],
connectors: [
jaw({
apiKey: 'YOUR_API_KEY',
appName: 'My App',
appLogoUrl: 'https://example.com/logo.png',
}),
],
transports: {
[mainnet.id]: http(),
[base.id]: http(),
[baseSepolia.id]: http(),
},
});
```
#### 2. Set Up Providers
```tsx
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App({ children }) {
return (
{children}
);
}
```
#### 3. Use the Hooks
```tsx
import { useAccount, useSendTransaction } from 'wagmi';
import { useConnect, useDisconnect } from '@jaw.id/wagmi';
function WalletButton() {
const { address, isConnected } = useAccount();
const { mutate: connect, isPending } = useConnect();
const { mutate: disconnect } = useDisconnect();
if (isConnected) {
return (
Connected: {address}
disconnect({})}>Disconnect
);
}
return (
connect({ connector: config.connectors[0] })} disabled={isPending}>
{isPending ? 'Connecting...' : 'Connect Wallet'}
);
}
```
### Standard Wagmi Hooks
All standard wagmi hooks work with the JAW connector. Use them directly from `wagmi`:
```typescript
import {
useAccount,
useSendTransaction,
useSignMessage,
useSignTypedData,
useSwitchChain,
useSendCalls,
useWriteContract,
useBalance,
} from 'wagmi';
```
\| Hook | Description |
\|------|-------------|
\| `useAccount` | Get connected account address and status |
\| `useSendTransaction` | Send a single transaction |
\| `useSignMessage` | Sign a personal message (EIP-191) |
\| `useSignTypedData` | Sign typed data (EIP-712) |
\| `useSwitchChain` | Switch to a different chain |
\| `useSendCalls` | Send atomic batch transactions (EIP-5792) |
\| `useWriteContract` | Call a contract write function |
\| `useBalance` | Get ETH or token balance |
:::info
When a paymaster is configured, transactions sent via `useSendTransaction`, `useSendCalls`, and `useWriteContract` are automatically sponsored (gasless).
:::
### JAW Hooks
For JAW-specific features, import hooks directly from `@jaw.id/wagmi`:
```typescript
// Direct import (recommended)
import { useConnect, useDisconnect, useGrantPermissions } from '@jaw.id/wagmi';
// Alternative: namespace import
import { Hooks } from '@jaw.id/wagmi';
const { mutate } = Hooks.useConnect();
```
\| Hook | Description |
\|------|-------------|
\| [useConnect](/wagmi/useConnect) | Connect with optional capabilities (SIWE, subnames) |
\| [useDisconnect](/wagmi/useDisconnect) | Disconnect and clean up session |
\| [useSign](/wagmi/useSign) | Unified signing (personal + typed data) with chain support |
\| [useGrantPermissions](/wagmi/useGrantPermissions) | Grant permissions to a spender |
\| [usePermissions](/wagmi/usePermissions) | Query current permissions |
\| [useRevokePermissions](/wagmi/useRevokePermissions) | Revoke a permission |
\| [useGetAssets](/wagmi/useGetAssets) | Query token balances across chains |
\| [useCapabilities](/wagmi/useCapabilities) | Query wallet capabilities per chain |
### Connector
\| Function | Description |
\|----------|-------------|
\| [jaw()](/wagmi/jaw) | Create a JAW connector for Wagmi |
### Why Use JAW Hooks?
#### useConnect vs wagmi's useConnect
\| Feature | `wagmi.useConnect` | `@jaw.id/wagmi.useConnect` |
\|---------|-------------------|------------------------|
\| Basic connection | Yes | Yes |
\| Request SIWE signature | No | Yes |
\| Request subname issuance | No | Yes |
\| Uses `wallet_connect` RPC | No | When capabilities provided |
Use `@jaw.id/wagmi`'s `useConnect` when you need capabilities like Sign-In with Ethereum or ENS subnames during connection.
#### useDisconnect vs wagmi's useDisconnect
Both work the same way. `@jaw.id/wagmi`'s version is provided for consistency.
### Actions (Non-React)
For vanilla JavaScript or other frameworks, use actions directly:
```typescript
import { connect, disconnect, grantPermissions } from '@jaw.id/wagmi';
// Use with your wagmi config
await connect(config, { connector: jawConnector });
```
### Related
* [Configuration](/configuration) - Full configuration options
* [Provider API](/api-reference) - Direct provider methods
* [Account API](/account) - Low-level Account class
## Connector
Source: https://docs.jaw.id/wagmi/jaw
## Connector
Create a JAW connector for your [Wagmi Config](https://wagmi.sh/core/api/createConfig).
```typescript
import { createConfig, http } from 'wagmi';
import { mainnet } from 'wagmi/chains';
import { jaw } from '@jaw.id/wagmi';
const config = createConfig({
chains: [mainnet],
connectors: [
jaw({ apiKey: 'YOUR_API_KEY' }),
],
transports: {
[mainnet.id]: http(),
},
});
```
### Signature
```typescript
function jaw(parameters: JawParameters): Connector
```
### Parameters
#### apiKey
Type: `string` (required)
Your JAW API key. Get one at [JAW Dashboard](https://dashboard.jaw.id/).
#### appName
Type: `string`
Display name for your application. Shown in the authentication UI.
#### appLogoUrl
Type: `string | null`
URL to your application's logo. Used in authentication UI.
#### defaultChainId
Type: `number`
Default chain ID to use on first connection.
#### ens
Type: `string`
ENS domain for issuing subnames (e.g., `'myapp.eth'`). When configured, users can receive a subname during account creation.
#### preference
Type: `JawProviderPreference`
Configuration for authentication behavior.
```typescript
interface JawProviderPreference {
/** Authentication mode (default: Mode.CrossPlatform) */
mode?: Mode.CrossPlatform | Mode.AppSpecific;
/** Whether to show testnet chains (default: false) */
showTestnets?: boolean;
/** UI handler for app-specific mode */
uiHandler?: UIHandler;
}
```
#### paymasters
Type: `Record }>`
Custom paymaster configuration by chain ID for gas sponsorship. See [paymasters](/configuration/paymasters) for details.
### Returns
`Connector` - A Wagmi-compatible connector instance.
### Connector Properties
The returned connector has these Wagmi-standard properties:
\| Property | Value |
\|----------|-------|
\| `id` | `'jaw'` |
\| `name` | `'JAW'` |
\| `type` | `'jaw'` |
\| `rdns` | `'keys.jaw.id'` |
### Example
```typescript
import { createConfig, http } from 'wagmi';
import { mainnet, base, baseSepolia } from 'wagmi/chains';
import { jaw } from '@jaw.id/wagmi';
const config = createConfig({
chains: [mainnet, base, baseSepolia],
connectors: [
jaw({
apiKey: 'YOUR_API_KEY',
appName: 'My DApp',
appLogoUrl: 'https://example.com/logo.png',
defaultChainId: 8453, // Base
ens: 'myapp.eth',
preference: {
showTestnets: true,
},
paymasters: {
8453: { url: 'https://my-paymaster.com/base' },
84532: { url: 'https://my-paymaster.com/base-sepolia' },
},
}),
],
transports: {
[mainnet.id]: http(),
[base.id]: http(),
[baseSepolia.id]: http(),
},
});
```
### Related
* [Configuration](/configuration) - Full configuration reference
* [useConnect](/wagmi/useConnect) - Connect with capabilities
* [mode](/configuration/mode) - Authentication mode and UI handler options
## useCapabilities
Source: https://docs.jaw.id/wagmi/useCapabilities
## useCapabilities
Hook to get wallet capabilities for supported chains. Implements EIP-5792 for capability discovery.
**Type:** `hook`
### Import
```typescript
import { useCapabilities } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useCapabilities(parameters?: {
address?: Address;
chainId?: number;
connector?: Connector;
chainFilter?: Hex[];
config?: Config;
query?: UseQueryParameters;
}): UseQueryResult
```
### Parameters
#### address
Type: `Address` (optional)
Specific account address to get capabilities for. When provided, allows querying capabilities without a connected wallet.
#### chainId
Type: `number` (optional)
Specific chain ID. Defaults to current chain.
#### connector
Type: `Connector` (optional)
Specific connector to use. Defaults to active connector.
#### chainFilter
Type: `Hex[]` (optional)
Array of chain IDs (hex format) to filter capabilities. If not provided, returns capabilities for all supported chains.
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### query
Type: `UseQueryParameters` (optional)
TanStack React Query options (excluding `gcTime` and `staleTime` which are managed internally).
### Returns
Returns a TanStack React Query result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `data` | `Record>` | Capabilities keyed by chain ID (hex) |
\| `isLoading` | `boolean` | Whether initial load is in progress |
\| `isFetching` | `boolean` | Whether any fetch is in progress |
\| `isSuccess` | `boolean` | Whether query succeeded |
\| `isError` | `boolean` | Whether query failed |
\| `error` | `Error` | Error if query failed |
\| `refetch` | `function` | Manually refetch capabilities |
#### data
When successful, `data` is an object of capabilities keyed by chain ID (hex):
```typescript
type WalletGetCapabilitiesResponse = Record>;
// Example structure:
{
"0x1": {
"atomicBatch": { "supported": true },
"atomic": { "status": "supported" },
"paymasterService": { "supported": true },
"permissions": { "supported": true },
"feeToken": {
"supported": true,
"tokens": [...]
}
},
"0x2105": {
// Base chain capabilities
}
}
```
### Behavior
1. **Works without connection** when `address` parameter is provided
2. **Auto-enables** when wallet is connected or address is provided
3. **Caches results** for optimal performance
4. **Returns all chains** by default, use `chainFilter` to limit
### Examples
#### Basic Usage
```tsx
import { useAccount } from 'wagmi';
import { useCapabilities } from '@jaw.id/wagmi';
function CapabilitiesDisplay() {
const { isConnected } = useAccount();
const { data: capabilities, isLoading } = useCapabilities();
if (!isConnected) return Connect wallet to view capabilities
;
if (isLoading) return Loading capabilities...
;
return (
{Object.entries(capabilities || {}).map(([chainId, caps]) => (
Chain {chainId}
{Object.entries(caps).map(([name, value]) => (
{name}: {JSON.stringify(value)}
))}
))}
);
}
```
#### Without Wallet Connection
```tsx
import { useCapabilities } from '@jaw.id/wagmi';
function CapabilitiesForAddress({ address }: { address: `0x${string}` }) {
// Works without wallet connection when address is provided
const { data: capabilities, isLoading } = useCapabilities({ address });
if (isLoading) return Loading...
;
return {JSON.stringify(capabilities, null, 2)} ;
}
```
#### Filter by Chain
```tsx
import { useCapabilities } from '@jaw.id/wagmi';
function BaseCapabilities() {
const { data: capabilities } = useCapabilities({
chainFilter: ['0x2105'], // Base mainnet only
});
// ...
}
```
#### Check Specific Capability
```tsx
import { useCapabilities } from '@jaw.id/wagmi';
function PaymasterSupport() {
const { data: capabilities } = useCapabilities();
const supportsPaymaster = (chainId: string) => {
const chainCaps = capabilities?.[chainId as `0x${string}`];
return (chainCaps?.paymasterService as { supported?: boolean })?.supported === true;
};
return (
Ethereum paymaster: {supportsPaymaster('0x1') ? 'Yes' : 'No'}
Base paymaster: {supportsPaymaster('0x2105') ? 'Yes' : 'No'}
);
}
```
### Available Capabilities
\| Capability | Description |
\|------------|-------------|
\| `atomicBatch` | Support for `wallet_sendCalls` (EIP-5792) |
\| `atomic` | Atomic transaction execution |
\| `paymasterService` | Gasless transactions via ERC-7677 |
\| `permissions` | Permission system support |
\| `feeToken` | Supported fee tokens for gas |
### Related
* [useGetAssets](/wagmi/useGetAssets) - Query token balances
* [usePermissions](/wagmi/usePermissions) - Query permissions
* [wallet\_getCapabilities](/api-reference/wallet_getCapabilities) - RPC method reference
## useConnect
Source: https://docs.jaw.id/wagmi/useConnect
## useConnect
Hook to connect to the wallet with optional capabilities.
**Type:** `hook`
### Import
```typescript
import { useConnect } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useConnect(parameters?: {
config?: Config;
mutation?: UseMutationParameters;
}): UseMutationResult
```
### Parameters
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### mutation
Type: `UseMutationParameters` (optional)
TanStack React Query mutation options.
### Returns
Returns a TanStack React Query mutation result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `mutate` | `function` | Function to trigger connection |
\| `mutateAsync` | `function` | Async version of mutate |
\| `data` | `{ accounts, chainId }` | Connection result |
\| `isPending` | `boolean` | Whether connection is in progress |
\| `isSuccess` | `boolean` | Whether connection succeeded |
\| `isError` | `boolean` | Whether connection failed |
\| `error` | `Error` | Error if connection failed |
#### data
When successful, `data` contains:
```typescript
{
accounts: Address[] | AccountWithCapabilities[];
chainId: number;
}
```
If capabilities were requested, accounts include capability information.
### Mutation Variables
When calling `mutate()`, you can pass:
#### connector
Type: `Connector` (required)
The connector to use for connection.
#### chainId
Type: `number` (optional)
Chain ID to connect to.
#### capabilities
Type: `WalletConnectCapabilities` (optional)
Capabilities to request during connection. When provided, uses `wallet_connect` instead of `eth_requestAccounts`.
```typescript
interface WalletConnectCapabilities {
/** SIWE parameters for authentication */
signInWithEthereum?: {
nonce: string;
chainId: string;
domain?: string;
uri?: string;
statement?: string;
};
/** Text records for subname issuance */
subnameTextRecords?: { key: string; value: string }[];
}
```
### Examples
#### Basic Connection
```tsx
import { useAccount } from 'wagmi';
import { useConnect, jaw } from '@jaw.id/wagmi';
function ConnectButton() {
const { isConnected } = useAccount();
const { mutate: connect, isPending } = useConnect();
if (isConnected) return Connected!
;
return (
connect({ connector: jaw({ apiKey: '...' }) })}
disabled={isPending}
>
{isPending ? 'Connecting...' : 'Connect'}
);
}
```
#### Using Config Connector
```tsx
import { useConnect } from '@jaw.id/wagmi';
import { config } from './config';
function ConnectButton() {
const { mutate: connect, isPending } = useConnect();
return (
connect({ connector: config.connectors[0] })}
disabled={isPending}
>
Connect
);
}
```
#### Connection with SIWE
Request a Sign-In with Ethereum signature during connection:
```tsx
import { useConnect, jaw } from '@jaw.id/wagmi';
function ConnectWithSIWE() {
const { mutate: connect, data, isPending } = useConnect();
const handleConnect = () => {
connect({
connector: jaw({ apiKey: '...' }),
capabilities: {
signInWithEthereum: {
nonce: crypto.randomUUID(),
chainId: '0x1',
domain: window.location.host,
uri: window.location.origin,
statement: 'Sign in to My DApp',
},
},
});
};
return (
Sign In with Ethereum
{data && (
Connected: {data.accounts[0].address}
SIWE Signature: {data.accounts[0].capabilities?.signInWithEthereum?.signature}
)}
);
}
```
#### Connection with Subname
Issue an ENS subname during connection (requires `ens` config option):
```tsx
import { useConnect, jaw } from '@jaw.id/wagmi';
function ConnectWithSubname() {
const { mutate: connect, isPending } = useConnect();
const handleConnect = () => {
connect({
connector: jaw({ apiKey: '...', ens: 'myapp.eth' }),
capabilities: {
subnameTextRecords: [
{ key: 'avatar', value: 'https://example.com/avatar.png' },
{ key: 'description', value: 'My profile' },
],
},
});
};
return (
Connect & Get Subname
);
}
```
#### With Mutation Callbacks
```tsx
import { useConnect } from '@jaw.id/wagmi';
function ConnectWithCallbacks() {
const { mutate: connect } = useConnect({
mutation: {
onSuccess: (data) => {
console.log('Connected:', data.accounts);
},
onError: (error) => {
console.error('Connection failed:', error);
},
},
});
return connect({ connector })}>Connect ;
}
```
### Difference from wagmi useConnect
\| Feature | `wagmi.useConnect` | `@jaw.id/wagmi.useConnect` |
\|---------|-------------------|------------------------|
\| Basic connection | Yes | Yes |
\| Capabilities parameter | No | Yes |
\| Uses `wallet_connect` | No | When capabilities provided |
\| Returns account capabilities | No | Yes (when requested) |
Use `@jaw.id/wagmi`'s `useConnect` when you need to request capabilities during connection. For basic connections without capabilities, either hook works.
### Related
* [useDisconnect](/wagmi/useDisconnect) - Disconnect from wallet
* [jaw()](/wagmi/jaw) - Create the connector
* [wallet\_connect](/api-reference/wallet_connect) - RPC method reference
## useDisconnect
Source: https://docs.jaw.id/wagmi/useDisconnect
## useDisconnect
Hook to disconnect from the wallet.
**Type:** `hook`
### Import
```typescript
import { useDisconnect } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useDisconnect(parameters?: {
config?: Config;
mutation?: UseMutationParameters;
}): UseMutationResult
```
### Parameters
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### mutation
Type: `UseMutationParameters` (optional)
TanStack React Query mutation options.
### Returns
Returns a TanStack React Query mutation result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `mutate` | `function` | Function to trigger disconnection |
\| `mutateAsync` | `function` | Async version of mutate |
\| `isPending` | `boolean` | Whether disconnection is in progress |
\| `isSuccess` | `boolean` | Whether disconnection succeeded |
\| `isError` | `boolean` | Whether disconnection failed |
\| `error` | `Error` | Error if disconnection failed |
### Mutation Variables
When calling `mutate()`, you can optionally pass:
#### connector
Type: `Connector` (optional)
Specific connector to disconnect from. If omitted, disconnects the active connector.
### Examples
#### Basic Usage
```tsx
import { useAccount } from 'wagmi';
import { useDisconnect } from '@jaw.id/wagmi';
function DisconnectButton() {
const { isConnected } = useAccount();
const { mutate: disconnect, isPending } = useDisconnect();
if (!isConnected) return null;
return (
disconnect({})} disabled={isPending}>
{isPending ? 'Disconnecting...' : 'Disconnect'}
);
}
```
#### With Callback
```tsx
import { useDisconnect } from '@jaw.id/wagmi';
function DisconnectButton() {
const { mutate: disconnect } = useDisconnect({
mutation: {
onSuccess: () => {
console.log('Disconnected successfully');
// Redirect to login page, clear local state, etc.
},
},
});
return disconnect({})}>Disconnect ;
}
```
#### Disconnect Specific Connector
```tsx
import { useDisconnect, jaw } from '@jaw.id/wagmi';
function DisconnectButton() {
const { mutate: disconnect } = useDisconnect();
const connector = jaw({ apiKey: '...' });
// Disconnect only this specific connector
return (
disconnect({ connector })}>
Disconnect JAW
);
}
```
#### Full Wallet Component
```tsx
import { useAccount } from 'wagmi';
import { useConnect, useDisconnect, jaw } from '@jaw.id/wagmi';
function WalletButton() {
const { address, isConnected } = useAccount();
const { mutate: connect, isPending: isConnecting } = useConnect();
const { mutate: disconnect, isPending: isDisconnecting } = useDisconnect();
if (isConnected) {
return (
{address?.slice(0, 6)}...{address?.slice(-4)}
disconnect({})} disabled={isDisconnecting}>
{isDisconnecting ? '...' : 'Disconnect'}
);
}
return (
connect({ connector: jaw({ apiKey: '...' }) })}
disabled={isConnecting}
>
{isConnecting ? 'Connecting...' : 'Connect'}
);
}
```
### Related
* [useConnect](/wagmi/useConnect) - Connect to wallet
* [jaw()](/wagmi/jaw) - Create the connector
## useGetAssets
Source: https://docs.jaw.id/wagmi/useGetAssets
## useGetAssets
Hook to get the assets for the connected account. Fetches token balances across supported chains.
**Type:** `hook`
### Import
```typescript
import { useGetAssets } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useGetAssets(parameters?: {
address?: Address;
chainId?: number;
connector?: Connector;
chainFilter?: string[];
assetTypeFilter?: AssetType[];
assetFilter?: AssetFilter;
config?: Config;
query?: UseQueryParameters;
}): UseQueryResult
```
### Parameters
#### address
Type: `Address` (optional)
Specific account address to get assets for. Defaults to connected account.
#### chainId
Type: `number` (optional)
Specific chain ID. Defaults to current chain.
#### connector
Type: `Connector` (optional)
Specific connector to use. Defaults to active connector.
#### chainFilter
Type: `string[]` (optional)
Array of chain IDs in hex format (e.g., `['0x1', '0xa']`) to filter results. If not provided, returns assets from all supported chains.
#### assetTypeFilter
Type: `AssetType[]` (optional)
Filter by asset type. Options: `'native'`, `'erc20'`.
```typescript
// Only get ERC-20 tokens
useGetAssets({ assetTypeFilter: ['erc20'] });
// Only get native tokens (ETH, etc.)
useGetAssets({ assetTypeFilter: ['native'] });
```
#### assetFilter
Type: `AssetFilter` (optional)
Filter by specific assets per chain. Maps chain ID (hex) to an array of assets to filter by.
```typescript
type AssetFilter = Record<`0x${string}`, AssetFilterEntry[]>;
type AssetFilterEntry = {
address: `0x${string}`;
type: 'native' | 'erc20';
};
// Example: Get only USDC on mainnet and Base
useGetAssets({
assetFilter: {
'0x1': [{ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', type: 'erc20' }],
'0x2105': [{ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', type: 'erc20' }],
},
});
```
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### query
Type: `UseQueryParameters` (optional)
TanStack React Query options (excluding `gcTime` and `staleTime` which are managed internally).
### Returns
Returns a TanStack React Query result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `data` | `WalletGetAssetsResponse` | Assets grouped by chain ID |
\| `isLoading` | `boolean` | Whether initial load is in progress |
\| `isFetching` | `boolean` | Whether any fetch is in progress |
\| `isSuccess` | `boolean` | Whether query succeeded |
\| `isError` | `boolean` | Whether query failed |
\| `error` | `Error` | Error if query failed |
\| `refetch` | `function` | Manually refetch assets |
#### data
When successful, `data` is an object mapping chain IDs to asset arrays:
```typescript
type WalletGetAssetsResponse = {
[chainId: string]: Asset[];
};
interface Asset {
/** Token contract address, null for native tokens */
address: string | null;
/** Balance in hex format */
balance: string;
/** Asset metadata */
metadata: {
decimals: number;
name: string;
symbol: string;
} | null;
/** Asset type: 'native' or 'erc20' */
type: 'native' | 'erc20';
}
```
### Behavior
1. **Auto-enables** when wallet is connected
2. **Listens for changes** via `assetsChanged` event
3. **Auto-refetches** when assets change (e.g., after transactions)
4. **Caches for 30 seconds** before becoming stale
### Examples
#### Basic Usage
```tsx
import { useAccount } from 'wagmi';
import { useGetAssets } from '@jaw.id/wagmi';
import { formatUnits } from 'viem';
function Portfolio() {
const { isConnected } = useAccount();
const { data: assets, isLoading } = useGetAssets();
if (!isConnected) return Connect wallet to view assets
;
if (isLoading) return Loading assets...
;
return (
{Object.entries(assets || {}).map(([chainId, chainAssets]) => (
Chain {parseInt(chainId, 16)}
{chainAssets.map((asset, i) => (
{asset.metadata?.symbol || 'Unknown'}: {' '}
{formatUnits(
BigInt(asset.balance),
asset.metadata?.decimals || 18
)}
))}
))}
);
}
```
#### Filter by Chain
```tsx
import { useGetAssets } from '@jaw.id/wagmi';
function MainnetAssets() {
const { data: assets } = useGetAssets({
chainFilter: ['0x1'], // Mainnet only
});
// ...
}
```
#### Filter by Asset Type
```tsx
import { useGetAssets } from '@jaw.id/wagmi';
function TokenBalances() {
// Only get ERC-20 tokens, exclude native ETH
const { data: assets } = useGetAssets({
assetTypeFilter: ['erc20'],
});
// ...
}
```
#### Manual Refresh
```tsx
import { useGetAssets } from '@jaw.id/wagmi';
function RefreshablePortfolio() {
const { data, refetch, isFetching } = useGetAssets();
return (
refetch()} disabled={isFetching}>
{isFetching ? 'Refreshing...' : 'Refresh'}
{/* Render assets */}
);
}
```
#### Disable Auto-Fetch
```tsx
import { useGetAssets } from '@jaw.id/wagmi';
function ManualAssets() {
const { data, refetch } = useGetAssets({
query: {
enabled: false, // Don't fetch automatically
},
});
return (
refetch()}>Load Assets
{data &&
{Object.keys(data).length} chains with assets
}
);
}
```
### Related
* [wallet\_getAssets](/api-reference/wallet_getAssets) - RPC method reference
* [usePermissions](/wagmi/usePermissions) - Query permissions
## useGetCallsHistory
Source: https://docs.jaw.id/wagmi/useGetCallsHistory
## useGetCallsHistory
Hook to get the call history for an account. Can be called with or without a connected wallet.
**Type:** `hook`
### Import
```typescript
import { useGetCallsHistory } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useGetCallsHistory(parameters?: {
address?: Address;
chainId?: number;
connector?: Connector;
index?: number;
limit?: number;
sort?: 'asc' | 'desc';
config?: Config;
query?: UseQueryParameters;
}): UseQueryResult
```
### Parameters
#### address
Type: `Address` (optional)
Specific account address to get history for. If not provided when connected, uses the connected account's address. **Required when not connected.**
#### chainId
Type: `number` (optional)
Chain ID to filter results by. When provided, only returns history items for that chain.
#### connector
Type: `Connector` (optional)
Specific connector to use. Defaults to active connector or JAW connector if available.
#### index
Type: `number` (optional)
Index cursor for pagination. Use the `index` from the last item in the previous response to fetch the next page.
#### limit
Type: `number` (optional)
Maximum number of bundles to return. Defaults to 20.
#### sort
Type: `'asc' | 'desc'` (optional)
Sort direction based on index. Defaults to `'desc'` (newest first).
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### query
Type: `UseQueryParameters` (optional)
TanStack React Query options (excluding `gcTime` and `staleTime` which are managed internally).
### Returns
Returns a TanStack React Query result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `data` | `CallsHistoryItem[]` | Array of call history items |
\| `isLoading` | `boolean` | Whether initial load is in progress |
\| `isFetching` | `boolean` | Whether any fetch is in progress |
\| `isSuccess` | `boolean` | Whether query succeeded |
\| `isError` | `boolean` | Whether query failed |
\| `error` | `Error` | Error if query failed |
\| `refetch` | `function` | Manually refetch history |
#### data
When successful, `data` is an array of call history items:
```typescript
interface CallsHistoryItem {
/** userOpHash */
id: `0x${string}`;
/** Auto-incrementing index per address (for cursor pagination) */
index: number;
/** Wallet address */
address: `0x${string}`;
/** 100=Pending, 200=Completed, 500=Onchain Revert */
status: number;
/** Unix timestamp in seconds */
timestamp: number;
/** Chain ID */
chainId: number;
/** Transaction hash (null when pending) */
transactionHash: `0x${string}` | null;
}
```
### Behavior
1. **Works without connection** when `address` is provided
2. **Uses connected address** automatically when wallet is connected
3. **Caches for 30 seconds** before becoming stale
4. **Supports pagination** via `index` cursor
### Examples
#### Basic Usage (Connected)
```tsx
import { useAccount } from 'wagmi';
import { useGetCallsHistory } from '@jaw.id/wagmi';
function TransactionHistory() {
const { isConnected } = useAccount();
const { data: history, isLoading } = useGetCallsHistory();
if (!isConnected) return Connect wallet to view history
;
if (isLoading) return Loading history...
;
return (
{history?.map((item) => (
{new Date(item.timestamp * 1000).toLocaleDateString()} -{' '}
{item.status === 200 ? 'Success' : item.status === 100 ? 'Pending' : 'Failed'}
))}
);
}
```
#### Without Connection (Address Required)
```tsx
import { useGetCallsHistory } from '@jaw.id/wagmi';
function AddressHistory({ address }: { address: `0x${string}` }) {
// Works without wallet connection!
const { data: history, isLoading } = useGetCallsHistory({ address });
if (isLoading) return Loading...
;
return (
History for {address}
{history?.length || 0} transactions found
);
}
```
#### With Pagination
```tsx
import { useState } from 'react';
import { useGetCallsHistory } from '@jaw.id/wagmi';
function PaginatedHistory({ address }: { address: `0x${string}` }) {
const [cursor, setCursor] = useState();
const { data: history, isLoading, isFetching } = useGetCallsHistory({
address,
index: cursor,
limit: 10,
sort: 'desc',
});
const loadMore = () => {
if (history && history.length > 0) {
setCursor(history[history.length - 1].index);
}
};
return (
{history?.map((item) => (
{item.status === 200 ? 'Completed' : 'Pending'}
))}
{isFetching ? 'Loading...' : 'Load More'}
);
}
```
#### Filtering by Status
```tsx
import { useGetCallsHistory } from '@jaw.id/wagmi';
function PendingTransactions() {
const { data: history } = useGetCallsHistory();
const pending = history?.filter((item) => item.status === 100) || [];
return (
Pending Transactions ({pending.length})
{pending.map((item) => (
Submitted: {new Date(item.timestamp * 1000).toLocaleString()}
))}
);
}
```
#### Manual Refresh
```tsx
import { useGetCallsHistory } from '@jaw.id/wagmi';
function RefreshableHistory() {
const { data, refetch, isFetching } = useGetCallsHistory();
return (
refetch()} disabled={isFetching}>
{isFetching ? 'Refreshing...' : 'Refresh'}
{data?.length || 0} transactions
);
}
```
### Related
* [wallet\_getCallsHistory](/api-reference/wallet_getCallsHistory) - RPC method reference
* [wallet\_getCallsStatus](/api-reference/wallet_getCallsStatus) - Get status of specific batch
* [useGetAssets](/wagmi/useGetAssets) - Query asset balances
## useGrantPermissions
Source: https://docs.jaw.id/wagmi/useGrantPermissions
## useGrantPermissions
Hook to grant permissions to a spender address, enabling session keys, subscriptions, and automated transactions.
**Type:** `hook`
### Import
```typescript
import { useGrantPermissions } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useGrantPermissions(parameters?: {
config?: Config;
mutation?: UseMutationParameters;
}): UseMutationResult
```
### Parameters
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### mutation
Type: `UseMutationParameters` (optional)
TanStack React Query mutation options.
### Returns
Returns a TanStack React Query mutation result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `mutate` | `function` | Function to grant permissions |
\| `mutateAsync` | `function` | Async version of mutate |
\| `data` | `WalletGrantPermissionsResponse` | Granted permission details |
\| `isPending` | `boolean` | Whether granting is in progress |
\| `isSuccess` | `boolean` | Whether granting succeeded |
\| `isError` | `boolean` | Whether granting failed |
\| `error` | `Error` | Error if granting failed |
#### data
When successful, `data` contains:
```typescript
interface WalletGrantPermissionsResponse {
/** Smart account this permission is valid for */
account: Address;
/** Entity that can use this permission */
spender: Address;
/** Timestamp when permission becomes valid */
start: number;
/** Timestamp when permission expires */
end: number;
/** Salt for uniqueness */
salt: Hex;
/** Array of call permissions */
calls: CallPermissionDetail[];
/** Array of spend permissions */
spends: SpendPermissionDetail[];
/** Permission identifier (hash) */
permissionId: Hex;
/** Chain ID in hex */
chainId: Hex;
}
```
### Mutation Variables
When calling `mutate()`, pass an object with the following properties:
#### expiry (required)
Type: `number`
Unix timestamp (in seconds) when the permission expires. The permission becomes invalid after this time.
```typescript
// Permission valid for 1 week
const expiry = Math.floor(Date.now() / 1000) + 86400 * 7;
```
#### spender (required)
Type: `Address`
The address that will be granted permission to execute calls on behalf of the account. This is typically:
* A session key address
* A backend service address
* An automation bot address
```typescript
const spender = '0x1234...'; // The address that can use this permission
```
#### permissions (required)
Type: `PermissionsDetail`
The permissions to grant. Contains two optional arrays: `calls` (what functions can be called) and `spends` (token spending limits).
```typescript
interface PermissionsDetail {
/** Call permissions - which contracts and functions can be called */
calls?: CallPermissionDetail[];
/** Spend permissions - token spending limits */
spends?: SpendPermissionDetail[];
}
```
##### permissions.calls
Type: `CallPermissionDetail[]` (optional)
Array of call permissions specifying which contract functions the spender can call.
```typescript
interface CallPermissionDetail {
/** Target contract address */
target: Address;
/** Function selector (4 bytes hex). Optional if functionSignature is provided. */
selector?: Hex;
/** Human-readable function signature. Selector is computed from this if not provided. */
functionSignature?: string;
}
```
\| Field | Type | Required | Description |
\|-------|------|----------|-------------|
\| `target` | `Address` | Yes | Contract address the spender can call |
\| `selector` | `Hex` | No\* | 4-byte function selector (e.g., `'0xa9059cbb'`) |
\| `functionSignature` | `string` | No\* | Human-readable signature (e.g., `'transfer(address,uint256)'`) |
\*Either `selector` or `functionSignature` must be provided.
:::tip
Use `functionSignature` for readability - the SDK computes the selector automatically:
```typescript
// These are equivalent:
{ target: USDC, selector: '0xa9059cbb' }
{ target: USDC, functionSignature: 'transfer(address,uint256)' }
```
:::
##### permissions.spends
Type: `SpendPermissionDetail[]` (optional)
Array of spend permissions specifying token spending limits per time period.
```typescript
interface SpendPermissionDetail {
/** Token address. Use NATIVE_TOKEN constant for ETH. */
token: Address;
/** Maximum amount per period (in wei, as string) */
allowance: string;
/** Time period unit for the limit */
unit: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year' | 'forever';
/** Multiplier for the period (1-255). Defaults to 1. */
multiplier?: number;
}
```
\| Field | Type | Required | Description |
\|-------|------|----------|-------------|
\| `token` | `Address` | Yes | Token contract address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for native ETH. |
\| `allowance` | `string` | Yes | Maximum spend amount per period in wei (as string, supports large numbers) |
\| `unit` | `SpendPeriod` | Yes | Time period: `'minute'`, `'hour'`, `'day'`, `'week'`, `'month'`, `'year'`, or `'forever'` |
\| `multiplier` | `number` | No | Period multiplier (1-255). E.g., `unit: 'day', multiplier: 3` = every 3 days. Defaults to 1. |
:::info
For native ETH spending limits, use the ERC-7528 native token address:
```typescript
const NATIVE_TOKEN = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
```
:::
#### address (optional)
Type: `Address`
Specific account address to grant permissions for. Defaults to the connected account.
#### chainId (optional)
Type: `number`
Target chain ID. Defaults to the connected chain.
#### connector (optional)
Type: `Connector`
Specific connector to use. Defaults to the active connector.
### Examples
#### Basic Usage - Allow Token Transfers
```tsx
import { useGrantPermissions } from '@jaw.id/wagmi';
import { parseUnits } from 'viem';
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
function GrantPermissionButton() {
const { mutate: grant, isPending, data } = useGrantPermissions();
const handleGrant = () => {
grant({
expiry: Math.floor(Date.now() / 1000) + 86400 * 7, // 1 week
spender: '0xYourBackendService...',
permissions: {
calls: [
{
target: USDC,
functionSignature: 'transfer(address,uint256)',
},
],
spends: [
{
token: USDC,
allowance: parseUnits('100', 6).toString(), // 100 USDC
unit: 'day',
},
],
},
});
};
return (
{isPending ? 'Granting...' : 'Grant Permission'}
{data &&
Permission ID: {data.permissionId}
}
);
}
```
#### Subscription Service - Monthly Limit
```tsx
import { useGrantPermissions } from '@jaw.id/wagmi';
import { parseUnits } from 'viem';
function SubscriptionButton() {
const { mutate: grant, isPending } = useGrantPermissions();
const handleSubscribe = () => {
grant({
expiry: Math.floor(Date.now() / 1000) + 86400 * 365, // 1 year
spender: '0xSubscriptionService...',
permissions: {
calls: [
{
target: USDC_ADDRESS,
functionSignature: 'transfer(address,uint256)',
},
],
spends: [
{
token: USDC_ADDRESS,
allowance: parseUnits('9.99', 6).toString(), // $9.99/month
unit: 'month',
},
],
},
});
};
return (
Subscribe for $9.99/month
);
}
```
#### DeFi Automation - Swap Permission
```tsx
import { useGrantPermissions } from '@jaw.id/wagmi';
const UNISWAP_ROUTER = '0x...';
function AutomatedTradingSetup() {
const { mutate: grant, isPending } = useGrantPermissions();
const handleSetup = () => {
grant({
expiry: Math.floor(Date.now() / 1000) + 86400 * 30, // 30 days
spender: '0xTradingBot...',
permissions: {
calls: [
{
target: UNISWAP_ROUTER,
functionSignature: 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)',
},
{
target: UNISWAP_ROUTER,
functionSignature: 'swapTokensForExactTokens(uint256,uint256,address[],address,uint256)',
},
],
spends: [
{
token: USDC_ADDRESS,
allowance: parseUnits('1000', 6).toString(), // 1000 USDC per week
unit: 'week',
},
{
token: WETH_ADDRESS,
allowance: parseUnits('0.5', 18).toString(), // 0.5 WETH per week
unit: 'week',
},
],
},
});
};
return (
Enable Automated Trading
);
}
```
#### Native ETH Spending Limit
```tsx
import { useGrantPermissions } from '@jaw.id/wagmi';
import { parseEther } from 'viem';
const NATIVE_TOKEN = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
function NativeSpendingLimit() {
const { mutate: grant, isPending } = useGrantPermissions();
const handleGrant = () => {
grant({
expiry: Math.floor(Date.now() / 1000) + 86400 * 7,
spender: '0xGamingContract...',
permissions: {
spends: [
{
token: NATIVE_TOKEN,
allowance: parseEther('0.1').toString(), // 0.1 ETH per day
unit: 'day',
},
],
},
});
};
return (
Allow 0.1 ETH/day for Gaming
);
}
```
#### With Period Multiplier
```tsx
// Allow 500 USDC every 2 weeks
grant({
expiry: Math.floor(Date.now() / 1000) + 86400 * 90, // 90 days
spender: '0xPayrollService...',
permissions: {
spends: [
{
token: USDC_ADDRESS,
allowance: parseUnits('500', 6).toString(),
unit: 'week',
multiplier: 2, // Every 2 weeks
},
],
},
});
```
#### With Callbacks
```tsx
import { useGrantPermissions } from '@jaw.id/wagmi';
function GrantWithCallbacks() {
const { mutate: grant } = useGrantPermissions({
mutation: {
onSuccess: (data) => {
console.log('Permission granted:', data.permissionId);
// Store permission ID for later revocation
savePermissionId(data.permissionId);
},
onError: (error) => {
console.error('Failed to grant permission:', error);
},
},
});
// ...
}
```
### Use Cases
* **Session Keys** - Allow a temporary key to perform specific actions without full wallet access
* **Subscription Services** - Grant recurring spending permissions for SaaS, content, or services
* **Automated Trading** - Allow a bot to execute specific trades within spending limits
* **Gaming** - Let a game contract execute moves without transaction prompts
* **DeFi Automation** - Enable auto-compounding, limit orders, or rebalancing
* **Payroll** - Allow scheduled payments to employees
### Related
* [usePermissions](/wagmi/usePermissions) - Get current permissions
* [useRevokePermissions](/wagmi/useRevokePermissions) - Revoke a permission
* [wallet\_grantPermissions](/api-reference/wallet_grantPermissions) - RPC method reference
## usePermissions
Source: https://docs.jaw.id/wagmi/usePermissions
## usePermissions
Hook to get the current permissions for the connected account. Automatically updates when permissions change.
**Type:** `hook`
### Import
```typescript
import { usePermissions } from '@jaw.id/wagmi';
```
### Signature
```typescript
function usePermissions(parameters?: {
address?: Address;
chainId?: number;
connector?: Connector;
config?: Config;
query?: UseQueryParameters;
}): UseQueryResult
```
### Parameters
#### address
Type: `Address` (optional)
Specific account address to get permissions for. Defaults to connected account.
#### chainId
Type: `number` (optional)
Specific chain ID. Defaults to current chain.
#### connector
Type: `Connector` (optional)
Specific connector to use. Defaults to active connector.
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### query
Type: `UseQueryParameters` (optional)
TanStack React Query options (excluding `gcTime` and `staleTime` which are managed internally).
### Returns
Returns a TanStack React Query result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `data` | `WalletGetPermissionsResponse` | Array of permissions |
\| `isLoading` | `boolean` | Whether initial load is in progress |
\| `isFetching` | `boolean` | Whether any fetch is in progress |
\| `isSuccess` | `boolean` | Whether query succeeded |
\| `isError` | `boolean` | Whether query failed |
\| `error` | `Error` | Error if query failed |
\| `refetch` | `function` | Manually refetch permissions |
#### data
When successful, `data` is an array of permissions:
```typescript
type WalletGetPermissionsResponse = Permission[];
interface Permission {
/** Permission identifier (hash) */
id: Hex;
/** Smart account address */
account: Address;
/** Spender address */
spender: Address;
/** Start timestamp */
start: number;
/** Expiry timestamp */
expiry: number;
/** Call permissions */
calls: CallPermissionDetail[];
/** Spend permissions */
spends: SpendPermissionDetail[];
}
```
### Behavior
1. **Auto-enables** when wallet is connected
2. **Listens for changes** via `permissionsChanged` event
3. **Auto-refetches** when permissions change on-chain
4. **Caches indefinitely** until invalidated by events
### Examples
#### Basic Usage
```tsx
import { useAccount } from 'wagmi';
import { usePermissions } from '@jaw.id/wagmi';
function PermissionsList() {
const { isConnected } = useAccount();
const { data: permissions, isLoading } = usePermissions();
if (!isConnected) return Connect wallet to view permissions
;
if (isLoading) return Loading permissions...
;
if (!permissions?.length) {
return No active permissions
;
}
return (
{permissions.map((permission) => (
Spender: {permission.spender}
Expires: {new Date(permission.expiry * 1000).toLocaleString()}
Calls: {permission.calls.length}
Spends: {permission.spends.length}
))}
);
}
```
#### For Specific Address
```tsx
import { usePermissions } from '@jaw.id/wagmi';
function PermissionsForAddress({ address }: { address: `0x${string}` }) {
const { data: permissions } = usePermissions({ address });
// ...
}
```
#### Disable Auto-Fetch
```tsx
import { usePermissions } from '@jaw.id/wagmi';
function ManualPermissions() {
const { data, refetch } = usePermissions({
query: {
enabled: false, // Don't fetch automatically
},
});
return (
refetch()}>Load Permissions
{data &&
{data.length} permissions found
}
);
}
```
### Related
* [useGrantPermissions](/wagmi/useGrantPermissions) - Grant new permissions
* [useRevokePermissions](/wagmi/useRevokePermissions) - Revoke a permission
* [wallet\_getPermissions](/api-reference/wallet_getPermissions) - RPC method reference
## useRevokePermissions
Source: https://docs.jaw.id/wagmi/useRevokePermissions
## useRevokePermissions
Hook to revoke an active permission by its ID. This permanently disables the permission, preventing the spender from executing any further calls.
**Type:** `hook`
### Import
```typescript
import { useRevokePermissions } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useRevokePermissions(parameters?: {
config?: Config;
mutation?: UseMutationParameters;
}): UseMutationResult
```
### Parameters
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### mutation
Type: `UseMutationParameters` (optional)
TanStack React Query mutation options.
### Returns
Returns a TanStack React Query mutation result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `mutate` | `function` | Function to revoke permission |
\| `mutateAsync` | `function` | Async version of mutate |
\| `data` | `RevokePermissionApiResponse` | Revocation result |
\| `isPending` | `boolean` | Whether revocation is in progress |
\| `isSuccess` | `boolean` | Whether revocation succeeded |
\| `isError` | `boolean` | Whether revocation failed |
\| `error` | `Error` | Error if revocation failed |
#### data
When successful, `data` contains:
```typescript
interface RevokePermissionApiResponse {
/** Indicates if the permission was revoked successfully */
success: boolean;
}
```
### Mutation Variables
When calling `mutate()`, pass an object with the following properties:
#### id (required)
Type: `Hex` (e.g., `` `0x${string}` ``)
The permission ID (hash) to revoke. You can obtain this from:
* The `permissionId` field returned when granting a permission
* The `permissionId` field from permissions returned by `usePermissions()`
```typescript
// From grant response
const { data } = useGrantPermissions();
const permissionId = data.permissionId; // '0x1234...'
// From permissions list
const { data: permissions } = usePermissions();
const permissionId = permissions[0].permissionId; // '0x1234...'
```
#### address (optional)
Type: `Address`
Specific account address to revoke the permission for. Defaults to the connected account.
```typescript
revoke({
id: '0x1234...',
address: '0xSpecificAccount...', // Optional: specify which account
});
```
#### chainId (optional)
Type: `number`
Target chain ID where the permission exists. Defaults to the connected chain.
:::warning
**Chain-Specific**: Permissions are chain-specific. Make sure you're revoking on the correct chain where the permission was granted.
:::
```typescript
revoke({
id: '0x1234...',
chainId: 8453, // Revoke on Base
});
```
#### connector (optional)
Type: `Connector`
Specific connector to use. Defaults to the active connector.
#### capabilities (optional)
Type: `RequestCapabilities`
Optional capabilities for the revocation transaction, such as paymaster service for sponsored (gasless) revocation.
```typescript
interface RequestCapabilities {
/** Paymaster service for sponsored transactions */
paymasterService?: {
/** URL of the paymaster service (ERC-7677 compliant) */
url: string;
/** Optional context for the paymaster */
context?: Record;
};
}
```
```typescript
// Sponsored revocation (gasless)
revoke({
id: '0x1234...',
capabilities: {
paymasterService: {
url: 'https://paymaster.example.com',
},
},
});
```
### Examples
#### Basic Usage
```tsx
import { useRevokePermissions } from '@jaw.id/wagmi';
function RevokeButton({ permissionId }: { permissionId: `0x${string}` }) {
const { mutate: revoke, isPending } = useRevokePermissions();
return (
revoke({ id: permissionId })}
disabled={isPending}
>
{isPending ? 'Revoking...' : 'Revoke Permission'}
);
}
```
#### With Confirmation Dialog
```tsx
import { useState } from 'react';
import { useRevokePermissions } from '@jaw.id/wagmi';
function RevokeWithConfirmation({ permission }) {
const { mutate: revoke, isPending } = useRevokePermissions();
const [showConfirm, setShowConfirm] = useState(false);
const handleRevoke = () => {
revoke(
{ id: permission.permissionId },
{
onSuccess: () => {
setShowConfirm(false);
// Permission list will auto-update via usePermissions
},
}
);
};
if (showConfirm) {
return (
Revoke permission for {permission.spender}?
This action cannot be undone.
{isPending ? 'Revoking...' : 'Confirm Revoke'}
setShowConfirm(false)}>Cancel
);
}
return setShowConfirm(true)}>Revoke ;
}
```
#### With Callbacks
```tsx
import { useRevokePermissions } from '@jaw.id/wagmi';
import { toast } from 'sonner';
function RevokeWithCallbacks() {
const { mutate: revoke } = useRevokePermissions({
mutation: {
onSuccess: () => {
toast.success('Permission revoked successfully');
},
onError: (error) => {
toast.error(`Failed to revoke: ${error.message}`);
},
},
});
// ...
}
```
#### Full Permissions Manager
```tsx
import { usePermissions, useRevokePermissions } from '@jaw.id/wagmi';
function PermissionsManager() {
const { data: permissions, isLoading } = usePermissions();
const { mutate: revoke, isPending, variables } = useRevokePermissions();
if (isLoading) return Loading permissions...
;
if (!permissions?.length) return No active permissions
;
return (
Active Permissions
{permissions.map((permission) => {
const isRevoking = isPending && variables?.id === permission.permissionId;
return (
Spender: {permission.spender}
Expires: {new Date(permission.end * 1000).toLocaleDateString()}
Call Permissions: {permission.calls.length}
Spend Limits: {permission.spends.length}
revoke({ id: permission.permissionId })}
disabled={isPending}
>
{isRevoking ? 'Revoking...' : 'Revoke'}
);
})}
);
}
```
#### Revoke on Specific Chain
```tsx
import { useRevokePermissions } from '@jaw.id/wagmi';
import { base } from 'wagmi/chains';
function RevokeOnBase({ permissionId }) {
const { mutate: revoke, isPending } = useRevokePermissions();
const handleRevoke = () => {
revoke({
id: permissionId,
chainId: base.id, // Revoke on Base chain
});
};
return (
Revoke Permission on Base
);
}
```
#### Sponsored Revocation (Gasless)
```tsx
import { useRevokePermissions } from '@jaw.id/wagmi';
function SponsoredRevoke({ permissionId }) {
const { mutate: revoke, isPending } = useRevokePermissions();
const handleRevoke = () => {
revoke({
id: permissionId,
capabilities: {
paymasterService: {
url: 'https://your-paymaster.com/api',
},
},
});
};
return (
Revoke (Gasless)
);
}
```
### Important Notes
:::warning
**Revocation is Permanent**: Once a permission is revoked, it cannot be restored. The spender will immediately lose the ability to execute calls using that permission. To re-enable access, you must grant a new permission.
:::
:::info
**Transaction Required**: Revoking a permission requires an on-chain transaction. The user will need to pay gas for the transaction (unless using a paymaster for gasless revocation).
:::
### Related
* [usePermissions](/wagmi/usePermissions) - Get current permissions
* [useGrantPermissions](/wagmi/useGrantPermissions) - Grant new permissions
* [wallet\_revokePermissions](/api-reference/wallet_revokePermissions) - RPC method reference
## useSign
Source: https://docs.jaw.id/wagmi/useSign
## useSign
Hook to sign messages using the unified `wallet_sign` method (ERC-7871). This combines the functionality of `useSignMessage` and `useSignTypedData` into a single hook, with support for specifying a target chain.
**Type:** `hook`
### Import
```typescript
import { useSign } from '@jaw.id/wagmi';
```
### Signature
```typescript
function useSign(parameters?: {
config?: Config;
mutation?: UseMutationParameters;
}): UseMutationResult
```
### Parameters
#### config
Type: `Config` (optional)
Wagmi config. If not provided, uses the config from `WagmiProvider`.
#### mutation
Type: `UseMutationParameters` (optional)
TanStack React Query mutation options.
### Returns
Returns a TanStack React Query mutation result:
\| Property | Type | Description |
\|----------|------|-------------|
\| `mutate` | `function` | Function to sign a message |
\| `mutateAsync` | `function` | Async version of mutate |
\| `data` | `Hex` | The signature |
\| `isPending` | `boolean` | Whether signing is in progress |
\| `isSuccess` | `boolean` | Whether signing succeeded |
\| `isError` | `boolean` | Whether signing failed |
\| `error` | `Error` | Error if signing failed |
### Mutation Variables
When calling `mutate()`, pass:
#### request
Type: `PersonalSignRequestData | TypedDataRequestData` (required)
The signing request, which can be one of two types:
##### Personal Sign (EIP-191)
```typescript
{
type: '0x45',
data: {
message: string;
}
}
```
##### Typed Data (EIP-712)
```typescript
{
type: '0x01',
data: {
types: Record;
primaryType: string;
domain: TypedDataDomain;
message: Record;
}
}
```
#### Optional Parameters
\| Parameter | Type | Description |
\|-----------|------|-------------|
\| `address` | `Address` | Specific account address |
\| `chainId` | `number` | Target chain ID for signing |
\| `connector` | `Connector` | Specific connector |
### Why Use useSign?
#### Unified API
Instead of choosing between `useSignMessage` and `useSignTypedData`, use a single hook that handles both:
\| Signature Type | Type Code | Standard |
\|---------------|-----------|----------|
\| Personal Sign | `0x45` | EIP-191 |
\| Typed Data | `0x01` | EIP-712 |
#### Chain-Specific Signing
Smart accounts can produce different signatures depending on which chain they're deployed on. The `chainId` parameter lets you sign for a specific chain without calling `wallet_switchEthereumChain` first:
```typescript
// Sign for Base without switching chains
signMessage({
chainId: 8453,
request: {
type: '0x45',
data: { message: 'Hello from Base' },
},
});
```
:::info
The `chainId` parameter specifies which chain's smart account to use for signing. This is separate from any chain ID that might be included in the message content itself (like in EIP-712's domain).
:::
### Examples
#### Personal Sign
```tsx
import { useSign } from '@jaw.id/wagmi';
function SignMessageButton() {
const { mutate: signMessage, data: signature, isPending } = useSign();
const handleSign = () => {
signMessage({
request: {
type: '0x45',
data: { message: 'Hello, World!' },
},
});
};
return (
{isPending ? 'Signing...' : 'Sign Message'}
{signature &&
Signature: {signature}
}
);
}
```
#### Typed Data (EIP-712)
```tsx
import { useSign } from '@jaw.id/wagmi';
function SignTypedDataButton() {
const { mutate: signMessage, data: signature, isPending } = useSign();
const handleSign = () => {
signMessage({
request: {
type: '0x01',
data: {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
],
Mail: [
{ name: 'from', type: 'string' },
{ name: 'to', type: 'string' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
domain: {
name: 'My dApp',
version: '1',
chainId: 1,
},
message: {
from: 'Alice',
to: 'Bob',
contents: 'Hello!',
},
},
},
});
};
return (
{isPending ? 'Signing...' : 'Sign Typed Data'}
);
}
```
#### Cross-Chain Signing
```tsx
import { useSign } from '@jaw.id/wagmi';
import { base, mainnet } from 'wagmi/chains';
function CrossChainSign() {
const { mutate: signMessage, isPending } = useSign();
const signForBase = () => {
signMessage({
chainId: base.id,
request: {
type: '0x45',
data: { message: 'Signed using Base smart account' },
},
});
};
const signForMainnet = () => {
signMessage({
chainId: mainnet.id,
request: {
type: '0x45',
data: { message: 'Signed using Mainnet smart account' },
},
});
};
return (
Sign for Base
Sign for Mainnet
);
}
```
#### With Callbacks
```tsx
import { useSign } from '@jaw.id/wagmi';
function SignWithCallbacks() {
const { mutate: signMessage } = useSign({
mutation: {
onSuccess: (signature) => {
console.log('Signature:', signature);
// Send signature to your backend
},
onError: (error) => {
console.error('Signing failed:', error);
},
},
});
// ...
}
```
### Comparison with Wagmi Hooks
\| Feature | `useSignMessage` | `useSignTypedData` | `useSign` |
\|---------|------------------|-------------------|-----------|
\| Personal sign (EIP-191) | Yes | No | Yes |
\| Typed data (EIP-712) | No | Yes | Yes |
\| Target chain parameter | No | No | Yes |
\| Smart account aware | No | No | Yes |
### Use Cases
* **Authentication** - Sign messages to prove account ownership
* **Gasless Signatures** - Sign data without sending a transaction
* **Multi-chain dApps** - Sign for different chains without switching
* **Permit Signatures** - Sign EIP-2612 permit messages
* **Off-chain Orders** - Sign trading orders for DEX aggregators
### Related
* [wallet\_sign](/api-reference/wallet_sign) - RPC method reference
* [personal\_sign](/api-reference/personal_sign) - Standard personal sign
* [eth\_signTypedData\_v4](/api-reference/eth_signTypedData_v4) - Standard typed data signing