Upgrade existing Turnkey wallets to Smart Wallets to enable gasless transactions, batching, and more in under 10 minutes. Keep Turnkey for key management, no wallet migration needed. Add battle-tested transaction infrastructure using EIP-7702 to upgrade EOAs to Smart Wallets:
- #1 gas abstraction infrastructure on the market
- 370M+ sponsored transactions
- 99.9% SLAs
- Trusted by Worldcoin, JP Morgan, Gensyn, and more
Don't have a wallet set up yet? Start with the Smart Wallet Quickstart to create one in minutes.
Use Turnkey's @turnkey/sdk-server package with Smart Wallets infrastructure in a server environment.
npm install @turnkey/sdk-server @turnkey/viem @account-kit/wallet-client @account-kit/infra @aa-sdk/core viem
# or
yarn add @turnkey/sdk-server @turnkey/viem @account-kit/wallet-client @account-kit/infra @aa-sdk/core viem
# or
pnpm add @turnkey/sdk-server @turnkey/viem @account-kit/wallet-client @account-kit/infra @aa-sdk/core viem- Alchemy API Key:
- Go to the dashboard
- Create or select an app and copy the API key
- Gas sponsorship Policy ID:
- Create a gas sponsorship policy in the dashboard and copy its Policy ID
- Turnkey Credentials:
- Go to the Turnkey Dashboard
- Create or select an organization and copy the Organization ID
- Create an API key pair and copy the API Public Key and Private Key
- Create or import a private key and copy the Private Key ID (UUID)
- Note the Ethereum address associated with that private key
Both the Smart Wallets configuration and the gas sponsorship policy must be linked to the application behind your API key for sponsorship to work.
Create a helper function that converts a Turnkey wallet into an Alchemy Smart Wallet client:
import { WalletClientSigner } from "@aa-sdk/core";
import { alchemy, baseSepolia } from "@account-kit/infra";
import { createSmartWalletClient } from "@account-kit/wallet-client";
import { Turnkey } from "@turnkey/sdk-server";
import { createAccount } from "@turnkey/viem";
import { createWalletClient } from "viem";
const ALCHEMY_API_KEY = "your-alchemy-api-key";
const ALCHEMY_GAS_POLICY_ID = "your-gas-policy-id";
const TURNKEY_ORGANIZATION_ID = "your-turnkey-org-id";
const TURNKEY_API_PRIVATE_KEY = "your-turnkey-api-private-key";
const TURNKEY_API_PUBLIC_KEY = "your-turnkey-api-public-key";
async function createTurnkeySmartWalletClient({
privateKeyId,
walletAddress,
}) {
// Initialize Turnkey SDK
const turnkey = new Turnkey({
defaultOrganizationId: TURNKEY_ORGANIZATION_ID,
apiBaseUrl: "https://api.turnkey.com",
apiPrivateKey: TURNKEY_API_PRIVATE_KEY,
apiPublicKey: TURNKEY_API_PUBLIC_KEY,
});
// Create a viem account using Turnkey's signing capabilities
const baseTurnkeyAccount = await createAccount({
client: turnkey.apiClient(),
organizationId: TURNKEY_ORGANIZATION_ID,
signWith: privateKeyId,
ethereumAddress: walletAddress,
});
// Wrap the account to fix the double 0x prefix bug in @turnkey/viem 0.14.8
const turnkeyAccount = {
...baseTurnkeyAccount,
signAuthorization: async (authorization) => {
if (!baseTurnkeyAccount.signAuthorization) {
throw new Error("signAuthorization not available on Turnkey account");
}
const result = await baseTurnkeyAccount.signAuthorization(authorization);
// Strip the extra 0x prefix if present
return {
...result,
r: result.r.replace(/^0x0x/, "0x"),
s: result.s.replace(/^0x0x/, "0x"),
};
},
};
// Create wallet client with Turnkey account
const walletClient = createWalletClient({
account: turnkeyAccount,
chain: baseSepolia,
transport: alchemy({ apiKey: ALCHEMY_API_KEY }),
});
// Create signer from wallet client
const signer = new WalletClientSigner(walletClient, "turnkey-custom");
// Create and return the Smart Wallet client
return createSmartWalletClient({
chain: baseSepolia,
transport: alchemy({ apiKey: ALCHEMY_API_KEY }),
signer,
policyId: ALCHEMY_GAS_POLICY_ID,
});
}Send gasless transactions using EIP-7702 to upgrade the Turnkey wallet to a smart wallet:
const TURNKEY_PRIVATE_KEY_ID = "your-private-key-uuid";
const TURNKEY_WALLET_ADDRESS = "0x...";
async function sendTransaction() {
console.log("Wallet address:", TURNKEY_WALLET_ADDRESS);
// Create Smart Wallet client from Turnkey wallet
const client = await createTurnkeySmartWalletClient({
privateKeyId: TURNKEY_PRIVATE_KEY_ID,
walletAddress: TURNKEY_WALLET_ADDRESS,
});
// Send a gasless transaction with EIP-7702
const result = await client.sendCalls({
from: TURNKEY_WALLET_ADDRESS,
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: "0x0",
data: "0x",
},
],
capabilities: {
eip7702Auth: true,
paymasterService: {
policyId: ALCHEMY_GAS_POLICY_ID,
},
},
});
console.log("Transaction sent:", result.id);
}Wait for the transaction to be confirmed onchain:
async function sendAndWaitForTransaction() {
const client = await createTurnkeySmartWalletClient({
privateKeyId: TURNKEY_PRIVATE_KEY_ID,
walletAddress: TURNKEY_WALLET_ADDRESS,
});
const result = await client.sendCalls({
from: TURNKEY_WALLET_ADDRESS,
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: "0x0",
data: "0x",
},
],
capabilities: {
eip7702Auth: true,
paymasterService: {
policyId: ALCHEMY_GAS_POLICY_ID,
},
},
});
console.log("Waiting for confirmation...");
// Wait for the transaction to be confirmed
const txStatus = await client.waitForCallsStatus({
id: result.id,
timeout: 60_000, // 60 seconds
});
const txnHash = txStatus.receipts?.[0]?.transactionHash;
console.log("Transaction confirmed!");
console.log("Transaction hash:", txnHash);
}Send multiple transactions in a single batch:
const result = await client.sendCalls({
from: TURNKEY_WALLET_ADDRESS,
calls: [
{ to: "0x...", data: "0x...", value: "0x0" },
{ to: "0x...", data: "0x...", value: "0x0" },
{ to: "0x...", data: "0x...", value: "0x0" },
],
capabilities: {
eip7702Auth: true,
paymasterService: {
policyId: ALCHEMY_GAS_POLICY_ID,
},
},
});- EIP-7702: Upgrades the Turnkey wallet to a smart wallet at transaction time without migration
- Gas Sponsorship: Use
paymasterServicewith your policy ID for gasless transactions - Server-Side: This example uses Turnkey's
@turnkey/sdk-serverpackage which is designed for server environments. However, the@account-kitpackages (@account-kit/wallet-client,@account-kit/infra, etc.) can be used in any JavaScript environment including browsers, React Native, and Node.js