# Solana signers

> Use Solana signers with Wallet APIs

> For the complete documentation index, see [llms.txt](/docs/llms.txt).

Solana Wallet APIs require an Ed25519 signer that can sign serialized Solana transactions. The `signer` parameter of `createSmartWalletClient` accepts a `SolanaSigner` when you use a Solana chain ID such as `"solana:devnet"` or `"solana:mainnet"`.

```ts
type SolanaSigner = {
  address: string;
  signTransaction(input: {
    transaction: Uint8Array;
  }): Promise<{ signedTransaction: Uint8Array }>;
};
```

Most apps do not need to implement this interface directly. Some providers already return this shape. For the rest, use an adapter from `@alchemy/wallet-apis/solana`.

## Install

<CodeGroup>
```shell npm
npm install @alchemy/wallet-apis
```

```shell pnpm
pnpm add @alchemy/wallet-apis
```

```shell yarn
yarn add @alchemy/wallet-apis
```

```shell bun
bun add @alchemy/wallet-apis
```
</CodeGroup>

Install the optional package that matches your signer source:

* `@solana/wallet-adapter-react`: `@solana/wallet-adapter-react @solana/web3.js`
* Injected providers such as Phantom: `@solana/web3.js`
* `@solana/kit` signers: `@solana/kit`
* Wallet Standard discovery: `@wallet-standard/app`

## Choose a signer source

| What you have | What to use |
| --- | --- |
| Privy Solana wallet from `@privy-io/react-auth/solana` | No adapter — see the [Privy guide](/docs/wallets/third-party/signers/privy#send-solana-transactions) |
| `useWallet()` from `@solana/wallet-adapter-react` | `fromWalletAdapter` |
| Injected provider such as `window.phantom.solana` | `fromWalletAdapter` |
| `@solana/kit` `KeyPairSigner` or `TransactionPartialSigner` | `fromKitSigner` |
| Raw Ed25519 keypair or key management service | `fromKeypair` |
| Low-level Wallet Standard wallet | `fromWalletStandard` |

## `@solana/wallet-adapter-react`

Use `fromWalletAdapter` for wallets returned by `useWallet()`. This adapter handles the `Uint8Array` to `VersionedTransaction` conversion required by the wallet adapter API.

```tsx title="wallet-adapter-signer.tsx"
import {
  alchemyWalletTransport,
  createSmartWalletClient,
} from "@alchemy/wallet-apis";
import { fromWalletAdapter } from "@alchemy/wallet-apis/solana";
import { useWallet } from "@solana/wallet-adapter-react";
import { useMemo } from "react";

function useWalletAdapterSolanaClient() {
  const wallet = useWallet();

  return useMemo(() => {
    if (!wallet.publicKey || !wallet.signTransaction) return undefined;

    return createSmartWalletClient({
      signer: fromWalletAdapter({
        publicKey: wallet.publicKey,
        signTransaction: wallet.signTransaction,
      }),
      transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
      chain: "solana:devnet",
      paymaster: { policyId: "YOUR_SOLANA_POLICY_ID" },
    });
  }, [wallet.publicKey, wallet.signTransaction]);
}
```

## Phantom injected provider

Use the same `fromWalletAdapter` adapter for injected providers that expose `publicKey` and `signTransaction(VersionedTransaction)`, such as `window.phantom.solana`.

```ts title="phantom-signer.ts"
import {
  alchemyWalletTransport,
  createSmartWalletClient,
} from "@alchemy/wallet-apis";
import { fromWalletAdapter } from "@alchemy/wallet-apis/solana";
import type { VersionedTransaction } from "@solana/web3.js";

interface PhantomSolanaProvider {
  publicKey?: { toBase58(): string };
  connect(): Promise<{ publicKey: { toBase58(): string } }>;
  signTransaction<T extends VersionedTransaction>(transaction: T): Promise<T>;
}

declare global {
  interface Window {
    phantom?: { solana?: PhantomSolanaProvider };
  }
}

const phantom = window.phantom?.solana;
if (!phantom) {
  throw new Error("Install Phantom to use the injected Solana provider");
}

const { publicKey } = await phantom.connect();

const client = createSmartWalletClient({
  signer: fromWalletAdapter({
    publicKey,
    signTransaction: (transaction) => phantom.signTransaction(transaction),
  }),
  transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
  chain: "solana:devnet",
  paymaster: { policyId: "YOUR_SOLANA_POLICY_ID" },
});
```

## `@solana/kit`

Use `fromKitSigner` for `@solana/kit` signers that implement `signTransactions`, including `KeyPairSigner` and `TransactionPartialSigner`.

```ts title="kit-signer.ts"
import {
  alchemyWalletTransport,
  createSmartWalletClient,
} from "@alchemy/wallet-apis";
import { fromKitSigner } from "@alchemy/wallet-apis/solana";
import { generateKeyPairSigner } from "@solana/kit";

const kitSigner = await generateKeyPairSigner();

const client = createSmartWalletClient({
  signer: fromKitSigner(kitSigner),
  transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
  chain: "solana:devnet",
  paymaster: { policyId: "YOUR_SOLANA_POLICY_ID" },
});
```

## Raw Ed25519 keypair

Use `fromKeypair` when your signer exposes an `address` and a `signMessage(bytes)` method that returns a 64-byte Ed25519 signature. This is the right adapter for a bare Ed25519 keypair or a key management service.

```ts title="keypair-signer.ts"
import {
  alchemyWalletTransport,
  createSmartWalletClient,
} from "@alchemy/wallet-apis";
import { fromKeypair } from "@alchemy/wallet-apis/solana";

interface Ed25519Keypair {
  address: string;
  privateKey: CryptoKey;
}

async function loadEd25519Keypair(): Promise<Ed25519Keypair> {
  // Load this from your app's key storage or KMS.
  throw new Error("Implement loadEd25519Keypair for your app");
}

const { address, privateKey } = await loadEd25519Keypair();

const client = createSmartWalletClient({
  signer: fromKeypair({
    address,
    async signMessage(message) {
      const messageBytes = Uint8Array.from(message);
      return new Uint8Array(
        await crypto.subtle.sign("Ed25519", privateKey, messageBytes),
      );
    },
  }),
  transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
  chain: "solana:devnet",
  paymaster: { policyId: "YOUR_SOLANA_POLICY_ID" },
});
```

Your `signMessage` implementation must return a valid 64-byte Ed25519 signature for the message bytes. Do not return placeholder bytes; Wallet APIs rejects missing or all-zero signatures.

## Wallet Standard

Use `fromWalletStandard` when you are working directly with the low-level Wallet Standard API. Most app developers should use Privy or `@solana/wallet-adapter-react` instead.

```ts title="wallet-standard-signer.ts"
import {
  alchemyWalletTransport,
  createSmartWalletClient,
} from "@alchemy/wallet-apis";
import {
  fromWalletStandard,
  type WalletStandardAccount,
  type WalletStandardWallet,
} from "@alchemy/wallet-apis/solana";
import { getWallets } from "@wallet-standard/app";

type ConnectableWalletStandardWallet = Omit<
  WalletStandardWallet,
  "features"
> & {
  features: {
    readonly [name: string]: unknown;
    readonly "standard:connect": {
      connect(): Promise<{ accounts: readonly WalletStandardAccount[] }>;
    };
    readonly "solana:signTransaction": unknown;
  };
};

function isSolanaStandardWallet(
  wallet: WalletStandardWallet,
): wallet is ConnectableWalletStandardWallet {
  return (
    "standard:connect" in wallet.features &&
    "solana:signTransaction" in wallet.features
  );
}

const wallets: readonly WalletStandardWallet[] = getWallets().get();
const wallet = wallets.find(isSolanaStandardWallet);
if (!wallet) {
  throw new Error("Connect a wallet that supports solana:signTransaction");
}

const { accounts } = await wallet.features["standard:connect"].connect();
const account = accounts[0];
if (!account) {
  throw new Error("No Solana account returned by the wallet");
}

const client = createSmartWalletClient({
  signer: fromWalletStandard(wallet, account),
  transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
  chain: "solana:devnet",
  paymaster: { policyId: "YOUR_SOLANA_POLICY_ID" },
});
```

## Next steps

Use your Solana signer to:

* [Send Solana transactions](/docs/wallets/transactions/send-transactions#solana-transactions)
* [Sponsor Solana transaction fees](/docs/wallets/transactions/sponsor-gas/solana)