TypeScript

从 1.x 升级?请参阅2.0 迁移指南。

安装

根据需要安装伞形包或单独的签名器:

# 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

需要 @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.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
);

或者安装单独的签名器包以减少依赖占用:

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,它是 Kit 的 TransactionPartialSigner,可与下面的 @solana/signers 部分签名器辅助函数配合使用。托管广播后端请参阅签名器能力。

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;
}

使用任意签名器签名并发送

无论签名器是何种形态,@solana/keychain-core 中的 signAndSendTransaction 都能将交易上链。发送型签名器通过其提供商广播;其他所有形态则使用您传入的 sendTransaction(core 不依赖 RPC):

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

与 Kit 客户端配合使用(keychainSigner 插件)

@solana/keychain-kit-plugin 可直接在 Kit 客户端 上安装一个密钥链签名器,将其配置为 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 TransactionPartialSigner
client.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?它是有效的 Kit TransactionPartialSigner,因此您可以改用 @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)则是一笔新的转账。@solana/keychain-core 中的 providerMayHaveAccepted(error) 和 providerStatus(error) 有助于对错误进行分类。重试前请先与提供商核对。

后端配置

内存

请从 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 开发者平台)

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 始终在服务端执行已批准的交易并代付 gas,因此该签名器只暴露 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"
});

参数

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 在构造时确定。每种模式恰好暴露一个交易方法,且三种模式都能对消息签名:

模式配置类型方法
黑盒未设置 chainFordefiBlackBoxSignersignTransactions()
原生自动已设置 chain,pushMode 省略或为 "auto"FordefiNativeSignersignAndSendTransactions()
原生手动已设置 chain,pushMode: "manual"FordefiNativeManualSignermodifyAndSignTransactions()

API 请求通过 ECDSA P-256 请求签名进行身份验证:将签名密钥作为 privateKeyPem 提供,或通过传入 requestSigner 将其保存在 KMS/HSM 中。

原生自动模式(推荐用于链上场景):设置 chain,Fordefi 会自行签名并广播交易。由于 Fordefi 可能在签名前替换 blockhash 或费用,该签名器是 Kit 的 TransactionSendingSigner:请将其与 signAndSendTransactionMessageWithSigners 配合使用,而非上文所示的部分签名器流程。原生自动模式仅接受唯一必需签名者为该保险库的未签名交易,并且不能与 @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 会重写消息(最近的 blockhash、Compute Budget 费用指令)并签名,但不会广播。modifyAndSignTransactions() 返回 Fordefi 签名后的交易,它会取代您提交的交易:请始终基于返回的交易继续操作。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_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 对原始字节进行签名,不负责广播;您需自行组装并提交交易。请将此模式与 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 签名器形态定义了一个接口。每个接口都在对应的 @solana/signers 接口基础上增加了 isAvailable(): Promise<boolean>:

  • SolanaTransactionSigner(Kit 的 TransactionPartialSigner):为您持有的交易返回签名。
  • SolanaModifyingSigner(Kit 的 TransactionModifyingSigner):重写交易、对其签名,并返回新交易,但不广播。
  • SolanaSendingSigner(Kit 的 TransactionSendingSigner):通过其提供商签名并广播。
  • SolanaMessageSigner(Kit 的 MessagePartialSigner):对链下消息签名。这与交易形态相互独立。

SolanaSigner 是三种交易形态的联合类型。每个工厂函数的返回类型都会指明其后端的确切形态。当配置仅在运行时才可知时,请使用 isSolanaTransactionSigner、isSolanaModifyingSigner、isSolanaSendingSigner 或 isSolanaMessageSigner 进行类型收窄。signerCapabilities(signer) 会一次性报告全部四种能力。

后端形态
memory, vault, aws-kms, gcp-kms, privy, turnkey, fireblocks, cdp, dfns, para, openfort, fordefi(黑盒)SolanaTransactionSigner & SolanaMessageSigner
utilaSolanaTransactionSigner(不支持消息签名)
fordefi(原生手动)SolanaModifyingSigner & SolanaMessageSigner
fordefi(原生自动)SolanaSendingSigner & SolanaMessageSigner
crossmintSolanaSendingSigner(不支持消息签名)
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?

©️ 2026 Solana 基金会版权所有