Rust

التثبيت

أضف solana-keychain إلى Cargo.toml مع الواجهات الخلفية التي تحتاجها فقط:

Cargo.toml
[dependencies]
# Memory signer only (default, Solana SDK 2.x)
solana-keychain = "2.0"
# Or specify backends explicitly (pick exactly one SDK feature)
solana-keychain = { version = "2.0", default-features = false, features = ["vault", "aws_kms", "sdk-v2"] }
# All remote backends on the Solana 4.x SDK line
solana-keychain = { version = "2.0", default-features = false, features = ["all", "sdk-v4"] }

هل تقوم بالترقية من الإصدار 1.x؟ راجع دليل الانتقال إلى 2.0.

علامات الميزات

الميزةالوصف
memoryتوقيع keypair محلي (افتراضي)
vaultمحرك HashiCorp Vault Transit
aws_kmsAWS KMS مع Ed25519
gcp_kmsGCP Cloud KMS مع Ed25519
privyمحافظ Privy المدمجة
turnkeyTurnkey API
fireblocksFireblocks MPC
cdpمنصة Coinbase للمطورين
crossmintمحافظ Crossmint المُدارة
dfnsبنية تحتية لمحافظ Dfns
openfortمحافظ Openfort المدمجة
paraمحافظ Para MPC
utilaحضانة Utila MPC
fordefiحضانة Fordefi MPC
ledgerمحفظة Ledger الصلبة عبر USB-HID (لغة Rust فقط، اختياري، غير مشمول في all)
allتفعيل جميع الواجهات الخلفية باستثناء ledger
sdk-v2حزمة تطوير سولانا SDK 2.x (الافتراضي)
sdk-v3حزمة تطوير سولانا SDK 3.x
sdk-v4حزمة تطوير سولانا SDK 4.x (مطلوبة لمعاملات الإصدار v1)
unsafe-debugيسجّل استجابات الأخطاء الكاملة من المزوّد؛ لا تفعّله أبدًا في بيئة الإنتاج

يجب تفعيل واحد فقط من sdk-v2 وsdk-v3 وsdk-v4.

الاستخدام الأساسي

تنفّذ جميع أدوات التوقيع السمة الأساسية SolanaSigner trait (pubkey وsign_message وis_available). وتنفّذ كل واجهة خلفية أيضًا سمة قدرة واحدة بالضبط:

  • TransactionSigner: يوقّع معاملتك كما هي.
  • ModifyingSigner: يعيد المزوّد كتابة المعاملة ثم يوقّعها.
  • SendingSigner: يوقّع المزوّد المعاملة ويبثّها.
use solana_keychain::{SignerError, SolanaSigner, TransactionSigner};
use solana_sdk::transaction::VersionedTransaction;
async fn sign_transaction(
signer: &impl TransactionSigner,
tx: &mut VersionedTransaction,
) -> Result<(), SignerError> {
// Get the signer's public key
let pubkey = signer.pubkey();
println!("Signing with: {}", pubkey);
// Check availability (useful for remote signers)
if !signer.is_available().await {
return Err(SignerError::NotAvailable("Signer offline".into()));
}
// Sign the transaction: returns Complete or Partial
let result = signer.sign_transaction(tx).await?;
let (base64_tx, signature) = result.into_signed_transaction();
println!("Signature: {}", signature);
Ok(())
}

حوّل معاملة Transaction القديمة باستخدام .into(). تعمل المعاملات القديمة ومعاملات v0 مع كل ميزات SDK؛ أما معاملات v1 فتتطلب sdk-v4.

قدرات أداة التوقيع

الواجهة الخلفيةسمة القدرةsign_message
CrossmintSendingSignerغير مدعوم
Fordefi الأصلي التلقائيSendingSignerنعم
Fordefi الأصلي اليدويModifyingSignerنعم
UtilaTransactionSignerغير مدعوم
CDPTransactionSignerحمولات UTF-8 فقط
LedgerTransactionSignerنعم، عبر غلاف خارج السلسلة
جميع الواجهات الأخرى (بما فيها Fordefi الصندوق الأسود)TransactionSignerنعم

تقوم دوال الإنشاء Signer::from_* بتشغيل init() نيابةً عنك. إذا أنشأت أنواع أدوات التوقيع Privy أو Fireblocks أو Dfns أو Crossmint أو Para أو Openfort أو Utila مباشرةً، فاستدعِ init().await قبل الاستخدام.

تكوين الواجهة الخلفية

موقع الذاكرة

للتطوير والاختبار باستخدام أزواج المفاتيح المحلية:

use solana_keychain::Signer;
// From base58 private key
let signer = Signer::from_memory("base58_private_key")?;
// From JSON keypair file path
let signer = Signer::from_memory_file("/path/to/keypair.json")?;
// From byte array string
let signer = Signer::from_memory("[1,2,3,...]")?;

HashiCorp Vault

لوحدة HSM ذاتية الاستضافة مع محرك Transit:

use solana_keychain::Signer;
let signer = Signer::from_vault(
"https://vault.example.com:8200".to_string(), // Vault address
"hvs.xxxxx".to_string(), // Vault token
"my-solana-key".to_string(), // Key name in Transit
"base58_public_key".to_string(), // Expected public key
None, // Default HTTP timeouts
)?;

AWS KMS

للتوقيع السحابي الأصلي باستخدام مفاتيح AWS KMS Ed25519:

use solana_keychain::Signer;
let signer = Signer::from_aws_kms(
"alias/my-solana-key".to_string(), // KMS key ID or alias
"base58_public_key".to_string(), // Expected public key
Some("us-east-1".to_string()), // Region (optional)
).await?;

Privy

لتوقيع المحفظة المدمجة:

use solana_keychain::Signer;
let signer = Signer::from_privy(
"app_id".to_string(), // Privy app ID
"app_secret".to_string(), // Privy app secret
"wallet_id".to_string(), // Wallet ID
None, // Default HTTP timeouts
).await?;

Turnkey

للتوقيع غير الوصائي:

use solana_keychain::Signer;
let signer = Signer::from_turnkey(
"api_public_key".to_string(), // Turnkey API public key
"api_private_key".to_string(), // Turnkey API private key
"org_id".to_string(), // Organization ID
"private_key_id".to_string(), // Private key ID in Turnkey
"base58_public_key".to_string(),// Expected public key
None, // Default HTTP timeouts
)?;

Fireblocks

للتوقيع المؤسسي باستخدام MPC:

use solana_keychain::{Signer, FireblocksSignerConfig};
let config = FireblocksSignerConfig {
api_key: "api_key".to_string(),
private_key_pem: "-----BEGIN RSA PRIVATE KEY-----\n...".to_string(),
vault_account_id: "0".to_string(),
asset_id: Some("SOL".to_string()), // None defaults to "SOL"; "SOL_TEST" for devnet
api_base_url: None,
poll_interval_ms: None,
max_poll_attempts: None,
use_program_call: None, // Some(true) signs via PROGRAM_CALL (sign-only, legacy/v0, hot wallet)
http_client_config: None,
};
let signer = Signer::from_fireblocks(config).await?;

GCP KMS

للتوقيع السحابي الأصلي باستخدام مفاتيح Ed25519 في GCP Cloud KMS:

use solana_keychain::Signer;
let signer = Signer::from_gcp_kms(
"projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1".to_string(),
"base58_public_key".to_string(),
).await?;

CDP (منصة Coinbase للمطورين)

للتوقيع عبر المحفظة المُدارة من Coinbase:

use solana_keychain::{Signer, CdpSignerConfig, CDP_NETWORK_MAINNET};
let signer = Signer::from_cdp(CdpSignerConfig {
api_key_id: "api_key_id".to_string(), // CDP API key ID
api_key_secret: "api_key_secret".to_string(), // CDP API private key (base64 Ed25519)
wallet_secret: "wallet_secret".to_string(), // CDP wallet secret (base64 PKCS#8 DER)
address: "base58_address".to_string(), // Solana account address
network: Some(CDP_NETWORK_MAINNET.to_string()), // Required to sign transactions with address lookup tables
api_base_url: None,
http_client_config: None, // Default HTTP timeouts
})?;

تقبل sign_message في CDP حمولات UTF-8 فقط.

Crossmint

Crossmint للإرسال فقط: تنفّذ واجهته البرمجية كل معاملة معتمدة على جانب الخادم، لذلك لا يوجد مسار للتوقيع فقط، وتفشل sign_message. استدعِ sign_and_send_transaction، التي تترك معاملتك دون تعديل وتعيد توقيع المعاملة التي تم تأكيدها فعليًا. وقد تختلف تلك المعاملة عن معاملتك إذا كانت Crossmint ترعى رسوم الغاز.

use solana_keychain::{Signer, CrossmintSignerConfig};
let config = CrossmintSignerConfig {
api_key: "api_key".to_string(),
wallet_locator: "wallet_locator".to_string(),
signer_secret: None,
signer: None,
api_base_url: None,
poll_interval_ms: None,
max_poll_attempts: None,
};
let signer = Signer::from_crossmint(config).await?;
let signature = signer
.as_sending_signer()
.expect("Crossmint is a sending signer")
.sign_and_send_transaction(&tx)
.await?;

Dfns

للتوقيع عبر البنية التحتية للمحافظ من Dfns:

use solana_keychain::{Signer, DfnsSignerConfig};
let config = DfnsSignerConfig {
auth_token: "auth_token".to_string(),
cred_id: "cred_id".to_string(),
private_key_pem: "-----BEGIN EC PRIVATE KEY-----\n...".to_string(),
wallet_id: "wallet_id".to_string(),
api_base_url: None,
http_client_config: None,
};
let signer = Signer::from_dfns(config).await?;

Para

للتوقيع عبر محفظة Para MPC:

use solana_keychain::Signer;
let signer = Signer::from_para(
"api_key".to_string(), // Para API key
"wallet_id".to_string(), // Para wallet ID
None, // Default API base URL
).await?;

Openfort

للتوقيع عبر محفظة Openfort الخلفية:

use solana_keychain::Signer;
let signer = Signer::from_openfort(
"sk_live_...".to_string(), // Openfort secret key
"acc_...".to_string(), // Account ID
"wallet_secret".to_string(), // Wallet secret (base64 PKCS#8 DER or PEM)
None, // Default HTTP timeouts
).await?;

Utila

للتوقيع عبر الحفظ المعتمد على MPC في Utila. إن sign_message غير مدعومة، وعليك بثّ المعاملة الموقّعة بنفسك.

use solana_keychain::{Signer, UtilaSignerConfig};
let signer = Signer::from_utila(UtilaSignerConfig {
service_account_email: "sa@example.com".to_string(),
service_account_private_key_pem: "-----BEGIN PRIVATE KEY-----\n...".to_string(),
vault_id: "vault_id".to_string(),
wallet_id: "wallet_id".to_string(),
network: "networks/solana-devnet".to_string(),
api_base_url: None,
poll_interval_ms: None,
max_poll_attempts: None,
designated_signers: None,
http_client_config: None,
}).await?;

Fordefi

للتوقيع عبر الحفظ المعتمد على MPC في Fordefi. تتم مصادقة طلبات API باستخدام توقيع طلب ECDSA P-256. قدّم واحدًا فقط من private_key_pem أو request_signer (من النوع Arc<dyn FordefiRequestSigner>، ويُستخدم لإبقاء ذلك المفتاح في KMS/HSM).

يأتي Fordefi في ثلاثة أنواع من أدوات التوقيع، تُحدَّد عند الإنشاء بواسطة chain و push_mode:

chainpush_modeالنوعالقدرةالسلوك
Noneأي قيمةFordefiBlackBoxSignerTransactionSignerيوقّع البايتات الخام؛ وتتولى أنت البث
Some(..)None أو AutoFordefiNativeAutoSignerSendingSignerقد يعيد Fordefi كتابة blockhash والرسوم، ثم يوقّع ويبثّ
Some(..)ManualFordefiNativeManualSignerModifyingSignerيعيد Fordefi الكتابة ويوقّع؛ وتتولى أنت بث المعاملة المُعادة

يستبدل الوضع اليدوي الأصلي معاملتك بالمعاملة التي وقّعها Fordefi. تابع العمل منها، وليس من المعاملة التي أنشأتها. ويجب أن يعمل قبل أي موقّع مطلوب آخر.

use solana_keychain::{
Signer, FordefiSignerConfig, FordefiPushMode, SolanaChainUniqueId, FordefiSolanaFee,
FordefiPriorityLevel,
};
let config = FordefiSignerConfig {
access_token: "api_token".to_string(),
vault_id: "vault_uuid".to_string(),
private_key_pem: Some(std::fs::read_to_string("./secret/private.pem")?),
request_signer: None, // Or Some(Arc::new(your_kms_signer))
public_key: "base58_public_key".to_string(), // Solana vault address
chain: Some(SolanaChainUniqueId::SolanaDevnet), // None for black box mode
fee: Some(FordefiSolanaFee::Priority {
priority_level: FordefiPriorityLevel::Medium,
}),
push_mode: Some(FordefiPushMode::Auto), // Manual: sign without broadcasting
api_base_url: None, // Default: https://api.fordefi.com
poll_interval_ms: None, // Default: 2000
max_poll_attempts: None, // Default: 50
http_client_config: None, // Default HTTP timeouts
};
let signer = Signer::from_fordefi(config).await?;

Ledger

للتوقيع عبر المحفظة الصلبة من خلال USB-HID (لغة Rust فقط). يتطلب ميزة ledger، وجهازًا مفتوح القفل يشغّل تطبيق سولانا، وعلى Linux قواعد udev الخاصة بـ Ledger. لا يشمله التدقيق الحالي؛ راجع حالة التدقيق.

use solana_keychain::{LedgerConfig, Signer};
let signer = Signer::from_ledger(LedgerConfig {
confirm_pubkey_on_device: true,
..LedgerConfig::default()
})
.await?;

توقّع sign_message غلافًا خارج السلسلة يحيط بحمولتك، وليس البايتات الخام؛ أعد بناءه باستخدام solana_keychain::ledger::ledger_offchain_envelope للتحقق. اضبط auto_open_app: false للاستخدام دون إشراف. وعند رفض الطلب على الجهاز تُعيد الدالة SignerError::UserRejected.

تعداد الموقّع الموحد

استخدم تعداد Signer لاختيار الخلفيات في وقت التشغيل:

use solana_keychain::{Signer, SolanaSigner, SignerError};
async fn get_signer(backend: &str) -> Result<Signer, SignerError> {
match backend {
"memory" => Signer::from_memory("base58_key"),
"vault" => Signer::from_vault(/* ... */),
"kms" => Signer::from_aws_kms(/* ... */).await,
_ => Err(SignerError::ConfigError("Unknown backend".into())),
}
}
// Use it generically
let signer = get_signer("kms").await?;
let pubkey = signer.pubkey();

ينفّذ Signer السمة SolanaSigner فقط. يمكنك الوصول إلى أي قدرة عبر as_transaction_signer() أو as_modifying_signer() أو as_sending_signer()، والتي تُعيد None عندما لا تدعم الواجهة الخلفية ذلك النمط:

if let Some(transaction_signer) = signer.as_transaction_signer() {
let result = transaction_signer.sign_transaction(&mut tx).await?;
}

أو دع sign_and_send تختار المسار بحسب الواجهة الخلفية. لا تتضمن الحزمة عميل RPC، لذا عليك توفير آلية البث؛ وفي الواجهة الخلفية المرسِلة لا يُستدعى الإغلاق (closure) أبدًا:

let signature = signer
.sign_and_send(&mut tx, |encoded| async move { broadcast(encoded).await })
.await?;

معالجة الأخطاء

إن SignerError::BroadcastUnconfirmed { provider_tx_id, idempotency_key, transaction_signature, .. } (من Crossmint أو Fordefi الأصلي التلقائي أو من إغلاق sign_and_send الفاشل) تعني أن المعاملة ربما تم تأكيدها. لا تعد المحاولة بشكل أعمى: طابِق أولًا provider_tx_id أو transaction_signature، أو أعد إرسال المعاملة المطابقة بايتًا ببايت فقط. وتحتاج تعبيرات match الشاملة على SignerError إلى هذا الفرع. راجع نموذج الأمان لمعرفة ما يضمنه كل نمط من أنماط التوقيع.

إضافة موقّعين مخصصين

راجع دليل إضافة الموقّعين لدمج خدمات إدارة المفاتيح الإضافية.

Is this page helpful?