2.0.0 は Go モジュールの最初の安定版リリースのため、移行作業はありません。 2.0 移行ガイド では、Rust と TypeScript に対する同じケイパビリティの分割について説明しています。
インストール
各バックエンドは独立した Go モジュールなので、ビルドとモジュールグラフにはインポートしたバックエンドだけが含まれます:
go get github.com/solana-foundation/solana-keychain/go/core/v2 # Interfaces, errors, helpersgo get github.com/solana-foundation/solana-keychain/go/signers/memory/v2 # Local keypair signergo get github.com/solana-foundation/solana-keychain/go/signers/vault/v2 # HashiCorp Vaultgo get github.com/solana-foundation/solana-keychain/go/signers/awskms/v2 # AWS KMSgo get github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2 # GCP KMSgo get github.com/solana-foundation/solana-keychain/go/signers/privy/v2 # Privygo get github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2 # Turnkeygo get github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2 # Fireblocksgo get github.com/solana-foundation/solana-keychain/go/signers/cdp/v2 # Coinbase Developer Platformgo get github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2 # Crossmintgo get github.com/solana-foundation/solana-keychain/go/signers/dfns/v2 # Dfnsgo get github.com/solana-foundation/solana-keychain/go/signers/openfort/v2 # Openfortgo get github.com/solana-foundation/solana-keychain/go/signers/para/v2 # Parago get github.com/solana-foundation/solana-keychain/go/signers/utila/v2 # Utilago get github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2 # Fordefi
モジュールには go/<module>/v2.0.0 の形式(例: go/signers/memory/v2.0.0)でタグが付けられます。すべてのモジュールは Go 1.25.0 を必要としますが、gcpkms のみ、google.golang.org/api が設定した下限のため Go 1.25.8 を必要とします。Ledger は Rust 専用で、Go モジュールはありません。
solana-go v2 と v1 トランザクション
これらのモジュールは
github.com/solana-foundation/solana-go/v2
v2.0.0 上に構築されており、*solana.Transaction を受け取ります。レガシー、v0、v1(solana.MessageVersionV1)のトランザクションに対応しています。ただし、UseProgramCall: true を指定した Fireblocks はレガシーと v0 のみを受け付けます。
基本的な使い方
すべての signer は、基本の
core.SolanaSigner インターフェース
(Pubkey、SignMessage、IsAvailable)を実装します。メソッドは context.Context を受け取り、ブロッキングします。さらに各バックエンドは、次のケイパビリティインターフェースのうちちょうど 1 つを実装します:
core.TransactionSigner:SignTransactionは渡されたトランザクションにそのまま署名します。core.ModifyingSigner:ModifyAndSignTransactionはプロバイダーにトランザクションを書き換えさせたうえで署名します。core.SendingSigner:SignAndSendTransactionはプロバイダーに署名とブロードキャストを行わせます。
各バックエンドパッケージは Config 構造体と New コンストラクターを公開します:
import ("context""fmt""github.com/solana-foundation/solana-go/v2""github.com/solana-foundation/solana-keychain/go/core/v2""github.com/solana-foundation/solana-keychain/go/signers/memory/v2")func signWithKeychain(ctx context.Context, tx *solana.Transaction) error {signer, err := memory.New(memory.Config{PrivateKeyPath: "/path/to/id.json"})if err != nil {return err}if !signer.IsAvailable(ctx) {return core.NewSignerError(core.CodeNotAvailable, "signer offline")}result, err := signer.SignTransaction(ctx, tx)if err != nil {return err}fmt.Println("signature:", result.Signature)fmt.Println("complete:", result.IsComplete())// result.EncodedTransaction is the base64 wire transactionreturn nil}
SignTransaction と ModifyAndSignTransaction は core.SignedTransaction(EncodedTransaction、Signature、Completeness)を返します。リモート HTTP バックエンドは、オプションの HTTPClient と HTTPClientConfig(タイムアウト)を受け付けます。デフォルトのクライアントは HTTPS を強制します。独自のクライアントを指定するとこの制限は回避されるため、そのセキュリティ体制はご自身の責任となります。
Signer のケイパビリティ
トランザクションに署名できないバックエンドには SignTransaction メソッドがそもそも存在しないため、ケイパビリティは具象型ではコンパイル時に確定し、core.SolanaSigner では型アサーションで判定されます:
| バックエンド | ケイパビリティ | SignMessage |
|---|---|---|
| memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfort | TransactionSigner | 対応 |
| cdp | TransactionSigner | UTF-8 ペイロードのみ |
| utila | TransactionSigner | CodeSigningFailed で失敗 |
fordefi ブラックボックス (fordefi.BlackBoxSigner) | TransactionSigner | 対応 |
fordefi ネイティブ手動 (fordefi.NativeManualSigner) | ModifyingSigner | 対応 |
fordefi ネイティブ自動 (fordefi.NativeAutoSigner) | SendingSigner | 対応 |
| crossmint | SendingSigner | CodeSigningFailed で失敗 |
switch s := signer.(type) {case core.SendingSigner:sig, err := s.SignAndSendTransaction(ctx, tx)case core.ModifyingSigner:signed, err := s.ModifyAndSignTransaction(ctx, tx)case core.TransactionSigner:signed, err := s.SignTransaction(ctx, tx)}
初期化
個別の Init ステップはありません。Privy、Fireblocks、Dfns、Crossmint、Para、Openfort、Utila は New の内部でウォレットアドレスを解決するため、それらのコンストラクターは context.Context を受け取ります。signer は必ず New で構築してください。ゼロ値の Crossmint、Para、Utila の signer は、ゼロアドレスで署名するのではなく CodeNotInitialized で失敗します。
任意の Signer での署名と送信
core.SignAndSendTransaction は、signer の形態にかかわらずトランザクションをオンチェーンに送り込みます。SendingSigner はプロバイダー経由でブロードキャストし、send 関数は無視されます。それ以外の形態はすべて署名のみを行い、base64 の結果(ModifyingSigner の場合はプロバイダーが書き換えたトランザクション)をユーザーの関数がブロードキャストします。Core には RPC への依存関係がありません:
import "github.com/solana-foundation/solana-go/v2/rpc"client := rpc.New("https://api.devnet.solana.com")sig, err := core.SignAndSendTransaction(ctx, signer, tx,func(ctx context.Context, encoded string) (solana.Signature, error) {return client.SendEncodedTransaction(ctx, encoded)})
バッチ署名
バッチ署名は、レート制限のある API 向けにリクエストごとの任意の間隔(スタッガー)を指定できる、並行処理のフリーヘルパーとして提供されています:
sigs, err := core.SignMessages(ctx, signer, [][]byte{msg1, msg2}, core.BatchOptions{MaxConcurrency: 4, // 0 = unboundedRequestDelay: 50 * time.Millisecond,})signed, err := core.SignTransactions(ctx, signer, txs, core.BatchOptions{})
core.SignTransactions は core.TransactionSigner を受け取るため、ブロードキャスト管理型の signer(Crossmint、Fordefi ネイティブ自動)と Fordefi ネイティブ手動では、これを使ったバッチ処理はできません。これらは 1 トランザクションずつ呼び出してください。呼び出しによってプロバイダー側で処理が発生する signer(UseProgramCall を指定した Fireblocks)は、core.BatchServerSideEffects を通じてそれを報告し、その場合バッチは順次実行されます。
バックエンド設定
Memory
PrivateKey(生のバイト列)、PrivateKeyString(base58 または [1,2,...] 形式のバイト配列)、PrivateKeyPath(Solana CLI の keypair ファイル)のうち、ちょうど 1 つを指定します:
import "github.com/solana-foundation/solana-keychain/go/signers/memory/v2"signer, err := memory.New(memory.Config{PrivateKeyPath: "/path/to/id.json",})
Go には確実にメモリをゼロクリアする方法がありません。ガベージコレクターが、回収されるまで鍵のバイト列をコピーして保持する場合があります(memory の keypair や、Crossmint と Openfort がローカルで導出する鍵が該当します)。ローカル鍵バックエンドを使用する際は、プロセスのメモリ全体を機密として扱ってください。
HashiCorp Vault
import "github.com/solana-foundation/solana-keychain/go/signers/vault/v2"signer, err := vault.New(vault.Config{VaultAddr: "https://vault.example.com:8200",Token: "hvs.xxxxx",KeyName: "my-solana-key",Pubkey: "base58_public_key",})
AWS KMS
import "github.com/solana-foundation/solana-keychain/go/signers/awskms/v2"signer, err := awskms.New(ctx, awskms.Config{KeyID: "alias/my-solana-key",PublicKey: "base58_public_key",Region: "us-east-1", // optional})
GCP KMS
import "github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2"signer, err := gcpkms.New(ctx, gcpkms.Config{KeyName: "projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",PublicKey: "base58_public_key",})if err != nil {return err}defer signer.Close()
Privy
import "github.com/solana-foundation/solana-keychain/go/signers/privy/v2"signer, err := privy.New(ctx, privy.Config{AppID: "app_id",AppSecret: "app_secret",WalletID: "wallet_id",})
Turnkey
import "github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2"signer, err := turnkey.New(turnkey.Config{APIPublicKey: "api_public_key",APIPrivateKey: "api_private_key",OrganizationID: "org_id",PrivateKeyID: "private_key_id",PublicKey: "base58_public_key",})
Fireblocks
import "github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2"signer, err := fireblocks.New(ctx, fireblocks.Config{APIKey: "api_key",PrivateKeyPEM: "-----BEGIN RSA PRIVATE KEY-----\n...",VaultAccountID: "0",AssetID: "SOL", // or "SOL_TEST" for devnetUseProgramCall: false, // true signs via sign-only PROGRAM_CALL (legacy/v0, hot wallet)})
CDP (Coinbase Developer Platform)
import "github.com/solana-foundation/solana-keychain/go/signers/cdp/v2"signer, err := cdp.New(cdp.Config{APIKeyID: "api_key_id",APIKeySecret: "api_key_secret", // base64 Ed25519WalletSecret: "wallet_secret", // base64 PKCS#8 DERAddress: "base58_address",Network: cdp.NetworkMainnet, // or cdp.NetworkDevnet; required for address lookup tables})
CDP の SignMessage は UTF-8 ペイロードのみを受け付けます。
Crossmint
Crossmint は送信専用です。その API は承認されたすべてのトランザクションをサーバー側で実行するため、*crossmint.Signer には SignAndSendTransaction があり、SignTransaction はありません。トランザクションが変更されることはありません。返される署名は Crossmint が着地させたトランザクションを識別するもので、Crossmint がガス代をスポンサーする場合は、ご自身のトランザクションの署名と異なることがあります。
import "github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2"signer, err := crossmint.New(ctx, crossmint.Config{APIKey: "api_key",WalletLocator: "wallet_locator",SignerSecret: "", // optional xmsk1_ secret: auto-approves what Crossmint presents})sig, err := signer.SignAndSendTransaction(ctx, tx)
Dfns
import "github.com/solana-foundation/solana-keychain/go/signers/dfns/v2"signer, err := dfns.New(ctx, dfns.Config{AuthToken: "auth_token",CredID: "cred_id",PrivateKeyPEM: "-----BEGIN EC PRIVATE KEY-----\n...",WalletID: "wallet_id",})
Openfort
import "github.com/solana-foundation/solana-keychain/go/signers/openfort/v2"signer, err := openfort.New(ctx, openfort.Config{SecretKey: "sk_live_...",AccountID: "acc_...",WalletSecret: "wallet_secret", // base64 PKCS#8 DER or PEM})
Para
import "github.com/solana-foundation/solana-keychain/go/signers/para/v2"signer, err := para.New(ctx, para.Config{APIKey: "sk_...",WalletID: "wallet_id",})
Utila
Utila は署名のみを行います。SignMessage は失敗するため、署名済みトランザクションはご自身でブロードキャストしてください。
import "github.com/solana-foundation/solana-keychain/go/signers/utila/v2"signer, err := utila.New(ctx, utila.Config{ServiceAccountEmail: "sa@example.com",ServiceAccountPrivateKeyPEM: "-----BEGIN PRIVATE KEY-----\n...",VaultID: "vault_id",WalletID: "wallet_id",Network: "networks/solana-devnet",})
Fordefi
Fordefi には 3 種類の signer タイプがあり、Config.Chain と Config.PushMode によって構築時に決まります。3 つともメッセージに署名できます:
| 設定 | 型 | エントリーポイント |
|---|---|---|
Chain 未設定 | *fordefi.BlackBoxSigner | SignTransaction |
Chain 設定済み、PushMode 未設定または PushModeAuto | *fordefi.NativeAutoSigner | SignAndSendTransaction |
Chain 設定済み、PushMode: PushModeManual | *fordefi.NativeManualSigner | ModifyAndSignTransaction |
fordefi.New は設定に応じて振り分け、core.SolanaSigner を返します。fordefi.NewBlackBox、fordefi.NewNativeAuto、fordefi.NewNativeManual は具象型を返し、他のモードの設定は拒否します。API リクエストは ECDSA P-256 のリクエスト署名で認証されます。PrivateKeyPEM か、鍵を KMS/HSM に保持するための RequestSigner のうち、ちょうど 1 つを指定してください。
ネイティブ自動モード: Fordefi はブロックハッシュと手数料を置き換えたうえで、署名してブロードキャストする場合があります。受け付けるのは、必要な署名者がボルトのみである未署名のトランザクションに限られます。
import "github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2"signer, err := fordefi.NewNativeAuto(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"), // Solana vault address (base58)PrivateKeyPEM: string(pemBytes),Chain: fordefi.ChainSolanaDevnet, // or fordefi.ChainSolanaMainnetFee: &fordefi.Fee{Type: fordefi.FeeTypePriority,PriorityLevel: fordefi.PriorityMedium,},})sig, err := signer.SignAndSendTransaction(ctx, tx)
ネイティブ手動モード: PushMode: fordefi.PushModeManual を設定します。Fordefi はメッセージ(最新のブロックハッシュ、Compute Budget の手数料 instructions)を書き換え、ブロードキャストせずに署名します。ModifyAndSignTransaction は tx を Fordefi が署名したトランザクションで置き換えます。以降は必ずそのトランザクションを使って続行してください。Fordefi は手数料支払者である必要があり、書き換えによって既存の署名が無効になるため、他の必要な署名者より先に署名しなければなりません。書き換え内容の差分は取得されないため、ブロードキャストの前に結果を確認してください。
signer, err := fordefi.NewNativeManual(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"),PrivateKeyPEM: string(pemBytes),Chain: fordefi.ChainSolanaDevnet,PushMode: fordefi.PushModeManual,})signed, err := signer.ModifyAndSignTransaction(ctx, tx)
ブラックボックスモード: Chain を未設定にします。Fordefi はメッセージのバイト列をそのまま署名し、ブロードキャストは行いません。Fordefi のブラックボックスボルトと組み合わせて使用します。
signer, err := fordefi.NewBlackBox(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_BB_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_BB_PUBLIC_KEY"),PrivateKeyPEM: string(pemBytes),})
アンブレラパッケージが存在しない理由
Rust には Signer enum、TypeScript には createKeychainSigner がありますが、Go には意図的にどちらもありません。Go はランタイムのディスパッチ switch をまたいだデッドコードの除去を行わないため、アンブレラパッケージを用意すると、すべてのバックエンドのベンダー SDK(AWS、GCP など)があらゆる利用者のビルドに含まれてしまいます。必要なバックエンドパッケージをインポートすること自体がセレクターです。実行時にバックエンドを選ぶ場合は、対応するバックエンドだけを対象とした switch をご自身のコードに書き、結果を core.SolanaSigner として保持してください。
エラー処理
すべてのエラーは、安定した Code(CodeConfigError、CodeHTTPError、CodeRemoteAPIError、CodeSigningFailed、CodeNotInitialized、CodeBroadcastUnconfirmed など)を持つ *core.SignerError です。Error() はコードごとに固定のメッセージのみを返し、鍵素材やプロバイダーの生のレスポンスは返しません。errors.As、errors.Is(err, &core.SignerError{Code: ...})、または core.CodeOf(err) で照合してください。
Crossmint と Fordefi ネイティブ自動モードでは、失敗してもトランザクションが何も反映されていないとは限りません。プロバイダーがトランザクションを受け付けた可能性がある場合、コードは core.CodeBroadcastUnconfirmed("SIGNER_BROADCAST_UNCONFIRMED")になります。作成が受け付けられた場合は ProviderTxID が設定され、IdempotencyKey にはメッセージから導出されたキーが入ります。バイト単位で同一のトランザクションを再送しても安全ですが、再構築したもの(たとえば新しいブロックハッシュを使ったもの)は新しい送金になります。core.SignAndSendTransaction も、send 関数が失敗した場合にこのコードを報告し、TransactionSignature に手数料支払者の署名を含めます。Fireblocks の PROGRAM_CALL は署名専用でキーを送信しません。このコードを報告するのは、ポーリングで Fireblocks がそれでもブロードキャストしたことが判明した場合のみです。
sig, err := core.SignAndSendTransaction(ctx, signer, tx, send)var se *core.SignerErrorif errors.As(err, &se) && se.Code == core.CodeBroadcastUnconfirmed {// Reconcile se.ProviderTxID, se.IdempotencyKey or se.TransactionSignature// with the provider before retrying.}
各署名形態が何を保証するかについては セキュリティモデル 、モジュールの全一覧については Go README 、API リファレンスについては pkg.go.dev をご覧ください。
カスタム Signer の追加
core.SolanaSigner と、ケイパビリティインターフェースをちょうど 1 つ実装し、バックエンドが対応できないメソッドは追加しないでください。呼び出し側は型アサーションでケイパビリティを検出します。追加のキー管理サービスを統合するには、Signer 追加ガイドをご覧ください。
Is this page helpful?