Skip to content
Alchemy Logo

Openfort

@alchemy/wallet-apis (v5.x.x) is currently in beta but is the recommended replacement for @account-kit/wallet-client (v4.x.x). If you run into any issues, please reach out.

Upgrade existing Openfort embedded wallets to Smart Wallets to enable gasless transactions, batching, and more in under 10 minutes. Keep Openfort for authentication, no wallet migration needed. Add battle-tested transaction infrastructure using EIP-7702 to upgrade your wallets to Smart Wallets:

Follow these steps to use Openfort signers with the Wallet Client SDK.

npm install @alchemy/wallet-apis @openfort/react wagmi viem @tanstack/react-query

  • Alchemy API key:
  • Gas sponsorship Policy ID (Gas Manager):
    • Create a gas sponsorship policy in the dashboard and copy its Policy ID
  • Openfort Publishable Key:
  • Openfort Shield Publishable Key:
    • In the Openfort Dashboard, navigate to Shield settings and copy the Shield Publishable Key

The gas sponsorship policy must be linked to the application behind your Alchemy API key for sponsorship to work.

Wrap your app with OpenfortProvider from @openfort/react, along with wagmi and React Query providers:

import { OpenfortProvider, getDefaultConfig } from "@openfort/react";
import { WagmiProvider, createConfig } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { arbitrumSepolia } from "viem/chains";
 
const config = createConfig(
  getDefaultConfig({
    appName: "My App",
    chains: [arbitrumSepolia],
  })
);
 
const queryClient = new QueryClient();
 
export function App() {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <OpenfortProvider
          publishableKey="your-openfort-publishable-key"
          walletConfig={{
            shieldPublishableKey: "your-shield-publishable-key",
          }}
        >
          <YourApp />
        </OpenfortProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}

Use wagmi's useWalletClient hook to get a viem WalletClient from the Openfort embedded wallet:

import { useWalletClient } from "wagmi";
import type { WalletClient } from "viem";
 
const useOpenfortSigner = (): WalletClient | undefined => {
  const { data: walletClient } = useWalletClient();
  return walletClient;
};

Use Openfort's React hooks to manage authentication state and conditionally render your wallet UI:

import { useUser, useUI, useSignOut } from "@openfort/react";
 
function OpenfortWallet() {
  const { isLoading, isAuthenticated } = useUser();
  const { setOpen } = useUI();
  const { signOut } = useSignOut();
  const signer = useOpenfortSigner();
 
  if (isLoading) {
    return <p>Loading...</p>;
  }
 
  if (!isAuthenticated) {
    return <button onClick={() => setOpen(true)}>Login with Openfort</button>;
  }
 
  return (
    <div>
      <button onClick={() => signOut()}>Logout</button>
      {signer ? <SendTransaction signer={signer} /> : <p>Loading signer...</p>}
    </div>
  );
}

Openfort provides a WalletClient signer, which does not support EIP-7702 authorization signing. Use requestAccount to create a smart wallet, then pass the account address to sendCalls. The returned address is stable for a given signer and can be stored — you don't need to call requestAccount before every transaction:

import { useMemo, useCallback } from "react";
import { zeroAddress } from "viem";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
import { arbitrumSepolia } from "viem/chains";
import type { WalletClient } from "viem";
 
function SendTransaction({ signer }: { signer: WalletClient }) {
  const client = useMemo(
    () =>
      createSmartWalletClient({
        signer,
        transport: alchemyWalletTransport({
          apiKey: "YOUR_ALCHEMY_API_KEY",
        }),
        chain: arbitrumSepolia,
        paymaster: {
          policyId: "YOUR_GAS_MANAGER_POLICY_ID",
        },
      }),
    [signer],
  );
 
  const handleSend = useCallback(async () => {
    // Request a smart wallet (required for WalletClient signers)
    const { address } = await client.requestAccount({
      creationHint: { accountType: "sma-b" },
    });
 
    // Send the transaction using the smart wallet address
    const { id } = await client.sendCalls({
      account: address,
      calls: [{ to: zeroAddress, value: BigInt(0), data: "0x" }],
    });
 
    // Wait for the transaction to be confirmed
    const result = await client.waitForCallsStatus({ id });
    console.log(`Transaction hash: ${result.receipts?.[0]?.transactionHash}`);
  }, [client]);
 
  return <button onClick={handleSend}>Send transaction</button>;
}

Was this page helpful?