Python

Η έκδοση 2.0 είναι η πρώτη σταθερή έκδοση του πακέτου Python. Ο οδηγός μετάβασης στην 2.0 καλύπτει τις μορφές υπογραφής που μοιράζεται με τα Rust και TypeScript.

Εγκατάσταση

Εγκαταστήστε το βασικό πακέτο, καθώς και ένα extra για κάθε backend που απαιτεί εξάρτηση παρόχου:

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]'

Απαιτείται Python 3.10 ή νεότερη έκδοση. Οι συναλλαγές είναι αντικείμενα solders VersionedTransaction· γίνονται δεκτά μηνύματα legacy, v0 και v1, εκτός από το Fireblocks με use_program_call=True, το οποίο δέχεται μόνο legacy και v0.

Τα Memory, Vault και Para μπορούν να εισαχθούν από τη ρίζα του πακέτου. Κάθε άλλο backend εισάγεται από το δικό του υποmodule (για παράδειγμα solana_keychain.aws_kms), και η εισαγωγή του χωρίς το extra του προκαλεί ImportError που αναφέρει το extra που πρέπει να εγκατασταθεί. Το Ledger υποστηρίζεται μόνο σε Rust.

Βασική χρήση

Κάθε backend διαθέτει μια dataclass ρυθμίσεων και ένα ασύγχρονο factory create_<backend>_signer που επιστρέφει έτοιμο προς χρήση signer. Όλες οι μέθοδοι υπογραφής είναι coroutines:

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 επιστρέφει ένα SignedTransaction με τα encoded_transaction, signature, is_complete και transaction. Το transaction είναι η έγκυρη υπογεγραμμένη συναλλαγή: συνεχίστε από αυτήν, ειδικά με έναν modifying signer, του οποίου το αποτέλεσμα είναι διαφορετικό αντικείμενο από αυτό που περάσατε.

Ενοποιημένο factory

Η create_keychain_signer δέχεται το όνομα ενός backend και τη dataclass ρυθμίσεων του συγκεκριμένου backend, και εισάγει το backend με lazy τρόπο, ώστε να χρειάζεται να εγκατασταθούν μόνο τα extras που χρησιμοποιείτε:

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",
),
)

Τα ονόματα αναφέρονται στο SUPPORTED_BACKENDS: aws-kms, cdp, crossmint, dfns, fireblocks, fordefi, gcp-kms, memory, openfort, para, privy, turnkey, utila και vault. Ένα άγνωστο όνομα, ή μια ρύθμιση λανθασμένης κλάσης, προκαλεί SignerError με SignerErrorCode.CONFIG_ERROR. Το factory δηλώνεται ότι επιστρέφει τη βασική κλάση SolanaSigner, οπότε περιορίστε τον τύπο με isinstance πριν από την υπογραφή (δείτε Δυνατότητες signer).

Απομακρυσμένοι πελάτες HTTP

Τα απομακρυσμένα backends HTTP δέχονται προαιρετικά ένα http_client (ένα httpx.AsyncClient) για προσαρμοσμένο TLS ή proxies. Όταν δεν έχει οριστεί, κάθε αίτημα χρησιμοποιεί έναν πελάτη μίας χρήσης με χρονικό όριο 60 δευτερολέπτων, επιβολή HTTPS στη βασική διεύθυνση URL και απόρριψη ανακατευθύνσεων.

Δυνατότητες signer

Κάθε backend κληρονομεί την ABC SolanaSigner (pubkey, sign_message, is_available) και επιπλέον ακριβώς μία κλάση δυνατοτήτων:

  • TransactionSigner: η sign_transaction(tx) υπογράφει τη συναλλαγή σας επιτόπου και επιστρέφει ένα SignedTransaction. Εσείς την αποστέλλετε στο δίκτυο.
  • ModifyingSigner: η modify_and_sign_transaction(tx) επιτρέπει στον πάροχο να ξαναγράψει τη συναλλαγή και στη συνέχεια την υπογράφει χωρίς να την αποστείλει. Το αντικείμενό σας παραμένει αμετάβλητο· συνεχίστε από το επιστρεφόμενο SignedTransaction.transaction.
  • SendingSigner: η sign_and_send_transaction(tx) υπογράφει και αποστέλλει μέσω του παρόχου και επιστρέφει το Signature της συναλλαγής που καταγράφηκε. Η συναλλαγή σας δεν τροποποιείται ποτέ.
BackendΚλάση δυνατοτήτωνsign_message
memory, vault, privy, turnkey, aws-kms, fireblocks, gcp-kms, dfns, para, openfortTransactionSignerΝαι
cdpTransactionSignerΜόνο payloads UTF-8, διαφορετικά SERIALIZATION_ERROR
utilaTransactionSignerΠροκαλεί SIGNING_FAILED
fordefi black box (FordefiBlackBoxSigner)TransactionSignerΝαι
fordefi native manual (FordefiNativeManualSigner)ModifyingSignerΝαι
fordefi native auto (FordefiNativeAutoSigner)SendingSignerΝαι
crossmintSendingSignerΠροκαλεί SIGNING_FAILED

Περιορίστε τον τύπο με isinstance. Όλες οι κλάσεις δυνατοτήτων εξάγονται από τη ρίζα του πακέτου:

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)

Αρχικοποίηση

Τα factories create_* και η create_keychain_signer εκτελούν για εσάς κάθε απαραίτητη ρύθμιση. Αν δημιουργήσετε απευθείας την κλάση signer για Privy, Fireblocks, Dfns, Crossmint, Para, Openfort ή Utila, εκτελέστε await signer.init() πριν από τη χρήση. Μέχρι τότε, το pubkey και κάθε κλήση υπογραφής προκαλούν SignerErrorCode.NOT_INITIALIZED.

Ρύθμιση backend

Memory

Δημιουργήστε το από ένα αρχείο keypair του Solana CLI, ένα string base58 ή "[1,2,...]", ακατέργαστα bytes, ή ένα Keypair του 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()))

Το κλειδί βρίσκεται στη μνήμη της διεργασίας και η Python δεν μπορεί να το μηδενίσει με ασφάλεια (zeroize). Χρησιμοποιήστε αυτό το backend για ανάπτυξη και δοκιμές.

HashiCorp Vault

Το κλειδί πρέπει να είναι κλειδί ed25519 στη μηχανή transit. Το απλό HTTP γίνεται δεκτό μόνο για διεύθυνση loopback, για το 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 είναι ένα αναγνωριστικό κλειδιού, ARN ή alias για ένα κλειδί ECC_NIST_EDWARDS25519. Περάστε έναν προδημιουργημένο πελάτη boto3 KMS στο client για προσαρμοσμένα διαπιστευτήρια ή endpoints· το region αγνοείται τότε:

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

Η έκδοση του κλειδιού πρέπει να είναι κλειδί EC_SIGN_ED25519. Το client δέχεται προαιρετικά έναν προδημιουργημένο KeyManagementServiceAsyncClient:

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",
)
)

Τα wallets που προστατεύονται από κλειδί εξουσιοδότησης δέχονται ένα PrivyAuthorizationConfig ως 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 υπογράφει με τη λειτουργία PROGRAM_CALL αντί για RAW. Αποστέλλεται μόνο για υπογραφή, οπότε το Fireblocks ούτε ξαναγράφει ούτε αποστέλλει τη συναλλαγή, και εσείς την αποστέλλετε όπως συνήθως. Απαιτεί hot wallet και πρέπει να ενεργοποιηθεί για το workspace σας από το 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 είναι μόνο για αποστολή. Το API του εκτελεί πάντα μια εγκεκριμένη συναλλαγή στην πλευρά του διακομιστή και καλύπτει το gas, επομένως το CrossmintSigner είναι SendingSigner και η sign_message προκαλεί SIGNING_FAILED. Η υπογραφή που επιστρέφεται αντιστοιχεί στη συναλλαγή που κατέγραψε το Crossmint, η οποία μπορεί να διαφέρει από τη δική σας. Ο ορισμός του signer_secret (ενός μυστικού delegated-signer της μορφής xmsk1_...) εγκρίνει τις συναλλαγές αυτόματα, κάτι που αναθέτει στο 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 υπογράφει μόνο συναλλαγές· η sign_message προκαλεί 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 διαθέτει τρεις λειτουργίες υπογραφής, που καθορίζονται κατά τη δημιουργία από τα chain και push_mode. Η create_fordefi_signer επιλέγει την κλάση, κάθε κλάση απορρίπτει μια ρύθμιση που προορίζεται για άλλη, και και οι τρεις υπογράφουν μηνύματα:

ΛειτουργίαΡύθμισηΚλάσηΜέθοδος
Black boxchain μη ορισμένοFordefiBlackBoxSignersign_transaction
Native autochain ορισμένο, push_mode μη ορισμένο ή "auto"FordefiNativeAutoSignersign_and_send_transaction
Native manualchain ορισμένο, push_mode="manual"FordefiNativeManualSignermodify_and_sign_transaction

Τα αιτήματα API πιστοποιούνται με υπογραφή αιτήματος ECDSA P-256: δώστε το κλειδί ως private_key_pem, ή κρατήστε το σε KMS/HSM περνώντας μια υποκλάση του FordefiRequestSigner ως request_signer.

Λειτουργία Native auto: ορίστε το chain ("solana_devnet" ή "solana_mainnet"), και το Fordefi μπορεί να αντικαταστήσει το blockhash και τις χρεώσεις, και στη συνέχεια υπογράφει και αποστέλλει τη συναλλαγή μόνο του. Δέχεται μόνο μη υπογεγραμμένη συναλλαγή της οποίας ο μοναδικός απαιτούμενος υπογράφων είναι το vault. Το fee μεταβιβάζεται αυτούσιο στο Fordefi:

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)

Λειτουργία Native manual: ορίστε το chain και push_mode="manual". Το Fordefi ξαναγράφει το μήνυμα (πρόσφατο blockhash, εντολές χρέωσης Compute Budget) και το υπογράφει, αλλά δεν το αποστέλλει. Η συναλλαγή που επιστρέφεται αντικαθιστά αυτήν που υποβάλατε, οπότε συνεχίστε πάντα από το result.transaction. Το Fordefi πρέπει να είναι ο πληρωτής των χρεώσεων και πρέπει να υπογράφει πριν από οποιονδήποτε άλλο απαιτούμενο υπογράφοντα: μια συναλλαγή που φέρει ήδη υπογραφές γίνεται δεκτή, αλλά η αναδιατύπωση τις ακυρώνει. Η αναδιατύπωση δεν παρουσιάζεται ως diff, οπότε ελέγξτε το αποτέλεσμα πριν από την αποστολή και αποστείλετε άμεσα, καθώς το Fordefi δεν επιστρέφει το ύψος λήξης του νέου blockhash.

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 υπογράφει ακριβώς τα bytes του μηνύματός σας και δεν το αποστέλλει. Χρησιμοποιήστε την με ένα 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 φέρνει μια συναλλαγή στο blockchain ανεξάρτητα από τη μορφή του signer. Ένας SendingSigner αποστέλλει μέσω του παρόχου του και η δική σας συνάρτηση αποστολής δεν καλείται ποτέ. Ένας TransactionSigner ή ModifyingSigner υπογράφει, και η δική σας συνάρτηση αποστολής αποστέλλει το αποτέλεσμα κωδικοποιημένο σε base64 (το πακέτο δεν διαθέτει πελάτη 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 μόνο υπογραφής χωρίς συνάρτηση αποστολής προκαλεί CONFIG_ERROR, και μια συναλλαγή που εξακολουθεί να στερείται υπογραφών μετά την υπογραφή προκαλεί SIGNING_FAILED.

Διαχείριση σφαλμάτων

Κάθε αποτυχία είναι ένα SignerError με σταθερό code από το 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 και 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 φέρει το κλειδί που προέκυψε από το μήνυμα με το οποίο εκτελέστηκε η δημιουργία. Η εκ νέου αποστολή της ίδιας byte-προς-byte συναλλαγής είναι ασφαλής· μια ανακατασκευασμένη (για παράδειγμα με νέο blockhash) αποτελεί νέα μεταφορά.
  • Από την sign_and_send_transaction, μια συνάρτηση αποστολής που αποτυγχάνει το προκαλεί με το transaction_signature ορισμένο στην υπογραφή της ολοκληρωμένης συναλλαγής.
  • Το Fireblocks το προκαλεί μόνο αν ένας έλεγχος (poll) δείξει ότι το Fireblocks αποκλήρωσε συναλλαγή use_program_call παρότι στάλθηκε μόνο για υπογραφή.
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

Μια ακυρωμένη κλήση προκαλεί εκ νέου asyncio.CancelledError, το οποίο δεν φέρει πεδία. Για να ανακτήσετε ένα αναγνωριστικό που έγινε δεκτό από τον πάροχο πριν από την ακύρωση, περάστε ένα PendingTransactionId() (από το solana_keychain.core) ως pending_transaction_id στη ρύθμιση Crossmint ή Fordefi native auto, και διαβάστε το .get() μετά την ακύρωση. Συμφιλιώστε την κατάσταση με τον πάροχο πριν από νέα προσπάθεια.

Το Keychain επικυρώνει το βήμα υπογραφής, όχι το τι κάνει η συναλλαγή: μια υπογραφή που επιστρέφει ο πάροχος επαληθεύεται με ed25519 έναντι του τοπικά υπολογισμένου μηνύματος πριν επισυναφθεί. Η Python δεν μπορεί να μηδενίσει με ασφάλεια τα buffers κλειδιών, οπότε με backends τοπικών κλειδιών (Memory, καθώς και τα API keys και τα PEM που φυλάσσονται στις ρυθμίσεις των απομακρυσμένων backends) αντιμετωπίστε ολόκληρη τη μνήμη της διεργασίας ως ευαίσθητη. Δείτε το μοντέλο ασφαλείας για το τι εγγυάται κάθε μορφή υπογραφής.

Προσθήκη προσαρμοσμένων signers

Δημιουργήστε υποκλάση (subclass) της μίας κλάσης δυνατοτήτων που ταιριάζει με το backend σας (TransactionSigner, ModifyingSigner ή SendingSigner) από το solana_keychain.core. Δείτε τον οδηγό Προσθήκης Signers για να ενσωματώσετε επιπλέον υπηρεσίες διαχείρισης κλειδιών.

Πόροι

Is this page helpful?

© 2026 Ίδρυμα Solana. Με επιφύλαξη παντός δικαιώματος.