Upgraden vanaf 1.x? Zie de 2.0-migratiegids.
Installatie
Installeer het overkoepelende pakket of individuele signers naar behoefte:
# 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
Vereist @solana/kit 8.1 of hoger. v1-transacties
(createTransactionMessage({ version: 1 })) worden ondersteund, behalve door Fireblocks
met useProgramCall: true, dat alleen legacy en v0 accepteert.
Basisgebruik
Uniforme Factory (Aanbevolen voor apps die meerdere signers willen ondersteunen)
Gebruik createKeychainSigner met een gediscrimineerde configuratie om elke
backend te creëren:
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);
Of installeer een individueel signer-pakket voor een kleinere afhankelijkheidsfootprint:
import { createPrivySigner } from "@solana/keychain-privy";const signer = await createPrivySigner({appId: "your-app-id",appSecret: "your-app-secret",walletId: "your-wallet-id"});
Gebruiken met Transaction Messages
Elke backend behalve Crossmint en de native modus van Fordefi retourneert een
SolanaTransactionSigner, een Kit TransactionPartialSigner die werkt
met de hieronder genoemde partial-signer-helpers van @solana/signers. Backends met beheerde broadcast
worden behandeld in Signer Capabilities.
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;}
Ondertekenen en verzenden met elke signer
signAndSendTransaction uit @solana/keychain-core krijgt een transactie on-chain,
ongeacht het type signer. Sending signers versturen via hun
provider; elk ander type gebruikt de sendTransaction die je meegeeft (core heeft geen
RPC-afhankelijkheid):
import { signAndSendTransaction } from "@solana/keychain-core";const signature = await signAndSendTransaction(signer, transaction, {sendTransaction: (tx) =>sendAndConfirmTransaction(tx, { commitment: "confirmed" })});
Gebruiken met een Kit Client (keychainSigner plugin)
@solana/keychain-kit-plugin installeert een keychain signer rechtstreeks op
een Kit client, en koppelt deze als de
payer en identity, zodat je de handmatige pipe-instelling zoals hierboven
beschreven overslaat:
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
De plugin accepteert dezelfde backend-getagde configuratie als createKeychainSigner,
behalve voor Crossmint en de native modus van Fordefi (chain ingesteld). Die backends herschrijven
de transactie aan de serverkant, dus ze kunnen niet fungeren als client-payer of
identity; de plugin weigert ze tijdens het compileren en tijdens runtime. Alleen de
backend waarnaar wordt doorverwezen, wordt gebundeld (backendpakketten worden geladen via dynamische
import()).
Gebruik keychainPayer of keychainIdentity om slechts één rol in te stellen
en backends te combineren op een enkele 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 }));
Heb je al een SolanaTransactionSigner? Dit is een geldige Kit
TransactionPartialSigner, dus je kunt hem in plaats daarvan installeren met
@solana/kit-plugin-signer
(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));
Annulering en onbevestigde broadcasts
signTransactions, modifyAndSignTransactions, signAndSendTransactions en
signMessages accepteren allemaal { abortSignal } als tweede argument. Afbreken
stopt het wachten; het maakt werk dat een provider al heeft geaccepteerd niet ongedaan.
Bij de native automodus van Crossmint en Fordefi betekent een fout niet dat er niets
is aangekomen. Als de provider de transactie mogelijk heeft geaccepteerd, is de foutcode
SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED").
context.providerTransactionId wordt ingesteld wanneer het aanmaken is geaccepteerd, en
context.idempotencyKey bevat de sleutel die van het bericht is afgeleid. Het opnieuw verzenden van de
byte-identieke transactie is veilig; een opnieuw opgebouwde transactie (bijvoorbeeld met een nieuwe
blockhash) is een nieuwe overdracht. providerMayHaveAccepted(error) en
providerStatus(error) uit @solana/keychain-core helpen bij het classificeren van de fout.
Stem af met de provider voordat je het opnieuw probeert.
Backendconfiguratie
Geheugen
Geef precies één van keyPair, privateKey, privateKeyString of
privateKeyPath op:
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 kan alleen verzenden. De API voert een goedgekeurde transactie altijd
serverzijdig uit en sponsort de gas, dus de signer biedt alleen
signAndSendTransactions(): er is geen signTransactions() of signMessages(),
en hij kan niet worden geïnstalleerd met @solana/keychain-kit-plugin. De geretourneerde
handtekening identificeert de transactie die Crossmint heeft verwerkt.
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 ondertekent alleen transacties; het heeft geen 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 heeft drie ondertekeningsmodi, vastgelegd bij de constructie via chain en
pushMode. Elke modus biedt precies één transactiemethode, en alle drie ondertekenen
berichten:
| Modus | Configuratie | Type | Methode |
|---|---|---|---|
| Black box | chain niet ingesteld | FordefiBlackBoxSigner | signTransactions() |
| Native auto | chain ingesteld, pushMode weggelaten of "auto" | FordefiNativeSigner | signAndSendTransactions() |
| Native handmatig | chain ingesteld, pushMode: "manual" | FordefiNativeManualSigner | modifyAndSignTransactions() |
API-verzoeken worden geauthenticeerd met een ECDSA P-256-verzoekhandtekening: geef de
ondertekeningssleutel op als privateKeyPem, of bewaar deze in een KMS/HSM door een
requestSigner mee te geven.
Native automodus (aanbevolen voor on-chain gebruik): stel chain in, en Fordefi
ondertekent en verzendt de transactie zelf. Omdat Fordefi de
blockhash of de kosten kan vervangen vóór het ondertekenen, is de signer een Kit
TransactionSendingSigner: gebruik hem met
signAndSendTransactionMessageWithSigners, niet met de hierboven getoonde partial-signer-flow.
De native automodus accepteert alleen een niet-ondertekende transactie waarvan de enige vereiste
ondertekenaar de vault is, en kan niet worden gebruikt met @solana/keychain-kit-plugin.
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);
Native handmatige modus: stel chain en pushMode: "manual" in. Fordefi herschrijft
het bericht (recente blockhash, Compute Budget-feeinstructies) en ondertekent het,
maar verzendt het niet. modifyAndSignTransactions() retourneert de transactie die
Fordefi heeft ondertekend en die de door jou ingediende vervangt: ga altijd verder met de
teruggegeven transactie. Fordefi moet de fee payer zijn en moet vóór elke
andere vereiste ondertekenaar ondertekenen. Het herschreven bericht wordt niet vergeleken, dus controleer het resultaat vóór
het verzenden.
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: laat chain weg. Fordefi ondertekent ruwe bytes en verstuurt niet; je assembleert en verzendt de transactie zelf. Gebruik dit met een 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 Capabilities
@solana/keychain-core definieert één interface per Kit-signertype. Elk voegt
isAvailable(): Promise<boolean> toe aan de bijbehorende @solana/signers-interface:
SolanaTransactionSigner(KitTransactionPartialSigner): retourneert handtekeningen voor een transactie die jij beheert.SolanaModifyingSigner(KitTransactionModifyingSigner): herschrijft de transactie, ondertekent deze en retourneert de nieuwe transactie zonder te verzenden.SolanaSendingSigner(KitTransactionSendingSigner): ondertekent en verzendt via zijn provider.SolanaMessageSigner(KitMessagePartialSigner): ondertekent off-chain berichten. Dit staat los van de transactietypen.
SolanaSigner is de unie van de drie transactietypen. Het retourtype van elke factory
benoemt het exacte type van de betreffende backend. Wanneer de configuratie pas tijdens
runtime bekend is, kun je vernauwen met isSolanaTransactionSigner, isSolanaModifyingSigner,
isSolanaSendingSigner of isSolanaMessageSigner. signerCapabilities(signer)
rapporteert alle vier tegelijk.
| Backend | Type |
|---|---|
| memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (black box) | SolanaTransactionSigner & SolanaMessageSigner |
| utila | SolanaTransactionSigner (geen berichtondertekening) |
| fordefi (native handmatig) | SolanaModifyingSigner & SolanaMessageSigner |
| fordefi (native auto) | SolanaSendingSigner & SolanaMessageSigner |
| crossmint | SolanaSendingSigner (geen berichtondertekening) |
import {isSolanaSendingSigner,isSolanaTransactionSigner} from "@solana/keychain-core";if (isSolanaSendingSigner(signer)) {await signer.signAndSendTransactions([transaction]);} else if (isSolanaTransactionSigner(signer)) {await signer.signTransactions([transaction]);}
Aangepaste Signers Bouwen
Implementeer de capability-interfaces die jouw backend ondersteunt:
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);}}
Implementeer alleen wat jouw backend ondersteunt. Kit classificeert signers op basis van welke methoden bestaan, dus voeg nooit een methode toe die alleen een fout genereert.
Zie de gids voor het toevoegen van signers om aanvullende sleutelbeheerservices te integreren.
Is this page helpful?