Versi 2.0 adalah rilis stabil pertama dari paket Python ini. Panduan migrasi 2.0 membahas bentuk penandatanganan yang sama dengan Rust dan TypeScript.
Instalasi
Instal paket dasar, ditambah satu extra untuk setiap backend yang membutuhkan dependensi provider:
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]'
Membutuhkan Python 3.10 atau yang lebih baru. Transaksi berupa objek
solders VersionedTransaction;
pesan legacy, v0, dan v1 semuanya diterima, kecuali oleh Fireblocks dengan
use_program_call=True, yang hanya menerima legacy dan v0.
Memory, Vault, dan Para dapat diimpor dari root paket. Setiap backend lainnya
diimpor dari submodulnya sendiri (misalnya solana_keychain.aws_kms), dan
mengimpor salah satunya tanpa extra-nya akan memunculkan ImportError yang menyebutkan extra yang
harus diinstal. Ledger hanya tersedia untuk Rust.
Penggunaan Dasar
Setiap backend memiliki dataclass konfigurasi dan factory async create_<backend>_signer
yang mengembalikan signer siap pakai. Semua metode penandatanganan adalah coroutine:
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 mengembalikan SignedTransaction dengan encoded_transaction,
signature, is_complete, dan transaction. transaction adalah transaksi
bertanda tangan yang otoritatif: lanjutkan dari objek ini, terutama dengan signer yang memodifikasi, yang
hasilnya merupakan objek berbeda dari yang Anda teruskan.
Factory Terpadu
create_keychain_signer menerima nama backend dan dataclass konfigurasi backend tersebut,
lalu mengimpor backend secara lazy, sehingga hanya extra yang Anda gunakan yang perlu
diinstal:
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",),)
Nama-nama tersebut tercantum di SUPPORTED_BACKENDS: aws-kms, cdp, crossmint,
dfns, fireblocks, fordefi, gcp-kms, memory, openfort, para,
privy, turnkey, utila, dan vault. Nama yang tidak dikenal, atau konfigurasi dengan
kelas yang salah, memunculkan SignerError dengan SignerErrorCode.CONFIG_ERROR. Factory
diketik sebagai pengembali SolanaSigner dasar, jadi persempit dengan
isinstance sebelum menandatangani (lihat Kapabilitas Signer).
Klien HTTP Jarak Jauh
Backend HTTP jarak jauh menerima http_client opsional (sebuah httpx.AsyncClient)
untuk TLS atau proxy kustom. Jika tidak diatur, setiap permintaan menggunakan klien sekali pakai
dengan batas waktu 60 detik, HTTPS diwajibkan pada URL dasar, dan pengalihan
(redirect) ditolak.
Kapabilitas Signer
Setiap backend merupakan subkelas dari ABC SolanaSigner (pubkey, sign_message,
is_available) ditambah tepat satu kelas kapabilitas:
TransactionSigner:sign_transaction(tx)menandatangani transaksi Anda di tempat dan mengembalikanSignedTransaction. Anda yang menyiarkannya.ModifyingSigner:modify_and_sign_transaction(tx)memungkinkan provider menulis ulang transaksi, lalu menandatanganinya tanpa menyiarkan. Objek Anda dibiarkan tidak berubah; lanjutkan dariSignedTransaction.transactionyang dikembalikan.SendingSigner:sign_and_send_transaction(tx)menandatangani dan menyiarkan melalui provider, lalu mengembalikanSignaturedari transaksi yang berhasil masuk. Transaksi Anda tidak pernah dimutasi.
| Backend | Kelas kapabilitas | sign_message |
|---|---|---|
| memory, vault, privy, turnkey, aws-kms, fireblocks, gcp-kms, dfns, para, openfort | TransactionSigner | Ya |
| cdp | TransactionSigner | Hanya payload UTF-8, selain itu SERIALIZATION_ERROR |
| utila | TransactionSigner | Memunculkan SIGNING_FAILED |
fordefi black box (FordefiBlackBoxSigner) | TransactionSigner | Ya |
fordefi native manual (FordefiNativeManualSigner) | ModifyingSigner | Ya |
fordefi native auto (FordefiNativeAutoSigner) | SendingSigner | Ya |
| crossmint | SendingSigner | Memunculkan SIGNING_FAILED |
Persempit dengan isinstance. Semua kelas kapabilitas diekspor dari root
paket:
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)
Inisialisasi
Factory create_* dan create_keychain_signer melakukan semua penyiapan yang diperlukan
untuk Anda. Jika Anda membuat kelas signer Privy, Fireblocks, Dfns, Crossmint, Para, Openfort, atau
Utila secara langsung, panggil await signer.init() sebelum digunakan. Sebelum itu,
pubkey dan setiap pemanggilan penandatanganan akan memunculkan SignerErrorCode.NOT_INITIALIZED.
Konfigurasi Backend
Memory
Buat dari file keypair Solana CLI, string base58 atau "[1,2,...]", byte
mentah, atau Keypair dari solders:
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()))
Kunci berada di memori proses, dan Python tidak dapat menghapusnya dengan zeroize. Gunakan backend ini untuk pengembangan dan pengujian.
HashiCorp Vault
Kunci harus berupa kunci ed25519 di transit engine. HTTP biasa hanya diterima
untuk alamat loopback, untuk 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 adalah ID kunci, ARN, atau alias untuk kunci ECC_NIST_EDWARDS25519. Teruskan
client KMS boto3 yang sudah dibuat untuk kredensial atau endpoint kustom; region
lalu diabaikan:
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
Versi kunci harus berupa kunci EC_SIGN_ED25519. client secara opsional menerima
KeyManagementServiceAsyncClient yang sudah dibuat:
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",))
Wallet yang dilindungi oleh kunci otorisasi menerima PrivyAuthorizationConfig sebagai
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 menandatangani dengan operasi PROGRAM_CALL, bukan RAW. Operasi ini
dikirim hanya untuk ditandatangani, sehingga Fireblocks tidak menulis ulang maupun menyiarkan
transaksi, dan Anda menyiarkannya seperti biasa. Opsi ini memerlukan hot wallet dan harus
diaktifkan untuk workspace Anda oleh 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 hanya mendukung pengiriman. API-nya selalu mengeksekusi transaksi yang disetujui
di sisi server dan menanggung gas, sehingga CrossmintSigner adalah SendingSigner dan
sign_message memunculkan SIGNING_FAILED. Signature yang dikembalikan mengidentifikasi
transaksi yang diteruskan Crossmint, yang mungkin berbeda dari transaksi Anda. Mengatur
signer_secret (secret delegated-signer berformat xmsk1_...) akan menyetujui transaksi
secara otomatis, yang berarti pilihan tentang apa yang disetujui didelegasikan kepada 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 hanya menandatangani transaksi; sign_message memunculkan 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 memiliki tiga mode penandatanganan, yang ditetapkan saat konstruksi oleh chain dan
push_mode. create_fordefi_signer memilih kelasnya, setiap kelas menolak
konfigurasi yang ditujukan untuk kelas lain, dan ketiganya dapat menandatangani pesan:
| Mode | Konfigurasi | Kelas | Metode |
|---|---|---|---|
| Black box | chain tidak diatur | FordefiBlackBoxSigner | sign_transaction |
| Native auto | chain diatur, push_mode tidak diatur atau "auto" | FordefiNativeAutoSigner | sign_and_send_transaction |
| Native manual | chain diatur, push_mode="manual" | FordefiNativeManualSigner | modify_and_sign_transaction |
Permintaan API diautentikasi dengan tanda tangan permintaan ECDSA P-256: berikan
kunci sebagai private_key_pem, atau simpan di KMS/HSM dengan meneruskan subkelas
FordefiRequestSigner sebagai request_signer.
Mode native auto: atur chain ("solana_devnet" atau "solana_mainnet"), dan
Fordefi dapat mengganti blockhash dan biaya, lalu menandatangani dan menyiarkan
transaksi itu sendiri. Mode ini hanya menerima transaksi yang belum ditandatangani dengan satu-satunya
signer yang diperlukan adalah vault. fee diteruskan ke Fordefi apa adanya:
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)
Mode native manual: atur chain dan push_mode="manual". Fordefi menulis ulang
pesan (blockhash terbaru, instruksi biaya Compute Budget) dan menandatanganinya,
tetapi tidak menyiarkannya. Transaksi yang dikembalikan menggantikan transaksi yang Anda kirimkan,
jadi selalu lanjutkan dari result.transaction. Fordefi harus menjadi pembayar biaya dan
harus menandatangani sebelum signer lain yang diperlukan: transaksi yang sudah memuat
tanda tangan tetap diterima, tetapi penulisan ulang membatalkannya. Penulisan ulang tidak di-diff,
jadi periksa hasilnya sebelum menyiarkan, dan siarkan segera, karena Fordefi
tidak mengembalikan tinggi kedaluwarsa blockhash yang baru.
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
Siarkan transaksi yang sudah diperiksa seperti pada Tanda Tangan dan Kirim, dan lakukan rekonsiliasi sebelum mencoba ulang jika pengiriman gagal.
Mode black box: abaikan chain. Fordefi menandatangani byte pesan Anda persis apa adanya dan
tidak menyiarkan. Gunakan mode ini dengan vault black box Fordefi.
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(),))
Tanda Tangan dan Kirim
sign_and_send_transaction membawa transaksi ke on-chain apa pun bentuk signer-nya.
SendingSigner menyiarkan melalui providernya dan fungsi kirim Anda
tidak pernah dipanggil. TransactionSigner atau ModifyingSigner menandatangani, dan fungsi kirim
Anda menyiarkan hasil berenkode base64 (paket ini tidak memiliki klien 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 khusus penandatanganan tanpa fungsi kirim memunculkan CONFIG_ERROR, dan
transaksi yang masih kekurangan tanda tangan setelah penandatanganan memunculkan SIGNING_FAILED.
Penanganan Error
Setiap kegagalan adalah SignerError dengan code yang stabil dari SignerErrorCode:
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, dan SIGNING_FAILED. Cocokkan berdasarkan code, bukan pesan:
str() dan repr() hanya membawa pesan generik tetap, tidak pernah materi kunci atau
respons mentah provider. status_code dan provider_error_code diatur ketika
kegagalan berasal dari respons provider.
SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED") berarti
transaksi mungkin sudah masuk:
- Pada Crossmint dan Fordefi native auto,
provider_transaction_iddiatur ketika pembuatan diterima, danidempotency_keymembawa kunci yang diturunkan dari pesan yang digunakan saat pembuatan dikirim. Mengirim ulang transaksi yang byte-nya identik aman; transaksi yang dibangun ulang (misalnya dengan blockhash baru) merupakan transfer baru. - Dari
sign_and_send_transaction, fungsi kirim yang gagal memunculkannya dengantransaction_signaturediatur ke signature transaksi yang telah selesai. - Fireblocks memunculkannya hanya jika hasil polling menunjukkan Fireblocks menyiarkan
transaksi
use_program_callmeskipun transaksi tersebut dikirim hanya untuk ditandatangani.
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
Panggilan yang dibatalkan memunculkan ulang asyncio.CancelledError, yang tidak membawa field apa pun. Untuk
memulihkan id yang diterima provider sebelum pembatalan, teruskan
PendingTransactionId() (dari solana_keychain.core) sebagai pending_transaction_id
pada konfigurasi Crossmint atau Fordefi native auto, lalu baca .get() setelah
pembatalan. Lakukan rekonsiliasi dengan provider sebelum mencoba ulang.
Keychain memvalidasi tahap penandatanganan, bukan apa yang dilakukan transaksi: signature yang dikembalikan provider diverifikasi dengan ed25519 terhadap pesan yang dihitung secara lokal sebelum dilampirkan. Python tidak dapat menghapus buffer kunci dengan zeroize, jadi dengan backend kunci lokal (Memory, serta kunci API dan PEM yang disimpan dalam konfigurasi backend jarak jauh) perlakukan seluruh memori proses sebagai data sensitif. Lihat model keamanan untuk jaminan yang diberikan setiap bentuk penandatanganan.
Menambahkan Signer Kustom
Buat subkelas dari satu kelas kapabilitas yang sesuai dengan backend Anda (TransactionSigner,
ModifyingSigner atau SendingSigner) dari solana_keychain.core. Lihat
panduan Adding Signers untuk mengintegrasikan
layanan manajemen kunci lainnya.
Referensi
Is this page helpful?