Оновлюєтеся з версії 1.x? Дивіться посібник з міграції на 2.0.
Встановлення
Встановіть загальний пакет або окремі підписанти за потреби:
# 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
Потрібен @solana/kit 8.1 або новіший. Транзакції v1
(createTransactionMessage({ version: 1 })) підтримуються, за винятком Fireblocks
із useProgramCall: true, який приймає лише legacy- та v0-транзакції.
Базове використання
Уніфікована фабрика (рекомендується для додатків, які хочуть підтримувати кілька підписантів)
Використовуйте createKeychainSigner з дискримінованою конфігурацією для
створення будь-якого бекенду:
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);
Або встановіть окремий пакет підписанта для меншого обсягу залежностей:
import { createPrivySigner } from "@solana/keychain-privy";const signer = await createPrivySigner({appId: "your-app-id",appSecret: "your-app-secret",walletId: "your-wallet-id"});
Використання з повідомленнями транзакцій
Кожен бекенд, окрім Crossmint і нативного режиму Fordefi, повертає
SolanaTransactionSigner, який є TransactionPartialSigner з Kit і працює
з допоміжними функціями часткових підписувачів @solana/signers, наведеними нижче. Бекенди з керованим broadcast
описано в розділі Можливості підписувачів.
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;}
Підписання й надсилання з будь-яким підписувачем
signAndSendTransaction з @solana/keychain-core доставляє транзакцію в
мережу незалежно від типу підписувача. Підписувачі з надсиланням транслюють її через свого
провайдера; усі інші типи використовують передану вами функцію sendTransaction (у core немає
залежності від RPC):
import { signAndSendTransaction } from "@solana/keychain-core";const signature = await signAndSendTransaction(signer, transaction, {sendTransaction: (tx) =>sendAndConfirmTransaction(tx, { commitment: "confirmed" })});
Використання з Kit Client (плагін keychainSigner)
@solana/keychain-kit-plugin встановлює підписувач ключового ланцюжка
безпосередньо на Kit client, підключаючи його
як payer та identity, що дозволяє пропустити ручне налаштування pipe,
показане вище:
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
Плагін приймає ту саму конфігурацію з тегом бекенду, що й createKeychainSigner,
окрім Crossmint і нативного режиму Fordefi (заданий chain). Ці бекенди переписують
транзакцію на стороні сервера, тому не можуть виступати клієнтським payer або
identity; плагін відхиляє їх і під час компіляції, і під час виконання. До складу збірки входить лише той
бекенд, до якого він звертається (пакети бекендів завантажуються через динамічний
import()).
Використовуйте keychainPayer або keychainIdentity, щоб призначити лише одну
роль і поєднувати бекенди на одному клієнті:
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 }));
Уже маєте SolanaTransactionSigner? Це чинний TransactionPartialSigner з Kit,
тож ви можете натомість встановити його через
@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));
Скасування та непідтверджені трансляції
signTransactions, modifyAndSignTransactions, signAndSendTransactions і
signMessages приймають { abortSignal } другим аргументом. Переривання
припиняє очікування, але не скасовує роботу, яку провайдер уже прийняв.
У Crossmint та нативному автоматичному режимі Fordefi збій не означає, що нічого
не було виконано. Якщо провайдер міг прийняти транзакцію, код помилки —
SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED").
context.providerTransactionId встановлюється, якщо створення було прийнято, а
context.idempotencyKey містить ключ, отриманий із повідомлення. Повторне надсилання
байт-у-байт ідентичної транзакції безпечне; перебудована транзакція (наприклад, з новим
blockhash) — це новий переказ. providerMayHaveAccepted(error) і
providerStatus(error) з @solana/keychain-core допомагають класифікувати помилку.
Перед повторною спробою звірте стан із провайдером.
Конфігурація бекенду
Пам’ять
Вкажіть рівно одне з: keyPair, privateKey, privateKeyString або
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 підтримує лише надсилання. Його API завжди виконує схвалену транзакцію
на стороні сервера та спонсорує газ, тому підписувач надає лише
signAndSendTransactions(): у нього немає signTransactions() чи signMessages(),
і його не можна встановити через @solana/keychain-kit-plugin. Повернений
підпис ідентифікує транзакцію, яку виконав Crossmint.
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 підписує лише транзакції; у нього немає 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 має три режими підписання, які фіксуються під час створення через chain і
pushMode. Кожен режим надає рівно один метод для транзакцій, а всі три підписують
повідомлення:
| Режим | Конфігурація | Тип | Метод |
|---|---|---|---|
| Чорний ящик | chain не задано | FordefiBlackBoxSigner | signTransactions() |
| Нативний автоматичний | chain задано, pushMode пропущено або "auto" | FordefiNativeSigner | signAndSendTransactions() |
| Нативний ручний | chain задано, pushMode: "manual" | FordefiNativeManualSigner | modifyAndSignTransactions() |
API-запити автентифікуються підписом запиту ECDSA P-256: передайте
ключ підпису як privateKeyPem або зберігайте його в KMS/HSM, передавши
requestSigner.
Нативний автоматичний режим (рекомендований для використання в мережі): задайте chain, і Fordefi
сам підписує та транслює транзакцію. Оскільки Fordefi може замінити
blockhash або комісії перед підписанням, підписувач є TransactionSendingSigner
з Kit: використовуйте його з
signAndSendTransactionMessageWithSigners, а не з потоком часткового підписувача, показаним
вище. Нативний автоматичний режим приймає лише непідписану транзакцію, єдиним необхідним
підписувачем якої є сховище (vault), і його не можна використовувати з @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);
Нативний ручний режим: задайте chain і pushMode: "manual". Fordefi переписує
повідомлення (recent blockhash, інструкції комісій Compute Budget) і підписує його,
але не транслює. modifyAndSignTransactions() повертає транзакцію,
підписану Fordefi, яка замінює ту, що ви надіслали: завжди продовжуйте з
поверненою транзакцією. Fordefi має бути платником комісії й підписувати раніше за будь-якого
іншого необхідного підписувача. Зміни не порівнюються (diff), тому перевіряйте результат перед
трансляцією.
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]);
Режим чорної скриньки: пропустіть chain. Fordefi підписує необроблені байти та не транслює; ви самостійно збираєте та надсилаєте транзакцію. Використовуйте це з vault-сховищем типу "чорна скринька" Fordefi.
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")});
Можливості підписувачів
@solana/keychain-core визначає один інтерфейс для кожного типу підписувача Kit. Кожен додає
isAvailable(): Promise<boolean> до відповідного інтерфейсу @solana/signers:
SolanaTransactionSigner(TransactionPartialSignerз Kit): повертає підписи для транзакції, якою ви володієте.SolanaModifyingSigner(TransactionModifyingSignerз Kit): переписує транзакцію, підписує її та повертає нову транзакцію без трансляції.SolanaSendingSigner(TransactionSendingSignerз Kit): підписує й транслює через свого провайдера.SolanaMessageSigner(MessagePartialSignerз Kit): підписує повідомлення поза мережею (off-chain). Це окремо від типів для транзакцій.
SolanaSigner — це об’єднання трьох типів для транзакцій. Тип, що повертається кожною фабрикою,
точно вказує тип її бекенду. Якщо конфігурація відома лише під час
виконання, звужуйте тип за допомогою isSolanaTransactionSigner, isSolanaModifyingSigner,
isSolanaSendingSigner або isSolanaMessageSigner. signerCapabilities(signer)
повідомляє про всі чотири одразу.
| Бекенд | Тип |
|---|---|
| memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (чорний ящик) | SolanaTransactionSigner & SolanaMessageSigner |
| utila | SolanaTransactionSigner (без підписання повідомлень) |
| fordefi (нативний ручний) | SolanaModifyingSigner & SolanaMessageSigner |
| fordefi (нативний автоматичний) | SolanaSendingSigner & SolanaMessageSigner |
| crossmint | SolanaSendingSigner (без підписання повідомлень) |
import {isSolanaSendingSigner,isSolanaTransactionSigner} from "@solana/keychain-core";if (isSolanaSendingSigner(signer)) {await signer.signAndSendTransactions([transaction]);} else if (isSolanaTransactionSigner(signer)) {await signer.signTransactions([transaction]);}
Створення власних підписантів
Реалізуйте інтерфейси можливостей, які підтримує ваш бекенд:
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);}}
Реалізуйте лише те, що підтримує ваш бекенд. Kit класифікує підписувачів за тим, які методи існують, тому ніколи не додавайте метод, який просто викидає помилку.
Перегляньте посібник із додавання підписантів, щоб інтегрувати додаткові служби керування ключами.
Is this page helpful?