الإصدار 2.0.0 هو أول إصدار مستقر لوحدات Go، لذا لا يوجد ما يستدعي الترحيل. يغطي دليل الترحيل إلى 2.0 نفس تقسيم القدرات في Rust وTypeScript.
التثبيت
كل واجهة خلفية هي وحدة Go مستقلة، لذا يقتصر بناؤك ورسم الوحدات لديك على الواجهات الخلفية التي تستوردها فقط:
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 التي تقبل المعاملات القديمة و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 بوضع الصندوق الأسود (fordefi.BlackBoxSigner) | TransactionSigner | نعم |
fordefi بالوضع الأصلي اليدوي (fordefi.NativeManualSigner) | ModifyingSigner | نعم |
fordefi بالوضع الأصلي التلقائي (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 المعاملة التي أعاد مزوّده كتابتها.
لا تعتمد النواة على أي 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)})
التوقيع على دفعات
يتوفر التوقيع على دفعات كدوال مساعدة حرة، تعمل بالتزامن مع فاصل زمني اختياري لكل طلب لواجهات برمجة التطبيقات ذات حدود المعدل:
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 بالوضع الأصلي التلقائي) ولا Fordefi بالوضع الأصلي
اليدوي عبرها على دفعات؛ استدعِهم معاملة واحدة في كل مرة. أما الموقِّع
الذي تنشئ استدعاءاته عملًا لدى المزوّد (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 طريقة موثوقة لتصفير الذاكرة: فقد ينسخ جامع المهملات بايتات المفاتيح ويحتفظ بها (keypairs الذاكرة، والمفاتيح التي تشتقها 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 للمطورين)
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.
الوضع الأصلي التلقائي: قد تستبدل 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)
الوضع الأصلي اليدوي: اضبط 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)
وضع الصندوق الأسود: اترك 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 لا تحذف الشيفرة الميتة عبر
عبارة تبديل وقت التشغيل، لذا ستفرض حزمة شاملة إدخال حزمة 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 لمرجع واجهة برمجة التطبيقات.
إضافة موقِّعين مخصصين
طبّق core.SolanaSigner مع واجهة قدرة واحدة بالضبط، ولا تضف أي
دالة لا تستطيع واجهتك الخلفية الوفاء بها: إذ يكتشف المستدعون القدرة عبر تأكيد النوع.
راجع دليل إضافة الموقِّعين لدمج
خدمات إدارة مفاتيح إضافية.
Is this page helpful?