A standalone, minimal dependency implementation of core Tari wallet functionality designed for lightweight applications, mobile wallets, web applications, and embedded systems.
The Tari Wallet Libraries provide essential wallet functionality extracted from the main Tari codebase, designed to be:
- πͺΆ Lightweight: Minimal dependencies, optimized for resource-constrained environments
- π Cross-platform: Native Rust, WASM, mobile, and web compatibility
- π Secure: Industry-standard cryptography with secure memory handling
- π§ Modular: Use only the components you need
- β Compatible: 100% compatible with main Tari wallet key derivation and address generation
- β Create wallets from seed phrases (24-word Tari CipherSeed format)
- β Generate new wallets with cryptographically secure entropy
- β Master key derivation following Tari specification
- β Wallet metadata management and secure storage
- β BIP39-like mnemonic generation and validation (Tari format)
- β Hierarchical deterministic key derivation
- β View and spend key generation
- β Stealth address support
- β Secure key zeroization and memory protection
- β Dual addresses (view + spend keys) for advanced features
- β Single addresses (spend key only) for simplified use
- β Multiple formats: Emoji π¦, Base58, and Hex
- β Payment ID embedding and extraction
- β Network support (MainNet, StageNet, Esmeralda, LocalNet)
- β GRPC-based blockchain scanning with Tari base nodes
- β Generic data processing callbacks for flexible result handling
- β Memory-only scanning (no storage dependency required)
- β Database persistence with resume functionality (optional)
- β UTXO discovery and wallet output reconstruction
- β Progress tracking and interactive error handling
- β Batch processing with configurable block ranges
- β Multiple scanning strategies (one-sided, recoverable, coinbase)
- β Multiple output formats (detailed, summary, JSON)
- β Range proof validation and rewinding
- β Encrypted data decryption using view keys
- β Commitment validation and verification
- β Payment ID extraction and decoding
- β Stealth address key recovery
- β Tari-compatible Schnorr signature generation
- β Domain-separated message signing for security
- β Hex-encoded signature components for transport
- β Complete signature verification workflows
- β CLI tool for signing and verification operations
- β JSON and compact output formats
Add to your Cargo.toml
:
[dependencies]
lightweight_wallet_libs = "0.1"
# Optional features
lightweight_wallet_libs = { version = "0.1", features = ["wasm", "grpc"] }
default
: Core wallet functionalitywasm
: WASM compatibility and JavaScript bindingsgrpc
: GRPC blockchain scanning support (memory-only)storage
: SQLite database support for persistent storagegrpc-storage
: Combined GRPC scanning with database persistence
use lightweight_wallet_libs::wallet::Wallet;
use lightweight_wallet_libs::data_structures::address::TariAddressFeatures;
// Generate a new wallet with a 24-word seed phrase
let wallet = Wallet::generate_new_with_seed_phrase(None)?;
// Export the seed phrase for backup
let seed_phrase = wallet.export_seed_phrase()?;
println!("Backup this seed phrase: {}", seed_phrase);
// Generate a dual Tari address (supports both interactive and one-sided payments)
let features = TariAddressFeatures::create_interactive_and_one_sided();
let address = wallet.get_dual_address(features, None)?;
println!("Your Tari address (emoji): {}", address.to_emoji_string());
println!("Your Tari address (base58): {}", address.to_base58());
// Generate a single address (spend key only, simpler)
let single_features = TariAddressFeatures::create_one_sided_only();
let single_address = wallet.get_single_address(single_features)?;
println!("Single address: {}", single_address.to_base58());
use lightweight_wallet_libs::wallet::Wallet;
use lightweight_wallet_libs::data_structures::address::TariAddressFeatures;
// Restore wallet from existing seed phrase
let seed_phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art";
let wallet = Wallet::new_from_seed_phrase(seed_phrase, None)?;
// Generate the same address as before
let address = wallet.get_dual_address(
TariAddressFeatures::create_interactive_and_one_sided(),
None
)?;
use lightweight_wallet_libs::key_management::{
generate_seed_phrase,
validate_seed_phrase,
seed_phrase::{CipherSeed, mnemonic_to_bytes},
};
// Generate a new 24-word seed phrase
let seed_phrase = generate_seed_phrase()?;
println!("Generated seed phrase: {}", seed_phrase);
// Validate an existing seed phrase
validate_seed_phrase(&seed_phrase)?;
println!("Seed phrase is valid!");
// Work with CipherSeed for advanced operations
let cipher_seed = CipherSeed::new(); // Creates with random entropy
let encrypted_bytes = cipher_seed.encipher(Some("optional_passphrase"))?;
// Convert bytes back to mnemonic
let encrypted_bytes = mnemonic_to_bytes(&seed_phrase)?;
let cipher_seed = CipherSeed::from_enciphered_bytes(&encrypted_bytes, Some("optional_passphrase"))?;
let entropy = cipher_seed.entropy();
println!("Extracted entropy: {:?}", entropy);
use lightweight_wallet_libs::crypto::signing::{
sign_message_with_hex_output,
verify_message_from_hex,
derive_tari_signing_key,
sign_message_with_tari_wallet
};
use tari_crypto::{
keys::{PublicKey, SecretKey},
ristretto::{RistrettoPublicKey, RistrettoSecretKey},
};
use tari_utilities::hex::Hex;
use rand::rngs::OsRng;
// Method 1: Using a random key (for testing)
let secret_key = RistrettoSecretKey::random(&mut OsRng);
let public_key = RistrettoPublicKey::from_secret_key(&secret_key);
let message = "Hello, Tari! This message is cryptographically signed.";
let (signature_hex, nonce_hex) = sign_message_with_hex_output(&secret_key, message)?;
// Method 2: Using Tari wallet-compatible key derivation (RECOMMENDED)
let seed_phrase = "your 24-word seed phrase here...";
let message = "Hello, Tari! Signed with real wallet key.";
// Derive the exact same communication key that Tari wallet uses
let tari_signing_key = derive_tari_signing_key(seed_phrase, None)?;
let tari_public_key = RistrettoPublicKey::from_secret_key(&tari_signing_key);
// Sign with the Tari wallet key
let (tari_sig_hex, tari_nonce_hex) = sign_message_with_tari_wallet(seed_phrase, message, None)?;
println!("Message: {}", message);
println!("Tari Signature: {}", tari_sig_hex);
println!("Tari Nonce: {}", tari_nonce_hex);
// Verify the signature
let is_valid = verify_message_from_hex(&tari_public_key, message, &tari_sig_hex, &tari_nonce_hex)?;
println!("Tari signature valid: {}", is_valid);
// This signature is cryptographically identical to what official Tari wallet would produce
The scanning functionality has been refactored into a comprehensive library API:
use lightweight_wallet_libs::scanning::{
WalletScanner, GrpcBlockchainScanner, create_wallet_from_seed_phrase,
MemoryDataProcessor, DataProcessor
};
// Method 1: Memory-only scanning (no storage dependency)
async fn scan_wallet_memory_only() -> Result<(), Box<dyn std::error::Error>> {
// Create scanner with progress tracking
let mut scanner = WalletScanner::new()
.with_batch_size(20)
.with_progress_callback(|info| {
println!("Progress: {:.2}% ({}/{} blocks, {} outputs found)",
info.progress_percent,
info.blocks_processed,
info.total_blocks,
info.outputs_found);
})
.with_verbose_logging(true);
// Create scan context from seed phrase
let (scan_context, birthday) = create_wallet_from_seed_phrase("your 24-word seed phrase")?;
// Create memory-only data processor
let mut data_processor = MemoryDataProcessor::new();
// Connect to GRPC scanner
let mut grpc_scanner = GrpcBlockchainScanner::new("http://localhost:18142".to_string()).await?;
// Perform scan with cancellation support
let mut cancel_rx = tokio::sync::watch::channel(false).1;
let result = scanner.scan_with_processor(
&mut grpc_scanner,
&scan_context,
birthday,
birthday + 1000,
&mut data_processor,
&mut cancel_rx
).await?;
match result {
ScanResult::Completed(wallet_state, metadata) => {
println!("Scan completed! Found {} transactions", wallet_state.transactions.len());
println!("Processed {} blocks with {} total transactions in memory",
data_processor.blocks.len(),
data_processor.total_transactions());
if let Some(meta) = metadata {
println!("Duration: {:?}", meta.duration());
}
}
ScanResult::Interrupted(wallet_state, _) => {
println!("Scan interrupted but partial data collected");
}
}
Ok(())
}
// Method 2: Database-backed scanning with persistence (requires storage feature)
#[cfg(feature = "storage")]
async fn scan_with_database() -> Result<(), Box<dyn std::error::Error>> {
use lightweight_wallet_libs::scanning::{
BinaryScanConfig, ScannerStorage, DatabaseDataProcessor
};
// Create scanner with database storage
let mut scanner = WalletScanner::new()
.with_batch_size(20)
.with_verbose_logging(true);
let (scan_context, birthday) = create_wallet_from_seed_phrase("your seed phrase")?;
// Create database processor for persistent storage
let mut storage_backend = ScannerStorage::new_with_database("wallet.db").await?;
let mut data_processor = DatabaseDataProcessor::new(storage_backend, true);
// Traditional scan method for backward compatibility
let config = BinaryScanConfig::new(birthday, birthday + 1000);
let mut grpc_scanner = GrpcBlockchainScanner::new("http://localhost:18142".to_string()).await?;
let mut cancel_rx = tokio::sync::watch::channel(false).1;
let result = scanner.scan(&mut grpc_scanner, &scan_context, &config, data_processor.storage_mut(), &mut cancel_rx).await?;
match result {
ScanResult::Completed(wallet_state, _) => {
println!("Scan completed and saved to database");
println!("Database statistics: {:?}", data_processor.get_statistics().await?);
}
ScanResult::Interrupted(_, _) => {
println!("Scan interrupted - can resume from database");
}
}
Ok(())
}
// Method 3: Custom data processor implementation
struct CustomDataProcessor {
// Your custom fields
}
#[async_trait::async_trait]
impl DataProcessor for CustomDataProcessor {
async fn process_block(&mut self, block_data: BlockData) -> WalletResult<()> {
// Custom processing logic - send to API, save to file, etc.
println!("Processing block {} with {} transactions",
block_data.height, block_data.transactions.len());
Ok(())
}
async fn process_progress(&mut self, progress_data: ProgressData) -> WalletResult<()> {
// Custom progress handling
println!("Progress: {:.1}%", progress_data.progress_percent());
Ok(())
}
}
async fn scan_with_custom_processor() -> Result<(), Box<dyn std::error::Error>> {
let mut scanner = WalletScanner::performance_optimized();
let (scan_context, birthday) = create_wallet_from_seed_phrase("your seed phrase")?;
let mut custom_processor = CustomDataProcessor { /* fields */ };
let mut grpc_scanner = GrpcBlockchainScanner::new("http://localhost:18142".to_string()).await?;
let mut cancel_rx = tokio::sync::watch::channel(false).1;
let result = scanner.scan_with_processor(
&mut grpc_scanner,
&scan_context,
birthday,
birthday + 1000,
&mut custom_processor,
&mut cancel_rx
).await?;
Ok(())
}
For direct blockchain querying without the scanning library:
use lightweight_wallet_libs::scanning::{GrpcScannerBuilder, BlockchainScanner};
use lightweight_wallet_libs::wallet::Wallet;
// Connect to a Tari base node
let mut scanner = GrpcScannerBuilder::new()
.with_base_url("http://127.0.0.1:18142".to_string())
.with_timeout(std::time::Duration::from_secs(30))
.build().await?;
// Create wallet for scanning
let wallet = Wallet::new_from_seed_phrase("your seed phrase here", None)?;
// Get blockchain tip and scan from wallet birthday
let tip_info = scanner.get_tip_info().await?;
let from_block = wallet.birthday();
let to_block = tip_info.best_block_height;
// Scan specific block range
let block_info = scanner.get_block_by_height(12345).await?;
if let Some(block) = block_info {
println!("Block {} has {} outputs", block.height, block.outputs.len());
}
The refactored scanner binary provides comprehensive blockchain analysis:
# Memory-only scanning (no storage dependency)
cargo run --bin scanner --features grpc -- --seed-phrase "your seed phrase"
cargo run --bin scanner --features grpc -- --view-key "64_char_hex_view_key"
# Flexible block range scanning (memory-only)
cargo run --bin scanner --features grpc -- --from-block 1000 --to-block 2000
cargo run --bin scanner --features grpc -- --blocks 1000,1500,2000,2500
# Multiple output formats (memory-only)
cargo run --bin scanner --features grpc -- --format detailed # Full transaction history
cargo run --bin scanner --features grpc -- --format summary # Compact overview
cargo run --bin scanner --features grpc -- --format json # Machine-readable
# Database persistence with resume functionality (requires storage)
cargo run --bin scanner --features grpc-storage -- --seed-phrase "your seed phrase" --database wallet.db
# Progress tracking with real-time statistics
cargo run --bin scanner --features grpc -- --seed-phrase "your seed phrase" --progress-frequency 5
For programmatic integration, use the scanning library API:
use lightweight_wallet_libs::scanning::{
WalletScanner, BinaryScanConfig, ScanContext, ScannerStorage,
OutputFormat, ScanResult, create_wallet_from_view_key
};
// Advanced scanning configuration
async fn advanced_scanning_example() -> Result<(), Box<dyn std::error::Error>> {
// 1. View-key only scanning (no wallet needed)
let (scan_context, _) = create_wallet_from_view_key(
"9d84cc4795b509dadae90bd68b42f7d630a6a3d56281c0b5dd1c0ed36390e70a"
)?;
// 2. Database-backed scanning with resume functionality
let mut storage = ScannerStorage::new_with_database("wallet.db").await?;
// 3. Custom configuration with specific blocks
let config = BinaryScanConfig::new(1000, 2000)
.with_specific_blocks(vec![1000, 1500, 2000, 2500])
.with_output_format(OutputFormat::Json)
.with_progress_frequency(5)
.with_batch_size(50);
// 4. Error handling and retry logic
let mut scanner = WalletScanner::new()
.with_retry_config(RetryConfig {
max_retries: 5,
base_delay: Duration::from_secs(1),
max_delay: Duration::from_secs(30),
exponential_backoff: true,
})
.with_timeout(Duration::from_secs(60));
// 5. Advanced progress tracking
let mut scanner = scanner.with_progress_callback(|info| {
println!("π Scan Progress:");
println!(" β’ Blocks: {}/{} ({:.2}%)",
info.blocks_processed, info.total_blocks, info.progress_percent);
println!(" β’ Speed: {:.1} blocks/sec", info.blocks_per_sec);
println!(" β’ Found: {} outputs, {} spent inputs",
info.outputs_found, info.inputs_found);
if let Some(eta) = info.eta {
println!(" β’ ETA: {:?}", eta);
}
});
// 6. Cancellation support for long-running scans
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
// Start scanning
let mut grpc_scanner = GrpcBlockchainScanner::new("http://localhost:18142".to_string()).await?;
let result = scanner.scan(&mut grpc_scanner, &scan_context, &config, &mut storage, &mut cancel_rx).await;
// 7. Advanced result processing
match result {
Ok(ScanResult::Completed(wallet_state, metadata)) => {
println!("π Scan completed successfully!");
println!(" β’ Total transactions: {}", wallet_state.transactions.len());
println!(" β’ Total balance: {} ΞΌT", wallet_state.total_balance());
if let Some(meta) = metadata {
println!(" β’ Blocks processed: {}", meta.blocks_processed);
println!(" β’ Duration: {:?}", meta.duration());
println!(" β’ Block range: {} to {}", meta.from_block, meta.to_block);
}
}
Ok(ScanResult::Interrupted(wallet_state, metadata)) => {
println!("βΈοΈ Scan was interrupted but can be resumed");
// Save state for resume functionality
if let Some(meta) = metadata {
println!(" β’ Resume from block: {}", meta.to_block + 1);
}
}
Err(e) => {
eprintln!("β Scan failed: {}", e);
// Implement custom error handling
}
}
Ok(())
}
// 8. Batch processing for multiple wallets
async fn batch_wallet_scanning() -> Result<(), Box<dyn std::error::Error>> {
let seed_phrases = vec![
"wallet one seed phrase...",
"wallet two seed phrase...",
"wallet three seed phrase...",
];
for (i, seed_phrase) in seed_phrases.iter().enumerate() {
println!("Scanning wallet {} of {}", i + 1, seed_phrases.len());
let (scan_context, birthday) = create_wallet_from_seed_phrase(seed_phrase)?;
let config = BinaryScanConfig::new(birthday, birthday + 1000);
let mut storage = ScannerStorage::new_memory();
// Scan each wallet independently
let mut scanner = WalletScanner::new().with_batch_size(25);
// ... perform scan
}
Ok(())
}
Scanner Features:
- Dual Input Methods: Use seed phrase (full wallet) or view key (view-only)
- Interactive Error Handling: Continue, skip, or abort on GRPC errors with resume commands
- Transaction History: Complete chronological transaction listing with spent/unspent tracking
- Payment ID Decoding: Automatic extraction and UTF-8 decoding of payment IDs
- Balance Analysis: Running balances, net flow calculations, and transaction breakdowns
- Maturity Tracking: Coinbase output maturity detection and immature balance warnings
lightweight_wallet_libs/
βββ wallet/ # Core wallet operations
βββ key_management/ # Key derivation and mnemonics
βββ data_structures/ # Wallet data types
βββ validation/ # Cryptographic validation
βββ extraction/ # UTXO processing
βββ scanning/ # Refactored blockchain scanning library
β βββ mod.rs # Public API and trait definitions
β βββ wallet_scanner.rs # Main scanning API and implementation
β βββ data_processor.rs # Generic data processing callback architecture
β βββ database_processor.rs# Database storage data processor
β βββ scan_config.rs # Configuration structures
β βββ storage_manager.rs # Storage abstraction (memory/database)
β βββ background_writer.rs # Async database operations
β βββ progress.rs # Progress tracking and callbacks
β βββ grpc_scanner.rs # GRPC blockchain scanner
β βββ http_scanner.rs # HTTP blockchain scanner
βββ crypto/ # Independent crypto primitives
β βββ signing.rs # Message signing and verification
β βββ hash_domain.rs # Domain separation for security
βββ errors/ # Comprehensive error handling
Wallet
: Main wallet struct for key management and address generationCipherSeed
: Tari's encrypted seed format with birthday trackingTariAddress
: Dual and single address types with multiple encoding formatsWalletScanner
: High-level scanning API with progress tracking and error handlingBlockchainScanner
: Low-level trait for GRPC/HTTP-based scanning implementationsScannerStorage
: Unified storage interface supporting memory and database modesValidationEngine
: Cryptographic proof and signature validationMessageSigning
: Tari-compatible Schnorr signature creation and verification
WalletScanner
: Main scanning API with configurable batching, progress tracking, and retry logicDataProcessor
: Generic trait for handling scan results (memory, database, custom implementations)MemoryDataProcessor
: In-memory data collection without persistence requirementsDatabaseDataProcessor
: Database-backed storage with resume functionality (requires storage feature)ScanContext
: Cryptographic context containing view keys and entropy for scanningBinaryScanConfig
: Configuration for block ranges, output formats, and scanning parameters (storage mode)ScannerStorage
: Storage abstraction supporting both memory-only and database-backed persistence (legacy)BackgroundWriter
: Async database writer for improved scanning performance (non-WASM)ProgressTracker
: Real-time progress tracking with customizable callbacks and ETA calculation
// Standard Rust usage
let wallet = Wallet::generate_new_with_seed_phrase(None)?;
// WASM-compatible with feature flag
#[cfg(feature = "wasm")]
use lightweight_wallet_libs::wasm::*;
- Android: Use via JNI bindings
- iOS: Use via C FFI or Swift Package Manager
- React Native: Use via WASM bindings
- β Quick wallet operations and testing
- β Manual blockchain scanning and analysis
- β One-off message signing operations
- β Learning and experimenting with Tari functionality
- β Scripting and automation tasks
- β Debugging and troubleshooting
- β Integration into applications and services
- β Custom progress tracking and error handling
- β Batch processing and automated workflows
- β Performance-critical scanning operations
- β Custom storage backends and configurations
- β Advanced retry logic and cancellation support
The project includes powerful command-line tools for wallet operations:
# Create new wallet with seed phrase
cargo run --bin wallet new-wallet
# Generate address from existing seed phrase
cargo run --bin wallet new-address "your 24-word seed phrase here"
# Create wallet with payment ID and custom network
cargo run --bin wallet new-wallet --network stagenet --payment-id "my-payment-123"
# Memory-only blockchain scanning (requires running Tari base node)
cargo run --bin scanner --features grpc -- --seed-phrase "your seed phrase"
# Scan specific block range with view key (memory-only)
cargo run --bin scanner --features grpc -- --view-key "your_64_char_hex_view_key" --from-block 1000 --to-block 2000
# Scan with database persistence and resume functionality (requires storage)
cargo run --bin scanner --features grpc-storage -- --seed-phrase "your seed phrase" --database wallet.db
# Scan with multiple output formats and progress tracking (memory-only)
cargo run --bin scanner --features grpc -- --seed-phrase "your seed phrase" --format summary --progress-frequency 10
# Scan specific blocks with JSON output (memory-only)
cargo run --bin scanner --features grpc -- --view-key "your_view_key" --blocks 1000,1500,2000 --format json
Refactored Scanner Features:
- ποΈ Library-Based: Now uses the scanning library API internally (~200 lines vs 2,895 lines)
- πͺΆ No Storage Dependency: Memory-only scanning with
--features grpc
(storage optional) - π Generic Data Processing: Pluggable callback architecture for flexible result handling
- π Enhanced Progress: Real-time progress with blocks/sec, ETA, and output counts
- πΎ Optional Database Support: Automatic resume functionality with SQLite persistence
- π Error Recovery: Improved error handling with retry logic and cancellation
- π― Better Performance: Async background database operations for faster scanning (storage mode)
- π§ͺ Better Testing: Library components are fully unit-testable
# Generate a new keypair
cargo run --bin signing --features storage -- generate --stdout
# Save keypair to files
cargo run --bin signing --features storage -- generate --secret-key-file secret.key --public-key-file public.key
# Sign a message using secret key file
cargo run --bin signing --features storage -- sign \
--secret-key-file secret.key \
--message "Hello, Tari! This is a signed message."
# Sign a message using wallet from database (requires storage feature)
cargo run --bin signing --features storage -- sign \
--wallet-name my_wallet \
--database-path wallet.db \
--message "Hello, Tari! Signed with wallet from database."
# Sign with JSON output format
cargo run --bin signing --features storage -- sign \
--secret-key-file secret.key \
--message "Test message" \
--format json \
--output-file signature.json
# Verify a signature using hex components
cargo run --bin signing --features storage -- verify \
--public-key-file public.key \
--message "Hello, Tari! This is a signed message." \
--signature <signature_hex> \
--nonce <nonce_hex> \
--verbose
# Verify using signature file (compact format)
cargo run --bin signing --features storage -- verify \
--public-key-file public.key \
--message "Test message" \
--signature-file signature.txt
# Verify using JSON signature file
cargo run --bin signing --features storage -- verify \
--public-key-file public.key \
--message "Test message" \
--signature-file signature.json
# Sign and verify workflow with files
echo "My important message" > message.txt
cargo run --bin signing --features storage -- sign \
--secret-key-file secret.key \
--message-file message.txt \
--output-file signature.txt
cargo run --bin signing --features storage -- verify \
--public-key-file public.key \
--message-file message.txt \
--signature-file signature.txt
# Complete database workflow: create wallet and sign
# 1. Generate a new seed phrase
SEED=$(cargo run --bin wallet --features storage -- generate | head -1 | cut -d' ' -f2-)
# 2. Add wallet to database
cargo run --bin wallet --features storage -- add-wallet \
--name my_signing_wallet \
--database wallet.db \
"$SEED"
# 3. Sign messages using the wallet from database
cargo run --bin signing --features storage -- sign \
--wallet-name my_signing_wallet \
--database-path wallet.db \
--message "Signed with database wallet!"
# 4. List available wallets
cargo run --bin wallet --features storage -- list --database wallet.db
- π Keypair Generation: Create new Ed25519 keypairs with secure randomness
- βοΈ Message Signing: Sign arbitrary messages with Schnorr signatures
- β Signature Verification: Verify signatures with detailed validation
- π File Support: Read keys/messages from files for automation
- π― Multiple Formats: Compact (sig:nonce) and JSON output formats
- π§ Flexible Input: Support command-line args and file inputs
- π Verbose Mode: Detailed output for debugging and verification
- π Tari Compatible: 100% compatible with Tari wallet message signing
- πΎ Database Integration: Sign with wallets stored in SQLite database (storage feature)
- π Seed Phrase Derivation: Uses Tari communication node identity key ("comms" branch)
- π Deterministic Keys: Same seed phrase always produces identical signatures
- β‘ Exit Codes: Returns proper exit codes (0=success, 1=invalid signature) for scripting
- Secure Memory: Automatic zeroization of sensitive data
- Constant-time Operations: Timing attack resistant comparisons
- Domain Separation: Cryptographic domain separation for security
- Memory Safety: Rust's memory safety guarantees
- Secure Randomness: Cryptographically secure random number generation
- Batch Operations: Optimized for processing multiple UTXOs
- Parallel Processing: Optional parallel validation (with
parallel
feature) - Memory Efficient: Minimal memory footprint for mobile/embedded use
- Fast Scanning: Efficient blockchain scanning with progress tracking
- π± Mobile wallet applications
- π Web wallets and browser extensions
- π§ Hardware wallet firmware
- π‘ Lightweight desktop applications
- π DeFi integrations requiring Tari addresses
- π Blockchain analysis tools
- βοΈ Message signing and authentication systems
- βοΈ Running Tari base nodes
- π Mining operations
- π Peer-to-peer networking
- πΎ Full blockchain storage
- ποΈ Consensus mechanisms
Feature | Main Tari | Libs |
---|---|---|
Purpose | Full blockchain protocol | Wallet functionality only |
Dependencies | Heavy (tari-* crates) | Minimal (crypto only) |
Size | ~100MB+ | ~5MB |
Platforms | Desktop/Server | All platforms + WASM |
Use Case | Run nodes/miners | Build wallet apps |
We welcome contributions! Please see our Contributing Guidelines for details.
# Clone the repository
git clone https://github.com/Krakaw/tari-wallet.git
cd tari-wallet
# Run tests
cargo test
# Run with all features
cargo test --all-features
# Check WASM compatibility
cargo check --target wasm32-unknown-unknown --features wasm
# Test signing binary
cargo test --bin signing --features storage
# Unit tests
cargo test
# Integration tests with GRPC (requires base node)
cargo test --features grpc
# Test specific binaries
cargo test --bin wallet --features storage
cargo test --bin scanner --features grpc # Memory-only mode
cargo test --bin scanner --features grpc-storage # With database
cargo test --bin signing --features storage
# WASM tests
wasm-pack test --node --features wasm
# Install tarpaulin for code coverage
cargo install cargo-tarpaulin
# Generate coverage report (uses tarpaulin.toml config)
cargo tarpaulin
# Generate coverage with custom options
cargo tarpaulin --all-features --out html --output-dir coverage
# View HTML coverage report
open coverage/tarpaulin-report.html # macOS
xdg-open coverage/tarpaulin-report.html # Linux
# Generate coverage for CI (XML format for Codecov)
cargo tarpaulin --all-features --out xml --output-dir coverage
The coverage configuration is defined in tarpaulin.toml
and excludes:
- Binary files (
src/bin/*
) - Examples and test files
- Long-running stress tests that would slow down CI
Current coverage target: 70% minimum (adjustable in tarpaulin.toml
)
- Rust: 1.70.0 or later
- WASM: All major browsers
- Mobile: iOS 12+, Android API 21+
- Tari: Compatible with main Tari wallet key derivation
This project is licensed under the BSD 3-Clause License.