Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Getting Started

The JAW SDK is a TypeScript library for integrating smart wallets with passkey authentication into your application.

Features

  • Passkey Authentication - Secure, passwordless authentication using WebAuthn
  • Gasless Transactions - Built-in paymaster support for sponsored transactions
  • Atomic Batch Operations - Execute multiple calls atomically via useSendCalls (EIP-5792)
  • Permission System - Grant granular spend and call permissions to third parties
  • Multi-Chain Support - Works across Ethereum and EVM-compatible chains
  • Identity-Centric by Design - Issue ENS subnames during onboarding, so your users are never exposed to hexadecimal addresses

Installation

npm
npm install @jaw.id/wagmi wagmi viem @tanstack/react-query

Quick Start

1. Configure Wagmi

Create your wagmi config with the JAW connector:

// config.ts
import { createConfig, http } from 'wagmi';
import { mainnet, base } from 'wagmi/chains';
import { jaw } from '@jaw.id/wagmi';
 
export const config = createConfig({
  chains: [mainnet, base],
  connectors: [
    jaw({
      apiKey: 'your-api-key',
      appName: 'My DApp',
      appLogoUrl: 'https://my-dapp.com/logo.png',
    }),
  ],
  transports: {
    [mainnet.id]: http(),
    [base.id]: http(),
  },
});

2. Set Up Providers

Wrap your app with the required providers:

// App.tsx
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { config } from './config';
 
const queryClient = new QueryClient();
 
function App({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </WagmiProvider>
  );
}

3. Connect & Interact

import { useAccount, useSendTransaction } from 'wagmi';
import { useConnect, useDisconnect } from '@jaw.id/wagmi';
import { parseEther } from 'viem';
 
function WalletButton() {
  const { address, isConnected } = useAccount();
  const { mutate: connect, isPending } = useConnect();
  const { mutate: disconnect } = useDisconnect();
  const { sendTransaction } = useSendTransaction();
 
  if (isConnected) {
    return (
      <div>
        <p>Connected: {address}</p>
        <button onClick={() => sendTransaction({
          to: '0x...',
          value: parseEther('0.01')
        })}>
          Send ETH
        </button>
        <button onClick={() => disconnect({})}>
          Disconnect
        </button>
      </div>
    );
  }
 
  return (
    <button
      onClick={() => connect({ connector: config.connectors[0] })}
      disabled={isPending}
    >
      {isPending ? 'Connecting...' : 'Connect Wallet'}
    </button>
  );
}

Wagmi Compatibility

With the JAW connector, standard wagmi hooks work out of the box:

Wagmi HookDescription
useAccountGet connected account info
useSendTransactionSend transactions (gasless if paymaster configured)
useSignMessageSign messages (EIP-191)
useSignTypedDataSign typed data (EIP-712)
useSwitchChainSwitch networks
useSendCallsAtomic batch operations (EIP-5792)
useWriteContractCall contract functions
useBalanceGet token balances

JAW-Specific Hooks

For JAW-specific features like permissions, import directly from @jaw.id/wagmi:

import {
  useConnect,
  useDisconnect,
  useGrantPermissions,
  usePermissions,
  useRevokePermissions
} from '@jaw.id/wagmi';
HookDescription
useConnectConnect with optional capabilities (SIWE, subnames)
useDisconnectDisconnect and clean up session
useGrantPermissionsGrant spend/call permissions to a spender
usePermissionsQuery current permissions
useRevokePermissionsRevoke a permission

Batch Transactions Example

Send multiple calls atomically using wagmi's useSendCalls:

import { useSendCalls } from 'wagmi';
import { encodeFunctionData } from 'viem';
 
function BatchTransfer() {
  const { sendCalls, isPending } = useSendCalls();
 
  const handleBatchTransfer = () => {
    sendCalls({
      calls: [
        {
          to: USDC_ADDRESS,
          data: encodeFunctionData({
            abi: erc20Abi,
            functionName: 'transfer',
            args: ['0xAlice...', 1000000n],
          }),
        },
        {
          to: USDC_ADDRESS,
          data: encodeFunctionData({
            abi: erc20Abi,
            functionName: 'transfer',
            args: ['0xBob...', 2000000n],
          }),
        },
      ],
    });
  };
 
  return (
    <button onClick={handleBatchTransfer} disabled={isPending}>
      {isPending ? 'Sending...' : 'Send to Alice & Bob'}
    </button>
  );
}

Next Steps

Using the Provider Directly

For non-React applications or advanced use cases, you can use the provider API directly:

import { JAW } from '@jaw.id/core';
 
const jaw = JAW.create({
  apiKey: 'your-api-key',
  appName: 'My DApp',
});
 
// EIP-1193 compatible provider
const accounts = await jaw.provider.request({
  method: 'wallet_connect',
});

See the Provider API Reference for all available methods.