Saltar al contenido principal

Billetera

El módulo Wallet gestiona pares de claves ed25519, firma mensajes y opcionalmente se conecta a un nodo RPC para consultas en cadena.

Gestión de Claves

Crear una Nueva Billetera

use savitri_sdk::Wallet;

// Par de claves aleatorio (criptográficamente seguro)
let wallet = Wallet::new();
println!("Address: {}", wallet.address()); // 64 hex chars (clave pública de 32 bytes)

Importar desde Clave Privada

// Desde bytes sin procesar
let private_key: [u8; 32] = [/* your key */];
let wallet = Wallet::from_private_key(&private_key)?;

// Desde string hexadecimal
let wallet = Wallet::from_private_key_hex("aabbccdd...64hexchars")?;

// Con prefijo 0x
let wallet = Wallet::from_private_key_hex("0xaabbccdd...64hexchars")?;

Exportar Claves

// Clave pública (segura para compartir)
let pubkey = wallet.public_key();
println!("Public key: {}", hex::encode(pubkey.as_bytes()));

// Dirección (derivada de la clave pública)
println!("Address: {}", wallet.address());

// Clave privada (NUNCA compartir ni registrar)
let privkey: [u8; 32] = wallet.private_key();

Firma

Firmar un Mensaje

let message = b"Hello, Savitri!";
let signature: [u8; 64] = wallet.sign_message(message);

Verificar una Firma

wallet.verify_signature(message, &signature)?;
// Devuelve Ok(()) si es válida, Err si es inválida

El esquema de firma usa Ed25519 (ed25519-dalek). Para la firma de transacciones, el mensaje primero se aplica SHA-256:

message = from_hex || to_hex || amount_le_u64 || nonce_le_u64 || fee_le_u128
hash = SHA-256(message)
sig = Ed25519_sign(hash)

Integración con RPC

Conecta una billetera a un nodo para consultas en cadena:

// Crear con conexión RPC
let wallet = Wallet::with_rpc("http://localhost:8545")?;

// O conectar más tarde
let mut wallet = Wallet::new();
wallet.connect_rpc("http://localhost:8545")?;

// Consultar saldo (requiere RPC)
let balance: String = wallet.get_balance().await?;
println!("Balance: {}", balance);

// Consultar nonce (requiere RPC)
let nonce: u64 = wallet.get_nonce().await?;
println!("Nonce: {}", nonce);

// Acceder al cliente RPC subyacente
if let Some(rpc) = wallet.rpc() {
let height = rpc.get_block_number().await?;
println!("Height: {}", height);
}

Seguridad

  • Puesta a cero: El material de la clave privada se pone a cero cuando la billetera se descarta (trait Drop mediante el crate zeroize).
  • Comportamiento al clonar: Las billeteras clonadas NO heredan la conexión RPC (comienzan desconectadas).
  • Sin persistencia: La billetera no guarda claves en disco. Usa tu propio almacenamiento seguro.
{
let wallet = Wallet::new();
// ... usar billetera ...
} // la billetera se descarta aquí — los bytes de la clave privada se ponen a cero en memoria