Wallet Implementation
Building a complete cryptocurrency wallet in Rust.
Advanced⏱️ 55 min📚 Prerequisites: 1
Wallet Implementation
A wallet manages private keys, signs transactions, and tracks balances. Let's build a complete wallet.
Wallet Structure
RUSTstruct Wallet { keypair: KeyPair, address: String, balance: u64, nonce: u64, transactions: Vec<Transaction>, } struct KeyPair { private_key: String, // In production: use proper crypto types public_key: String, }
Wallet Operations
Creating a Wallet
RUSTimpl Wallet { fn new() -> Self { let keypair = generate_keypair(); let address = derive_address(&keypair.public_key); Wallet { keypair, address, balance: 0, nonce: 0, transactions: Vec::new(), } } }
Creating Transactions
RUSTfn create_transaction(&mut self, to: String, amount: u64, fee: u64) -> Result<Transaction, String> { if self.balance < amount + fee { return Err(String::from("Insufficient balance")); } let tx = Transaction { from: self.address.clone(), to, amount, fee, nonce: self.nonce, signature: None, }; // Sign transaction let signed_tx = self.sign_transaction(tx)?; self.nonce += 1; Ok(signed_tx) }
Signing Transactions
RUSTfn sign_transaction(&self, mut tx: Transaction) -> Result<Transaction, String> { // Create message to sign let message = format!("{}{}{}{}", tx.from, tx.to, tx.amount, tx.nonce); // Sign with private key (simplified) tx.signature = Some(format!("sig_{}", message)); Ok(tx) }
Wallet Features
- Key Management: Generate and store keys securely
- Transaction Creation: Build and sign transactions
- Balance Tracking: Monitor account balance
- Transaction History: Keep record of all transactions
- Nonce Management: Track transaction nonces
Security Considerations
- Private Key Storage: Must be encrypted
- Key Derivation: Use proper key derivation functions
- Secure Random: Use cryptographically secure RNG
- Backup: Provide key backup/recovery
HD Wallets
Hierarchical Deterministic (HD) wallets:
- BIP32: Key derivation
- BIP39: Mnemonic phrases
- BIP44: Multi-account structure
Implementation Example
RUSTstruct Wallet { address: String, balance: u64, nonce: u64, } impl Wallet { fn new() -> Self { Wallet { address: String::from("0xWallet123"), balance: 0, nonce: 0, } } fn send(&mut self, to: String, amount: u64) -> Result<(), String> { if self.balance < amount { return Err(String::from("Insufficient balance")); } self.balance -= amount; self.nonce += 1; Ok(()) } }
Code Examples
Wallet Structure
Complete wallet implementation
RUST
struct KeyPair {
private_key: String,
public_key: String,
address: String,
}
struct Wallet {
keypair: KeyPair,
balance: u64,
nonce: u64,
}
impl Wallet {
fn new() -> Self {
let keypair = KeyPair {
private_key: String::from("private_key_secret"),
public_key: String::from("public_key_abc123"),
address: String::from("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"),
};
Wallet {
keypair,
balance: 0,
nonce: 0,
}
}
fn address(&self) -> &str {
&self.keypair.address
}
fn get_balance(&self) -> u64 {
self.balance
}
fn update_balance(&mut self, new_balance: u64) {
self.balance = new_balance;
}
fn increment_nonce(&mut self) {
self.nonce += 1;
}
}
fn main() {
let mut wallet = Wallet::new();
println!("Wallet address: {}", wallet.address());
println!("Initial balance: {}", wallet.get_balance());
wallet.update_balance(1000);
wallet.increment_nonce();
println!("Updated balance: {}", wallet.get_balance());
println!("Nonce: {}", wallet.nonce);
}Explanation:
A wallet manages keys, balance, and nonce. It provides methods to access wallet information and update state. In production, private keys must be stored securely (encrypted).
Transaction Creation
Creating and signing transactions
RUST
struct Transaction {
from: String,
to: String,
amount: u64,
fee: u64,
nonce: u64,
signature: Option<String>,
}
struct Wallet {
address: String,
balance: u64,
nonce: u64,
}
impl Wallet {
fn create_transaction(&mut self, to: String, amount: u64, fee: u64) -> Result<Transaction, String> {
if self.balance < amount + fee {
return Err(String::from("Insufficient balance"));
}
let tx = Transaction {
from: self.address.clone(),
to,
amount,
fee,
nonce: self.nonce,
signature: None,
};
let signed_tx = self.sign(tx)?;
self.nonce += 1;
Ok(signed_tx)
}
fn sign(&self, mut tx: Transaction) -> Result<Transaction, String> {
let message = format!("{}{}{}{}", tx.from, tx.to, tx.amount, tx.nonce);
tx.signature = Some(format!("sig_{}", message));
Ok(tx)
}
}
fn main() {
let mut wallet = Wallet {
address: String::from("0xAlice"),
balance: 1000,
nonce: 0,
};
match wallet.create_transaction(String::from("0xBob"), 200, 10) {
Ok(tx) => {
println!("Transaction created!");
println!("From: {}, To: {}, Amount: {}", tx.from, tx.to, tx.amount);
println!("Nonce: {}, Signed: {}", tx.nonce, tx.signature.is_some());
},
Err(e) => println!("Error: {}", e),
}
}Explanation:
Wallets create and sign transactions. The nonce increments with each transaction to prevent replay attacks. Signatures prove transaction authorization.
Exercises
Create Wallet
Create a wallet that can track balance and nonce!
Starter Code:
RUST
struct Wallet {
address: String,
balance: u64,
nonce: u64,
}
fn main() {
let mut wallet = Wallet::new();
wallet.balance = 1000;
wallet.send(200);
println!("Balance: {}, Nonce: {}", wallet.get_balance(), wallet.nonce);
}