Upgrade existing Privy wallets to Smart Wallets to enable gasless transactions (EVM & Solana), batching, token swaps, and more in under 10 minutes. Keep Privy for authentication, no wallet migration needed. Add our battle-tested transaction infrastructure using EIP-7702 to upgrade your wallets to Smart Wallets:
- #1 gas abstraction infrastructure on the market
- 370M+ sponsored transactions
- 99.9% SLAs
- Trusted by Worldcoin, JP Morgan, Gensyn, and more
- Solana gas sponsorship support
Don't have social login or a wallet set up yet? Start with the Smart Wallet Quickstart to create one in minutes.
Follow these steps to integrate Privy with Smart Wallets.
npm install @account-kit/privy-integration
# or
yarn add @account-kit/privy-integration
# or
pnpm add @account-kit/privy-integrationSolana Support (Optional): To use useAlchemySolanaTransaction, install @solana/web3.js and import from @account-kit/privy-integration/solana. This dependency is optional—skip it if you only need EVM features.
- Alchemy API Key:
- Go to the Alchemy Dashboard
- Create or select an app and copy the API key
- Gas sponsorship Policy ID (Gas Manager):
- Create a gas sponsorship policy in the dashboard and copy its Policy ID
- Privy App ID:
- Go to the Privy Dashboard
- Create or select an app and copy the App ID
Both the Smart Wallets configuration and the gas sponsorship policy must be linked to the application behind your Alchemy API key for sponsorship to work.
import { PrivyProvider } from "@privy-io/react-auth";
import { AlchemyProvider } from "@account-kit/privy-integration";
function App() {
return (
<PrivyProvider appId="your-privy-app-id" config={{}}>
<AlchemyProvider apiKey="your-alchemy-api-key" policyId="your-gas-policy-id">
<YourApp />
</AlchemyProvider>
</PrivyProvider>
);
}Props for AlchemyProvider:
apiKey|jwt|rpcUrl(pick a valid transport config)policyId(optional) for EVM gas sponsorshipsolanaPolicyId(optional) for Solana gas sponsorshipsolanaRpcUrl(optional) for Solana RPC URL (separate from EVM)disableSponsorship(optional) to opt-out per defaultaccountAuthMode(optional) -'eip7702'(default, recommended) or'owner'for a traditional smart accountwalletAddress(optional) - specify which wallet address to use if user has multiple wallets (defaults to first wallet)
import { useAlchemySendTransaction } from "@account-kit/privy-integration";
function SendButtons() {
const { sendTransaction, isLoading } = useAlchemySendTransaction();
const single = async () =>
await sendTransaction({ to: "0x...", data: "0x...", value: "0x0" });
const batch = async () =>
await sendTransaction([
{ to: "0x...", data: "0x..." },
{ to: "0x...", data: "0x..." },
]);
return (
<>
<button onClick={single} disabled={isLoading}>Send</button>
<button onClick={batch} disabled={isLoading}>Send Batch</button>
</>
);
}Control sponsorship per call:
await sendTransaction({ to: "0x...", data: "0x..." });
await sendTransaction({ to: "0x...", data: "0x..." }, { disableSponsorship: true });import { useAlchemyPrepareSwap, useAlchemySubmitSwap } from "@account-kit/privy-integration";
function SwapButton() {
const { prepareSwap } = useAlchemyPrepareSwap();
const { submitSwap, isLoading } = useAlchemySubmitSwap();
const handleSwap = async () => {
const prepared = await prepareSwap({
fromToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum mainnet
fromAmount: "0xde0b6b3a7640000",
});
await submitSwap(prepared);
};
return <button onClick={handleSwap} disabled={isLoading}>Swap</button>;
}import { useAlchemySolanaTransaction } from "@account-kit/privy-integration/solana";
function SolanaButton() {
const { sendTransactionAsync, isPending } = useAlchemySolanaTransaction({
rpcUrl: "https://solana-mainnet.g.alchemy.com/v2/your-api-key",
policyId: "your-solana-policy-id", // optional
});
const handleTransfer = async () => {
const result = await sendTransactionAsync({
transfer: {
amount: 1_000_000_000, // 1 SOL in lamports
toAddress: "recipient-base58-address",
},
});
console.log("Transaction hash:", result.hash);
};
return <button onClick={handleTransfer} disabled={isPending}>Send SOL</button>;
}import { useAlchemyClient } from "@account-kit/privy-integration";
function Advanced() {
const { getClient } = useAlchemyClient();
const doOp = async () => {
const { client, account } = await getClient();
await client.sendCalls({
from: account.address,
calls: [{ to: "0x...", data: "0x" }],
capabilities: { eip7702Auth: true, paymasterService: { policyId: "your-policy-id" } },
});
};
return <button onClick={doOp}>Advanced Op</button>;
}The integration supports two modes via accountAuthMode:
'eip7702'(default, recommended): Uses EIP-7702 to delegate the Privy wallet to a smart account. No deployment needed, funds stay at the wallet address.'owner': Uses a traditional smart account with Privy wallet as owner. The smart account has a separate address. Use for environments without EIP-7702 support.
// Default (EIP-7702) - recommended
<AlchemyProvider apiKey="...">
<YourApp />
</AlchemyProvider>
// Traditional smart account mode
<AlchemyProvider apiKey="..." accountAuthMode="owner">
<YourApp />
</AlchemyProvider>Getting the Smart Account Address (owner mode):
When using owner mode, access the smart account address (different from the Privy signer address):
import { useAlchemyClient } from "@account-kit/privy-integration";
function MyComponent() {
const { getClient } = useAlchemyClient();
const getAddress = async () => {
const { account } = await getClient();
console.log("Smart account:", account.address);
// Different from Privy signer address in owner mode
};
}- EVM: EIP-7702 (default) delegates your wallet to a smart account at send time. Alternatively, use
accountAuthMode="owner"for a traditional smart account. - Solana: Gas sponsorship via Alchemy's fee payer service for Privy's embedded Solana wallets.
- The hooks API mirrors Privy's transaction hooks for easy migration.