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 }))はサポートされていますが、useProgramCall: trueを指定したFireblocksは例外で、レガシーと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を返します。これはKitのTransactionPartialSignerであり、以下の@solana/signersのpartial-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;}
任意の署名者で署名して送信する
@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 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をお持ちですか?これは有効な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はいずれも、第2引数に{ abortSignal }を指定できます。中止すると待機は止まりますが、プロバイダーがすでに受け付けた処理が取り消されるわけではありません。
CrossmintおよびFordefiのネイティブ自動モードでは、失敗したからといって何も反映されていないとは限りません。プロバイダーがトランザクションを受け付けた可能性がある場合、エラーコードはSignerErrorCode.BROADCAST_UNCONFIRMED("SIGNER_BROADCAST_UNCONFIRMED")になります。作成リクエストが受理された場合はcontext.providerTransactionIdが設定され、context.idempotencyKeyにはメッセージから導出されたキーが格納されます。バイト単位で同一のトランザクションを再送しても安全ですが、再構築したもの(たとえば新しいブロックハッシュを使用したもの)は新しい送金になります。@solana/keychain-coreのproviderMayHaveAccepted(error)とproviderStatus(error)は、エラーの分類に役立ちます。再試行する前に、プロバイダー側の状態と照合してください。
バックエンド設定
メモリ
keyPair、privateKey、privateKeyString、privateKeyPathのうち、ちょうど1つを指定してください:
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"});
パラメータ
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には3つの署名モードがあり、chainとpushModeによって構築時に固定されます。各モードが公開するトランザクションメソッドはちょうど1つで、3つのモードすべてがメッセージに署名できます:
| モード | 設定 | 型 | メソッド |
|---|---|---|---|
| ブラックボックス | chain未設定 | FordefiBlackBoxSigner | signTransactions() |
| ネイティブ自動 | chainを設定、pushModeは省略または"auto" | FordefiNativeSigner | signAndSendTransactions() |
| ネイティブ手動 | chainを設定、pushMode: "manual" | FordefiNativeManualSigner | modifyAndSignTransactions() |
APIリクエストはECDSA P-256のリクエスト署名で認証されます。署名鍵をprivateKeyPemとして指定するか、requestSignerを渡してKMS/HSM内に保管したままにします。
ネイティブ自動モード(オンチェーンでの利用に推奨):chainを設定すると、Fordefi自身がトランザクションに署名してブロードキャストします。Fordefiは署名前にブロックハッシュや手数料を置き換える場合があるため、署名者はKitのTransactionSendingSignerとなります。上記のpartial-signerのフローではなく、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はメッセージ(最新のブロックハッシュ、Compute Budgetのfee instructions)を書き換えて署名しますが、ブロードキャストは行いません。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の署名者の形態ごとに1つのインターフェースを定義しています。それぞれが、対応する@solana/signersのインターフェースにisAvailable(): Promise<boolean>を追加したものです:
SolanaTransactionSigner(KitのTransactionPartialSigner):ユーザーが所有するトランザクションに対する署名を返します。SolanaModifyingSigner(KitのTransactionModifyingSigner):トランザクションを書き換えて署名し、ブロードキャストせずに新しいトランザクションを返します。SolanaSendingSigner(KitのTransactionSendingSigner):プロバイダー経由で署名とブロードキャストを行います。SolanaMessageSigner(KitのMessagePartialSigner):オフチェーンメッセージに署名します。トランザクションの形態とは別のものです。
SolanaSignerは3つのトランザクション形態のユニオン型です。各ファクトリーの戻り値の型は、そのバックエンドの正確な形態を示します。設定が実行時にしか分からない場合は、isSolanaTransactionSigner、isSolanaModifyingSigner、isSolanaSendingSigner、isSolanaMessageSignerで絞り込みます。signerCapabilities(signer)は4つすべてを一度に返します。
| バックエンド | 形態 |
|---|---|
| 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?