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

للتوقيع عبر حضانة Utila MPC. لا تُدعم 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

للتوقيع عبر حضانة Fordefi MPC. تُوثَّق طلبات 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، وجهازًا مفتوح القفل يشغّل تطبيق Solana، وعلى Linux قواعد udev الخاصة بـ Ledger. لا يشمل التدقيق الحالي 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، لذا توفّر أنت آلية البث؛ وفي الواجهة الخلفية المرسِلة لا تُستدعى الدالة المُمرَّرة أبدًا:

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?