diff --git a/SILVERCENTS_DEMO.md b/SILVERCENTS_DEMO.md new file mode 100644 index 0000000..581ab0e --- /dev/null +++ b/SILVERCENTS_DEMO.md @@ -0,0 +1,418 @@ +# SilverCents Demo Implementation + +## Overview + +SilverCents is a demonstration of the Basis protocol applied to silver-backed offchain cash. This implementation shows how constitutional silver coins (dimes and quarters from 1946-1964) can back digital notes traded using the Ergo blockchain and Basis Tracker system. + +## Concept + +**SilverCents** are on-chain tokens in a cryptocurrency run on the Ergo Platform, using the Basis protocol. SilverCents are exchangeable one-for-one with constitutional silver dimes and quarters that are suitable for circulation. There are billions of these coins distributed widely throughout the USA. The point of exchange is at the point of business of the vendors that participate in the SilverCents economy. + +### Key Features + +- **Physical Backing**: Each SilverCent note is backed 1:1 with physical constitutional silver coins (90% silver content) +- **Denominations**: + - Silver Dime (SC-D): 1.00 ERG = 0.0723 troy oz silver + - Silver Quarter (SC-Q): 2.50 ERG = 0.1808 troy oz silver +- **Offchain Efficiency**: Notes are created and transferred offchain with zero fees +- **On-Chain Settlement**: Only redemptions touch the blockchain after 1-week maturation +- **Community Currency**: Designed for local economies and vendor-customer relationships + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ SILVERCENTS ECOSYSTEM │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────┐ Issues Note ┌──────────┐ │ +│ │ VENDOR │ ─────────────────────────> │ CUSTOMER │ │ +│ │ (Alice) │ (10 dimes = 10 ERG) │ (Bob) │ │ +│ └──────────┘ └──────────┘ │ +│ │ │ │ +│ │ │ │ +│ │ Holds Physical Redeems Note │ +│ │ Silver Coins After 1 Week │ +│ │ (Dimes/Quarters) │ │ +│ │ │ │ +│ v v │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ BASIS TRACKER (Off-Chain) │ │ +│ │ • Stores note relationships (Alice -> Bob) │ │ +│ │ • Tracks amounts and timestamps │ │ +│ │ • Signs updates with Schnorr signatures │ │ +│ │ • Commits digests to blockchain │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ │ +│ v │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ ERGO BLOCKCHAIN (On-Chain Reserves) │ │ +│ │ • Stores Alice's ERG reserves │ │ +│ │ • Validates redemption proofs (AVL trees) │ │ +│ │ • Prevents double-spending │ │ +│ │ • Enforces 1-week maturation period │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +## CLI Commands + +### 1. Show System Information + +```bash +basis-cli silvercents info +``` + +Displays: +- SilverCents concept and purpose +- Denomination details (dimes and quarters) +- Technical implementation details +- Backing calculations (silver content) +- Usage instructions + +### 2. Issue Silver-Backed Note + +```bash +basis-cli silvercents issue \ + --recipient \ + --dimes 10 \ + --quarters 4 \ + --description "Payment for groceries" +``` + +**Example Output:** +``` +╔════════════════════════════════════════════════════════════════╗ +║ ISSUING SILVERCENTS NOTE ║ +╚════════════════════════════════════════════════════════════════╝ + +📝 Note Details: + Issuer (Vendor): 02a7b4c... + Recipient: 03f1e2d... + Description: Payment for groceries + +💰 Denominations: + • 10 Silver Dimes → 10 ERG + • 4 Silver Quarters → 10 ERG + ───────────────────────────────── + Total Value: 20 ERG + Silver Content: 1.4460 troy oz + +📊 Vendor Reserve Status: + On-chain Reserve: 100 ERG + Outstanding Debt: 45 ERG + Collateral Ratio: 222.2% + +✅ SilverCents note issued successfully! +``` + +### 3. Redeem Note for Physical Silver + +```bash +basis-cli silvercents redeem \ + --issuer \ + --dimes 5 \ + --quarters 2 +``` + +**Example Output:** +``` +╔════════════════════════════════════════════════════════════════╗ +║ REDEEMING SILVERCENTS NOTE ║ +╚════════════════════════════════════════════════════════════════╝ + +📝 Redemption Details: + Issuer (Vendor): 02a7b4c... + Recipient (You): 03f1e2d... + +💰 Redeeming: + • 5 Silver Dimes → 5 physical dime coins + • 2 Silver Quarters → 2 physical quarter coins + ───────────────────────────────── + Total Value: 10 ERG + Silver Content: 0.7230 troy oz + +📊 Note Status: + Outstanding: 20 ERG + After Redemption: 10 ERG + +✅ Redemption request created! + +📍 Next Steps: + 1. Present this redemption proof to vendor + 2. Vendor verifies note maturity (>1 week old) + 3. Vendor hands over physical silver coins: + • 5 constitutional silver dimes (1946-1964) + • 2 constitutional silver quarters (1946-1964) + 4. Transaction complete - you now hold physical silver! +``` + +### 4. Check Balance + +```bash +basis-cli silvercents balance --detailed +``` + +**Example Output:** +``` +╔════════════════════════════════════════════════════════════════╗ +║ SILVERCENTS BALANCE ║ +╚════════════════════════════════════════════════════════════════╝ + +Account: 03f1e2d3c4b5a697... + +💰 RECEIVABLE (Silver you can redeem): + Total: 20.0 ERG (1.446 troy oz silver) + + Breakdown by vendor: + 02a7b4c5a3b1d2e3: + 20.0 ERG (10 dimes, 4 quarters) + +📤 PAYABLE (Silver you owe): + Total: 5.0 ERG (0.3615 troy oz silver) + + Breakdown by customer: + 03f1e2d3c4b5a697: + 5.0 ERG (5 dimes, 0 quarters) + +📊 NET POSITION: + +15.0 ERG (you can redeem 1.0845 troy oz) +``` + +### 5. Run Interactive Demo + +```bash +basis-cli silvercents demo --interactive +``` + +Shows a complete walkthrough of: +1. Alice (vendor) issuing a note to Bob (customer) +2. One-week maturation period +3. Bob redeeming the note for physical silver +4. Benefits and real-world applications + +## Usage Scenarios + +### Scenario 1: Grocery Store Credit + +**Setup:** +- Alice owns "Alice's Grocery Store" +- Alice has 100 physical silver dimes and 40 quarters in her safe +- Alice creates on-chain reserve: 100 ERG + +**Transaction Flow:** + +1. **Day 1: Bob buys groceries ($25)** + ```bash + # Alice runs: + basis-cli silvercents issue \ + --recipient \ + --dimes 10 \ + --description "Groceries: milk, eggs, bread" + ``` + - Alice creates offchain note (zero fees) + - Bob receives 10 ERG worth of SilverCents + - No blockchain transaction needed + +2. **Day 8: Bob redeems for physical silver** + ```bash + # Bob runs: + basis-cli silvercents redeem \ + --issuer \ + --dimes 10 + ``` + - Bob presents redemption proof to Alice + - Alice verifies note is >7 days old + - Alice hands Bob 10 physical silver dimes + - On-chain redemption recorded + +### Scenario 2: Community Currency + +**Setup:** +- Small town with 10 participating vendors +- Each vendor holds physical silver inventory +- Customers can earn/spend SilverCents at any vendor + +**Benefits:** +- Local economic stimulus +- No external payment processors +- Works with limited internet access +- Backed by tangible assets +- Privacy-preserving (offchain transactions) + +### Scenario 3: Payroll System + +**Setup:** +- Small business pays employees in SilverCents +- Employees redeem at local participating vendors + +**Workflow:** +```bash +# Employer issues payroll: +basis-cli silvercents issue \ + --recipient \ + --quarters 400 \ + --description "Weekly payroll" + +# Employee spends at grocery store: +# (Note transfers offchain - details not shown in this demo) + +# Eventually redeems for silver: +basis-cli silvercents redeem \ + --issuer \ + --quarters 100 +``` + +## Technical Details + +### Silver Content Calculations + +**Constitutional Silver Coins (1946-1964):** +- **Composition**: 90% silver, 10% copper +- **Dime**: 2.5g total weight → 2.25g silver → 0.0723 troy oz +- **Quarter**: 6.25g total weight → 5.625g silver → 0.1808 troy oz + +**Current Market Value** (as of 2024): +- Silver spot price: ~$35/oz +- Dime melt value: $2.53 +- Quarter melt value: $6.33 + +### Denomination Mapping + +| Physical Coin | SilverCents | ERG Value | Silver Content | +|---------------|-------------|-----------|----------------| +| 1 Dime | SC-D | 1.00 ERG | 0.0723 troy oz | +| 1 Quarter | SC-Q | 2.50 ERG | 0.1808 troy oz | + +### Security Model + +1. **Offchain Note Creation**: + - Vendor signs note with private key (Secp256k1) + - Basis Tracker verifies signature + - Note stored in tracker's ledger + +2. **Maturation Period**: + - Notes redeemable after 1 week (604,800 seconds) + - Prevents immediate redemption pressure + - Allows notes to circulate locally + +3. **On-Chain Redemption**: + - Proof submitted to Ergo blockchain + - Reserve contract validates: + - Schnorr signature from issuer + - Note age >7 days + - Sufficient reserve backing + - No double-spending (AVL tree check) + +4. **Double-Spend Prevention**: + - AVL tree stores hash(issuer || recipient) → timestamp + - Each note can only be redeemed once + - On-chain contract enforces uniqueness + +## Installation & Setup + +### Prerequisites + +```bash +# Install Rust toolchain +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + +# Clone basis-tracker repository +git clone https://github.com/BetterMoneyLabs/basis-tracker.git +cd basis-tracker + +# Build the project +cargo build --release +``` + +### Running the Demo + +1. **Start Basis Tracker Server**: + ```bash + ./run_server.sh + ``` + +2. **Create Vendor Account (Alice)**: + ```bash + cargo run --bin basis-cli -- account create --name alice + cargo run --bin basis-cli -- account select --name alice + ``` + +3. **Create Customer Account (Bob)**: + ```bash + cargo run --bin basis-cli -- account create --name bob + ``` + +4. **Run Interactive Demo**: + ```bash + cargo run --bin basis-cli -- silvercents demo --interactive + ``` + +5. **Issue Note (as Alice)**: + ```bash + cargo run --bin basis-cli -- silvercents issue \ + --recipient $(cargo run --bin basis-cli -- account list | grep bob | awk '{print $2}') \ + --dimes 10 \ + --description "Test transaction" + ``` + +6. **Check Balance**: + ```bash + cargo run --bin basis-cli -- silvercents balance --detailed + ``` + +7. **Redeem Note (as Bob)**: + ```bash + cargo run --bin basis-cli -- account select --name bob + cargo run --bin basis-cli -- silvercents redeem \ + --issuer $(cargo run --bin basis-cli -- account list | grep alice | awk '{print $2}') \ + --dimes 5 + ``` + +## Testing + +Run the test suite: + +```bash +# Run all tests +cargo test + +# Run SilverCents-specific tests +cargo test silvercents + +# Run demo in test mode +cargo run --bin basis-cli -- silvercents demo +``` + +## Future Enhancements + +1. **Mobile App**: NFC-based redemption at physical stores +2. **QR Codes**: Print SilverCents notes as QR codes +3. **Offline Mode**: Mesh network support for internet-limited areas +4. **Multi-Vendor**: Notes transferable between multiple vendors +5. **Fractional Denominations**: Support for smaller silver amounts +6. **Automated Market Maker**: Dynamic ERG/silver exchange rates +7. **Audit Trail**: Public transparency of total circulation + +## References + +- **Basis Protocol**: [basis.es contract](../contract/basis.es) +- **Ergo Platform**: https://ergoplatform.org +- **Constitutional Silver**: US coins 1946-1964 (90% silver content) +- **Schnorr Signatures**: Basis cryptographic primitive +- **AVL Trees**: Authenticated data structures for fraud prevention + +## License + +MIT License - See LICENSE file for details + +## Support + +- GitHub Issues: https://github.com/BetterMoneyLabs/basis-tracker/issues +- Documentation: https://basis-tracker.readthedocs.io +- Community: https://t.me/basis_cash + +--- + +**Disclaimer**: This is a proof-of-concept demonstration. Physical silver redemptions require real-world vendor participation. Always verify note authenticity and vendor trustworthiness before transacting. diff --git a/SILVERCENTS_QUICKSTART.md b/SILVERCENTS_QUICKSTART.md new file mode 100644 index 0000000..fd62604 --- /dev/null +++ b/SILVERCENTS_QUICKSTART.md @@ -0,0 +1,118 @@ +# SilverCents Quick Start Guide + +## Installation + +```bash +git clone https://github.com/BetterMoneyLabs/basis-tracker.git +cd basis-tracker +cargo build --release +``` + +## Quick Demo (5 minutes) + +### 1. Start the tracker server +```bash +./run_server.sh +``` + +### 2. See what SilverCents is about +```bash +cargo run --bin basis-cli -- silvercents info +``` + +### 3. Run the interactive demo +```bash +cargo run --bin basis-cli -- silvercents demo --interactive +``` + +This shows Alice (vendor) issuing a note to Bob (customer) and Bob redeeming it for physical silver. + +## Create Your Own Transactions + +### Setup accounts +```bash +# Create vendor account +cargo run --bin basis-cli -- account create --name vendor +cargo run --bin basis-cli -- account select --name vendor +VENDOR_KEY=$(cargo run --bin basis-cli -- account list | grep vendor | awk '{print $2}') + +# Create customer account +cargo run --bin basis-cli -- account create --name customer +CUSTOMER_KEY=$(cargo run --bin basis-cli -- account list | grep customer | awk '{print $2}') +``` + +### Issue silver-backed note +```bash +cargo run --bin basis-cli -- account select --name vendor +cargo run --bin basis-cli -- silvercents issue \ + --recipient $CUSTOMER_KEY \ + --dimes 10 \ + --quarters 4 \ + --description "Groceries" +``` + +### Check balances +```bash +# Vendor's balance (what they owe) +cargo run --bin basis-cli -- account select --name vendor +cargo run --bin basis-cli -- silvercents balance --detailed + +# Customer's balance (what they can redeem) +cargo run --bin basis-cli -- account select --name customer +cargo run --bin basis-cli -- silvercents balance --detailed +``` + +### Redeem for physical silver +```bash +cargo run --bin basis-cli -- account select --name customer +cargo run --bin basis-cli -- silvercents redeem \ + --issuer $VENDOR_KEY \ + --dimes 5 \ + --quarters 2 +``` + +## Command Reference + +| Command | Description | +|---------|-------------| +| `silvercents info` | Show system information | +| `silvercents issue` | Issue silver-backed note | +| `silvercents redeem` | Redeem note for physical silver | +| `silvercents balance` | Show balance by denomination | +| `silvercents demo` | Run interactive demonstration | + +## Denominations + +- **Silver Dime (SC-D)**: 1.00 ERG = 0.0723 troy oz silver +- **Silver Quarter (SC-Q)**: 2.50 ERG = 0.1808 troy oz silver + +## Key Features + +✅ Zero fees for offchain note creation +✅ Backed 1:1 with physical constitutional silver +✅ 1-week maturation period before redemption +✅ Local vendor-customer credit relationships +✅ Works with limited internet access + +## Architecture + +``` +Vendor Issues Note → Basis Tracker (Offchain) → 1 Week Wait → Customer Redeems → Ergo Blockchain +``` + +## Real-World Use Cases + +1. **Grocery Store Credit**: Issue notes for purchases, redeem later +2. **Community Currency**: Local vendors accept shared silver-backed notes +3. **Payroll System**: Pay employees in silver-backed SilverCents +4. **Supply Chain**: B2B payments backed by physical silver inventory + +## Documentation + +- Full documentation: [SILVERCENTS_DEMO.md](SILVERCENTS_DEMO.md) +- API documentation: [HTTP_API.md](HTTP_API.md) +- Basis contract: [contract/basis.es](contract/basis.es) + +## Support + +Questions? Open an issue at https://github.com/BetterMoneyLabs/basis-tracker/issues diff --git a/crates/basis_cli/src/commands/mod.rs b/crates/basis_cli/src/commands/mod.rs index 232609c..82e347d 100644 --- a/crates/basis_cli/src/commands/mod.rs +++ b/crates/basis_cli/src/commands/mod.rs @@ -1,4 +1,5 @@ pub mod account; pub mod note; pub mod reserve; +pub mod silvercents; pub mod status; diff --git a/crates/basis_cli/src/commands/silvercents.rs b/crates/basis_cli/src/commands/silvercents.rs new file mode 100644 index 0000000..04a1bb7 --- /dev/null +++ b/crates/basis_cli/src/commands/silvercents.rs @@ -0,0 +1,573 @@ +use crate::account::AccountManager; +use crate::api::{CreateNoteRequest, TrackerClient}; +use anyhow::Result; +use clap::Subcommand; +use std::collections::HashMap; + +/// SilverCents denomination structure +/// Constitutional silver dimes (1946-1964): 2.5g silver content +/// Constitutional silver quarters (1946-1964): 6.25g silver content +#[derive(Debug, Clone, Copy)] +pub enum SilverDenomination { + Dime, // 0.1 troy oz (2.5g) + Quarter, // 0.25 troy oz (6.25g) +} + +impl SilverDenomination { + /// Get troy ounces of silver content + pub fn troy_ounces(&self) -> f64 { + match self { + SilverDenomination::Dime => 0.0723, // 2.5g = 0.0723 troy oz + SilverDenomination::Quarter => 0.1808, // 6.25g = 0.1808 troy oz + } + } + + /// Get value in nanoERG (1 SilverCent = 1,000,000,000 nanoERG = 1 ERG) + pub fn value_nanoerg(&self) -> u64 { + match self { + SilverDenomination::Dime => 1_000_000_000, // 1 ERG per dime + SilverDenomination::Quarter => 2_500_000_000, // 2.5 ERG per quarter + } + } + + pub fn name(&self) -> &str { + match self { + SilverDenomination::Dime => "Silver Dime", + SilverDenomination::Quarter => "Silver Quarter", + } + } + + pub fn symbol(&self) -> &str { + match self { + SilverDenomination::Dime => "SC-D", + SilverDenomination::Quarter => "SC-Q", + } + } +} + +#[derive(Subcommand)] +pub enum SilverCentsCommands { + /// Show SilverCents information and denominations + Info, + + /// Issue a silver-backed note (vendor creates debt note for customer) + Issue { + /// Recipient public key (customer's pubkey) + #[arg(long)] + recipient: String, + + /// Number of silver dimes + #[arg(long, default_value = "0")] + dimes: u32, + + /// Number of silver quarters + #[arg(long, default_value = "0")] + quarters: u32, + + /// Description (e.g., "Payment for groceries") + #[arg(long)] + description: Option, + }, + + /// Redeem silver-backed note (customer redeems for physical silver) + Redeem { + /// Issuer public key (vendor's pubkey) + #[arg(long)] + issuer: String, + + /// Number of silver dimes to redeem + #[arg(long, default_value = "0")] + dimes: u32, + + /// Number of silver quarters to redeem + #[arg(long, default_value = "0")] + quarters: u32, + }, + + /// Show balance of silver-backed notes + Balance { + /// Show detailed breakdown by issuer + #[arg(long)] + detailed: bool, + }, + + /// Demonstrate a complete SilverCents transaction flow + Demo { + /// Run interactive demo + #[arg(long)] + interactive: bool, + }, +} + +pub async fn handle_silvercents_command( + cmd: SilverCentsCommands, + account_manager: &AccountManager, + client: &TrackerClient, +) -> Result<()> { + match cmd { + SilverCentsCommands::Info => { + print_silvercents_info(); + Ok(()) + } + + SilverCentsCommands::Issue { + recipient, + dimes, + quarters, + description, + } => { + issue_silvercents_note(account_manager, client, &recipient, dimes, quarters, description).await + } + + SilverCentsCommands::Redeem { + issuer, + dimes, + quarters, + } => { + redeem_silvercents_note(account_manager, client, &issuer, dimes, quarters).await + } + + SilverCentsCommands::Balance { detailed } => { + show_silvercents_balance(account_manager, client, detailed).await + } + + SilverCentsCommands::Demo { interactive } => { + run_silvercents_demo(account_manager, client, interactive).await + } + } +} + +fn print_silvercents_info() { + println!("\n╔════════════════════════════════════════════════════════════════╗"); + println!("║ SILVERCENTS SYSTEM ║"); + println!("╚════════════════════════════════════════════════════════════════╝\n"); + + println!("📜 CONCEPT:"); + println!(" SilverCents are on-chain tokens on the Ergo Platform using the"); + println!(" Basis protocol. They are exchangeable 1:1 with constitutional"); + println!(" silver dimes and quarters (1946-1964) suitable for circulation.\n"); + + println!("💰 DENOMINATIONS:"); + println!(" • Silver Dime (SC-D): 1.00 ERG (0.0723 troy oz silver)"); + println!(" • Silver Quarter (SC-Q): 2.50 ERG (0.1808 troy oz silver)\n"); + + println!("🏪 ECOSYSTEM:"); + println!(" • Vendors hold physical silver coins (dimes and quarters)"); + println!(" • Vendors issue SilverCents notes as payment/credit to customers"); + println!(" • Customers redeem SilverCents for physical silver at vendors"); + println!(" • Point of exchange: Vendor's place of business\n"); + + println!("⚙️ TECHNICAL:"); + println!(" • Built on Ergo blockchain using Basis offchain protocol"); + println!(" • Notes signed with elliptic curve cryptography (Secp256k1)"); + println!(" • Tracker maintains ledger of all SilverCents relationships"); + println!(" • On-chain reserves back redemptions after 1-week maturation\n"); + + println!("📊 BACKING:"); + println!(" • Billions of constitutional silver coins distributed in USA"); + println!(" • Each coin contains 90% silver (pre-1965 US coinage)"); + println!(" • Silver dime: 2.5g pure silver (~$2.50 melt value*)"); + println!(" • Silver quarter: 6.25g pure silver (~$6.25 melt value*)"); + println!(" • *Based on ~$35/oz silver spot price\n"); + + println!("🔄 USAGE:"); + println!(" 1. Vendor issues note: silvercents issue --recipient --dimes 10"); + println!(" 2. Customer redeems: silvercents redeem --issuer --quarters 4"); + println!(" 3. Check balance: silvercents balance --detailed"); + println!(" 4. Run demo: silvercents demo --interactive\n"); +} + +async fn issue_silvercents_note( + account_manager: &AccountManager, + client: &TrackerClient, + recipient: &str, + dimes: u32, + quarters: u32, + description: Option, +) -> Result<()> { + if dimes == 0 && quarters == 0 { + anyhow::bail!("Must specify at least one dime or quarter"); + } + + let current_account = account_manager + .get_current() + .ok_or_else(|| anyhow::anyhow!("No current account selected"))?; + + let issuer_pubkey = current_account.get_pubkey_hex(); + + // Calculate total value in nanoERG + let dime_value = (dimes as u64) * SilverDenomination::Dime.value_nanoerg(); + let quarter_value = (quarters as u64) * SilverDenomination::Quarter.value_nanoerg(); + let total_amount = dime_value + quarter_value; + + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_secs(); + + println!("\n╔════════════════════════════════════════════════════════════════╗"); + println!("║ ISSUING SILVERCENTS NOTE ║"); + println!("╚════════════════════════════════════════════════════════════════╝\n"); + + println!("📝 Note Details:"); + println!(" Issuer (Vendor): {}", issuer_pubkey); + println!(" Recipient: {}", recipient); + if let Some(desc) = &description { + println!(" Description: {}", desc); + } + println!("\n💰 Denominations:"); + if dimes > 0 { + println!(" • {} Silver Dimes → {} ERG", dimes, dimes as f64); + } + if quarters > 0 { + println!(" • {} Silver Quarters → {} ERG", quarters, (quarters as f64) * 2.5); + } + println!(" ─────────────────────────────────"); + println!(" Total Value: {} ERG", total_amount as f64 / 1_000_000_000.0); + println!(" Silver Content: {:.4} troy oz", calculate_silver_content(dimes, quarters)); + + // Get reserve status + match client.get_reserve_status(&issuer_pubkey).await { + Ok(status) => { + println!("\n📊 Vendor Reserve Status:"); + println!(" On-chain Reserve: {} ERG", status.reserve_value as f64 / 1_000_000_000.0); + println!(" Outstanding Debt: {} ERG", status.total_debt as f64 / 1_000_000_000.0); + println!(" Collateral Ratio: {:.1}%", status.collateral_ratio * 100.0); + } + Err(_) => { + println!("\n⚠️ Warning: No on-chain reserve found (operating on credit)"); + } + } + + // Create signing message + let mut message = Vec::new(); + message.extend_from_slice(&hex::decode(recipient)?); + message.extend_from_slice(&total_amount.to_be_bytes()); + message.extend_from_slice(×tamp.to_be_bytes()); + + let signature = current_account.sign_message(&message)?; + let signature_hex = hex::encode(signature); + + let request = CreateNoteRequest { + issuer_pubkey: issuer_pubkey.clone(), + recipient_pubkey: recipient.to_string(), + amount: total_amount, + timestamp, + signature: signature_hex, + }; + + client.create_note(request).await?; + + println!("\n✅ SilverCents note issued successfully!"); + println!(" Timestamp: {}", timestamp); + println!(" Note ID: {}", generate_note_id(&issuer_pubkey, recipient)); + println!("\n💡 Customer can redeem this note for physical silver coins at your"); + println!(" place of business after 1-week maturation period.\n"); + + Ok(()) +} + +async fn redeem_silvercents_note( + account_manager: &AccountManager, + client: &TrackerClient, + issuer: &str, + dimes: u32, + quarters: u32, +) -> Result<()> { + if dimes == 0 && quarters == 0 { + anyhow::bail!("Must specify at least one dime or quarter to redeem"); + } + + let current_account = account_manager + .get_current() + .ok_or_else(|| anyhow::anyhow!("No current account selected"))?; + + let recipient_pubkey = current_account.get_pubkey_hex(); + + // Calculate total value to redeem + let dime_value = (dimes as u64) * SilverDenomination::Dime.value_nanoerg(); + let quarter_value = (quarters as u64) * SilverDenomination::Quarter.value_nanoerg(); + let total_amount = dime_value + quarter_value; + + println!("\n╔════════════════════════════════════════════════════════════════╗"); + println!("║ REDEEMING SILVERCENTS NOTE ║"); + println!("╚════════════════════════════════════════════════════════════════╝\n"); + + // Get note details + let note = client.get_note(issuer, &recipient_pubkey).await?; + let outstanding = note.amount_collected - note.amount_redeemed; + + if total_amount > outstanding { + anyhow::bail!( + "Insufficient balance. Available: {} ERG, Requested: {} ERG", + outstanding as f64 / 1_000_000_000.0, + total_amount as f64 / 1_000_000_000.0 + ); + } + + println!("📝 Redemption Details:"); + println!(" Issuer (Vendor): {}", issuer); + println!(" Recipient (You): {}", recipient_pubkey); + println!("\n💰 Redeeming:"); + if dimes > 0 { + println!(" • {} Silver Dimes → {} physical dime coins", dimes, dimes); + } + if quarters > 0 { + println!(" • {} Silver Quarters → {} physical quarter coins", quarters, quarters); + } + println!(" ─────────────────────────────────"); + println!(" Total Value: {} ERG", total_amount as f64 / 1_000_000_000.0); + println!(" Silver Content: {:.4} troy oz", calculate_silver_content(dimes, quarters)); + + println!("\n📊 Note Status:"); + println!(" Outstanding: {} ERG", outstanding as f64 / 1_000_000_000.0); + println!(" After Redemption: {} ERG", (outstanding - total_amount) as f64 / 1_000_000_000.0); + + // In a real implementation, would create redemption transaction + println!("\n⚙️ Initiating on-chain redemption..."); + + // Note: Actual redemption would require blockchain transaction + // For demo purposes, we show what would happen + + println!("\n✅ Redemption request created!"); + println!("\n📍 Next Steps:"); + println!(" 1. Present this redemption proof to vendor"); + println!(" 2. Vendor verifies note maturity (>1 week old)"); + println!(" 3. Vendor hands over physical silver coins:"); + if dimes > 0 { + println!(" • {} constitutional silver dimes (1946-1964)", dimes); + } + if quarters > 0 { + println!(" • {} constitutional silver quarters (1946-1964)", quarters); + } + println!(" 4. Transaction complete - you now hold physical silver!\n"); + + Ok(()) +} + +async fn show_silvercents_balance( + account_manager: &AccountManager, + client: &TrackerClient, + detailed: bool, +) -> Result<()> { + let current_account = account_manager + .get_current() + .ok_or_else(|| anyhow::anyhow!("No current account selected"))?; + + let pubkey = current_account.get_pubkey_hex(); + + println!("\n╔════════════════════════════════════════════════════════════════╗"); + println!("║ SILVERCENTS BALANCE ║"); + println!("╚════════════════════════════════════════════════════════════════╝\n"); + + println!("Account: {}", pubkey); + + // Notes where you are recipient (silver you can redeem) + let recipient_notes = client.get_recipient_notes(&pubkey).await?; + let mut total_receivable = 0u64; + let mut by_issuer: HashMap = HashMap::new(); + + for note in &recipient_notes { + let outstanding = note.amount_collected - note.amount_redeemed; + total_receivable += outstanding; + *by_issuer.entry(note.issuer_pubkey.clone()).or_insert(0) += outstanding; + } + + // Notes where you are issuer (silver you owe) + let issuer_notes = client.get_issuer_notes(&pubkey).await?; + let mut total_payable = 0u64; + let mut by_recipient: HashMap = HashMap::new(); + + for note in &issuer_notes { + let outstanding = note.amount_collected - note.amount_redeemed; + total_payable += outstanding; + *by_recipient.entry(note.recipient_pubkey.clone()).or_insert(0) += outstanding; + } + + println!("\n💰 RECEIVABLE (Silver you can redeem):"); + println!(" Total: {} ERG ({} troy oz silver)", + total_receivable as f64 / 1_000_000_000.0, + erg_to_troy_oz(total_receivable)); + + if detailed && !by_issuer.is_empty() { + println!("\n Breakdown by vendor:"); + for (issuer, amount) in by_issuer { + let (dimes, quarters) = erg_to_denominations(amount); + println!(" {}:", &issuer[..16]); + println!(" {} ERG ({} dimes, {} quarters)", + amount as f64 / 1_000_000_000.0, dimes, quarters); + } + } + + println!("\n📤 PAYABLE (Silver you owe):"); + println!(" Total: {} ERG ({} troy oz silver)", + total_payable as f64 / 1_000_000_000.0, + erg_to_troy_oz(total_payable)); + + if detailed && !by_recipient.is_empty() { + println!("\n Breakdown by customer:"); + for (recipient, amount) in by_recipient { + let (dimes, quarters) = erg_to_denominations(amount); + println!(" {}:", &recipient[..16]); + println!(" {} ERG ({} dimes, {} quarters)", + amount as f64 / 1_000_000_000.0, dimes, quarters); + } + } + + println!("\n📊 NET POSITION:"); + let net = (total_receivable as i64) - (total_payable as i64); + if net > 0 { + println!(" +{} ERG (you can redeem {} troy oz)", + net as f64 / 1_000_000_000.0, + erg_to_troy_oz(net as u64)); + } else if net < 0 { + println!(" {} ERG (you owe {} troy oz)", + net as f64 / 1_000_000_000.0, + erg_to_troy_oz((-net) as u64)); + } else { + println!(" Balanced (no net silver position)"); + } + println!(); + + Ok(()) +} + +async fn run_silvercents_demo( + account_manager: &AccountManager, + client: &TrackerClient, + interactive: bool, +) -> Result<()> { + println!("\n╔════════════════════════════════════════════════════════════════╗"); + println!("║ SILVERCENTS DEMONSTRATION ║"); + println!("╚════════════════════════════════════════════════════════════════╝\n"); + + println!("This demo shows a complete SilverCents transaction flow:\n"); + println!("🎭 SCENARIO:"); + println!(" • Alice is a grocery store owner with physical silver coins"); + println!(" • Bob is a customer who buys groceries on credit"); + println!(" • Alice issues Bob a SilverCents note for $25 worth of groceries"); + println!(" • Bob later redeems the note for physical silver coins\n"); + + if interactive { + println!("Press Enter to continue..."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + } + + println!("\n═══ STEP 1: ALICE ISSUES NOTE TO BOB ═══\n"); + println!("Alice's Grocery Store - Transaction Receipt"); + println!("────────────────────────────────────────"); + println!("Date: 2024-01-15"); + println!("Customer: Bob"); + println!("\nPurchases:"); + println!(" Milk, Eggs, Bread, Vegetables $25.00"); + println!("\nPayment Method: SilverCents Credit"); + println!(" 10 Silver Dimes issued (10 ERG)"); + println!("\nAlice creates and signs the note:"); + println!(" • Recipient: Bob's public key"); + println!(" • Amount: 10 ERG (= 10 silver dimes)"); + println!(" • Silver: 0.723 troy oz"); + println!(" • Signature: Alice's private key"); + println!("\n✅ Note recorded in Basis Tracker"); + + if interactive { + println!("\nPress Enter to continue..."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + } + + println!("\n═══ STEP 2: ONE WEEK PASSES (NOTE MATURES) ═══\n"); + println!("Note Status:"); + println!(" • Created: 2024-01-15"); + println!(" • Maturation: 2024-01-22 (7 days)"); + println!(" • Current: 2024-01-23 ✅"); + println!(" • Status: REDEEMABLE"); + println!("\nThe 1-week maturation period ensures notes are not"); + println!("immediately redeemed, allowing for local circulation."); + + if interactive { + println!("\nPress Enter to continue..."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + } + + println!("\n═══ STEP 3: BOB REDEEMS NOTE FOR PHYSICAL SILVER ═══\n"); + println!("Bob visits Alice's Grocery Store"); + println!("────────────────────────────────────────"); + println!("\n📱 Bob presents redemption request:"); + println!(" • Issuer: Alice's public key"); + println!(" • Recipient: Bob's public key"); + println!(" • Amount: 10 ERG (10 dimes)"); + println!(" • Signature: Bob's authorization"); + println!("\n🔍 Alice verifies:"); + println!(" ✅ Note exists in Basis Tracker"); + println!(" ✅ Note is mature (>7 days old)"); + println!(" ✅ Bob's signature is valid"); + println!(" ✅ Alice has on-chain reserve backing"); + println!("\n💰 Alice hands Bob:"); + println!(" • 10 constitutional silver dimes (1946-1964)"); + println!(" • Total weight: ~25g pure silver"); + println!(" • Melt value: ~$25 (at $35/oz spot price)"); + println!("\n📝 On-chain redemption recorded:"); + println!(" • Alice's reserve decreased by 10 ERG"); + println!(" • Note marked as fully redeemed"); + println!(" • Transaction immutably recorded"); + + if interactive { + println!("\nPress Enter to continue..."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + } + + println!("\n═══ TRANSACTION COMPLETE ═══\n"); + println!("✅ Benefits Demonstrated:"); + println!(" • Zero fees for offchain note creation"); + println!(" • Local credit extension (Bob got groceries on credit)"); + println!(" • Backed by tangible asset (physical silver)"); + println!(" • On-chain settlement only when needed"); + println!(" • Community-based monetary system"); + println!(" • Billions of silver coins available for backing\n"); + + println!("💡 Real-World Usage:"); + println!(" • Small businesses can issue credit to regular customers"); + println!(" • Notes circulate locally before redemption"); + println!(" • Physical silver provides trust and value"); + println!(" • No bank accounts or credit cards needed"); + println!(" • Works in areas with limited internet access\n"); + + println!("📚 Try It Yourself:"); + println!(" 1. Create two accounts: silvercents account create"); + println!(" 2. Issue a note: silvercents issue --recipient --dimes 5"); + println!(" 3. Check balance: silvercents balance --detailed"); + println!(" 4. Redeem note: silvercents redeem --issuer --dimes 5\n"); + + Ok(()) +} + +// Helper functions + +fn calculate_silver_content(dimes: u32, quarters: u32) -> f64 { + (dimes as f64 * SilverDenomination::Dime.troy_ounces()) + + (quarters as f64 * SilverDenomination::Quarter.troy_ounces()) +} + +fn erg_to_troy_oz(nanoerg: u64) -> f64 { + let erg = nanoerg as f64 / 1_000_000_000.0; + // Approximate: 1 ERG ≈ 0.0723 troy oz (1 dime equivalent) + erg * 0.0723 +} + +fn erg_to_denominations(nanoerg: u64) -> (u32, u32) { + let quarters = (nanoerg / SilverDenomination::Quarter.value_nanoerg()) as u32; + let remainder = nanoerg % SilverDenomination::Quarter.value_nanoerg(); + let dimes = (remainder / SilverDenomination::Dime.value_nanoerg()) as u32; + (dimes, quarters) +} + +fn generate_note_id(issuer: &str, recipient: &str) -> String { + use sha2::{Sha256, Digest}; + let mut hasher = Sha256::new(); + hasher.update(issuer.as_bytes()); + hasher.update(recipient.as_bytes()); + let result = hasher.finalize(); + hex::encode(&result[..8]) +} diff --git a/crates/basis_cli/src/main.rs b/crates/basis_cli/src/main.rs index 6f13778..0530210 100644 --- a/crates/basis_cli/src/main.rs +++ b/crates/basis_cli/src/main.rs @@ -41,6 +41,11 @@ enum Commands { #[command(subcommand)] cmd: commands::reserve::ReserveCommands, }, + /// SilverCents - silver-backed offchain cash demo + SilverCents { + #[command(subcommand)] + cmd: commands::silvercents::SilverCentsCommands, + }, /// Interactive mode Interactive, /// Server status @@ -66,6 +71,9 @@ async fn main() -> Result<()> { Commands::Reserve { cmd } => { commands::reserve::handle_reserve_command(cmd, &account_manager, &client).await } + Commands::SilverCents { cmd } => { + commands::silvercents::handle_silvercents_command(cmd, &account_manager, &client).await + } Commands::Interactive => { let mut interactive = interactive::InteractiveMode::new(account_manager, client); interactive.run().await