Python

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 memerlukan dependensi penyedia:

pip install solana-keychain # memory, vault and para
pip install 'solana-keychain[aws-kms]' # AWS KMS (boto3)
pip install 'solana-keychain[gcp-kms]' # GCP KMS (google-cloud-kms)
pip install 'solana-keychain[privy]' # Privy
pip install 'solana-keychain[turnkey]' # Turnkey
pip install 'solana-keychain[fireblocks]' # Fireblocks
pip install 'solana-keychain[cdp]' # Coinbase Developer Platform
pip install 'solana-keychain[crossmint]' # Crossmint
pip install 'solana-keychain[dfns]' # Dfns
pip install 'solana-keychain[openfort]' # Openfort
pip install 'solana-keychain[utila]' # Utila
pip install 'solana-keychain[fordefi]' # Fordefi
# Several at once
pip install 'solana-keychain[aws-kms,privy]'

Memerlukan 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 di Rust.

Penggunaan Dasar

Setiap backend memiliki dataclass konfigurasi dan factory async create_<backend>_signer yang mengembalikan signer yang siap digunakan. Semua metode penandatanganan adalah coroutine:

import asyncio
from solana_keychain import MemorySigner
from solders.transaction import VersionedTransaction
async 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 yang telah ditandatangani dan bersifat otoritatif: lanjutkan dari objek ini, terutama dengan modifying signer, yang hasilnya merupakan objek berbeda dari yang Anda berikan.

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_signer
from solana_keychain.privy import PrivySignerConfig
signer = await create_keychain_signer(
"privy",
PrivySignerConfig(
app_id="your-app-id",
app_secret="your-app-secret",
wallet_id="your-wallet-id",
),
)

Nama-nama tersebut terdaftar 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, akan memunculkan SignerError dengan SignerErrorCode.CONFIG_ERROR. Factory ini bertipe pengembalian SolanaSigner dasar, jadi persempit tipenya 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 base URL, dan pengalihan (redirect) ditolak.

Kapabilitas Signer

Setiap backend mewarisi ABC SolanaSigner (pubkey, sign_message, is_available) ditambah tepat satu kelas kapabilitas:

  • TransactionSigner: sign_transaction(tx) menandatangani transaksi Anda di tempat dan mengembalikan SignedTransaction. Anda yang menyiarkannya.
  • ModifyingSigner: modify_and_sign_transaction(tx) memungkinkan penyedia menulis ulang transaksi, lalu menandatanganinya tanpa menyiarkannya. Objek Anda tidak diubah; lanjutkan dari SignedTransaction.transaction yang dikembalikan.
  • SendingSigner: sign_and_send_transaction(tx) menandatangani dan menyiarkan melalui penyedia, lalu mengembalikan Signature dari transaksi yang berhasil masuk. Transaksi Anda tidak pernah dimutasi.
BackendKelas kapabilitassign_message
memory, vault, privy, turnkey, aws-kms, fireblocks, gcp-kms, dfns, para, openfortTransactionSignerYa
cdpTransactionSignerHanya payload UTF-8, selain itu SERIALIZATION_ERROR
utilaTransactionSignerMemunculkan SIGNING_FAILED
fordefi black box (FordefiBlackBoxSigner)TransactionSignerYa
fordefi native manual (FordefiNativeManualSigner)ModifyingSignerYa
fordefi native auto (FordefiNativeAutoSigner)SendingSignerYa
crossmintSendingSignerMemunculkan SIGNING_FAILED

Persempit dengan isinstance. Semua kelas kapabilitas diekspor dari root paket:

from solana_keychain import ModifyingSigner, SendingSigner, TransactionSigner
if 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 menangani 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_signer
from solders.keypair import Keypair
signer = 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 bytes
signer = await create_memory_signer(MemorySignerConfig(keypair=Keypair()))

Kunci berada di memori proses, dan Python tidak dapat menghapusnya dengan nol (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_signer
signer = 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. Berikan client KMS boto3 yang sudah dibuat sebelumnya untuk kredensial atau endpoint kustom; region kemudian diabaikan:

from solana_keychain.aws_kms import AwsKmsSignerConfig, create_aws_kms_signer
signer = 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 sebelumnya:

from solana_keychain.gcp_kms import GcpKmsSignerConfig, create_gcp_kms_signer
signer = 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_signer
signer = 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_signer
signer = await create_turnkey_signer(
TurnkeySignerConfig(
api_public_key="api_public_key", # hex P-256
api_private_key="api_private_key", # hex P-256
organization_id="org_id",
private_key_id="private_key_id",
public_key="base58_public_key",
)
)

Fireblocks

from solana_keychain.fireblocks import FireblocksSignerConfig, create_fireblocks_signer
signer = 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 penandatanganan, sehingga Fireblocks tidak menulis ulang maupun menyiarkan transaksi, dan Anda menyiarkannya seperti biasa. Ini memerlukan hot wallet dan harus diaktifkan untuk workspace Anda oleh Fireblocks.

CDP (Coinbase Developer Platform)

from solana_keychain.cdp import CdpSignerConfig, create_cdp_signer
signer = 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_signer
signer = 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 berhasil dimasukkan oleh Crossmint, yang mungkin berbeda dari transaksi Anda. Mengatur signer_secret (secret delegated-signer berformat xmsk1_...) akan menyetujui transaksi secara otomatis, yang berarti menyerahkan keputusan tentang apa yang disetujui kepada Crossmint.

Dfns

from solana_keychain.dfns import DfnsSignerConfig, create_dfns_signer
signer = 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_signer
signer = await create_openfort_signer(
OpenfortSignerConfig(
secret_key="sk_...",
account_id="acc_...",
wallet_secret="wallet_secret",
)
)

Para

from solana_keychain import ParaSignerConfig, create_para_signer
signer = 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_signer
signer = 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:

ModeKonfigurasiKelasMetode
Black boxchain tidak diaturFordefiBlackBoxSignersign_transaction
Native autochain diatur, push_mode tidak diatur atau "auto"FordefiNativeAutoSignersign_and_send_transaction
Native manualchain diatur, push_mode="manual"FordefiNativeManualSignermodify_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 wajib adalah vault. fee diteruskan ke Fordefi apa adanya:

import os
from solana_keychain.fordefi import FordefiSignerConfig, create_fordefi_signer
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"], # 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 (recent blockhash, 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 (fee payer) dan harus menandatangani sebelum signer wajib lainnya: transaksi yang sudah memuat tanda tangan tetap diterima, tetapi penulisan ulang membatalkannya. Penulisan ulang tidak dibandingkan (diff), jadi periksa hasilnya sebelum menyiarkan, dan siarkan dengan segera, karena Fordefi tidak mengembalikan tinggi kedaluwarsa dari 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 telah diperiksa seperti pada Sign and Send, dan lakukan rekonsiliasi sebelum mencoba ulang jika pengiriman gagal.

Mode black box: abaikan chain. Fordefi menandatangani byte pesan Anda persis apa adanya dan tidak menyiarkannya. Gunakan 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(),
)
)

Sign and Send

sign_and_send_transaction memasukkan transaksi ke chain apa pun bentuk signer-nya. SendingSigner menyiarkan melalui penyedianya dan fungsi pengiriman Anda tidak pernah dipanggil. TransactionSigner atau ModifyingSigner menandatangani, dan fungsi pengiriman Anda menyiarkan hasil yang dikodekan base64 (paket ini tidak memiliki klien RPC):

import httpx
from solana_keychain import sign_and_send_transaction
from solders.signature import Signature
async 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 yang hanya menandatangani tanpa fungsi pengiriman akan memunculkan CONFIG_ERROR, dan transaksi yang masih kekurangan tanda tangan setelah penandatanganan akan memunculkan SIGNING_FAILED.

Penanganan Error

Setiap kegagalan adalah SignerError dengan code 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 pesannya: str() dan repr() hanya memuat pesan generik tetap, tidak pernah materi kunci atau respons mentah penyedia. status_code dan provider_error_code diatur ketika kegagalan berasal dari respons penyedia.

SignerErrorCode.BROADCAST_UNCONFIRMED ("SIGNER_BROADCAST_UNCONFIRMED") berarti transaksi mungkin sudah masuk:

  • Pada Crossmint dan Fordefi native auto, provider_transaction_id diatur ketika permintaan pembuatan diterima, dan idempotency_key membawa kunci yang diturunkan dari pesan yang digunakan saat pembuatan dikirim. Mengirim ulang transaksi yang identik byte demi byte aman; transaksi yang dibangun ulang (misalnya dengan blockhash baru) adalah transfer baru.
  • Dari sign_and_send_transaction, fungsi pengiriman yang gagal memunculkannya dengan transaction_signature diatur ke signature transaksi yang telah selesai.
  • Fireblocks memunculkannya hanya jika hasil polling menunjukkan Fireblocks menyiarkan transaksi use_program_call meskipun dikirim hanya untuk penandatanganan.
from solana_keychain import SignerError, SignerErrorCode
try:
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

Pemanggilan yang dibatalkan memunculkan kembali asyncio.CancelledError, yang tidak membawa field apa pun. Untuk memulihkan id yang diterima penyedia sebelum pembatalan, berikan PendingTransactionId() (dari solana_keychain.core) sebagai pending_transaction_id pada konfigurasi Crossmint atau Fordefi native auto, lalu baca .get() setelah pembatalan. Lakukan rekonsiliasi dengan penyedia sebelum mencoba ulang.

Keychain memvalidasi tahap penandatanganan, bukan apa yang dilakukan transaksi: signature yang dikembalikan penyedia diverifikasi ed25519 terhadap pesan yang dihitung secara lokal sebelum dilampirkan. Python tidak dapat menghapus buffer kunci dengan nol (zeroize), jadi pada backend dengan 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 dari 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 tambahan.

Sumber Daya

Is this page helpful?

© 2026 Yayasan Solana. Semua hak dilindungi.