Learn how to create and manage Sub Accounts using Wagmi hooks and Base Account provider methods.

Prerequisites

Make sure you have:

Overview

Sub Accounts allow you to create child accounts that can spend from the parent account’s balance using Spend Permissions. This reduces the need for frequent user signatures and improves the user experience.

Creating Sub Accounts

Use the Base Account provider to create Sub Accounts:
import { useAccount, useConnector } from 'wagmi'
import { useState } from 'react'

export function CreateSubAccount() {
  const { address, isConnected } = useAccount()
  const connector = useConnector()
  const [subAccount, setSubAccount] = useState<string | null>(null)
  const [isCreating, setIsCreating] = useState(false)

  const createSubAccount = async () => {
    if (!connector || !isConnected) return

    setIsCreating(true)
    try {
      const provider = connector.provider
      
      // Create a new Sub Account
      const result = await provider?.request({
        method: 'wallet_addSubAccount',
        params: [{
          version: '1.0',
          chainId: `0x${Number(8453).toString(16)}`, // Base mainnet
          from: address,
        }]
      })

      if (result?.subAccount) {
        setSubAccount(result.subAccount)
        console.log('Sub Account created:', result.subAccount)
      }
    } catch (error) {
      console.error('Failed to create Sub Account:', error)
    } finally {
      setIsCreating(false)
    }
  }

  return (
    <div className="space-y-4">
      <h3 className="text-lg font-semibold">Sub Account Management</h3>
      
      {!subAccount ? (
        <button
          onClick={createSubAccount}
          disabled={!isConnected || isCreating}
          className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
        >
          {isCreating ? 'Creating Sub Account...' : 'Create Sub Account'}
        </button>
      ) : (
        <div className="p-4 bg-green-50 border border-green-200 rounded">
          <p className="text-sm text-green-700">
            Sub Account created: <span className="font-mono">{subAccount}</span>
          </p>
        </div>
      )}
    </div>
  )
}

Listing Sub Accounts

Retrieve existing Sub Accounts for the connected wallet:
import { useAccount, useConnector } from 'wagmi'
import { useState, useEffect } from 'react'

export function SubAccountsList() {
  const { address, isConnected } = useAccount()
  const connector = useConnector()
  const [subAccounts, setSubAccounts] = useState<string[]>([])
  const [isLoading, setIsLoading] = useState(false)

  const fetchSubAccounts = async () => {
    if (!connector || !isConnected) return

    setIsLoading(true)
    try {
      const provider = connector.provider
      
      const result = await provider?.request({
        method: 'wallet_getSubAccounts',
        params: [{
          version: '1.0',
          chainId: `0x${Number(8453).toString(16)}`,
          from: address,
        }]
      })

      if (result?.subAccounts) {
        setSubAccounts(result.subAccounts)
      }
    } catch (error) {
      console.error('Failed to fetch Sub Accounts:', error)
    } finally {
      setIsLoading(false)
    }
  }

  useEffect(() => {
    if (isConnected) {
      fetchSubAccounts()
    }
  }, [isConnected, address])

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <h3 className="text-lg font-semibold">Your Sub Accounts</h3>
        <button
          onClick={fetchSubAccounts}
          disabled={isLoading}
          className="px-3 py-1 bg-gray-500 text-white rounded text-sm"
        >
          {isLoading ? 'Loading...' : 'Refresh'}
        </button>
      </div>

      {subAccounts.length === 0 ? (
        <p className="text-gray-500">No Sub Accounts found</p>
      ) : (
        <div className="space-y-2">
          {subAccounts.map((subAccount, index) => (
            <div
              key={subAccount}
              className="p-3 bg-blue-50 border border-blue-200 rounded"
            >
              <div className="flex items-center justify-between">
                <span className="font-mono text-sm">{subAccount}</span>
                <span className="text-xs text-blue-600">Sub Account #{index + 1}</span>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  )
}

Using Sub Accounts for Transactions

Once you have Sub Accounts, you can use them to perform transactions:
import { useAccount, useConnector, useWriteContract } from 'wagmi'
import { useState } from 'react'

export function SubAccountTransactions() {
  const { address } = useAccount()
  const connector = useConnector()
  const [selectedSubAccount, setSelectedSubAccount] = useState('')
  const [isLoading, setIsLoading] = useState(false)

  const sendTransactionFromSubAccount = async () => {
    if (!connector || !selectedSubAccount) return

    setIsLoading(true)
    try {
      const provider = connector.provider
      
      // Send transaction using Sub Account
      const result = await provider?.request({
        method: 'wallet_sendCalls',
        params: [{
          version: '1.0',
          chainId: `0x${Number(8453).toString(16)}`,
          from: selectedSubAccount, // Use Sub Account as sender
          calls: [{
            to: '0x...' as `0x${string}`,
            value: '0x0',
            data: '0x' as `0x${string}`
          }]
        }]
      })

      console.log('Transaction sent from Sub Account:', result)
    } catch (error) {
      console.error('Sub Account transaction failed:', error)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div className="space-y-4">
      <h3 className="text-lg font-semibold">Sub Account Transactions</h3>
      
      <div>
        <label className="block mb-2">Select Sub Account:</label>
        <input
          type="text"
          value={selectedSubAccount}
          onChange={(e) => setSelectedSubAccount(e.target.value)}
          className="w-full p-2 border rounded"
          placeholder="0x... (Sub Account address)"
        />
      </div>

      <button
        onClick={sendTransactionFromSubAccount}
        disabled={!selectedSubAccount || isLoading}
        className="px-4 py-2 bg-green-500 text-white rounded disabled:opacity-50"
      >
        {isLoading ? 'Sending...' : 'Send from Sub Account'}
      </button>
    </div>
  )
}

Complete Example

Here’s a complete component that combines all Sub Account functionality:
import { useAccount, useConnector } from 'wagmi'
import { useState, useEffect } from 'react'

export function SubAccountManager() {
  const { address, isConnected } = useAccount()
  const connector = useConnector()
  const [subAccounts, setSubAccounts] = useState<string[]>([])
  const [isCreating, setIsCreating] = useState(false)
  const [isLoading, setIsLoading] = useState(false)

  const fetchSubAccounts = async () => {
    if (!connector || !isConnected) return

    setIsLoading(true)
    try {
      const provider = connector.provider
      const result = await provider?.request({
        method: 'wallet_getSubAccounts',
        params: [{
          version: '1.0',
          chainId: `0x${Number(8453).toString(16)}`,
          from: address,
        }]
      })

      if (result?.subAccounts) {
        setSubAccounts(result.subAccounts)
      }
    } catch (error) {
      console.error('Failed to fetch Sub Accounts:', error)
    } finally {
      setIsLoading(false)
    }
  }

  const createSubAccount = async () => {
    if (!connector || !isConnected) return

    setIsCreating(true)
    try {
      const provider = connector.provider
      const result = await provider?.request({
        method: 'wallet_addSubAccount',
        params: [{
          version: '1.0',
          chainId: `0x${Number(8453).toString(16)}`,
          from: address,
        }]
      })

      if (result?.subAccount) {
        // Refresh the list
        await fetchSubAccounts()
      }
    } catch (error) {
      console.error('Failed to create Sub Account:', error)
    } finally {
      setIsCreating(false)
    }
  }

  useEffect(() => {
    if (isConnected) {
      fetchSubAccounts()
    }
  }, [isConnected])

  if (!isConnected) {
    return <p>Please connect your wallet first</p>
  }

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <h2 className="text-xl font-bold">Sub Account Manager</h2>
        <button
          onClick={createSubAccount}
          disabled={isCreating}
          className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
        >
          {isCreating ? 'Creating...' : 'Create Sub Account'}
        </button>
      </div>

      <div className="space-y-4">
        <div className="flex items-center justify-between">
          <h3 className="text-lg font-semibold">Your Sub Accounts ({subAccounts.length})</h3>
          <button
            onClick={fetchSubAccounts}
            disabled={isLoading}
            className="px-3 py-1 bg-gray-500 text-white rounded text-sm"
          >
            {isLoading ? 'Loading...' : 'Refresh'}
          </button>
        </div>

        {subAccounts.length === 0 ? (
          <p className="text-gray-500">No Sub Accounts found. Create one to get started!</p>
        ) : (
          <div className="grid gap-3">
            {subAccounts.map((subAccount, index) => (
              <div
                key={subAccount}
                className="p-4 bg-blue-50 border border-blue-200 rounded-lg"
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="font-mono text-sm">{subAccount}</p>
                    <p className="text-xs text-blue-600">Sub Account #{index + 1}</p>
                  </div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  )
}

Learn More