Add gsio-client and gsio-wallet crates with initial implementations

- Introduced `gsio-client` crate for interacting with GSIO nodes, including ledger entry management and node discovery.
- Introduced `gsio-wallet` crate for key management, transaction creation, and wallet functionality.
- Updated workspace configuration to include new crates.
This commit is contained in:
geoffsee
2025-06-15 13:34:12 -04:00
parent 2f2ddc7f6d
commit 4c0848e2f3
10 changed files with 1146 additions and 49 deletions

View File

@@ -0,0 +1,20 @@
[package]
name = "gsio-wallet"
version = "0.1.0"
publish = false
edition = "2024"
license = "MIT"
[dependencies]
tokio = { version = "1.45.1", features = ["rt-multi-thread", "macros", "time"] }
tracing = { version = "0.1.41" }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.7.0", features = ["v4", "serde"] }
chrono = { version = "0.4.35", features = ["serde"] }
thiserror = "1.0"
rand = "0.7.3"
rand_core = "0.5.1"
ed25519-dalek = { version = "1.0.1", features = ["serde"] }
hex = "0.4.3"

View File

@@ -0,0 +1,65 @@
# GSIO Wallet
A wallet implementation for the GSIO network.
## Features
- Key management (generate, store, retrieve keys)
- Transaction creation and signing
- Balance tracking
- Transaction history
## Usage
```rust
use gsio_wallet::{Wallet, TransactionType};
// Create a new wallet
let mut wallet = Wallet::new();
// Generate a new keypair
let address = wallet.generate_keypair().unwrap();
println!("Generated address: {}", address);
// Create a transaction
let transaction = wallet.create_transaction(
&address,
"recipient_address",
100,
10,
TransactionType::Transfer,
None,
).unwrap();
// Sign the transaction
let mut signed_transaction = transaction.clone();
wallet.sign_transaction(&mut signed_transaction).unwrap();
// Submit the transaction (in an async context)
async {
let tx_id = wallet.submit_transaction(&signed_transaction).await.unwrap();
println!("Transaction submitted: {}", tx_id);
};
// Get account balance
let balance = wallet.get_balance(&address).unwrap();
println!("Balance: {}", balance);
// Get transaction history
let history = wallet.get_transaction_history(&address).unwrap();
println!("Transaction history: {:?}", history);
```
## Implementation Details
This is a stubbed implementation of a wallet for the GSIO network. The actual implementation would need to be integrated with the GSIO network to handle real transactions and balances.
The wallet uses Ed25519 for cryptographic operations, which provides strong security for digital signatures.
## Future Improvements
- Implement wallet persistence with encryption
- Add support for multiple accounts in a single wallet
- Implement transaction verification
- Add support for different transaction types
- Integrate with the GSIO network for real transactions

View File

@@ -0,0 +1,256 @@
//! GSIO Wallet Library
//!
//! This library provides wallet functionality for the GSIO network.
//! It allows creating and managing wallets, generating and storing keys,
//! signing transactions, and tracking balances.
use chrono::{DateTime, Utc};
use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature, Signer, SignatureError};
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use thiserror::Error;
use tracing::{debug, error, info};
use uuid::Uuid;
/// Error type for GSIO wallet operations
#[derive(Error, Debug)]
pub enum WalletError {
#[error("IO error: {0}")]
IoError(#[from] io::Error),
#[error("JSON serialization error: {0}")]
SerializationError(#[from] serde_json::Error),
#[error("Signature error: {0}")]
SignatureError(#[from] SignatureError),
#[error("Key not found: {0}")]
KeyNotFound(String),
#[error("Wallet not found: {0}")]
WalletNotFound(String),
#[error("Invalid wallet data: {0}")]
InvalidWalletData(String),
#[error("Insufficient funds: required {0}, available {1}")]
InsufficientFunds(u64, u64),
}
/// Transaction type
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TransactionType {
Transfer,
Stake,
Unstake,
// Other transaction types can be added here
}
/// Transaction status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TransactionStatus {
Pending,
Confirmed,
Failed,
}
/// Transaction record
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
pub id: String,
pub transaction_type: TransactionType,
pub amount: u64,
pub fee: u64,
pub sender: String,
pub recipient: String,
pub timestamp: DateTime<Utc>,
pub status: TransactionStatus,
pub signature: Option<String>,
pub data: Option<JsonValue>,
}
/// Wallet account information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Account {
pub address: String,
pub public_key: String,
pub balance: u64,
pub nonce: u64,
pub transactions: Vec<String>,
}
/// GSIO Wallet for managing keys and transactions
pub struct Wallet {
keypair: Option<Keypair>,
accounts: HashMap<String, Account>,
wallet_path: Option<PathBuf>,
}
impl Wallet {
/// Create a new empty wallet
pub fn new() -> Self {
Self {
keypair: None,
accounts: HashMap::new(),
wallet_path: None,
}
}
/// Generate a new keypair
pub fn generate_keypair(&mut self) -> Result<String, WalletError> {
let mut csprng = OsRng;
let keypair = Keypair::generate(&mut csprng);
let address = format!("gsio_{}", hex::encode(&keypair.public.to_bytes()[0..20]));
self.keypair = Some(keypair);
// Create a new account for this keypair
let account = Account {
address: address.clone(),
public_key: hex::encode(self.keypair.as_ref().unwrap().public.to_bytes()),
balance: 0,
nonce: 0,
transactions: Vec::new(),
};
self.accounts.insert(address.clone(), account);
Ok(address)
}
/// Load wallet from file
pub fn load(&mut self, path: &Path) -> Result<(), WalletError> {
// This is a stub implementation
info!("Loading wallet from: {:?}", path);
self.wallet_path = Some(path.to_path_buf());
// In a real implementation, this would load the wallet data from the file
// For now, we'll just return Ok to indicate success
Ok(())
}
/// Save wallet to file
pub fn save(&self) -> Result<(), WalletError> {
// This is a stub implementation
if let Some(path) = &self.wallet_path {
info!("Saving wallet to: {:?}", path);
// In a real implementation, this would save the wallet data to the file
} else {
return Err(WalletError::IoError(io::Error::new(
io::ErrorKind::NotFound,
"Wallet path not set",
)));
}
// For now, we'll just return Ok to indicate success
Ok(())
}
/// Get account by address
pub fn get_account(&self, address: &str) -> Result<&Account, WalletError> {
self.accounts
.get(address)
.ok_or_else(|| WalletError::WalletNotFound(address.to_string()))
}
/// Get account balance
pub fn get_balance(&self, address: &str) -> Result<u64, WalletError> {
let account = self.get_account(address)?;
Ok(account.balance)
}
/// Create a new transaction
pub fn create_transaction(
&self,
sender: &str,
recipient: &str,
amount: u64,
fee: u64,
transaction_type: TransactionType,
data: Option<JsonValue>,
) -> Result<Transaction, WalletError> {
// Check if sender account exists
let sender_account = self.get_account(sender)?;
// Check if sender has enough funds
if sender_account.balance < amount + fee {
return Err(WalletError::InsufficientFunds(
amount + fee,
sender_account.balance,
));
}
// Create transaction
let transaction = Transaction {
id: Uuid::new_v4().to_string(),
transaction_type,
amount,
fee,
sender: sender.to_string(),
recipient: recipient.to_string(),
timestamp: Utc::now(),
status: TransactionStatus::Pending,
signature: None,
data,
};
Ok(transaction)
}
/// Sign a transaction
pub fn sign_transaction(&self, transaction: &mut Transaction) -> Result<(), WalletError> {
// This is a stub implementation
if self.keypair.is_none() {
return Err(WalletError::KeyNotFound("No keypair loaded".to_string()));
}
// In a real implementation, this would sign the transaction with the keypair
// For now, we'll just set a dummy signature
transaction.signature = Some("dummy_signature".to_string());
Ok(())
}
/// Submit a transaction to the network
pub async fn submit_transaction(&self, transaction: &Transaction) -> Result<String, WalletError> {
// This is a stub implementation
info!("Submitting transaction: {:?}", transaction);
// In a real implementation, this would submit the transaction to the network
// For now, we'll just return the transaction ID to indicate success
Ok(transaction.id.clone())
}
/// Get transaction history for an account
pub fn get_transaction_history(&self, address: &str) -> Result<Vec<String>, WalletError> {
let account = self.get_account(address)?;
Ok(account.transactions.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wallet_creation() {
let wallet = Wallet::new();
assert!(wallet.keypair.is_none());
assert!(wallet.accounts.is_empty());
}
#[test]
fn test_keypair_generation() {
let mut wallet = Wallet::new();
let address = wallet.generate_keypair().unwrap();
assert!(wallet.keypair.is_some());
assert!(wallet.accounts.contains_key(&address));
}
// More tests would be added here in a real implementation
}