الإصدار 2.0 هو أول إصدار مستقر من حزمة Python. يغطي دليل الترحيل إلى الإصدار 2.0 أشكال التوقيع التي تشترك فيها مع Rust وTypeScript.
التثبيت
ثبّت الحزمة الأساسية، مع إضافة واحدة لكل واجهة خلفية تحتاج إلى تبعية من المزوّد:
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 من جذر الحزمة. أما كل واجهة خلفية أخرى
فتُستورد من وحدتها الفرعية الخاصة (مثل solana_keychain.aws_kms)، وعند
استيراد إحداها دون إضافتها الاختيارية يُطلق الخطأ ImportError الذي يذكر اسم الإضافة
المطلوب تثبيتها. أما Ledger فهي متاحة في Rust فقط.
الاستخدام الأساسي
لكل واجهة خلفية dataclass للإعدادات ودالة مصنع غير متزامنة create_<backend>_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 هي المعاملة الموقّعة
المعتمدة: تابع العمل منها، خاصةً مع موقّع معدِّل، إذ تكون
نتيجته كائنًا مختلفًا عن الذي مررته.
المصنع الموحّد
تأخذ create_keychain_signer اسم الواجهة الخلفية وdataclass الإعدادات الخاص بها،
وتستورد الواجهة الخلفية عند الحاجة فقط، لذا لا يلزم تثبيت سوى الإضافات
التي تستخدمها:
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. تم تحديد نوع
المصنع على أنه يعيد SolanaSigner الأساسي، لذا ضيّق نوعه باستخدام
isinstance قبل التوقيع (راجع قدرات الموقّع).
عملاء HTTP البعيدون
تقبل واجهات HTTP الخلفية البعيدة معاملًا اختياريًا http_client (من نوع httpx.AsyncClient)
لإعدادات TLS مخصصة أو وكلاء. وعند عدم تعيينه، يستخدم كل طلب عميلًا
لمرة واحدة بمهلة 60 ثانية، مع فرض HTTPS على عنوان URL الأساسي، ورفض
إعادة التوجيه.
قدرات الموقّع
ترث كل واجهة خلفية الفئة المجردة 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الخاص بالمعاملة التي وصلت إلى الشبكة. لا يتم تعديل معاملتك أبدًا.
| الواجهة الخلفية | فئة القدرة | 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 الصندوق الأسود (FordefiBlackBoxSigner) | TransactionSigner | نعم |
fordefi الأصلي اليدوي (FordefiNativeManualSigner) | ModifyingSigner | نعم |
fordefi الأصلي التلقائي (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 مباشرةً، فاستدعِ await signer.init() قبل الاستخدام. وإلى ذلك الحين،
تطلق pubkey وكل استدعاء توقيع الخطأ SignerErrorCode.NOT_INITIALIZED.
إعدادات الواجهات الخلفية
Memory
يمكن الإنشاء من ملف keypair الخاص بـ سولانا CLI، أو سلسلة base58 أو "[1,2,...]"، أو بايتات
خام، أو كائن 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 تصفيره. استخدم هذه الواجهة الخلفية للتطوير والاختبار.
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 أو اسم مستعار لمفتاح ECC_NIST_EDWARDS25519. مرّر
client من boto3 KMS مُنشأً مسبقًا لاستخدام بيانات اعتماد أو نقاط نهاية مخصصة؛ وسيتم
حينها تجاهل 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 كتابة المعاملة ولا تبثّها،
وأنت تبثّها كالمعتاد. ويتطلب محفظة ساخنة ويجب أن تفعّله
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 للإرسال فقط. تنفّذ واجهتها البرمجية دائمًا المعاملة المعتمدة
على الخادم وتتحمل رسوم الغاز، لذا فإن CrossmintSigner هو SendingSigner
وتطلق sign_message الخطأ SIGNING_FAILED. يحدد التوقيع المُعاد
المعاملة التي بثّتها Crossmint، وقد تختلف عن معاملتك. يؤدي تعيين
signer_secret (سر موقّع مفوَّض بصيغة 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 الفئة، وترفض كل فئة
إعدادات مخصصة لفئة أخرى، وتوقّع الفئات الثلاث جميعها الرسائل:
| الوضع | الإعدادات | الفئة | الدالة |
|---|---|---|---|
| الصندوق الأسود | chain غير معيّن | FordefiBlackBoxSigner | sign_transaction |
| أصلي تلقائي | chain معيّن، وpush_mode غير معيّن أو "auto" | FordefiNativeAutoSigner | sign_and_send_transaction |
| أصلي يدوي | 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 والرسوم، ثم توقّع المعاملة وتبثّها
بنفسها. ولا تقبل سوى معاملة غير موقّعة يكون الموقّع الوحيد المطلوب فيها
هو الخزنة. يتم تمرير 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 كتابة
الرسالة (recent blockhash وتعليمات رسوم Compute Budget) وتوقّعها،
لكنها لا تبثّها. تحل المعاملة المُعادة محل التي أرسلتها،
لذا تابع دائمًا من result.transaction. يجب أن تكون Fordefi دافع الرسوم وأن
توقّع قبل أي موقّع مطلوب آخر: تُقبل المعاملة التي تحمل بالفعل
توقيعات، لكن إعادة الكتابة تبطلها. لا تتم مقارنة إعادة الكتابة بالأصل،
لذا افحص النتيجة قبل البث، وابثّ بسرعة، لأن 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 بايتات رسالتك الدقيقة
ولا تبثّها. استخدم هذا الوضع مع خزنة 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 المعاملة إلى السلسلة أيًا كان شكل
الموقّع. يبثّ 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)
يطلق موقّع للتوقيع فقط دون دالة إرسال الخطأ 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المفتاح المشتق من الرسالة التي أُرسل الإنشاء بموجبها. إعادة إرسال المعاملة المطابقة بايتًا ببايت آمنة؛ أما المعاملة المعاد بناؤها (مثلًا بـ blockhash جديد) فهي تحويل جديد. - من
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، الذي لا يحمل أي حقول. لاسترداد
معرّف قبله المزوّد قبل الإلغاء، مرّر
PendingTransactionId() (من solana_keychain.core) كقيمة لـ pending_transaction_id في إعدادات Crossmint أو
Fordefi native auto، واقرأ .get() بعد
الإلغاء. قم بالمطابقة مع المزوّد قبل إعادة المحاولة.
تتحقق Keychain من حلقة التوقيع، لا مما تفعله المعاملة: يتم التحقق من توقيع أعاده المزوّد بخوارزمية ed25519 مقابل الرسالة المحسوبة محليًا قبل إرفاقه. لا يستطيع Python تصفير مخازن المفاتيح، لذا مع الواجهات الخلفية ذات المفاتيح المحلية (Memory، ومفاتيح API وملفات PEM المحفوظة في إعدادات الواجهات الخلفية البعيدة) اعتبر ذاكرة العملية بأكملها حساسة. راجع نموذج الأمان لمعرفة ما يضمنه كل شكل من أشكال التوقيع.
إضافة موقّعين مخصصين
قم بإنشاء فئة فرعية من فئة القدرات الواحدة التي تطابق الواجهة الخلفية لديك (TransactionSigner،
ModifyingSigner أو SendingSigner) من solana_keychain.core. راجع
دليل إضافة المُوقِّعين لدمج
خدمات إدارة المفاتيح الإضافية.
الموارد
Is this page helpful?