الإصدار 2.0.0 هو أول إصدار مستقر لوحدات Go، لذا لا يوجد ما يستدعي الترحيل. دليل الترحيل إلى 2.0 يغطي التقسيم نفسه للقدرات في Rust وTypeScript.
التثبيت
كل واجهة خلفية هي وحدة Go مستقلة، لذا لا يحتوي بناؤك ولا رسم الوحدات (module graph) لديك إلا على الواجهات الخلفية التي تستوردها:
go get github.com/solana-foundation/solana-keychain/go/core/v2 # Interfaces, errors, helpersgo get github.com/solana-foundation/solana-keychain/go/signers/memory/v2 # Local keypair signergo get github.com/solana-foundation/solana-keychain/go/signers/vault/v2 # HashiCorp Vaultgo get github.com/solana-foundation/solana-keychain/go/signers/awskms/v2 # AWS KMSgo get github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2 # GCP KMSgo get github.com/solana-foundation/solana-keychain/go/signers/privy/v2 # Privygo get github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2 # Turnkeygo get github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2 # Fireblocksgo get github.com/solana-foundation/solana-keychain/go/signers/cdp/v2 # Coinbase Developer Platformgo get github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2 # Crossmintgo get github.com/solana-foundation/solana-keychain/go/signers/dfns/v2 # Dfnsgo get github.com/solana-foundation/solana-keychain/go/signers/openfort/v2 # Openfortgo get github.com/solana-foundation/solana-keychain/go/signers/para/v2 # Parago get github.com/solana-foundation/solana-keychain/go/signers/utila/v2 # Utilago get github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2 # Fordefi
تُوسَم الوحدات بالوسم go/<module>/v2.0.0 (على سبيل المثال
go/signers/memory/v2.0.0). تتطلب كل وحدة Go 1.25.0، باستثناء gcpkms،
التي تتطلب Go 1.25.8 بسبب الحد الأدنى الذي تفرضه google.golang.org/api.
Ledger مخصصة لـ Rust فقط وليس لها وحدة Go.
معاملات solana-go v2 وv1
تُبنى الوحدات على
github.com/solana-foundation/solana-go/v2
الإصدار v2.0.0 وتتعامل مع *solana.Transaction الخاص به. المعاملات من نوع Legacy وv0 وv1
(solana.MessageVersionV1) مدعومة، باستثناء Fireblocks
مع UseProgramCall: true، الذي يقبل Legacy وv0 فقط.
الاستخدام الأساسي
يطبّق كل موقِّع الواجهة الأساسية
core.SolanaSigner
(Pubkey وSignMessage وIsAvailable). تأخذ الدوال المعامل context.Context وتكون
حاجزة (blocking). كما تطبّق كل واجهة خلفية واجهة قدرة واحدة بالضبط:
core.TransactionSigner: تقومSignTransactionبتوقيع معاملتك كما هي.core.ModifyingSigner: تتيحModifyAndSignTransactionللمزوّد إعادة كتابة المعاملة ثم توقيعها.core.SendingSigner: تجعلSignAndSendTransactionالمزوّد يوقّع المعاملة ويبثّها.
تعرض حزمة كل واجهة خلفية بنية Config ودالة إنشاء New:
import ("context""fmt""github.com/solana-foundation/solana-go/v2""github.com/solana-foundation/solana-keychain/go/core/v2""github.com/solana-foundation/solana-keychain/go/signers/memory/v2")func signWithKeychain(ctx context.Context, tx *solana.Transaction) error {signer, err := memory.New(memory.Config{PrivateKeyPath: "/path/to/id.json"})if err != nil {return err}if !signer.IsAvailable(ctx) {return core.NewSignerError(core.CodeNotAvailable, "signer offline")}result, err := signer.SignTransaction(ctx, tx)if err != nil {return err}fmt.Println("signature:", result.Signature)fmt.Println("complete:", result.IsComplete())// result.EncodedTransaction is the base64 wire transactionreturn nil}
تُرجع SignTransaction وModifyAndSignTransaction قيمة من النوع
core.SignedTransaction (EncodedTransaction وSignature وCompleteness).
تقبل الواجهات الخلفية البعيدة عبر HTTP اختيارياً HTTPClient وHTTPClientConfig
(المهلات الزمنية). يفرض العميل الافتراضي استخدام HTTPS؛ وتوفير عميلك الخاص يتجاوز ذلك،
وتصبح مسؤولاً عن وضعه الأمني.
قدرات الموقِّع
الواجهة الخلفية التي لا تستطيع توقيع معاملة لا تحتوي على دالة SignTransaction
إطلاقاً، لذا فإن القدرة حقيقة تُعرف وقت الترجمة للأنواع الفعلية، وتُعرف عبر تأكيد النوع
(type assertion) في حالة core.SolanaSigner:
| الواجهة الخلفية | القدرة | SignMessage |
|---|---|---|
| memory, vault, privy, turnkey, awskms, gcpkms, fireblocks, dfns, para, openfort | TransactionSigner | نعم |
| cdp | TransactionSigner | حمولات UTF-8 فقط |
| utila | TransactionSigner | يفشل مع CodeSigningFailed |
fordefi black box (fordefi.BlackBoxSigner) | TransactionSigner | نعم |
fordefi native manual (fordefi.NativeManualSigner) | ModifyingSigner | نعم |
fordefi native auto (fordefi.NativeAutoSigner) | SendingSigner | نعم |
| crossmint | SendingSigner | يفشل مع CodeSigningFailed |
switch s := signer.(type) {case core.SendingSigner:sig, err := s.SignAndSendTransaction(ctx, tx)case core.ModifyingSigner:signed, err := s.ModifyAndSignTransaction(ctx, tx)case core.TransactionSigner:signed, err := s.SignTransaction(ctx, tx)}
التهيئة
لا توجد خطوة Init منفصلة. تحدّد Privy وFireblocks وDfns وCrossmint وPara
وOpenfort وUtila عنوان المحفظة داخل New، ولهذا تأخذ
دوال الإنشاء لديها المعامل context.Context. أنشئ الموقِّعين دائماً عبر New: فموقِّع
Crossmint أو Para أو Utila بالقيمة الصفرية يفشل برمز CodeNotInitialized
بدلاً من التوقيع للعنوان الصفري.
التوقيع والإرسال بأي موقِّع
تُوصل core.SignAndSendTransaction المعاملة إلى السلسلة أياً كان شكل
الموقِّع. يبثّ SendingSigner عبر مزوّده ويتجاهل دالة الإرسال؛
أما كل شكل آخر فيوقّع وتقوم دالتك ببثّ النتيجة بصيغة base64،
وهي في حالة ModifyingSigner المعاملة التي أعاد مزوّده كتابتها.
لا تعتمد النواة (Core) على أي RPC:
import "github.com/solana-foundation/solana-go/v2/rpc"client := rpc.New("https://api.devnet.solana.com")sig, err := core.SignAndSendTransaction(ctx, signer, tx,func(ctx context.Context, encoded string) (solana.Signature, error) {return client.SendEncodedTransaction(ctx, encoded)})
التوقيع الدفعي
يُتاح التوقيع الدفعي في صورة دوال مساعدة حرة، تعمل بالتزامن مع تباعد اختياري لكل طلب لواجهات API ذات الحدود على المعدل:
sigs, err := core.SignMessages(ctx, signer, [][]byte{msg1, msg2}, core.BatchOptions{MaxConcurrency: 4, // 0 = unboundedRequestDelay: 50 * time.Millisecond,})signed, err := core.SignTransactions(ctx, signer, txs, core.BatchOptions{})
تأخذ core.SignTransactions المعامل core.TransactionSigner، لذا فإن
الموقِّعين الذين يديرون البث (Crossmint وFordefi native auto) وFordefi native
manual لا يمكن تجميعهم دفعياً عبرها؛ استدعِهم معاملةً واحدة في كل مرة. أما
الموقِّع الذي تنشئ استدعاءاته عملاً على جانب المزوّد (Fireblocks مع UseProgramCall)
فيُبلغ عن ذلك عبر core.BatchServerSideEffects، وعندها تعمل الدفعة
بالتتابع.
إعداد الواجهة الخلفية
Memory
وفّر واحداً فقط من PrivateKey (بايتات خام) أو PrivateKeyString (base58 أو مصفوفة بايتات
بصيغة [1,2,...]) أو PrivateKeyPath (ملف keypair الخاص بـ سولانا CLI):
import "github.com/solana-foundation/solana-keychain/go/signers/memory/v2"signer, err := memory.New(memory.Config{PrivateKeyPath: "/path/to/id.json",})
لا توفر Go طريقة موثوقة لتصفير الذاكرة: فقد ينسخ جامع النفايات بايتات المفاتيح ويحتفظ بها (keypair المخزنة في الذاكرة، والمفاتيح التي تشتقها Crossmint وOpenfort محلياً) إلى حين الجمع. تعامل مع ذاكرة العملية بأكملها على أنها حساسة عند استخدام الواجهات الخلفية ذات المفاتيح المحلية.
HashiCorp Vault
import "github.com/solana-foundation/solana-keychain/go/signers/vault/v2"signer, err := vault.New(vault.Config{VaultAddr: "https://vault.example.com:8200",Token: "hvs.xxxxx",KeyName: "my-solana-key",Pubkey: "base58_public_key",})
AWS KMS
import "github.com/solana-foundation/solana-keychain/go/signers/awskms/v2"signer, err := awskms.New(ctx, awskms.Config{KeyID: "alias/my-solana-key",PublicKey: "base58_public_key",Region: "us-east-1", // optional})
GCP KMS
import "github.com/solana-foundation/solana-keychain/go/signers/gcpkms/v2"signer, err := gcpkms.New(ctx, gcpkms.Config{KeyName: "projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1",PublicKey: "base58_public_key",})if err != nil {return err}defer signer.Close()
Privy
import "github.com/solana-foundation/solana-keychain/go/signers/privy/v2"signer, err := privy.New(ctx, privy.Config{AppID: "app_id",AppSecret: "app_secret",WalletID: "wallet_id",})
Turnkey
import "github.com/solana-foundation/solana-keychain/go/signers/turnkey/v2"signer, err := turnkey.New(turnkey.Config{APIPublicKey: "api_public_key",APIPrivateKey: "api_private_key",OrganizationID: "org_id",PrivateKeyID: "private_key_id",PublicKey: "base58_public_key",})
Fireblocks
import "github.com/solana-foundation/solana-keychain/go/signers/fireblocks/v2"signer, err := fireblocks.New(ctx, fireblocks.Config{APIKey: "api_key",PrivateKeyPEM: "-----BEGIN RSA PRIVATE KEY-----\n...",VaultAccountID: "0",AssetID: "SOL", // or "SOL_TEST" for devnetUseProgramCall: false, // true signs via sign-only PROGRAM_CALL (legacy/v0, hot wallet)})
CDP (Coinbase Developer Platform)
import "github.com/solana-foundation/solana-keychain/go/signers/cdp/v2"signer, err := cdp.New(cdp.Config{APIKeyID: "api_key_id",APIKeySecret: "api_key_secret", // base64 Ed25519WalletSecret: "wallet_secret", // base64 PKCS#8 DERAddress: "base58_address",Network: cdp.NetworkMainnet, // or cdp.NetworkDevnet; required for address lookup tables})
تقبل SignMessage في CDP حمولات UTF-8 فقط.
Crossmint
Crossmint للإرسال فقط: إذ تنفّذ واجهتها البرمجية كل معاملة معتمدة
على جانب الخادم، لذا يحتوي *crossmint.Signer على SignAndSendTransaction ولا يحتوي على
SignTransaction. لا تُعدَّل معاملتك أبداً؛ والتوقيع المُرجَع
يحدد المعاملة التي استقرت عبر Crossmint، وقد يختلف عن توقيع معاملتك إذا
كانت Crossmint ترعى رسوم الغاز.
import "github.com/solana-foundation/solana-keychain/go/signers/crossmint/v2"signer, err := crossmint.New(ctx, crossmint.Config{APIKey: "api_key",WalletLocator: "wallet_locator",SignerSecret: "", // optional xmsk1_ secret: auto-approves what Crossmint presents})sig, err := signer.SignAndSendTransaction(ctx, tx)
Dfns
import "github.com/solana-foundation/solana-keychain/go/signers/dfns/v2"signer, err := dfns.New(ctx, dfns.Config{AuthToken: "auth_token",CredID: "cred_id",PrivateKeyPEM: "-----BEGIN EC PRIVATE KEY-----\n...",WalletID: "wallet_id",})
Openfort
import "github.com/solana-foundation/solana-keychain/go/signers/openfort/v2"signer, err := openfort.New(ctx, openfort.Config{SecretKey: "sk_live_...",AccountID: "acc_...",WalletSecret: "wallet_secret", // base64 PKCS#8 DER or PEM})
Para
import "github.com/solana-foundation/solana-keychain/go/signers/para/v2"signer, err := para.New(ctx, para.Config{APIKey: "sk_...",WalletID: "wallet_id",})
Utila
توقّع Utila المعاملات فقط؛ أما SignMessage فتفشل، وعليك بثّ المعاملة الموقَّعة
بنفسك.
import "github.com/solana-foundation/solana-keychain/go/signers/utila/v2"signer, err := utila.New(ctx, utila.Config{ServiceAccountEmail: "sa@example.com",ServiceAccountPrivateKeyPEM: "-----BEGIN PRIVATE KEY-----\n...",VaultID: "vault_id",WalletID: "wallet_id",Network: "networks/solana-devnet",})
Fordefi
تأتي Fordefi بثلاثة أنواع من الموقِّعين، تُحدَّد عند الإنشاء بواسطة Config.Chain و
Config.PushMode. وجميعها توقّع الرسائل:
| الإعداد | النوع | نقطة الدخول |
|---|---|---|
Chain غير مضبوط | *fordefi.BlackBoxSigner | SignTransaction |
Chain مضبوط، وPushMode غير مضبوط أو PushModeAuto | *fordefi.NativeAutoSigner | SignAndSendTransaction |
Chain مضبوط، وPushMode: PushModeManual | *fordefi.NativeManualSigner | ModifyAndSignTransaction |
تتولى fordefi.New التوجيه بحسب الإعداد وتُرجع core.SolanaSigner؛
أما fordefi.NewBlackBox وfordefi.NewNativeAuto وfordefi.NewNativeManual
فتُرجع النوع الفعلي وترفض إعدادات الأوضاع الأخرى. تُوثَّق طلبات API
بتوقيع طلب ECDSA P-256: وفّر واحداً فقط من
PrivateKeyPEM، أو RequestSigner للإبقاء على ذلك المفتاح داخل KMS/HSM.
الوضع الأصلي التلقائي (Native auto): قد تستبدل Fordefi قيمة blockhash والرسوم، ثم توقّع وتبثّ. وهي تقبل فقط معاملة غير موقَّعة يكون الموقِّع الوحيد المطلوب فيها هو الخزنة (vault).
import "github.com/solana-foundation/solana-keychain/go/signers/fordefi/v2"signer, err := fordefi.NewNativeAuto(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"), // Solana vault address (base58)PrivateKeyPEM: string(pemBytes),Chain: fordefi.ChainSolanaDevnet, // or fordefi.ChainSolanaMainnetFee: &fordefi.Fee{Type: fordefi.FeeTypePriority,PriorityLevel: fordefi.PriorityMedium,},})sig, err := signer.SignAndSendTransaction(ctx, tx)
الوضع الأصلي اليدوي (Native manual): اضبط PushMode: fordefi.PushModeManual. تعيد Fordefi كتابة
الرسالة (blockhash الحديث وتعليمات رسوم Compute Budget) وتوقّعها
دون بثّ. تستبدل ModifyAndSignTransaction المتغير tx بالمعاملة
التي وقّعتها Fordefi: تابع منها دائماً. يجب أن تكون Fordefi هي
دافع الرسوم وأن توقّع قبل أي موقِّع مطلوب آخر، لأن إعادة الكتابة تُبطل
التواقيع الموجودة. لا تُجرى مقارنة بين النسختين بعد إعادة الكتابة، لذا افحص النتيجة قبل
البثّ.
signer, err := fordefi.NewNativeManual(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_PUBLIC_KEY"),PrivateKeyPEM: string(pemBytes),Chain: fordefi.ChainSolanaDevnet,PushMode: fordefi.PushModeManual,})signed, err := signer.ModifyAndSignTransaction(ctx, tx)
وضع الصندوق الأسود (Black box): اترك Chain غير مضبوط. توقّع Fordefi بايتات رسالتك بالضبط
ولا تبثّها. استخدم هذا مع خزنة Fordefi من نوع الصندوق الأسود.
signer, err := fordefi.NewBlackBox(ctx, fordefi.Config{AccessToken: os.Getenv("FORDEFI_ACCESS_TOKEN"),VaultID: os.Getenv("FORDEFI_BB_VAULT_ID"),PublicKey: os.Getenv("FORDEFI_BB_PUBLIC_KEY"),PrivateKeyPEM: string(pemBytes),})
لماذا لا توجد حزمة شاملة
لدى Rust تعداد Signer ولدى TypeScript الدالة createKeychainSigner؛ أما Go
فلا تملك أياً منهما عن قصد. لا تحذف Go الشيفرة الميتة عبر
عبارة توجيه وقت التشغيل (dispatch switch)، لذا ستفرض الحزمة الشاملة إدخال حزمة SDK الخاصة بمزوّد كل واجهة خلفية (AWS وGCP
وغيرهما) في بناء كل مستهلك. استيراد حزمة الواجهة الخلفية التي
تحتاجها هو أداة الاختيار. ولاختيار واجهة خلفية وقت التشغيل، اكتب عبارة الاختيار في شيفرتك
أنت على الواجهات الخلفية التي تدعمها فقط، واحتفظ بالنتيجة بوصفها
core.SolanaSigner.
معالجة الأخطاء
كل خطأ هو *core.SignerError مع Code ثابت (CodeConfigError و
CodeHTTPError وCodeRemoteAPIError وCodeSigningFailed و
CodeNotInitialized وCodeBroadcastUnconfirmed وغيرها). تُرجع Error()
رسالة ثابتة لكل رمز فقط، ولا تُرجع أبداً مادة المفاتيح أو استجابات المزوّد الخام.
طابِق باستخدام errors.As أو errors.Is(err, &core.SignerError{Code: ...}) أو
core.CodeOf(err).
في Crossmint ووضع Fordefi الأصلي التلقائي، لا يعني الفشل أن شيئاً لم
يصل إلى السلسلة. فعندما يكون المزوّد قد قبل المعاملة، يكون الرمز
core.CodeBroadcastUnconfirmed ("SIGNER_BROADCAST_UNCONFIRMED").
يُضبط ProviderTxID عند قبول الإنشاء، ويحمل IdempotencyKey
المفتاح المشتق من الرسالة. إعادة إرسال المعاملة المطابقة بايتاً ببايت
آمنة؛ أما المعاملة المعاد بناؤها (مثلاً بقيمة blockhash جديدة) فتُعد تحويلاً جديداً.
كما تُبلغ core.SignAndSendTransaction عن هذا الرمز عندما تفشل دالة الإرسال
لديك، مع توقيع دافع الرسوم في TransactionSignature. أما Fireblocks
PROGRAM_CALL فهي للتوقيع فقط ولا ترسل أي مفتاح؛ ولا تُبلغ عن هذا الرمز إلا عندما
يُظهر الاستعلام الدوري أن Fireblocks بثّت المعاملة رغم ذلك.
sig, err := core.SignAndSendTransaction(ctx, signer, tx, send)var se *core.SignerErrorif errors.As(err, &se) && se.Code == core.CodeBroadcastUnconfirmed {// Reconcile se.ProviderTxID, se.IdempotencyKey or se.TransactionSignature// with the provider before retrying.}
راجع نموذج الأمان لمعرفة ما يضمنه كل شكل من أشكال التوقيع، و ملف Go README للاطلاع على قائمة الوحدات الكاملة، و pkg.go.dev لمرجع واجهة API.
إضافة موقِّعين مخصصين
طبّق core.SolanaSigner مع واجهة قدرة واحدة بالضبط، ولا تضف أي
دالة لا تستطيع واجهتك الخلفية الوفاء بها: إذ يكتشف المستدعون القدرة عبر تأكيد النوع.
راجع دليل إضافة الموقِّعين لدمج
خدمات إدارة مفاتيح إضافية.
Is this page helpful?