Installation
Ajoutez solana-keychain à votre Cargo.toml avec uniquement les backends dont
vous avez besoin :
[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 linesolana-keychain = { version = "2.0", default-features = false, features = ["all", "sdk-v4"] }
Vous migrez depuis la version 1.x ? Consultez le guide de migration vers la version 2.0.
Indicateurs de fonctionnalités
| Fonctionnalité | Description |
|---|---|
memory | Signature keypair locale (par défaut) |
vault | Moteur Transit HashiCorp Vault |
aws_kms | AWS KMS avec Ed25519 |
gcp_kms | GCP Cloud KMS avec Ed25519 |
privy | Portefeuilles intégrés Privy |
turnkey | API Turnkey |
fireblocks | MPC Fireblocks |
cdp | Coinbase Developer Platform |
crossmint | Portefeuilles gérés Crossmint |
dfns | Infrastructure de portefeuilles Dfns |
openfort | Portefeuilles intégrés Openfort |
para | Portefeuilles MPC Para |
utila | Conservation MPC Utila |
fordefi | Garde MPC Fordefi |
ledger | Portefeuille matériel Ledger via USB-HID (Rust uniquement, sur option, non inclus dans all) |
all | Active tous les backends sauf ledger |
sdk-v2 | SDK Solana 2.x (par défaut) |
sdk-v3 | SDK Solana 3.x |
sdk-v4 | SDK Solana 4.x (requis pour les transactions v1) |
unsafe-debug | Journalise les réponses d'erreur complètes du fournisseur ; ne l'activez jamais en production |
Une seule des options sdk-v2, sdk-v3 et sdk-v4 doit être activée, ni plus, ni moins.
Utilisation de base
Tous les signataires implémentent le
trait SolanaSigner
de base (pubkey, sign_message, is_available). Chaque backend implémente en outre exactement
un trait de capacité :
TransactionSigner: signe votre transaction telle quelle.ModifyingSigner: le fournisseur réécrit la transaction, puis la signe.SendingSigner: le fournisseur la signe et la diffuse.
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 keylet 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 Partiallet result = signer.sign_transaction(tx).await?;let (base64_tx, signature) = result.into_signed_transaction();println!("Signature: {}", signature);Ok(())}
Convertissez une Transaction héritée (legacy) avec .into(). Les transactions legacy et v0 fonctionnent
avec toutes les fonctionnalités du SDK ; les transactions v1 nécessitent sdk-v4.
Capacités des signataires
| Backend | Trait de capacité | sign_message |
|---|---|---|
| Crossmint | SendingSigner | Non pris en charge |
| Fordefi natif automatique | SendingSigner | Oui |
| Fordefi natif manuel | ModifyingSigner | Oui |
| Utila | TransactionSigner | Non pris en charge |
| CDP | TransactionSigner | Charges utiles UTF-8 uniquement |
| Ledger | TransactionSigner | Oui, via une enveloppe hors chaîne |
| Tous les autres (y compris Fordefi boîte noire) | TransactionSigner | Oui |
Les constructeurs Signer::from_* exécutent init() pour vous. Si vous construisez
directement les types de signataires Privy, Fireblocks, Dfns, Crossmint, Para, Openfort ou Utila,
appelez init().await avant de les utiliser.
Configuration des backends
Signataire en mémoire
Pour le développement et les tests avec des paires de clés locales :
use solana_keychain::Signer;// From base58 private keylet signer = Signer::from_memory("base58_private_key")?;// From JSON keypair file pathlet signer = Signer::from_memory_file("/path/to/keypair.json")?;// From byte array stringlet signer = Signer::from_memory("[1,2,3,...]")?;
HashiCorp Vault
Pour HSM auto-hébergé avec moteur 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 keyNone, // Default HTTP timeouts)?;
AWS KMS
Pour signature cloud-native avec clés Ed25519 AWS KMS :
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 keySome("us-east-1".to_string()), // Region (optional)).await?;
Privy
Pour signature de portefeuille intégré :
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 IDNone, // Default HTTP timeouts).await?;
Turnkey
Pour signature non-custodiale :
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 keyNone, // Default HTTP timeouts)?;
Fireblocks
Pour la signature MPC institutionnelle :
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 devnetapi_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
Pour la signature native cloud avec les clés Ed25519 de 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 Developer Platform)
Pour la signature de portefeuille géré par 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 IDapi_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 addressnetwork: Some(CDP_NETWORK_MAINNET.to_string()), // Required to sign transactions with address lookup tablesapi_base_url: None,http_client_config: None, // Default HTTP timeouts})?;
sign_message de CDP n'accepte que les charges utiles UTF-8.
Crossmint
Crossmint fonctionne uniquement en mode envoi : son API exécute chaque transaction approuvée
côté serveur, il n'existe donc aucun chemin de signature seule, et sign_message échoue. Appelez
sign_and_send_transaction, qui laisse votre transaction intacte et renvoie
la signature de la transaction effectivement enregistrée. Cette transaction peut différer de
la vôtre si Crossmint sponsorise les frais de gas.
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
Pour la signature de l'infrastructure de portefeuille 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
Pour la signature de portefeuille MPC Para :
use solana_keychain::Signer;let signer = Signer::from_para("api_key".to_string(), // Para API key"wallet_id".to_string(), // Para wallet IDNone, // Default API base URL).await?;
Openfort
Pour la signature avec un portefeuille backend 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
Pour la signature avec la conservation MPC d'Utila. sign_message n'est pas pris en charge, et vous
diffusez vous-même la transaction signée.
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
Pour la signature avec la conservation MPC de Fordefi. Les requêtes API sont authentifiées par une signature de requête ECDSA
P-256. Fournissez exactement l'un des éléments suivants : private_key_pem ou
request_signer (un Arc<dyn FordefiRequestSigner>, utilisé pour conserver cette clé dans un
KMS/HSM).
Fordefi existe en trois types de signataires, fixés à la construction par chain et
push_mode :
chain | push_mode | Type | Capacité | Comportement |
|---|---|---|---|---|
None | n'importe lequel | FordefiBlackBoxSigner | TransactionSigner | Signe les octets bruts ; vous diffusez |
Some(..) | None ou Auto | FordefiNativeAutoSigner | SendingSigner | Fordefi peut réécrire le blockhash et les frais, puis signe et diffuse |
Some(..) | Manual | FordefiNativeManualSigner | ModifyingSigner | Fordefi réécrit et signe ; vous diffusez la transaction renvoyée |
Le mode natif manuel remplace votre transaction par celle que Fordefi a signée. Poursuivez à partir de celle-ci, jamais de celle que vous avez construite. Il doit s'exécuter avant tout autre signataire requis.
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 addresschain: Some(SolanaChainUniqueId::SolanaDevnet), // None for black box modefee: Some(FordefiSolanaFee::Priority {priority_level: FordefiPriorityLevel::Medium,}),push_mode: Some(FordefiPushMode::Auto), // Manual: sign without broadcastingapi_base_url: None, // Default: https://api.fordefi.compoll_interval_ms: None, // Default: 2000max_poll_attempts: None, // Default: 50http_client_config: None, // Default HTTP timeouts};let signer = Signer::from_fordefi(config).await?;
Ledger
Pour la signature avec un portefeuille matériel via USB-HID (Rust uniquement). Nécessite la fonctionnalité ledger,
un appareil déverrouillé exécutant l'application Solana et, sous Linux, les règles udev de Ledger.
Ledger n'est pas couvert par l'audit actuel ; consultez
l'état de l'audit.
use solana_keychain::{LedgerConfig, Signer};let signer = Signer::from_ledger(LedgerConfig {confirm_pubkey_on_device: true,..LedgerConfig::default()}).await?;
sign_message signe une enveloppe hors chaîne encapsulant votre charge utile, et non les octets
bruts ; reconstruisez-la avec solana_keychain::ledger::ledger_offchain_envelope pour
la vérifier. Définissez auto_open_app: false pour une utilisation sans surveillance. Une invite refusée sur
l'appareil renvoie SignerError::UserRejected.
Énumération unifiée des signataires
Utilisez l'énumération Signer pour sélectionner les backends à l'exécution :
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 genericallylet signer = get_signer("kms").await?;let pubkey = signer.pubkey();
Signer n'implémente que SolanaSigner. Accédez à une capacité via
as_transaction_signer(), as_modifying_signer() ou as_sending_signer(),
qui renvoient None lorsque le backend ne prend pas en charge ce mode :
if let Some(transaction_signer) = signer.as_transaction_signer() {let result = transaction_signer.sign_transaction(&mut tx).await?;}
Ou laissez sign_and_send router selon le backend. La crate n'inclut aucun client RPC, c'est donc à vous de
fournir la diffusion ; pour un backend d'envoi, la closure n'est jamais appelée :
let signature = signer.sign_and_send(&mut tx, |encoded| async move { broadcast(encoded).await }).await?;
Gestion des erreurs
SignerError::BroadcastUnconfirmed { provider_tx_id, idempotency_key, transaction_signature, .. }
(provenant de Crossmint, de Fordefi natif automatique ou d'une closure sign_and_send en échec)
signifie que la transaction a peut-être été enregistrée. Ne réessayez pas à l'aveugle : rapprochez d'abord
provider_tx_id ou transaction_signature, ou renvoyez uniquement la transaction
identique octet pour octet. Les match exhaustifs sur SignerError doivent inclure cette branche.
Consultez le
modèle de sécurité
pour connaître les garanties offertes par chaque mode de signature.
Ajout de signataires personnalisés
Consultez le guide d'ajout de signataires pour intégrer des services supplémentaires de gestion de clés.
Is this page helpful?