@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 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
Follow these steps to use Turnkey signers with the Wallet Client SDK.
npm install @alchemy/wallet-apis @turnkey/react-wallet-kit @turnkey/viem viem- 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
- Turnkey Organization ID & Auth Proxy Config ID:
- Go to the Turnkey Dashboard
- Create or select an organization and copy the Organization ID
- Set up an Auth Proxy and copy the Config ID
The gas sponsorship policy must be linked to the application behind your Alchemy API key for sponsorship to work.
Wrap your app with TurnkeyProvider from @turnkey/react-wallet-kit:
import { TurnkeyProvider } from "@turnkey/react-wallet-kit";
import "@turnkey/react-wallet-kit/styles.css";
export function App() {
return (
<TurnkeyProvider
config={{
organizationId: "YOUR_TURNKEY_ORGANIZATION_ID",
authProxyConfigId: "YOUR_TURNKEY_AUTH_PROXY_CONFIG_ID",
auth: {
createSuborgParams: {
emailOtpAuth: {
customWallet: {
walletName: "Default Wallet",
walletAccounts: [
{
curve: "CURVE_SECP256K1",
pathFormat: "PATH_FORMAT_BIP32",
path: "m/44'/60'/0'/0/0",
addressFormat: "ADDRESS_FORMAT_ETHEREUM",
},
],
},
},
},
},
}}
>
<YourApp />
</TurnkeyProvider>
);
}Use useTurnkey from @turnkey/react-wallet-kit and createAccount from @turnkey/viem to convert a Turnkey wallet into a viem LocalAccount:
import { useTurnkey } from "@turnkey/react-wallet-kit";
import { createAccount } from "@turnkey/viem";
import { useEffect, useState } from "react";
import type { LocalAccount } from "viem";
const useTurnkeySigner = () => {
const { httpClient, wallets, session } = useTurnkey();
const [signer, setSigner] = useState<LocalAccount>();
// Use the first Ethereum account from the first wallet
const account = wallets[0]?.accounts?.find(
(a) => a.addressFormat === "ADDRESS_FORMAT_ETHEREUM",
);
useEffect(() => {
if (!httpClient || !account || !session || signer) return;
createAccount({
client: httpClient,
organizationId: session.organizationId,
signWith: account.address,
}).then(setSigner);
}, [httpClient, account, session, signer]);
return signer;
};Use useTurnkey to manage authentication state and conditionally render your wallet UI once the user is logged in:
import { useTurnkey, ClientState, AuthState } from "@turnkey/react-wallet-kit";
function TurnkeyWallet() {
const { clientState, authState, handleLogin, logout } = useTurnkey();
const signer = useTurnkeySigner();
if (clientState !== ClientState.Ready) return <p>Loading...</p>;
if (authState !== AuthState.Authenticated) {
return <button onClick={() => handleLogin()}>Login with Turnkey</button>;
}
return (
<div>
<button onClick={() => logout()}>Logout</button>
{signer ? <SendTransaction signer={signer} /> : <p>Loading signer...</p>}
</div>
);
}Pass the Turnkey signer to createSmartWalletClient and use it to send transactions:
import { useMemo, useCallback } from "react";
import { zeroAddress } from "viem";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
import { arbitrumSepolia } from "viem/chains";
function SendTransaction({ signer }: { signer: LocalAccount }) {
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 () => {
// Send the transaction
const { id } = await client.sendCalls({
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>;
}- The client defaults to EIP-7702, which delegates the Turnkey wallet to a smart account at send time. No deployment or wallet migration needed. See the EIP-7702 guide for non-7702 mode.
- See the Sponsor gas guide for more on gas sponsorship configuration.