Skip to content

Wallet actions

Once your app is wrapped in OpenfortProvider and the user has an embedded wallet, you can send transactions through the smart account.

Choose your preferred approach:

  • Using wagmi hooks (recommended) - Use wagmi's built-in hooks for better state management and type safety
  • Switch to use provider directly - Use the wallet client directly without additional dependencies

This page shows the wagmi approach. Use the helper below as a minimal starting point for single-call transfers.

Send an ERC-20 transfer

useSendUsdc.ts
import { useCallback } from 'react';
import { parseUnits } from 'viem';
import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
 
const usdcAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; // replace with your token
const usdcAbi = [{
  name: 'transfer',
  type: 'function',
  stateMutability: 'nonpayable',
  inputs: [
    { name: 'to', type: 'address' },
    { name: 'amount', type: 'uint256' },
  ],
  outputs: [{ name: 'success', type: 'bool' }],
}] as const;
 
export function useSendUsdc() {
  const { address } = useAccount();
  const { writeContract, data: hash, isPending, error } = useWriteContract();
  const { isLoading: isConfirming, isSuccess: isConfirmed } =
    useWaitForTransactionReceipt({ hash });
 
  const sendUsdc = useCallback(async (to: `0x${string}`, amount: string) => {
    if (!address) throw new Error('Wallet not connected');
 
    const units = parseUnits(amount, 6);
 
    writeContract({
      address: usdcAddress,
      abi: usdcAbi,
      functionName: 'transfer',
      args: [to, units],
    });
  }, [address, writeContract]);
 
  return {
    sendUsdc,
    hash,
    isPending,
    isConfirming,
    isConfirmed,
    error,
  };
}

Use the hook in your component like this:

TransferButton.tsx
import { useSendUsdc } from './useSendUsdc';
 
export function TransferButton() {
  const { sendUsdc, isPending, isConfirming, isConfirmed, error } = useSendUsdc();
 
  const handleTransfer = () => {
    sendUsdc('0x742d35Cc6634C0532925a3b8D24ec3Ad3E5b6ca', '10.5');
  };
 
  return (
    <div>
      <button
        onClick={handleTransfer}
        disabled={isPending || isConfirming}
      >
        {isPending ? 'Preparing...' : isConfirming ? 'Confirming...' : 'Send USDC'}
      </button>
      {isConfirmed && <p>Transfer confirmed!</p>}
      {error && <p>Error: {error.message}</p>}
    </div>
  );
}

For multi-step flows (e.g. ERC-20 approvals before deposits) follow the composition in the recipes mentioned above.

Sponsor gas from the dashboard

Keep the experience gasless—or recover costs in ERC-20 tokens—by attaching a gas policy created in the Openfort dashboard.

  1. Navigate to Dashboard → Sponsor policies, create a policy, and copy the generated pol_... identifier.
  2. Configure match rules (chain, method, contract) so only the intended wallet_sendCalls bundles qualify.
  3. Choose Pay gas for user to sponsor execution or Charge dynamic/fixed amount of ERC-20 to charge users before the transaction is sent.

Wire the policy into ethereumProviderPolicyId inside walletConfig so the SDK appends it automatically.

Providers.tsx
const config = createConfig(
  getDefaultConfig({
    appName: "Openfort demo",
    chains: [polygonAmoy],
    ssr: true,
  })
);
 
export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <OpenfortProvider
          publishableKey={"YOUR_OPENFORT_PUBLISHABLE_KEY"}
          walletConfig={{
            shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
            createEncryptedSessionEndpoint: "YOUR_BACKEND_ENDPOINT",
            ethereumProviderPolicyId: {
              [polygonAmoy.id]: 'pol_...',
            },
          }}
        >
          {children}
        </OpenfortProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}

Dashboard edits apply immediately—matching wallet_sendCalls bundles will respect the latest sponsorship rules without redeploying your frontend.

More examples