バージョン2.0は、Pythonパッケージの最初の安定版リリースです。 2.0移行ガイド では、RustおよびTypeScriptと共通の署名の形式について説明しています。
インストール
ベースパッケージをインストールし、プロバイダーの依存関係が必要なバックエンドごとに、extraを1つずつ追加でインストールします。
pip install solana-keychain # memory, vault and parapip install 'solana-keychain[aws-kms]' # AWS KMS (boto3)pip install 'solana-keychain[gcp-kms]' # GCP KMS (google-cloud-kms)pip install 'solana-keychain[privy]' # Privypip install 'solana-keychain[turnkey]' # Turnkeypip install 'solana-keychain[fireblocks]' # Fireblockspip install 'solana-keychain[cdp]' # Coinbase Developer Platformpip install 'solana-keychain[crossmint]' # Crossmintpip install 'solana-keychain[dfns]' # Dfnspip install 'solana-keychain[openfort]' # Openfortpip install 'solana-keychain[utila]' # Utilapip install 'solana-keychain[fordefi]' # Fordefi# Several at oncepip install 'solana-keychain[aws-kms,privy]'
Python 3.10以降が必要です。トランザクションは
solders の VersionedTransaction オブジェクトです。
レガシー、v0、v1のメッセージはすべて受け付けられますが、
use_program_call=True を指定したFireblocksだけは、レガシーとv0のみを受け付けます。
Memory、Vault、Paraはパッケージのルートからインポートできます。それ以外のバックエンドは
すべて、それぞれのサブモジュール(例: solana_keychain.aws_kms)からインポートします。
extraなしでインポートすると、インストールすべきextraの名前を示す ImportError が発生します。
LedgerはRust専用です。
基本的な使い方
各バックエンドには、設定用のdataclassと、すぐに使えるsignerを返す非同期の
create_<backend>_signer ファクトリがあります。署名メソッドはすべてコルーチンです。
import asynciofrom solana_keychain import MemorySignerfrom solders.transaction import VersionedTransactionasync def sign(transaction: VersionedTransaction) -> str:signer = MemorySigner.from_private_key_file("/path/to/id.json")print("Signing with:", signer.pubkey)# Check availability (useful for remote signers)if not await signer.is_available():raise RuntimeError("Signer offline")result = await signer.sign_transaction(transaction)print("Signature:", result.signature)print("Fully signed:", result.is_complete)return result.encoded_transaction # base64 wire transaction
sign_transaction は、encoded_transaction、signature、is_complete、
transaction を持つ SignedTransaction を返します。transaction は信頼できる
署名済みトランザクションです。特にトランザクションを変更するsignerの場合、
結果は渡したオブジェクトとは別のオブジェクトになるため、以降はこの transaction を使用してください。
統合ファクトリ
create_keychain_signer は、バックエンド名とそのバックエンドの設定dataclassを受け取り、
バックエンドを遅延インポートします。そのため、使用するextraだけをインストールすれば済みます。
from solana_keychain import create_keychain_signerfrom solana_keychain.privy import PrivySignerConfigsigner = await create_keychain_signer("privy",PrivySignerConfig(app_id="your-app-id",app_secret="your-app-secret",wallet_id="your-wallet-id",),)
使用できる名前は SUPPORTED_BACKENDS に一覧されています: aws-kms、cdp、crossmint、
dfns、fireblocks、fordefi、gcp-kms、memory、openfort、para、
privy、turnkey、utila、vault。未知の名前や、クラスが一致しない設定を渡すと、
SignerErrorCode.CONFIG_ERROR を持つ SignerError が発生します。
このファクトリの戻り値の型は基底クラスの SolanaSigner であるため、署名の前に
isinstance で絞り込んでください(Signerの機能を参照)。
リモートHTTPクライアント
リモートHTTPバックエンドは、カスタムTLSやプロキシ用に、オプションの http_client
(httpx.AsyncClient)を受け付けます。未設定の場合、各リクエストは1回限りのクライアントを使用し、
タイムアウトは60秒、ベースURLにはHTTPSが強制され、リダイレクトは拒否されます。
Signerの機能
すべてのバックエンドは SolanaSigner ABC(pubkey、sign_message、
is_available)を継承し、さらにちょうど1つの機能クラスを継承します。
TransactionSigner:sign_transaction(tx)は、渡されたトランザクションをその場で署名し、SignedTransactionを返します。ブロードキャストは自分で行います。ModifyingSigner:modify_and_sign_transaction(tx)は、プロバイダーによるトランザクションの 書き換えを許可したうえで、ブロードキャストせずに署名します。渡したオブジェクトは 変更されません。返されたSignedTransaction.transactionを使って続行してください。SendingSigner:sign_and_send_transaction(tx)は、プロバイダー経由で署名とブロードキャストを行い、 反映されたトランザクションのSignatureを返します。渡したトランザクションが 変更されることはありません。
| バックエンド | 機能クラス | sign_message |
|---|---|---|
| memory, vault, privy, turnkey, aws-kms, fireblocks, gcp-kms, dfns, para, openfort | TransactionSigner | 対応 |
| cdp | TransactionSigner | UTF-8ペイロードのみ。それ以外は SERIALIZATION_ERROR |
| utila | TransactionSigner | SIGNING_FAILED が発生 |
fordefi black box(FordefiBlackBoxSigner) | TransactionSigner | 対応 |
fordefi native manual(FordefiNativeManualSigner) | ModifyingSigner | 対応 |
fordefi native auto(FordefiNativeAutoSigner) | SendingSigner | 対応 |
| crossmint | SendingSigner | SIGNING_FAILED が発生 |
isinstance で絞り込みます。すべての機能クラスはパッケージのルートからエクスポートされています。
from solana_keychain import ModifyingSigner, SendingSigner, TransactionSignerif isinstance(signer, SendingSigner):signature = await signer.sign_and_send_transaction(transaction)elif isinstance(signer, ModifyingSigner):result = await signer.modify_and_sign_transaction(transaction)elif isinstance(signer, TransactionSigner):result = await signer.sign_transaction(transaction)
初期化
create_* ファクトリと create_keychain_signer は、必要なセットアップを自動的に行います。
Privy、Fireblocks、Dfns、Crossmint、Para、Openfort、Utilaのsignerクラスを直接生成する場合は、
使用前に await signer.init() を呼び出してください。それまでは、pubkey とすべての署名呼び出しで
SignerErrorCode.NOT_INITIALIZED が発生します。
バックエンドの設定
Memory
Solana CLIのkeypairファイル、base58または "[1,2,...]" 形式の文字列、生のバイト列、
あるいは solders の Keypair から構築できます。
from solana_keychain import MemorySigner, MemorySignerConfig, create_memory_signerfrom solders.keypair import Keypairsigner = MemorySigner.from_private_key_file("/path/to/id.json")signer = MemorySigner.from_private_key_string("base58_private_key")signer = MemorySigner.from_bytes(secret_key_bytes) # 64 or 32 bytessigner = await create_memory_signer(MemorySignerConfig(keypair=Keypair()))
キーはプロセスのメモリ上に保持され、Pythonではゼロ化できません。このバックエンドは 開発とテストにのみ使用してください。
HashiCorp Vault
キーはtransitエンジン内のed25519キーである必要があります。プレーンHTTPは、
vault server -dev 用のループバックアドレスの場合にのみ受け付けられます。
from solana_keychain import VaultSignerConfig, create_vault_signersigner = await create_vault_signer(VaultSignerConfig(api_base_url="https://vault.example.com:8200",token="hvs.xxxxx",key_name="my-solana-key",public_key="base58_public_key",))
AWS KMS
key_id は、ECC_NIST_EDWARDS25519 キーのキーID、ARN、またはエイリアスです。カスタムの認証情報や
エンドポイントを使う場合は、構築済みのboto3 KMS client を渡してください。その場合、region は
無視されます。
from solana_keychain.aws_kms import AwsKmsSignerConfig, create_aws_kms_signersigner = await create_aws_kms_signer(AwsKmsSignerConfig(key_id="alias/my-solana-key",public_key="base58_public_key",region="us-east-1", # optional, defaults to the AWS config chain))
GCP KMS
キーバージョンは EC_SIGN_ED25519 キーである必要があります。client には、構築済みの
KeyManagementServiceAsyncClient を任意で渡せます。
from solana_keychain.gcp_kms import GcpKmsSignerConfig, create_gcp_kms_signersigner = await create_gcp_kms_signer(GcpKmsSignerConfig(key_name="projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",public_key="base58_public_key",))
Privy
from solana_keychain.privy import PrivySignerConfig, create_privy_signersigner = await create_privy_signer(PrivySignerConfig(app_id="app_id",app_secret="app_secret",wallet_id="wallet_id",))
認可キーで保護されたウォレットでは、PrivyAuthorizationConfig を
authorization_context として渡します。
Turnkey
from solana_keychain.turnkey import TurnkeySignerConfig, create_turnkey_signersigner = await create_turnkey_signer(TurnkeySignerConfig(api_public_key="api_public_key", # hex P-256api_private_key="api_private_key", # hex P-256organization_id="org_id",private_key_id="private_key_id",public_key="base58_public_key",))
Fireblocks
from solana_keychain.fireblocks import FireblocksSignerConfig, create_fireblocks_signersigner = await create_fireblocks_signer(FireblocksSignerConfig(api_key="api_key",private_key_pem="-----BEGIN RSA PRIVATE KEY-----\n...",vault_account_id="0",asset_id="SOL", # or "SOL_TEST" for devnet))
use_program_call=True を指定すると、RAWの代わりにPROGRAM_CALLオペレーションで署名します。
署名のみで送信されるため、Fireblocksはトランザクションの書き換えもブロードキャストも行わず、
ブロードキャストはこれまでどおり自分で行います。ホットウォレットが必要で、Fireblocks側で
ワークスペースに対して有効化してもらう必要があります。
CDP(Coinbase Developer Platform)
from solana_keychain.cdp import CdpSignerConfig, create_cdp_signersigner = await create_cdp_signer(CdpSignerConfig(api_key_id="api_key_id",api_key_secret="api_key_secret",wallet_secret="wallet_secret",address="base58_address",network="solana", # or "solana-devnet"; required for address lookup tables))
Crossmint
from solana_keychain.crossmint import CrossmintSignerConfig, create_crossmint_signersigner = await create_crossmint_signer(CrossmintSignerConfig(api_key="api_key",wallet_locator="wallet_locator",))signature = await signer.sign_and_send_transaction(transaction)
Crossmintは送信専用です。そのAPIは、承認されたトランザクションを常にサーバーサイドで実行し、
ガス代をスポンサーするため、CrossmintSigner は SendingSigner であり、
sign_message は SIGNING_FAILED を発生させます。返される署名は、Crossmintが反映した
トランザクションを識別するもので、渡したものとは異なる場合があります。
signer_secret(xmsk1_... 形式のdelegated-signerシークレット)を設定すると、
トランザクションが自動的に承認されます。これは、何を承認するかの判断をCrossmintに委ねることを意味します。
Dfns
from solana_keychain.dfns import DfnsSignerConfig, create_dfns_signersigner = await create_dfns_signer(DfnsSignerConfig(auth_token="auth_token",cred_id="cred_id",private_key_pem="-----BEGIN EC PRIVATE KEY-----\n...",wallet_id="wallet_id",))
Openfort
from solana_keychain.openfort import OpenfortSignerConfig, create_openfort_signersigner = await create_openfort_signer(OpenfortSignerConfig(secret_key="sk_...",account_id="acc_...",wallet_secret="wallet_secret",))
Para
from solana_keychain import ParaSignerConfig, create_para_signersigner = await create_para_signer(ParaSignerConfig(api_key="sk_...",wallet_id="wallet_uuid",))
Utila
Utilaはトランザクションの署名のみに対応しており、sign_message は SIGNING_FAILED を発生させます。
from solana_keychain.utila import UtilaSignerConfig, create_utila_signersigner = await create_utila_signer(UtilaSignerConfig(service_account_email="sa@example.com",service_account_private_key_pem="-----BEGIN PRIVATE KEY-----\n...",vault_id="vault_id",wallet_id="wallet_id",network="networks/solana-devnet",))
Fordefi
Fordefiには3つの署名モードがあり、構築時に chain と push_mode によって決まります。
create_fordefi_signer が適切なクラスを選択し、各クラスは他のモード向けの設定を拒否します。
メッセージの署名は3つすべてで可能です。
| モード | 設定 | クラス | メソッド |
|---|---|---|---|
| Black box | chain 未設定 | FordefiBlackBoxSigner | sign_transaction |
| Native auto | chain 設定済み、push_mode 未設定または "auto" | FordefiNativeAutoSigner | sign_and_send_transaction |
| Native manual | chain 設定済み、push_mode="manual" | FordefiNativeManualSigner | modify_and_sign_transaction |
APIリクエストは、ECDSA P-256のリクエスト署名で認証されます。キーを private_key_pem として
指定するか、FordefiRequestSigner のサブクラスを request_signer として渡して、
KMS/HSM内でキーを保持してください。
Native autoモード: chain("solana_devnet" または "solana_mainnet")を設定すると、
Fordefiがブロックハッシュと手数料を置き換える場合があり、その後トランザクションの署名と
ブロードキャストをFordefi自身が行います。受け付けるのは、必要な署名者がvaultのみである
未署名のトランザクションに限られます。fee はそのままFordefiに渡されます。
import osfrom solana_keychain.fordefi import FordefiSignerConfig, create_fordefi_signersigner = await create_fordefi_signer(FordefiSignerConfig(access_token=os.environ["FORDEFI_ACCESS_TOKEN"],vault_id=os.environ["FORDEFI_VAULT_ID"],public_key=os.environ["FORDEFI_PUBLIC_KEY"], # vault address (base58)private_key_pem=open("./secret/private.pem").read(),chain="solana_devnet",fee={"type": "custom", "priority_fee": "1000"}, # optional))signature = await signer.sign_and_send_transaction(transaction)
Native manualモード: chain を設定し、push_mode="manual" を指定します。Fordefiは
メッセージ(最近のブロックハッシュ、Compute Budgetの手数料命令)を書き換えて署名しますが、
ブロードキャストは行いません。返されるトランザクションは、送信したものを置き換えるため、
必ず result.transaction から続行してください。Fordefiは手数料支払者であり、他の必要な署名者より
先に署名する必要があります。すでに署名が含まれているトランザクションも受け付けられますが、
書き換えによってそれらの署名は無効になります。書き換え内容の差分は提供されないため、
ブロードキャストの前に結果を確認し、速やかにブロードキャストしてください。Fordefiは新しい
ブロックハッシュの有効期限の高さを返しません。
signer = await create_fordefi_signer(FordefiSignerConfig(access_token=os.environ["FORDEFI_ACCESS_TOKEN"],vault_id=os.environ["FORDEFI_VAULT_ID"],public_key=os.environ["FORDEFI_PUBLIC_KEY"],private_key_pem=open("./secret/private.pem").read(),chain="solana_devnet",push_mode="manual",))result = await signer.modify_and_sign_transaction(transaction)... # inspect result.transaction, then add any remaining signatures
確認したトランザクションは、署名と送信と同様にブロードキャストし、 送信に失敗した場合は、再試行する前に状態を照合してください。
Black boxモード: chain を省略します。Fordefiは渡されたメッセージのバイト列をそのまま
署名し、ブロードキャストは行いません。Fordefi black box vaultで使用してください。
signer = await create_fordefi_signer(FordefiSignerConfig(access_token=os.environ["FORDEFI_ACCESS_TOKEN"],vault_id=os.environ["FORDEFI_BB_VAULT_ID"],public_key=os.environ["FORDEFI_BB_PUBLIC_KEY"],private_key_pem=open("./secret/private.pem").read(),))
署名と送信
sign_and_send_transaction は、signerの形式に関係なく、トランザクションをオンチェーンに反映させます。
SendingSigner はプロバイダー経由でブロードキャストし、送信関数は一切呼び出されません。
TransactionSigner または ModifyingSigner は署名を行い、送信関数が base64 エンコードされた結果を
ブロードキャストします(このパッケージにはRPCクライアントは含まれていません)。
import httpxfrom solana_keychain import sign_and_send_transactionfrom solders.signature import Signatureasync def send(encoded: str) -> Signature:async with httpx.AsyncClient() as client:response = await client.post("https://api.devnet.solana.com",json={"jsonrpc": "2.0","id": 1,"method": "sendTransaction","params": [encoded, {"encoding": "base64"}],},)return Signature.from_string(response.json()["result"])signature = await sign_and_send_transaction(signer, transaction, send)
署名のみのsignerで送信関数がない場合は CONFIG_ERROR が発生し、署名後も署名が不足している
トランザクションでは SIGNING_FAILED が発生します。
エラー処理
すべての失敗は、SignerErrorCode の安定した code を持つ SignerError として発生します:
BROADCAST_UNCONFIRMED、CONFIG_ERROR、EXPECTED_SOLANA_SIGNER、HTTP_ERROR、
INVALID_PRIVATE_KEY、INVALID_PUBLIC_KEY、IO_ERROR、NOT_AVAILABLE、
NOT_INITIALIZED、OTHER、PARSING_ERROR、REMOTE_API_ERROR、
SERIALIZATION_ERROR、SIGNING_FAILED。メッセージではなく code で判定してください。
str() と repr() には固定の汎用メッセージのみが含まれ、キー素材やプロバイダーの生のレスポンスが
含まれることはありません。status_code と provider_error_code は、失敗がプロバイダーの
レスポンスに起因する場合に設定されます。
SignerErrorCode.BROADCAST_UNCONFIRMED("SIGNER_BROADCAST_UNCONFIRMED")は、
トランザクションが反映された可能性があることを意味します。
- CrossmintおよびFordefi native autoでは、作成リクエストが受理された時点で
provider_transaction_idが設定され、idempotency_keyには、作成リクエストの送信時に 使用されたメッセージから導出されたキーが格納されます。バイト単位で同一のトランザクションを 再送しても安全ですが、再構築したもの(たとえば新しいブロックハッシュを使ったもの)は 新しい送金として扱われます。 sign_and_send_transactionで送信関数が失敗した場合、完了したトランザクションの署名をtransaction_signatureに設定してこのエラーが発生します。- Fireblocksがこのエラーを発生させるのは、署名のみで送信したにもかかわらず、
ポーリングの結果、Fireblocksが
use_program_callのトランザクションを ブロードキャストしたことが判明した場合だけです。
from solana_keychain import SignerError, SignerErrorCodetry:signature = await sign_and_send_transaction(signer, transaction, send)except SignerError as error:if error.code is SignerErrorCode.BROADCAST_UNCONFIRMED:reconcile(error.provider_transaction_id,error.idempotency_key,error.transaction_signature,)raise
キャンセルされた呼び出しは、フィールドを持たない asyncio.CancelledError を再度発生させます。
キャンセル前にプロバイダーが受理したIDを回収するには、solana_keychain.core の
PendingTransactionId() をCrossmintまたはFordefi native autoの設定の
pending_transaction_id として渡し、キャンセル後に .get() を読み取ります。
再試行する前に、プロバイダーと状態を照合してください。
Keychainが検証するのは署名の経路であり、トランザクションの内容ではありません。 プロバイダーが返した署名は、添付される前に、ローカルで計算したメッセージに対してed25519で検証されます。 Pythonではキーのバッファをゼロ化できないため、ローカルキーのバックエンド(Memory、および リモートバックエンドの設定に保持されるAPIキーとPEM)では、プロセスのメモリ全体を 機密として扱ってください。各署名形式が何を保証するかについては、 セキュリティモデル を参照してください。
カスタムSignerの追加
バックエンドに対応する機能クラス(TransactionSigner、ModifyingSigner、SendingSigner のいずれか)を solana_keychain.core からサブクラス化してください。追加のキー管理サービスを統合する方法については、署名者の追加ガイドをご覧ください。
リソース
Is this page helpful?