Η έκδοση 2.0 είναι η πρώτη σταθερή έκδοση του πακέτου Python. Ο οδηγός μετάβασης στην 2.0 καλύπτει τις μορφές υπογραφής που μοιράζεται με τα Rust και TypeScript.
Εγκατάσταση
Εγκαταστήστε το βασικό πακέτο, συν ένα extra για κάθε backend που απαιτεί εξάρτηση από πάροχο:
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·
γίνονται δεκτά μηνύματα legacy, v0 και v1, εκτός από το Fireblocks με
use_program_call=True, που δέχεται μόνο legacy και v0.
Τα Memory, Vault και Para μπορούν να εισαχθούν από τη ρίζα του πακέτου. Κάθε άλλο backend
εισάγεται από τη δική του υπομονάδα (για παράδειγμα solana_keychain.aws_kms), και η
εισαγωγή του χωρίς το extra του προκαλεί ένα ImportError που αναφέρει το extra που
πρέπει να εγκατασταθεί. Το Ledger είναι διαθέσιμο μόνο σε Rust.
Βασική χρήση
Κάθε backend διαθέτει μια dataclass διαμόρφωσης και ένα ασύγχρονο factory create_<backend>_signer
που επιστρέφει έναν signer έτοιμο για χρήση. Όλες οι μέθοδοι υπογραφής είναι coroutines:
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 επιστρέφει ένα SignedTransaction με τα encoded_transaction,
signature, is_complete και transaction. Το transaction είναι η έγκυρη
υπογεγραμμένη συναλλαγή: συνεχίστε από αυτήν, ειδικά με έναν signer που τροποποιεί, του οποίου το
αποτέλεσμα είναι διαφορετικό αντικείμενο από αυτό που περάσατε.
Ενιαίο factory
Το create_keychain_signer δέχεται το όνομα ενός backend και τη dataclass διαμόρφωσης
του συγκεκριμένου backend, και εισάγει το backend με lazy τρόπο, οπότε χρειάζεται να
εγκατασταθούν μόνο τα extras που χρησιμοποιείτε:
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. Ένα άγνωστο όνομα ή μια διαμόρφωση
λανθασμένης κλάσης προκαλεί 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, openfort | TransactionSigner | Ναι |
| cdp | TransactionSigner | Μόνο payloads 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)
Αρχικοποίηση
Τα 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_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 δεν μπορεί να το μηδενίσει με ασφάλεια. Χρησιμοποιήστε αυτό το backend για ανάπτυξη και δοκιμές.
HashiCorp Vault
Το κλειδί πρέπει να είναι κλειδί ed25519 στη μηχανή transit. Το απλό HTTP γίνεται δεκτό
μόνο για διεύθυνση loopback, για το 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 είναι ένα αναγνωριστικό κλειδιού, ARN ή alias για κλειδί ECC_NIST_EDWARDS25519. Περάστε έναν
ήδη δημιουργημένο client του boto3 KMS για προσαρμοσμένα διαπιστευτήρια ή endpoints· η 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 υπογράφει με τη λειτουργία PROGRAM_CALL αντί για RAW. Αποστέλλεται
μόνο για υπογραφή, οπότε το Fireblocks ούτε ξαναγράφει ούτε αναμεταδίδει τη
συναλλαγή, και εσείς την αναμεταδίδετε ως συνήθως. Απαιτεί hot wallet και πρέπει να
ενεργοποιηθεί για το workspace σας από το 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 του εκτελεί πάντα μια εγκεκριμένη συναλλαγή
στην πλευρά του διακομιστή και καλύπτει το gas, οπότε το CrossmintSigner είναι SendingSigner και
η sign_message προκαλεί SIGNING_FAILED. Η υπογραφή που επιστρέφεται προσδιορίζει τη
συναλλαγή που κατέγραψε το Crossmint, η οποία μπορεί να διαφέρει από τη δική σας. Ο ορισμός του
signer_secret (ενός μυστικού delegated-signer xmsk1_...) εγκρίνει τις συναλλαγές
αυτόματα, κάτι που αναθέτει στο 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 έχει τρεις λειτουργίες υπογραφής, που καθορίζονται κατά τη δημιουργία από τα chain και
push_mode. Η create_fordefi_signer επιλέγει την κλάση, κάθε κλάση απορρίπτει μια
διαμόρφωση που προορίζεται για άλλη, και οι τρεις υπογράφουν μηνύματα:
| Λειτουργία | Διαμόρφωση | Κλάση | Μέθοδος |
|---|---|---|---|
| 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 ή κρατήστε το σε KMS/HSM περνώντας μια
υποκλάση του FordefiRequestSigner ως request_signer.
Λειτουργία native auto: ορίστε το chain ("solana_devnet" ή "solana_mainnet") και
το Fordefi μπορεί να αντικαταστήσει το blockhash και τις χρεώσεις, και στη συνέχεια υπογράφει και αναμεταδίδει
τη συναλλαγή το ίδιο. Δέχεται μόνο μη υπογεγραμμένη συναλλαγή της οποίας ο μοναδικός απαιτούμενος
υπογράφων είναι το 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 ξαναγράφει
το μήνυμα (πρόσφατο 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 του μηνύματός σας και
δεν αναμεταδίδει. Χρησιμοποιήστε την με ένα vault Fordefi black box.
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 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.
Διαχείριση σφαλμάτων
Κάθε αποτυχία είναι ένα 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 συναλλαγής είναι ασφαλής· μια ανακατασκευασμένη (για παράδειγμα με νέο blockhash) αποτελεί νέα μεταφορά. - Από την
sign_and_send_transaction, μια συνάρτηση αποστολής που αποτυγχάνει το προκαλεί με τοtransaction_signatureορισμένο στην υπογραφή της ολοκληρωμένης συναλλαγής. - Το Fireblocks το προκαλεί μόνο αν ένας έλεγχος (poll) δείξει ότι το 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, το οποίο δεν φέρει πεδία. Για να
ανακτήσετε ένα αναγνωριστικό που δέχτηκε ο πάροχος πριν από την ακύρωση, περάστε ένα
PendingTransactionId() (από το solana_keychain.core) ως pending_transaction_id της διαμόρφωσης Crossmint ή
Fordefi native auto και διαβάστε το .get() μετά
την ακύρωση. Επαληθεύστε την κατάσταση με τον πάροχο πριν από νέα προσπάθεια.
Το Keychain επικυρώνει το βήμα υπογραφής, όχι το τι κάνει η συναλλαγή: μια υπογραφή που επιστρέφει ο πάροχος επαληθεύεται με ed25519 έναντι του τοπικά υπολογισμένου μηνύματος πριν επισυναφθεί. Η Python δεν μπορεί να μηδενίσει με ασφάλεια τους buffers κλειδιών, οπότε με backends τοπικών κλειδιών (Memory, καθώς και τα κλειδιά API και τα PEM που διατηρούνται στις διαμορφώσεις των απομακρυσμένων backends) θεωρήστε ολόκληρη τη μνήμη της διεργασίας ευαίσθητη. Δείτε το μοντέλο ασφάλειας για το τι εγγυάται κάθε μορφή υπογραφής.
Προσθήκη προσαρμοσμένων signers
Δημιουργήστε υποκλάση της μίας κλάσης δυνατοτήτων που αντιστοιχεί στο backend σας (TransactionSigner,
ModifyingSigner ή SendingSigner) από το solana_keychain.core. Δείτε τον
οδηγό Adding Signers για να ενσωματώσετε
επιπλέον υπηρεσίες διαχείρισης κλειδιών.
Πόροι
Is this page helpful?