Instalasi
Tambahkan solana-keychain ke Cargo.toml Anda dengan hanya backend yang Anda
butuhkan:
[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"] }
Upgrade dari 1.x? Lihat panduan Migrasi ke 2.0.
Tanda Fitur
| Fitur | Deskripsi |
|---|---|
memory | Penandatanganan keypair lokal (default) |
vault | Mesin Transit HashiCorp Vault |
aws_kms | AWS KMS dengan Ed25519 |
gcp_kms | GCP Cloud KMS dengan Ed25519 |
privy | Dompet tertanam Privy |
turnkey | API Turnkey |
fireblocks | Fireblocks MPC |
cdp | Coinbase Developer Platform |
crossmint | Dompet terkelola Crossmint |
dfns | Infrastruktur dompet Dfns |
openfort | Dompet tertanam Openfort |
para | Dompet MPC Para |
utila | Kustodi MPC Utila |
fordefi | Kustodi MPC Fordefi |
ledger | Dompet perangkat keras Ledger melalui USB-HID (hanya Rust, opt-in, tidak termasuk dalam all) |
all | Aktifkan semua backend kecuali ledger |
sdk-v2 | Solana SDK 2.x (default) |
sdk-v3 | Solana SDK 3.x |
sdk-v4 | Solana SDK 4.x (diperlukan untuk transaksi v1) |
unsafe-debug | Mencatat log respons error lengkap dari provider; jangan pernah mengaktifkannya di production |
Tepat satu dari sdk-v2, sdk-v3, dan sdk-v4 harus diaktifkan.
Penggunaan Dasar
Semua signer mengimplementasikan
trait SolanaSigner
dasar (pubkey, sign_message, is_available). Setiap backend juga mengimplementasikan tepat
satu trait kapabilitas:
TransactionSigner: menandatangani transaksi Anda apa adanya.ModifyingSigner: provider menulis ulang transaksi, lalu menandatanganinya.SendingSigner: provider menandatangani dan menyiarkannya.
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(())}
Konversikan Transaction legacy dengan .into(). Transaksi legacy dan v0 berfungsi
di setiap fitur SDK; transaksi v1 memerlukan sdk-v4.
Kapabilitas Signer
| Backend | Trait kapabilitas | sign_message |
|---|---|---|
| Crossmint | SendingSigner | Tidak didukung |
| Fordefi native auto | SendingSigner | Ya |
| Fordefi native manual | ModifyingSigner | Ya |
| Utila | TransactionSigner | Tidak didukung |
| CDP | TransactionSigner | Hanya payload UTF-8 |
| Ledger | TransactionSigner | Ya, melalui envelope off-chain |
| Semua lainnya (termasuk Fordefi black box) | TransactionSigner | Ya |
Konstruktor Signer::from_* menjalankan init() untuk Anda. Jika Anda membuat
tipe signer Privy, Fireblocks, Dfns, Crossmint, Para, Openfort, atau Utila
secara langsung, panggil init().await sebelum digunakan.
Konfigurasi Backend
Penandatangan Memori
Untuk pengembangan dan pengujian dengan keypair lokal:
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
Untuk HSM yang dihosting sendiri dengan mesin 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
Untuk penandatanganan native-cloud dengan kunci 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
Untuk penandatanganan dompet tertanam:
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
Untuk penandatanganan non-kustodian:
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
Untuk penandatanganan MPC institusional:
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
Untuk penandatanganan cloud-native dengan kunci 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)
Untuk penandatanganan dompet terkelola 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 CDP hanya menerima payload UTF-8.
Crossmint
Crossmint hanya mendukung pengiriman: API-nya mengeksekusi setiap transaksi yang disetujui
di sisi server, sehingga tidak ada jalur khusus tanda tangan, dan sign_message gagal. Panggil
sign_and_send_transaction, yang tidak mengubah transaksi Anda dan mengembalikan
tanda tangan dari transaksi yang berhasil masuk. Transaksi tersebut bisa berbeda dari
transaksi Anda jika Crossmint mensponsori 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
Untuk penandatanganan infrastruktur dompet 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
Untuk penandatanganan dompet 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
Untuk penandatanganan dompet 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
Untuk penandatanganan kustodi MPC Utila. sign_message tidak didukung, dan Anda
menyiarkan transaksi yang telah ditandatangani sendiri.
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
Untuk penandatanganan kustodi MPC Fordefi. Permintaan API diautentikasi dengan tanda tangan permintaan
ECDSA P-256. Berikan tepat satu dari private_key_pem, atau
request_signer (sebuah Arc<dyn FordefiRequestSigner>, digunakan untuk menyimpan kunci tersebut di
KMS/HSM).
Fordefi hadir dalam tiga tipe signer, yang ditetapkan saat konstruksi melalui chain dan
push_mode:
chain | push_mode | Tipe | Kapabilitas | Perilaku |
|---|---|---|---|---|
None | apa saja | FordefiBlackBoxSigner | TransactionSigner | Menandatangani byte mentah; Anda yang menyiarkan |
Some(..) | None atau Auto | FordefiNativeAutoSigner | SendingSigner | Fordefi dapat menulis ulang blockhash dan biaya, lalu menandatangani dan menyiarkan |
Some(..) | Manual | FordefiNativeManualSigner | ModifyingSigner | Fordefi menulis ulang dan menandatangani; Anda menyiarkan transaksi yang dikembalikan |
Mode native manual mengganti transaksi Anda dengan transaksi yang ditandatangani Fordefi. Lanjutkan dari transaksi tersebut, jangan pernah dari transaksi yang Anda buat. Mode ini harus dijalankan sebelum signer wajib lainnya.
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
Untuk penandatanganan dompet perangkat keras melalui USB-HID (hanya Rust). Memerlukan fitur
ledger, perangkat yang tidak terkunci dengan aplikasi Solana berjalan, dan, di Linux, aturan udev
Ledger. Ledger tidak tercakup dalam audit saat ini; lihat
status audit.
use solana_keychain::{LedgerConfig, Signer};let signer = Signer::from_ledger(LedgerConfig {confirm_pubkey_on_device: true,..LedgerConfig::default()}).await?;
sign_message menandatangani envelope off-chain yang membungkus payload Anda, bukan byte
mentahnya; bangun ulang dengan solana_keychain::ledger::ledger_offchain_envelope untuk
verifikasi. Setel auto_open_app: false untuk penggunaan tanpa pengawasan. Permintaan yang ditolak pada
perangkat mengembalikan SignerError::UserRejected.
Enum Signer Terpadu
Gunakan enum Signer untuk memilih backend saat 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();
Signer hanya mengimplementasikan SolanaSigner. Akses kapabilitas melalui
as_transaction_signer(), as_modifying_signer(), atau as_sending_signer(),
yang mengembalikan None jika backend tidak memiliki bentuk tersebut:
if let Some(transaction_signer) = signer.as_transaction_signer() {let result = transaction_signer.sign_transaction(&mut tx).await?;}
Atau biarkan sign_and_send mengarahkan berdasarkan backend. Crate ini tidak memiliki klien RPC, jadi Anda
yang menyediakan penyiaran; untuk backend pengirim, closure tidak pernah dipanggil:
let signature = signer.sign_and_send(&mut tx, |encoded| async move { broadcast(encoded).await }).await?;
Penanganan Error
SignerError::BroadcastUnconfirmed { provider_tx_id, idempotency_key, transaction_signature, .. }
(dari Crossmint, Fordefi native auto, atau closure sign_and_send yang gagal)
berarti transaksi mungkin sudah masuk. Jangan mencoba ulang secara membabi buta: rekonsiliasi
provider_tx_id atau transaction_signature terlebih dahulu, atau kirim ulang hanya transaksi
yang identik byte demi byte. match yang menyeluruh pada SignerError memerlukan arm ini.
Lihat
model keamanan
untuk mengetahui apa yang dijamin oleh setiap bentuk penandatanganan.
Menambahkan Signer Kustom
Lihat panduan Menambahkan Signer untuk mengintegrasikan layanan manajemen kunci tambahan.
Is this page helpful?