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 packagespnpm add @solana/keychain-core # Core interfaces (required for custom signers)pnpm add @solana/keychain-memory # Local keypair signerpnpm add @solana/keychain-vault # HashiCorp Vaultpnpm add @solana/keychain-aws-kms # AWS KMSpnpm add @solana/keychain-gcp-kms # GCP KMSpnpm add @solana/keychain-privy # Privypnpm add @solana/keychain-turnkey # Turnkeypnpm add @solana/keychain-fireblocks # Fireblockspnpm add @solana/keychain-cdp # Coinbase Developer Platformpnpm add @solana/keychain-crossmint # Crossmintpnpm add @solana/keychain-dfns # Dfnspnpm add @solana/keychain-openfort # Openfortpnpm add @solana/keychain-para # Parapnpm add @solana/keychain-utila # Utilapnpm 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.1const signer = await createKeychainSigner({backend: "privy",appId: "your-app-id",appSecret: "your-app-secret",walletId: "your-wallet-id"});// Sign an already-compiled transactionconst 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 builderconst transaction = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(signer, tx)// ... set a lifetime and add instructions);// Sign with the standard signers APIconst 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 TransactionPartialSignerclient.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:
| Modus | Konfiguration | Typ | Methode |
|---|---|---|---|
| Black Box | chain nicht gesetzt | FordefiBlackBoxSigner | signTransactions() |
| Nativ automatisch | chain gesetzt, pushMode weggelassen oder "auto" | FordefiNativeSigner | signAndSendTransactions() |
| Nativ manuell | chain gesetzt, pushMode: "manual" | FordefiNativeManualSigner | modifyAndSignTransactions() |
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.
| Backend | Form |
|---|---|
| memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (Black Box) | SolanaTransactionSigner & SolanaMessageSigner |
| utila | SolanaTransactionSigner (keine Nachrichtensignierung) |
| fordefi (nativ manuell) | SolanaModifyingSigner & SolanaMessageSigner |
| fordefi (nativ automatisch) | SolanaSendingSigner & SolanaMessageSigner |
| crossmint | SolanaSendingSigner (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?