Nâng cấp từ 1.x? Xem hướng dẫn di chuyển sang 2.0.
Cài đặt
Cài đặt gói tổng hợp (umbrella package) hoặc từng signer riêng lẻ tùy nhu cầu:
# 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
Yêu cầu @solana/kit 8.1 trở lên. Giao dịch v1
(createTransactionMessage({ version: 1 })) được hỗ trợ, ngoại trừ Fireblocks
với useProgramCall: true, vốn chỉ chấp nhận legacy và v0.
Cách sử dụng cơ bản
Factory hợp nhất (Khuyến nghị cho các ứng dụng muốn hỗ trợ nhiều signer)
Dùng createKeychainSigner với cấu hình phân biệt (discriminated config) để tạo bất kỳ backend nào:
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);
Hoặc cài đặt gói signer riêng lẻ để giảm dung lượng phụ thuộc:
import { createPrivySigner } from "@solana/keychain-privy";const signer = await createPrivySigner({appId: "your-app-id",appSecret: "your-app-secret",walletId: "your-wallet-id"});
Sử dụng với Transaction Message
Mọi backend, trừ Crossmint và chế độ native của Fordefi, đều trả về một
SolanaTransactionSigner, vốn là một TransactionPartialSigner của Kit và hoạt động
cùng các helper partial-signer của @solana/signers bên dưới. Các backend
quản lý việc broadcast được trình bày trong Khả năng của Signer.
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;}
Ký và gửi với bất kỳ Signer nào
signAndSendTransaction từ @solana/keychain-core đưa giao dịch lên
chain bất kể signer có dạng nào. Các signer dạng gửi (sending) sẽ broadcast thông qua
provider của chúng; mọi dạng khác dùng sendTransaction mà bạn truyền vào (core không phụ thuộc
vào RPC):
import { signAndSendTransaction } from "@solana/keychain-core";const signature = await signAndSendTransaction(signer, transaction, {sendTransaction: (tx) =>sendAndConfirmTransaction(tx, { commitment: "confirmed" })});
Sử dụng với Kit Client (plugin keychainSigner)
@solana/keychain-kit-plugin cài đặt trực tiếp một keychain signer lên
Kit client, thiết lập nó làm payer và
identity để bạn bỏ qua bước thiết lập pipe thủ công như đã trình bày ở trên:
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
Plugin chấp nhận cùng cấu hình gắn thẻ backend như createKeychainSigner,
trừ Crossmint và chế độ native của Fordefi (đã đặt chain). Các backend đó viết lại
giao dịch ở phía máy chủ, nên chúng không thể đóng vai trò payer hay
identity của client; plugin sẽ từ chối chúng ở thời điểm biên dịch và thời điểm chạy. Chỉ
backend mà nó điều phối tới mới được đóng gói (các gói backend được tải qua
import() động).
Dùng keychainPayer hoặc keychainIdentity để chỉ thiết lập một vai trò, và kết hợp nhiều backend
trên cùng một 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 }));
Đã có sẵn một SolanaTransactionSigner? Nó là một TransactionPartialSigner hợp lệ của Kit,
nên bạn có thể cài đặt nó bằng
@solana/kit-plugin-signer
thay thế (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));
Hủy bỏ và các Broadcast chưa được xác nhận
signTransactions, modifyAndSignTransactions, signAndSendTransactions và
signMessages đều nhận { abortSignal } làm đối số thứ hai. Việc hủy bỏ
chỉ dừng việc chờ đợi; nó không hoàn tác công việc mà provider đã chấp nhận.
Với chế độ native auto của Crossmint và Fordefi, một lỗi không có nghĩa là giao dịch
chưa được ghi nhận. Khi provider có thể đã chấp nhận giao dịch, mã lỗi là
SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED").
context.providerTransactionId được đặt khi yêu cầu tạo đã được chấp nhận, và
context.idempotencyKey chứa khóa được suy ra từ message. Gửi lại giao dịch
giống hệt từng byte là an toàn; một giao dịch được dựng lại (ví dụ với
blockhash mới) là một lần chuyển mới. providerMayHaveAccepted(error) và
providerStatus(error) từ @solana/keychain-core giúp phân loại lỗi.
Hãy đối chiếu với provider trước khi thử lại.
Cấu hình Backend
Memory
Cung cấp chính xác một trong các tùy chọn keyPair, privateKey, privateKeyString hoặc
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 chỉ hỗ trợ gửi. API của Crossmint luôn thực thi giao dịch đã được duyệt
ở phía máy chủ và tài trợ phí gas, nên signer chỉ cung cấp
signAndSendTransactions(): không có signTransactions() hay signMessages(),
và không thể cài đặt cùng @solana/keychain-kit-plugin. Chữ ký
trả về xác định giao dịch mà Crossmint đã đưa lên chain.
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 chỉ ký giao dịch; không có 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 có ba chế độ ký, được cố định khi khởi tạo bởi chain và
pushMode. Mỗi chế độ cung cấp đúng một phương thức giao dịch, và cả ba đều ký
message:
| Chế độ | Cấu hình | Kiểu | Phương thức |
|---|---|---|---|
| Black box | chain không được đặt | FordefiBlackBoxSigner | signTransactions() |
| Native auto | chain được đặt, pushMode bị bỏ qua hoặc là "auto" | FordefiNativeSigner | signAndSendTransactions() |
| Native manual | chain được đặt, pushMode: "manual" | FordefiNativeManualSigner | modifyAndSignTransactions() |
Các yêu cầu API được xác thực bằng chữ ký yêu cầu ECDSA P-256: cung cấp
khóa ký dưới dạng privateKeyPem, hoặc giữ khóa trong KMS/HSM bằng cách truyền
requestSigner.
Chế độ native auto (khuyến nghị cho việc sử dụng on-chain): đặt chain, và Fordefi
sẽ tự ký và broadcast giao dịch. Vì Fordefi có thể thay thế
blockhash hoặc phí trước khi ký, signer là một TransactionSendingSigner của Kit:
hãy dùng nó với signAndSendTransactionMessageWithSigners, không dùng quy trình partial-signer
như đã trình bày ở trên. Chế độ native auto chỉ chấp nhận giao dịch chưa ký mà signer bắt buộc duy nhất
là vault, và không thể dùng cùng @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);
Chế độ native manual: đặt chain và pushMode: "manual". Fordefi viết lại
message (blockhash gần đây, các instruction phí Compute Budget) và ký nó,
nhưng không broadcast. modifyAndSignTransactions() trả về giao dịch
mà Fordefi đã ký, thay thế giao dịch bạn đã gửi: luôn tiếp tục từ giao dịch
được trả về. Fordefi phải là người trả phí (fee payer) và phải ký trước mọi
signer bắt buộc khác. Phần viết lại không được so sánh khác biệt (diff), vì vậy hãy kiểm tra kết quả trước khi
broadcast.
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]);
Chế độ black box: bỏ qua chain. Fordefi ký các byte thô và không
broadcast; bạn tự ghép và gửi giao dịch. Hãy dùng chế độ này với
vault black box của 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")});
Khả năng của Signer
@solana/keychain-core định nghĩa một interface cho mỗi dạng signer của Kit. Mỗi interface bổ sung
isAvailable(): Promise<boolean> vào interface tương ứng của @solana/signers:
SolanaTransactionSigner(TransactionPartialSignercủa Kit): trả về chữ ký cho một giao dịch mà bạn sở hữu.SolanaModifyingSigner(TransactionModifyingSignercủa Kit): viết lại giao dịch, ký và trả về giao dịch mới mà không broadcast.SolanaSendingSigner(TransactionSendingSignercủa Kit): ký và broadcast thông qua provider của nó.SolanaMessageSigner(MessagePartialSignercủa Kit): ký các message off-chain. Dạng này tách biệt với các dạng giao dịch.
SolanaSigner là union của ba dạng giao dịch. Kiểu trả về của mỗi factory
chỉ rõ chính xác dạng của backend tương ứng. Khi cấu hình chỉ được biết tại
thời điểm chạy, hãy thu hẹp kiểu bằng isSolanaTransactionSigner, isSolanaModifyingSigner,
isSolanaSendingSigner hoặc isSolanaMessageSigner. signerCapabilities(signer)
báo cáo cả bốn cùng một lúc.
| Backend | Dạng |
|---|---|
| memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi (black box) | SolanaTransactionSigner & SolanaMessageSigner |
| utila | SolanaTransactionSigner (không ký message) |
| fordefi (native manual) | SolanaModifyingSigner & SolanaMessageSigner |
| fordefi (native auto) | SolanaSendingSigner & SolanaMessageSigner |
| crossmint | SolanaSendingSigner (không ký message) |
import {isSolanaSendingSigner,isSolanaTransactionSigner} from "@solana/keychain-core";if (isSolanaSendingSigner(signer)) {await signer.signAndSendTransactions([transaction]);} else if (isSolanaTransactionSigner(signer)) {await signer.signTransactions([transaction]);}
Xây dựng Signer tùy chỉnh
Triển khai các interface khả năng mà backend của bạn hỗ trợ:
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);}}
Chỉ triển khai những gì backend của bạn hỗ trợ. Kit phân loại signer dựa trên những phương thức hiện có, vì vậy đừng bao giờ thêm một phương thức chỉ để ném lỗi.
Xem hướng dẫn Thêm Signer để tích hợp các dịch vụ quản lý khóa bổ sung.
Is this page helpful?