Rust

Instalação

Adicione solana-keychain ao seu Cargo.toml com apenas os backends que você precisa:

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"] }

A atualizar da versão 1.x? Consulte o guia de migração para a 2.0.

Flags de Funcionalidades

RecursoDescrição
memoryAssinatura por keypair local (padrão)
vaultMotor de Trânsito HashiCorp Vault
aws_kmsAWS KMS com Ed25519
gcp_kmsGCP Cloud KMS com Ed25519
privyCarteiras incorporadas Privy
turnkeyAPI Turnkey
fireblocksMPC Fireblocks
cdpCoinbase Developer Platform
crossmintCarteiras gerenciadas Crossmint
dfnsInfraestrutura de carteiras Dfns
openfortCarteiras incorporadas Openfort
paraCarteiras MPC Para
utilaCustódia MPC Utila
fordefiCustódia MPC da Fordefi
ledgerCarteira de hardware Ledger via USB-HID (apenas Rust, opcional, não incluída em all)
allAtiva todos os backends, exceto ledger
sdk-v2Solana SDK 2.x (padrão)
sdk-v3Solana SDK 3.x
sdk-v4Solana SDK 4.x (necessário para transações v1)
unsafe-debugRegistra 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 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(())
}

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

BackendTrait de capacidadesign_message
CrossmintSendingSignerNão suportado
Fordefi nativo automáticoSendingSignerSim
Fordefi nativo manualModifyingSignerSim
UtilaTransactionSignerNão suportado
CDPTransactionSignerApenas payloads UTF-8
LedgerTransactionSignerSim, através de um envelope off-chain
Todos os outros (incl. Fordefi black box)TransactionSignerSim

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 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

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 key
None, // 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 key
Some("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 ID
None, // 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 key
None, // 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 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

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 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
})?;

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 ID
None, // 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:

chainpush_modeTipoCapacidadeComportamento
NonequalquerFordefiBlackBoxSignerTransactionSignerAssina bytes brutos; você transmite
Some(..)None ou AutoFordefiNativeAutoSignerSendingSignerA Fordefi pode reescrever o blockhash e as taxas, assina e transmite
Some(..)ManualFordefiNativeManualSignerModifyingSignerA 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 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

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 generically
let 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?

© 2026 Fundação Solana. Todos os direitos reservados.