Rust

Instalacja

Dodaj solana-keychain do swojego Cargo.toml z tylko tymi backendami, których potrzebujesz:

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

Aktualizujesz z wersji 1.x? Zobacz przewodnik po migracji do wersji 2.0.

Flagi funkcji

FunkcjaOpis
memoryLokalne podpisywanie keypair (domyślne)
vaultSilnik tranzytowy HashiCorp Vault
aws_kmsAWS KMS z Ed25519
gcp_kmsGCP Cloud KMS z Ed25519
privyWbudowane portfele Privy
turnkeyAPI Turnkey
fireblocksFireblocks MPC
cdpPlatforma deweloperska Coinbase
crossmintZarządzane portfele Crossmint
dfnsInfrastruktura portfeli Dfns
openfortWbudowane portfele Openfort
paraPortfele MPC Para
utilaUsługa powiernicza Utila MPC
fordefiCustody MPC Fordefi
ledgerPortfel sprzętowy Ledger przez USB-HID (tylko Rust, opcjonalny, nie wchodzi w skład all)
allWłącza wszystkie backendy poza ledger
sdk-v2Solana SDK 2.x (domyślny)
sdk-v3Solana SDK 3.x
sdk-v4Solana SDK 4.x (wymagany dla transakcji v1)
unsafe-debugZapisuje w logach pełne odpowiedzi błędów dostawcy; nigdy nie włączaj na produkcji

Włączona musi być dokładnie jedna z funkcji: sdk-v2, sdk-v3 lub sdk-v4.

Podstawowe użycie

Wszystkie signery implementują bazowy trait SolanaSigner (pubkey, sign_message, is_available). Każdy backend implementuje też dokładnie jeden trait możliwości:

  • TransactionSigner: podpisuje transakcję w postaci, w jakiej ją przekazano.
  • ModifyingSigner: dostawca modyfikuje transakcję, a następnie ją podpisuje.
  • SendingSigner: dostawca podpisuje transakcję i ją rozgłasza.
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(())
}

Przekonwertuj starszą transakcję Transaction za pomocą .into(). Transakcje legacy i v0 działają ze wszystkimi funkcjami SDK; transakcje v1 wymagają sdk-v4.

Możliwości signerów

BackendTrait możliwościsign_message
CrossmintSendingSignerNieobsługiwane
Fordefi native autoSendingSignerTak
Fordefi native manualModifyingSignerTak
UtilaTransactionSignerNieobsługiwane
CDPTransactionSignerTylko dane w UTF-8
LedgerTransactionSignerTak, przez kopertę off-chain
Wszystkie pozostałe (w tym Fordefi black box)TransactionSignerTak

Konstruktory Signer::from_* same wywołują init(). Jeśli typy signerów Privy, Fireblocks, Dfns, Crossmint, Para, Openfort lub Utila tworzysz bezpośrednio, wywołaj init().await przed użyciem.

Konfiguracja backendu

Podpisujący w pamięci

Do rozwoju i testowania z lokalnymi keypair:

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

Do samodzielnie hostowanego HSM z silnikiem 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

Do natywnego podpisywania w chmurze z kluczami 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

Do podpisywania wbudowanym portfelem:

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

Do podpisywania non-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

Do podpisywania instytucjonalnego 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

Do podpisywania natywnego w chmurze za pomocą kluczy 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 Developer Platform)

Do podpisywania zarządzanym portfelem 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
})?;

Metoda sign_message w CDP akceptuje wyłącznie dane w UTF-8.

Crossmint

Crossmint obsługuje wyłącznie wysyłanie: jego API wykonuje każdą zatwierdzoną transakcję po stronie serwera, więc nie istnieje ścieżka samego podpisywania, a sign_message kończy się błędem. Wywołaj sign_and_send_transaction, która nie modyfikuje Twojej transakcji i zwraca sygnaturę transakcji, która trafiła do sieci. Ta transakcja może różnić się od Twojej, jeśli Crossmint sponsoruje opłaty 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

Do podpisywania infrastrukturą portfela 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

Do podpisywania portfelem 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

Do podpisywania przez backendowy portfel 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

Do podpisywania z użyciem usługi powierniczej Utila MPC. sign_message nie jest obsługiwane, a podpisaną transakcję rozgłaszasz samodzielnie.

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

Do podpisywania z użyciem custody MPC Fordefi. Żądania API są uwierzytelniane za pomocą podpisu żądania ECDSA P-256. Podaj dokładnie jedno z: private_key_pem lub request_signer (Arc<dyn FordefiRequestSigner>, używany do przechowywania tego klucza w KMS/HSM).

Fordefi występuje w trzech typach signerów, ustalanych podczas tworzenia na podstawie chain i push_mode:

chainpush_modeTypMożliwośćZachowanie
NonedowolnyFordefiBlackBoxSignerTransactionSignerPodpisuje surowe bajty; rozgłaszasz samodzielnie
Some(..)None lub AutoFordefiNativeAutoSignerSendingSignerFordefi może zmienić blockhash i opłaty, podpisuje i rozgłasza
Some(..)ManualFordefiNativeManualSignerModifyingSignerFordefi modyfikuje i podpisuje; zwróconą transakcję rozgłaszasz samodzielnie

Tryb native manual zastępuje Twoją transakcję transakcją podpisaną przez Fordefi. Kontynuuj pracę na niej, nigdy na tej, którą zbudowałeś(-aś). Musi on zostać uruchomiony przed każdym innym wymaganym signerem.

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

Do podpisywania za pomocą portfela sprzętowego przez USB-HID (tylko Rust). Wymaga funkcji ledger, odblokowanego urządzenia z aplikacją Solana oraz, w systemie Linux, reguł udev Ledgera. Ledger nie jest objęty obecnym audytem; zobacz status audytu.

use solana_keychain::{LedgerConfig, Signer};
let signer = Signer::from_ledger(LedgerConfig {
confirm_pubkey_on_device: true,
..LedgerConfig::default()
})
.await?;

sign_message podpisuje kopertę off-chain opakowującą Twoje dane, a nie surowe bajty; odtwórz ją za pomocą solana_keychain::ledger::ledger_offchain_envelope, aby zweryfikować. Ustaw auto_open_app: false do użycia bez nadzoru. Odrzucenie monitu na urządzeniu zwraca SignerError::UserRejected.

Ujednolicone wyliczenie Signer

Użyj wyliczenia Signer, aby wybrać backendy w czasie wykonywania:

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 implementuje tylko SolanaSigner. Dostęp do możliwości uzyskasz przez as_transaction_signer(), as_modifying_signer() lub as_sending_signer(), które zwracają None, gdy backend nie ma danego kształtu:

if let Some(transaction_signer) = signer.as_transaction_signer() {
let result = transaction_signer.sign_transaction(&mut tx).await?;
}

Możesz też pozwolić, aby sign_and_send wybrał ścieżkę zależnie od backendu. Crate nie zawiera klienta RPC, więc rozgłaszanie dostarczasz sam; w przypadku backendu wysyłającego domknięcie nigdy nie jest wywoływane:

let signature = signer
.sign_and_send(&mut tx, |encoded| async move { broadcast(encoded).await })
.await?;

Obsługa błędów

SignerError::BroadcastUnconfirmed { provider_tx_id, idempotency_key, transaction_signature, .. } (z Crossmint, Fordefi native auto lub z nieudanego domknięcia sign_and_send) oznacza, że transakcja mogła trafić do sieci. Nie ponawiaj na ślepo: najpierw uzgodnij provider_tx_id lub transaction_signature albo wyślij ponownie wyłącznie transakcję identyczną bajt w bajt. Wyczerpujące wyrażenia match dla SignerError wymagają tego wariantu. Zobacz model bezpieczeństwa , aby dowiedzieć się, co gwarantuje każdy sposób podpisywania.

Dodawanie niestandardowych Signerów

Zobacz przewodnik po dodawaniu Signerów, aby zintegrować dodatkowe usługi zarządzania kluczami.

Is this page helpful?