TypeScript

Upgrade von 1.x? Siehe den 2.0-Migrationsleitfaden.

Installation

Installieren Sie das Umbrella-Paket oder einzelne Signer nach Bedarf:

# Umbrella package (includes all signers)
pnpm add @solana/keychain
# Or install individual packages
pnpm add @solana/keychain-core # Core interfaces (required for custom signers)
pnpm add @solana/keychain-memory # Local keypair signer
pnpm add @solana/keychain-vault # HashiCorp Vault
pnpm add @solana/keychain-aws-kms # AWS KMS
pnpm add @solana/keychain-gcp-kms # GCP KMS
pnpm add @solana/keychain-privy # Privy
pnpm add @solana/keychain-turnkey # Turnkey
pnpm add @solana/keychain-fireblocks # Fireblocks
pnpm add @solana/keychain-cdp # Coinbase Developer Platform
pnpm add @solana/keychain-crossmint # Crossmint
pnpm add @solana/keychain-dfns # Dfns
pnpm add @solana/keychain-openfort # Openfort
pnpm add @solana/keychain-para # Para
pnpm add @solana/keychain-utila # Utila
pnpm add @solana/keychain-fordefi # Fordefi
# Kit client plugins (keychainSigner / keychainPayer / keychainIdentity)
pnpm add @solana/keychain-kit-plugin

Erfordert @solana/kit 8.1 oder neuer. v1-Transaktionen (createTransactionMessage({ version: 1 })) werden unterstützt, außer von Fireblocks mit useProgramCall: true, das nur Legacy und v0 akzeptiert.

Grundlegende Verwendung

Einheitliche Factory (Empfohlen für Apps, die mehrere Signer unterstützen möchten)

Verwenden Sie createKeychainSigner mit einer diskriminierten Konfiguration, um ein beliebiges Backend zu erstellen:

import { createKeychainSigner } from "@solana/keychain";
import { signTransactionWithSigners } from "@solana/signers"; // requires @solana/signers >= 8.1
const signer = await createKeychainSigner({
backend: "privy",
appId: "your-app-id",
appSecret: "your-app-secret",
walletId: "your-wallet-id"
});
// Sign an already-compiled transaction
const signedTx = await signTransactionWithSigners(
[signer],
compiledTransaction
);

Oder installieren Sie ein einzelnes Signer-Paket für einen kleineren Dependency-Footprint:

import { createPrivySigner } from "@solana/keychain-privy";
const signer = await createPrivySigner({
appId: "your-app-id",
appSecret: "your-app-secret",
walletId: "your-wallet-id"
});

Verwendung mit Transaktionsnachrichten

Jedes Backend außer Crossmint und dem nativen Modus von Fordefi gibt einen SolanaTransactionSigner zurück, der ein Kit-TransactionPartialSigner ist und mit den unten aufgeführten @solana/signers-Partial-Signer-Helfern funktioniert. Backends mit verwaltetem Broadcast werden unter Signer-Fähigkeiten behandelt.

import type { SolanaTransactionSigner } from "@solana/keychain-core";
import { signTransactionMessageWithSigners } from "@solana/signers";
import {
createTransactionMessage,
setTransactionMessageFeePayerSigner,
pipe
} from "@solana/kit";
async function signWithKeychain(signer: SolanaTransactionSigner) {
// Check availability (useful for remote signers)
if (!(await signer.isAvailable())) {
throw new Error("Signer offline");
}
// Use with @solana/kit transaction builder
const transaction = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(signer, tx)
// ... set a lifetime and add instructions
);
// Sign with the standard signers API
const signedTx = await signTransactionMessageWithSigners(transaction);
return signedTx;
}

Mit beliebigem Signer signieren und senden

signAndSendTransaction aus @solana/keychain-core bringt eine Transaktion unabhängig von der Form des Signers on-chain. Sendende Signer übertragen sie über ihren Anbieter; jede andere Form verwendet die von Ihnen übergebene sendTransaction (Core hat keine RPC-Abhängigkeit):

import { signAndSendTransaction } from "@solana/keychain-core";
const signature = await signAndSendTransaction(signer, transaction, {
sendTransaction: (tx) =>
sendAndConfirmTransaction(tx, { commitment: "confirmed" })
});

Verwendung mit einem Kit-Client (keychainSigner-Plugin)

@solana/keychain-kit-plugin installiert einen Keychain-Signer direkt auf einem Kit-Client und richtet ihn als payer und identity ein, sodass die manuelle pipe-Einrichtung wie oben beschrieben entfällt:

import { createClient } from "@solana/kit";
import { keychainSigner } from "@solana/keychain-kit-plugin";
const client = await createClient().use(
keychainSigner({
backend: "privy",
appId: process.env.PRIVY_APP_ID!,
appSecret: process.env.PRIVY_APP_SECRET!,
walletId: process.env.PRIVY_WALLET_ID!
})
);
client.payer; // SolanaTransactionSigner, also a Kit TransactionPartialSigner
client.identity; // same signer instance

Das Plugin akzeptiert dieselbe Backend-getaggte Konfiguration wie createKeychainSigner, außer Crossmint und dem nativen Modus von Fordefi (chain gesetzt). Diese Backends schreiben die Transaktion serverseitig um und können daher nicht als Client-payer oder identity fungieren; das Plugin lehnt sie zur Kompilierzeit und zur Laufzeit ab. Nur das Backend, an das delegiert wird, wird gebündelt (Backend-Pakete werden über dynamisches import() geladen).

Verwende keychainPayer oder keychainIdentity, um nur eine Rolle festzulegen, und kombiniere Backends auf einem einzelnen Client:

import { createClient } from "@solana/kit";
import { keychainIdentity, keychainPayer } from "@solana/keychain-kit-plugin";
const client = await createClient()
.use(
keychainPayer({
backend: "memory",
privateKeyPath: `${process.env.HOME}/.config/solana/id.json`
})
)
.use(keychainIdentity({ backend: "turnkey", ...turnkeyConfig }));

Sie haben bereits einen SolanaTransactionSigner? Er ist ein gültiger Kit- TransactionPartialSigner, daher können Sie ihn stattdessen mit @solana/kit-plugin-signer installieren (pnpm add @solana/kit-plugin-signer):

import { createClient } from "@solana/kit";
import { signer } from "@solana/kit-plugin-signer";
import { createKeychainSigner } from "@solana/keychain";
const mySigner = await createKeychainSigner({
backend: "vault",
...vaultConfig
});
const client = createClient().use(signer(mySigner));

Abbruch und unbestätigte Broadcasts

signTransactions, modifyAndSignTransactions, signAndSendTransactions und signMessages akzeptieren alle { abortSignal } als zweites Argument. Ein Abbruch beendet das Warten; er macht keine Arbeit rückgängig, die ein Anbieter bereits akzeptiert hat.

Im nativen Auto-Modus von Crossmint und Fordefi bedeutet ein Fehler nicht, dass nichts übermittelt wurde. Wenn der Anbieter die Transaktion möglicherweise akzeptiert hat, lautet der Fehlercode SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED"). context.providerTransactionId ist gesetzt, wenn die Erstellung akzeptiert wurde, und context.idempotencyKey enthält den aus der Nachricht abgeleiteten Schlüssel. Das erneute Senden der bytegleichen Transaktion ist sicher; eine neu erstellte (zum Beispiel mit einem neuen Blockhash) ist eine neue Überweisung. providerMayHaveAccepted(error) und providerStatus(error) aus @solana/keychain-core helfen bei der Klassifizierung des Fehlers. Gleichen Sie den Stand mit dem Anbieter ab, bevor Sie es erneut versuchen.

Backend-Konfiguration

Memory

Geben Sie genau eines der folgenden Felder an: keyPair, privateKey, privateKeyString oder privateKeyPath:

import { createMemorySigner } from "@solana/keychain-memory";
const signer = await createMemorySigner({
privateKeyPath: "/path/to/id.json"
});

HashiCorp Vault

import { createVaultSigner } from "@solana/keychain-vault";
const signer = createVaultSigner({
vaultAddr: "https://vault.example.com:8200",
vaultToken: "hvs.xxxxx",
keyName: "my-solana-key",
publicKey: "base58_public_key"
});

AWS KMS

import { createAwsKmsSigner } from "@solana/keychain-aws-kms";
const signer = createAwsKmsSigner({
keyId: "alias/my-solana-key",
publicKey: "base58_public_key",
region: "us-east-1" // optional
});

GCP KMS

import { createGcpKmsSigner } from "@solana/keychain-gcp-kms";
const signer = createGcpKmsSigner({
keyName:
"projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",
publicKey: "base58_public_key"
});

Privy

import { createPrivySigner } from "@solana/keychain-privy";
const signer = await createPrivySigner({
appId: "app_id",
appSecret: "app_secret",
walletId: "wallet_id"
});

Turnkey

import { createTurnkeySigner } from "@solana/keychain-turnkey";
const signer = createTurnkeySigner({
apiPublicKey: "api_public_key",
apiPrivateKey: "api_private_key",
organizationId: "org_id",
privateKeyId: "private_key_id",
publicKey: "base58_public_key"
});

Fireblocks

import { createFireblocksSigner } from "@solana/keychain-fireblocks";
const signer = await createFireblocksSigner({
apiKey: "api_key",
privateKeyPem: "-----BEGIN RSA PRIVATE KEY-----\n...",
vaultAccountId: "0",
assetId: "SOL" // or "SOL_TEST" for devnet
});

CDP (Coinbase Developer Platform)

import { createCdpSigner } from "@solana/keychain-cdp";
const signer = await createCdpSigner({
cdpApiKeyId: "api_key_id",
cdpApiKeySecret: "api_key_secret",
cdpWalletSecret: "wallet_secret",
address: "base58_address",
network: "solana" // or "solana-devnet"; required for address lookup tables
});

Crossmint

import { createCrossmintSigner } from "@solana/keychain-crossmint";
const signer = await createCrossmintSigner({
apiKey: "api_key",
walletLocator: "wallet_locator"
});

Crossmint unterstützt nur das Senden. Die API führt eine genehmigte Transaktion immer serverseitig aus und übernimmt die Gas-Kosten, daher stellt der Signer nur signAndSendTransactions() bereit: Es gibt weder signTransactions() noch signMessages(), und er kann nicht mit @solana/keychain-kit-plugin installiert werden. Die zurückgegebene Signatur identifiziert die Transaktion, die Crossmint übermittelt hat.

const [signature] = await signer.signAndSendTransactions([transaction]);
// or: await signAndSendTransactionMessageWithSigners(transactionMessage);

Dfns

import { createDfnsSigner } from "@solana/keychain-dfns";
const signer = await createDfnsSigner({
authToken: "auth_token",
credId: "cred_id",
privateKeyPem: "-----BEGIN EC PRIVATE KEY-----\n...",
walletId: "wallet_id"
});

Openfort

import { createOpenfortSigner } from "@solana/keychain-openfort";
const signer = await createOpenfortSigner({
secretKey: "sk_...",
walletSecret: "wallet_secret",
accountId: "account_id"
});

Para

import { createParaSigner } from "@solana/keychain-para";
const signer = await createParaSigner({
apiKey: "api_key",
walletId: "wallet_id"
});

Utila

Utila signiert nur Transaktionen; es gibt kein signMessages().

import { createUtilaSigner } from "@solana/keychain-utila";
const signer = await createUtilaSigner({
serviceAccountEmail: "sa@example.com",
serviceAccountPrivateKeyPem: "-----BEGIN PRIVATE KEY-----\n...",
vaultId: "vault_id",
walletId: "wallet_id",
network: "networks/solana-devnet"
});

Fordefi

Fordefi hat drei Signiermodi, die bei der Erstellung durch chain und pushMode festgelegt werden. Jeder Modus stellt genau eine Transaktionsmethode bereit, und alle drei signieren Nachrichten:

ModusKonfigurationTypMethode
Black Boxchain nicht gesetztFordefiBlackBoxSignersignTransactions()
Nativ automatischchain gesetzt, pushMode weggelassen oder "auto"FordefiNativeSignersignAndSendTransactions()
Nativ manuellchain gesetzt, pushMode: "manual"FordefiNativeManualSignermodifyAndSignTransactions()

API-Anfragen werden mit einer ECDSA-P-256-Anfragesignatur authentifiziert: Geben Sie den Signierschlüssel als privateKeyPem an oder bewahren Sie ihn in einem KMS/HSM auf, indem Sie einen requestSigner übergeben.

Nativer Auto-Modus (empfohlen für die On-Chain-Nutzung): Setzen Sie chain, und Fordefi signiert und sendet die Transaktion selbst. Da Fordefi vor dem Signieren den Blockhash oder die Fee ersetzen kann, ist der Signer ein Kit- TransactionSendingSigner: Verwenden Sie ihn mit signAndSendTransactionMessageWithSigners, nicht mit dem oben gezeigten Partial-Signer-Ablauf. Der native Auto-Modus akzeptiert nur eine unsignierte Transaktion, deren einziger erforderlicher Signer der Vault ist, und er kann nicht mit @solana/keychain-kit-plugin verwendet werden.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { signAndSendTransactionMessageWithSigners } from "@solana/signers";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_VAULT_ID!,
publicKey: process.env.FORDEFI_PUBLIC_KEY!, // Solana vault address (base58)
privateKeyPem: readFileSync("./secret/private.pem", "utf8"),
chain: "solana_devnet", // or "solana_mainnet"
fee: { type: "custom", priority_fee: "1000" } // optional
});
const signature =
await signAndSendTransactionMessageWithSigners(transactionMessage);

Nativer manueller Modus: Setzen Sie chain und pushMode: "manual". Fordefi schreibt die Nachricht um (aktueller Blockhash, Compute-Budget-Fee-Anweisungen) und signiert sie, sendet sie aber nicht. modifyAndSignTransactions() gibt die von Fordefi signierte Transaktion zurück, die die von Ihnen übermittelte ersetzt: Machen Sie immer mit der zurückgegebenen Transaktion weiter. Fordefi muss der Fee-Payer sein und vor allen anderen erforderlichen Signern signieren. Die Umschreibung wird nicht als Diff dargestellt, prüfen Sie daher das Ergebnis vor dem Senden.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_VAULT_ID!,
publicKey: process.env.FORDEFI_PUBLIC_KEY!,
privateKeyPem: readFileSync("./secret/private.pem", "utf8"),
chain: "solana_devnet",
pushMode: "manual"
});
const [signedTransaction] = await signer.modifyAndSignTransactions([
transaction
]);

Black-Box-Modus: Lassen Sie chain weg. Fordefi signiert rohe Bytes und sendet diese nicht; Sie stellen die Transaktion selbst zusammen und übermitteln sie. Verwenden Sie dies mit einem Fordefi-Black-Box-Vault.

import { createFordefiSigner } from "@solana/keychain-fordefi";
import { readFileSync } from "node:fs";
const signer = await createFordefiSigner({
accessToken: process.env.FORDEFI_ACCESS_TOKEN!,
vaultId: process.env.FORDEFI_BB_VAULT_ID!,
publicKey: process.env.FORDEFI_BB_PUBLIC_KEY!,
privateKeyPem: readFileSync("./secret/private.pem", "utf8")
});

Signer-Fähigkeiten

@solana/keychain-core definiert eine Schnittstelle pro Kit-Signer-Form. Jede ergänzt isAvailable(): Promise<boolean> zur passenden @solana/signers-Schnittstelle:

  • SolanaTransactionSigner (Kit-TransactionPartialSigner): gibt Signaturen für eine Transaktion zurück, die Ihnen gehört.
  • SolanaModifyingSigner (Kit-TransactionModifyingSigner): schreibt die Transaktion um, signiert sie und gibt die neue Transaktion zurück, ohne sie zu senden.
  • SolanaSendingSigner (Kit-TransactionSendingSigner): signiert und sendet über seinen Anbieter.
  • SolanaMessageSigner (Kit-MessagePartialSigner): signiert Off-Chain-Nachrichten. Dies ist von den Transaktionsformen getrennt.

SolanaSigner ist die Vereinigung der drei Transaktionsformen. Der Rückgabetyp jeder Factory benennt die exakte Form ihres Backends. Wenn die Konfiguration erst zur Laufzeit bekannt ist, grenzen Sie sie mit isSolanaTransactionSigner, isSolanaModifyingSigner, isSolanaSendingSigner oder isSolanaMessageSigner ein. signerCapabilities(signer) meldet alle vier auf einmal.

BackendForm
memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (Black Box)SolanaTransactionSigner & SolanaMessageSigner
utilaSolanaTransactionSigner (keine Nachrichtensignierung)
fordefi (nativ manuell)SolanaModifyingSigner & SolanaMessageSigner
fordefi (nativ automatisch)SolanaSendingSigner & SolanaMessageSigner
crossmintSolanaSendingSigner (keine Nachrichtensignierung)
import {
isSolanaSendingSigner,
isSolanaTransactionSigner
} from "@solana/keychain-core";
if (isSolanaSendingSigner(signer)) {
await signer.signAndSendTransactions([transaction]);
} else if (isSolanaTransactionSigner(signer)) {
await signer.signTransactions([transaction]);
}

Benutzerdefinierte Signer erstellen

Implementieren Sie die Capability-Schnittstellen, die Ihr Backend unterstützt:

import type {
SolanaMessageSigner,
SolanaTransactionSigner
} from "@solana/keychain-core";
import type { Address } from "@solana/addresses";
import type {
MessagePartialSignerConfig,
SignableMessage,
TransactionPartialSignerConfig
} from "@solana/signers";
import type { Transaction } from "@solana/transactions";
class MyCustomSigner implements SolanaTransactionSigner, SolanaMessageSigner {
constructor(readonly address: Address) {}
async isAvailable(): Promise<boolean> {
return await myBackend.healthCheck();
}
async signMessages(
messages: readonly SignableMessage[],
config?: MessagePartialSignerConfig
) {
return await myBackend.signMessages(messages, config?.abortSignal);
}
async signTransactions(
transactions: readonly Transaction[],
config?: TransactionPartialSignerConfig
) {
return await myBackend.signTransactions(transactions, config?.abortSignal);
}
}

Implementieren Sie nur das, was Ihr Backend unterstützt. Kit klassifiziert Signer danach, welche Methoden vorhanden sind, fügen Sie also niemals eine Methode hinzu, die nur einen Fehler auslöst.

Weitere Informationen zur Integration zusätzlicher Schlüsselverwaltungsdienste findest du im Leitfaden zum Hinzufügen von Signern.

Is this page helpful?

© 2026 Solana Foundation. Alle Rechte vorbehalten.