Instalação
Adicione solana-keychain ao seu Cargo.toml com apenas os backends que você
precisa:
[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"] }
A atualizar da versão 1.x? Consulte o guia de migração para a 2.0.
Flags de Funcionalidades
| Recurso | Descrição |
|---|---|
memory | Assinatura por keypair local (padrão) |
vault | Motor de Trânsito HashiCorp Vault |
aws_kms | AWS KMS com Ed25519 |
gcp_kms | GCP Cloud KMS com Ed25519 |
privy | Carteiras incorporadas Privy |
turnkey | API Turnkey |
fireblocks | MPC Fireblocks |
cdp | Coinbase Developer Platform |
crossmint | Carteiras gerenciadas Crossmint |
dfns | Infraestrutura de carteiras Dfns |
openfort | Carteiras incorporadas Openfort |
para | Carteiras MPC Para |
utila | Custódia MPC Utila |
fordefi | Custódia MPC da Fordefi |
ledger | Carteira de hardware Ledger via USB-HID (apenas Rust, opcional, não incluída em all) |
all | Ativa todos os backends, exceto ledger |
sdk-v2 | Solana SDK 2.x (padrão) |
sdk-v3 | Solana SDK 3.x |
sdk-v4 | Solana SDK 4.x (necessário para transações v1) |
unsafe-debug | Registra as respostas de erro completas do provedor; nunca ative em produção |
Exatamente um entre sdk-v2, sdk-v3 e sdk-v4 deve estar ativado.
Uso Básico
Todos os signers implementam a
trait SolanaSigner
base (pubkey, sign_message, is_available). Cada backend também implementa exatamente
uma trait de capacidade:
TransactionSigner: assina a sua transação tal como foi fornecida.ModifyingSigner: o provedor reescreve a transação e depois assina-a.SendingSigner: o provedor assina e transmite a transação.
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(())}
Converta uma Transaction legada com .into(). As transações legadas e v0 funcionam
em todas as features de SDK; as transações v1 exigem sdk-v4.
Capacidades do Signer
| Backend | Trait de capacidade | sign_message |
|---|---|---|
| Crossmint | SendingSigner | Não suportado |
| Fordefi nativo automático | SendingSigner | Sim |
| Fordefi nativo manual | ModifyingSigner | Sim |
| Utila | TransactionSigner | Não suportado |
| CDP | TransactionSigner | Apenas payloads UTF-8 |
| Ledger | TransactionSigner | Sim, através de um envelope off-chain |
| Todos os outros (incl. Fordefi black box) | TransactionSigner | Sim |
Os construtores Signer::from_* executam init() por si. Se construir
diretamente os tipos de signer Privy, Fireblocks, Dfns, Crossmint, Para, Openfort ou Utila,
chame init().await antes de usar.
Configuração de Backends
Signatário de Memória
Para desenvolvimento e testes com keypairs locais:
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
Para HSM auto-hospedado com motor 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
Para assinatura nativa em nuvem com chaves Ed25519 do 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
Para assinatura com carteira incorporada:
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
Para assinatura não-custodial:
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
Para assinatura MPC institucional:
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
Para assinatura nativa na nuvem com chaves Ed25519 do 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)
Para assinatura com carteira gerenciada pela 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})?;
O sign_message da CDP aceita apenas payloads UTF-8.
Crossmint
A Crossmint é apenas de envio: a sua API executa todas as transações aprovadas
no lado do servidor, pelo que não existe um caminho apenas de assinatura e sign_message falha. Chame
sign_and_send_transaction, que deixa a sua transação intacta e devolve
a assinatura da transação que foi efetivamente confirmada. Essa transação pode ser diferente
da sua se a Crossmint patrocinar o gás.
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
Para assinatura com infraestrutura de carteira 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 assinatura com carteira 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
Para assinatura com carteira de 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
Para assinatura com custódia MPC Utila. sign_message não é suportado e
você mesmo transmite a transação assinada.
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
Para assinatura com custódia MPC da Fordefi. Os pedidos à API são autenticados com uma assinatura de pedido ECDSA
P-256. Forneça exatamente um entre private_key_pem ou
request_signer (um Arc<dyn FordefiRequestSigner>, usado para manter essa chave num
KMS/HSM).
A Fordefi disponibiliza três tipos de signer, fixados na construção por chain e
push_mode:
chain | push_mode | Tipo | Capacidade | Comportamento |
|---|---|---|---|---|
None | qualquer | FordefiBlackBoxSigner | TransactionSigner | Assina bytes brutos; você transmite |
Some(..) | None ou Auto | FordefiNativeAutoSigner | SendingSigner | A Fordefi pode reescrever o blockhash e as taxas, assina e transmite |
Some(..) | Manual | FordefiNativeManualSigner | ModifyingSigner | A Fordefi reescreve e assina; você transmite a transação devolvida |
O modo nativo manual substitui a sua transação pela que a Fordefi assinou. Continue a partir dela, nunca da que você construiu. Tem de ser executado antes de qualquer outro signer obrigatório.
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
Para assinatura com carteira de hardware via USB-HID (apenas Rust). Requer a feature ledger,
um dispositivo desbloqueado com a aplicação Solana e, no Linux, as regras udev da Ledger.
A Ledger não está coberta pela auditoria atual; consulte o
estado da auditoria.
use solana_keychain::{LedgerConfig, Signer};let signer = Signer::from_ledger(LedgerConfig {confirm_pubkey_on_device: true,..LedgerConfig::default()}).await?;
sign_message assina um envelope off-chain que encapsula o seu payload, não os bytes
brutos; reconstrua-o com solana_keychain::ledger::ledger_offchain_envelope para
verificar. Defina auto_open_app: false para uso não assistido. Um pedido recusado no
dispositivo devolve SignerError::UserRejected.
Enum de Assinante Unificado
Use o enum Signer para selecionar backends em tempo de execução:
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 implementa apenas SolanaSigner. Aceda a uma capacidade através de
as_transaction_signer(), as_modifying_signer() ou as_sending_signer(),
que devolvem None quando o backend não tem essa forma:
if let Some(transaction_signer) = signer.as_transaction_signer() {let result = transaction_signer.sign_transaction(&mut tx).await?;}
Ou deixe o sign_and_send encaminhar conforme o backend. O crate não tem cliente RPC, pelo que
você fornece a transmissão; num backend de envio, a closure nunca é chamada:
let signature = signer.sign_and_send(&mut tx, |encoded| async move { broadcast(encoded).await }).await?;
Tratamento de Erros
SignerError::BroadcastUnconfirmed { provider_tx_id, idempotency_key, transaction_signature, .. }
(proveniente da Crossmint, da Fordefi nativo automático ou de uma closure sign_and_send com falha)
significa que a transação pode ter sido confirmada. Não tente novamente às cegas: reconcilie primeiro
provider_tx_id ou transaction_signature, ou reenvie apenas a transação
idêntica byte a byte. Os matches exaustivos sobre SignerError precisam deste ramo.
Consulte o
modelo de segurança
para saber o que cada forma de assinatura garante.
Adicionando Assinantes Personalizados
Consulte o guia de Adição de Assinantes para integrar serviços adicionais de gerenciamento de chaves.
Is this page helpful?