Installation
Add solana-keychain to your Cargo.toml with only the backends you need:
[dependencies]# Memory signer only (default)solana-keychain = "1.2"# Or specify backends explicitlysolana-keychain = { version = "1.2", default-features = false, features = ["vault", "aws_kms"] }# All backendssolana-keychain = { version = "1.2", features = ["all"] }
Feature Flags
| Feature | Description |
|---|---|
memory | Local keypair signing (default) |
vault | HashiCorp Vault Transit engine |
aws_kms | AWS KMS with Ed25519 |
gcp_kms | GCP Cloud KMS with Ed25519 |
privy | Privy embedded wallets |
turnkey | Turnkey API |
fireblocks | Fireblocks MPC |
cdp | Coinbase Developer Platform |
crossmint | Crossmint managed wallets |
dfns | Dfns wallet infrastructure |
openfort | Openfort embedded wallets |
para | Para MPC wallets |
utila | Utila MPC custody |
fordefi | Fordefi MPC custody |
all | Enable all backends |
Basic Usage
All signers implement the
SolanaSigner trait:
use solana_keychain::{SolanaSigner, Signer, SignerError, SignTransactionResult};use solana_sdk::transaction::Transaction;async fn sign_transaction(signer: &impl SolanaSigner,tx: &mut Transaction,) -> 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(())}
Backend Configuration
Memory Signer
For development and testing with local keypairs:
use solana_keychain::Signer;// From base58 private keylet signer = Signer::from_memory("base58_private_key")?;// From JSON file pathlet signer = Signer::from_memory("/path/to/keypair.json")?;// From byte array stringlet signer = Signer::from_memory("[1,2,3,...]")?;
HashiCorp Vault
For self-hosted HSM with Transit engine:
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
For cloud-native signing with AWS KMS Ed25519 keys:
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
For embedded wallet signing:
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
For non-custodial signing:
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
For institutional MPC signing:
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: "SOL".to_string(), // or "SOL_TEST" for devnet};let signer = Signer::from_fireblocks(config).await?;
GCP KMS
For cloud-native signing with GCP Cloud KMS Ed25519 keys:
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)
For Coinbase managed wallet signing:
use solana_keychain::Signer;let signer = Signer::from_cdp("api_key_id".to_string(), // CDP API key ID"api_key_secret".to_string(), // CDP API private key (base64 Ed25519)"wallet_secret".to_string(), // CDP wallet secret (base64 PKCS#8 DER)"base58_address".to_string(), // Solana account addressNone, // Default HTTP timeouts)?;
Crossmint
For Crossmint managed wallet signing:
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?;
Dfns
For Dfns wallet infrastructure signing:
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(),app_id: "app_id".to_string(),wallet_id: "wallet_id".to_string(),api_base_url: None,http_client_config: None,};let signer = Signer::from_dfns(config).await?;
Para
For Para MPC wallet signing:
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?;
Fordefi
For Fordefi MPC custody signing. API requests are authenticated with an ECDSA
P-256 request signature parsed from private_key_pem; to keep that key in a
KMS/HSM, implement FordefiRequestSigner and use
Signer::from_fordefi_with_signer.
Fordefi has two signing modes. Set chain for native Solana mode, where
Fordefi may replace the blockhash or fees and broadcasts the transaction itself.
Leave chain as None for black box mode, where Fordefi signs raw bytes
and you broadcast the transaction yourself.
use solana_keychain::{Signer, FordefiSignerConfig, SolanaChainUniqueId, FordefiSolanaFee, FordefiPriorityLevel,};let config = FordefiSignerConfig {access_token: "api_token".to_string(),vault_id: "vault_uuid".to_string(),private_key_pem: std::fs::read_to_string("./secret/private.pem")?,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,}),api_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)?;
Unified Signer Enum
Use the Signer enum to select backends at runtime:
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();
Adding Custom Signers
See the Adding Signers guide to integrate additional key management services.
Is this page helpful?