User ID: {user?.id}
+ +Embedded: {embeddedWallet.address}
+ )} + {externalWallets.map((w) => ( ++ {w.walletClientType}: {w.address} +
+ ))} +Wallet: {wallet.address}
; +} +``` + +## Embedded Wallet Management + +### Sign a Message + +```typescript +import { useWallets } from "@privy-io/react-auth"; + +async function signMessage(wallets: ReturnTypeSolana address: {solanaWallet.address}
; +} +``` + +## Smart Wallet Integration + +### Privy + Safe (Account Abstraction) + +Privy embedded wallets can serve as the signer/owner for a Safe smart account, enabling gas sponsorship and batched transactions. + +```typescript +import { PrivyProvider } from "@privy-io/react-auth"; + +Signer (EOA): {embeddedWallet.address}
+ )} + {smartWallet && ( +Smart Wallet (Safe): {smartWallet.address}
+ )} +Please log in first.
; + } + + if (!embeddedWallet) { + returnNo embedded wallet found. Wait for wallet creation.
; + } + + async function handleSend() { + if (!embeddedWallet) return; + if (!recipient || !amount) return; + + setTxState("switching-chain"); + setError(null); + setTxHash(null); + + try { + await embeddedWallet.switchChain(base.id); + + setTxState("awaiting-signature"); + + const provider = await embeddedWallet.getEthereumProvider(); + const walletClient = createWalletClient({ + chain: base, + transport: custom(provider), + }); + + const publicClient = createPublicClient({ + chain: base, + transport: http(), + }); + + const [account] = await walletClient.getAddresses(); + + const hash = await walletClient.sendTransaction({ + account, + to: recipient as `0x${string}`, + value: parseEther(amount), + }); + + setTxHash(hash); + setTxState("pending"); + + const receipt = await publicClient.waitForTransactionReceipt({ + hash, + }); + + if (receipt.status === "success") { + setTxState("confirmed"); + } else { + setTxState("failed"); + setError("Transaction reverted on-chain."); + } + } catch (err) { + setTxState("failed"); + const message = err instanceof Error ? err.message : "Unknown error"; + + // User rejection -- silently reset + if ( + message.includes("User rejected") || + message.includes("user denied") + ) { + setTxState("idle"); + return; + } + + setError(message); + } + } + + function reset() { + setTxState("idle"); + setTxHash(null); + setError(null); + } + + const explorerUrl = txHash + ? `https://basescan.org/tx/${txHash}` + : null; + + const buttonLabels: RecordFrom: {embeddedWallet.address}
+ Submitted.{" "} + + View on BaseScan + +
+ )} + + {txState === "confirmed" && explorerUrl && ( ++ Confirmed.{" "} + + View on BaseScan + +
+ +{error}
+ +Please log in first.
; + } + + if (!smartWallet) { + return ( +Smart wallet not available.
+ {embeddedWallet && ( +EOA signer ready: {embeddedWallet.address}
+ Ensure smartWallets.enabled: true is set in
+ PrivyProvider config.
+
{smartWallet.address}{embeddedWallet.address}+ The smart wallet address is a Safe contract owned by your embedded + wallet. Transactions are sponsored -- you pay zero gas. +
+ + + + {txHash && explorerUrl && ( ++ Transaction: {" "} + + View on BaseScan + +
+ )} + + {error && ( +{error}
+Sign in with your email or Google account.
+ +Loading wallet...
+ ) : embeddedWallet ? ( +{embeddedWallet.address}No embedded wallet found.
+ )} +Connected: ${address.slice(0, 6)}...${address.slice(-4)}
+User: @${context.user.username} (FID: ${context.user.fid})
+ + +