// heromodels/examples/finance_example/main.rs use chrono::{Duration, Utc}; use heromodels::models::finance::marketplace::{ Bid, BidStatus, Listing, ListingStatus, ListingType, }; use heromodels::models::finance::{Account, Asset, AssetType}; fn main() { println!("Finance Models Example\n"); // --- PART 1: ACCOUNTS AND ASSETS --- println!("=== ACCOUNTS AND ASSETS ===\n"); // Create a new account with auto-generated ID let mut account = Account::new( None, // id (auto-generated) "Main ETH Wallet", // name 1001, // user_id "My primary Ethereum wallet", // description "ethereum", // ledger "0x1234567890abcdef1234567890abcdef12345678", // address "0xpubkey123456789", // pubkey ); println!( "Created Account: '{}' (ID: {})", account.name, account.base_data.id ); println!("Owner: User {}", account.user_id); println!("Blockchain: {}", account.ledger); println!("Address: {}", account.address); println!(""); // Create some assets // Asset with auto-generated ID let eth_asset = Asset::new( None, // id (auto-generated) "Ethereum", // name "Native ETH cryptocurrency", // description 1.5, // amount "0x0000000000000000000000000000000000000000", // address (ETH has no contract address) AssetType::Native, // asset_type 18, // decimals ); // Assets with explicit IDs let usdc_asset = Asset::new( Some(102), // id "USDC", // name "USD Stablecoin on Ethereum", // description 1000.0, // amount "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // address (USDC contract) AssetType::Erc20, // asset_type 6, // decimals ); let nft_asset = Asset::new( Some(103), // id "CryptoPunk #1234", // name "Rare digital collectible", // description 1.0, // amount "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb", // address (CryptoPunks contract) AssetType::Erc721, // asset_type 0, // decimals ); // Add assets to the account account = account.add_asset(eth_asset.clone()); account = account.add_asset(usdc_asset.clone()); account = account.add_asset(nft_asset.clone()); println!("Added Assets to Account:"); for asset in &account.assets { println!( "- {} ({:?}): {} units", asset.name, asset.asset_type, asset.formatted_amount() ); } println!("\nTotal Account Value (raw sum): {}", account.total_value()); println!(""); // Update account details account = account.update_details( Some("Primary Ethereum Wallet"), // new name None::, // keep same description None::, // keep same address Some("0xnewpubkey987654321"), // new pubkey ); println!("Updated Account Details:"); println!("New Name: {}", account.name); println!("New Pubkey: {}", account.pubkey); println!(""); // Find an asset by name if let Some(found_asset) = account.find_asset_by_name("USDC") { println!("Found USDC Asset:"); println!("- Amount: {} USDC", found_asset.formatted_amount()); println!("- Contract: {}", found_asset.address); println!(""); } // --- PART 2: MARKETPLACE LISTINGS --- println!("\n=== MARKETPLACE LISTINGS ===\n"); // Create a fixed price listing with auto-generated ID let mut fixed_price_listing = Listing::new( None, // id (auto-generated) "1000 USDC for Sale", // title "Selling 1000 USDC tokens at fixed price", // description "102", // asset_id (referencing the USDC asset) AssetType::Erc20, // asset_type "1001", // seller_id 1.05, // price (in ETH) "ETH", // currency ListingType::FixedPrice, // listing_type Some(Utc::now() + Duration::days(7)), // expires_at (7 days from now) vec!["token".to_string(), "stablecoin".to_string()], // tags Some("https://example.com/usdc.png"), // image_url ); println!( "Created Fixed Price Listing: '{}' (ID: {})", fixed_price_listing.title, fixed_price_listing.base_data.id ); println!( "Price: {} {}", fixed_price_listing.price, fixed_price_listing.currency ); println!( "Type: {:?}, Status: {:?}", fixed_price_listing.listing_type, fixed_price_listing.status ); println!("Expires: {}", fixed_price_listing.expires_at.unwrap()); println!(""); // Complete the fixed price sale match fixed_price_listing.complete_sale("2001", 1.05) { Ok(updated_listing) => { fixed_price_listing = updated_listing; println!("Fixed Price Sale Completed:"); println!("Status: {:?}", fixed_price_listing.status); println!("Buyer: {}", fixed_price_listing.buyer_id.unwrap()); println!( "Sale Price: {} {}", fixed_price_listing.sale_price.unwrap(), fixed_price_listing.currency ); println!("Sold At: {}", fixed_price_listing.sold_at.unwrap()); println!(""); } Err(e) => println!("Error completing sale: {}", e), } // Create an auction listing for the NFT with explicit ID let mut auction_listing = Listing::new( Some(202), // id (explicit) "CryptoPunk #1234 Auction", // title "Rare CryptoPunk NFT for auction", // description "103", // asset_id (referencing the NFT asset) AssetType::Erc721, // asset_type "1001", // seller_id 10.0, // starting_price (in ETH) "ETH", // currency ListingType::Auction, // listing_type Some(Utc::now() + Duration::days(3)), // expires_at (3 days from now) vec![ "nft".to_string(), "collectible".to_string(), "cryptopunk".to_string(), ], // tags Some("https://example.com/cryptopunk1234.png"), // image_url ); println!( "Created Auction Listing: '{}' (ID: {})", auction_listing.title, auction_listing.base_data.id ); println!( "Starting Price: {} {}", auction_listing.price, auction_listing.currency ); println!( "Type: {:?}, Status: {:?}", auction_listing.listing_type, auction_listing.status ); println!(""); // Create some bids let bid1 = Bid::new( auction_listing.base_data.id.to_string(), // listing_id 2001, // bidder_id 11.0, // amount "ETH", // currency ); let bid2 = Bid::new( auction_listing.base_data.id.to_string(), // listing_id 2002, // bidder_id 12.5, // amount "ETH", // currency ); let bid3 = Bid::new( auction_listing.base_data.id.to_string(), // listing_id 2003, // bidder_id 15.0, // amount "ETH", // currency ); // Add bids to the auction println!("Adding Bids to Auction:"); // Using clone() to avoid ownership issues with match expressions match auction_listing.clone().add_bid(bid1) { Ok(updated_listing) => { auction_listing = updated_listing; println!("- Bid added: 11.0 ETH from User 2001"); } Err(e) => println!("Error adding bid: {}", e), } match auction_listing.clone().add_bid(bid2) { Ok(updated_listing) => { auction_listing = updated_listing; println!("- Bid added: 12.5 ETH from User 2002"); } Err(e) => println!("Error adding bid: {}", e), } match auction_listing.clone().add_bid(bid3) { Ok(updated_listing) => { auction_listing = updated_listing; println!("- Bid added: 15.0 ETH from User 2003"); } Err(e) => println!("Error adding bid: {}", e), } println!("\nCurrent Auction Status:"); println!( "Current Price: {} {}", auction_listing.price, auction_listing.currency ); if let Some(highest_bid) = auction_listing.highest_bid() { println!( "Highest Bid: {} {} from User {}", highest_bid.amount, highest_bid.currency, highest_bid.bidder_id ); } println!("Total Bids: {}", auction_listing.bids.len()); println!(""); // Complete the auction match auction_listing.clone().complete_sale("2003", 15.0) { Ok(updated_listing) => { auction_listing = updated_listing; println!("Auction Completed:"); println!("Status: {:?}", auction_listing.status); println!( "Winner: User {}", auction_listing.buyer_id.as_ref().unwrap() ); println!( "Winning Bid: {} {}", auction_listing.sale_price.as_ref().unwrap(), auction_listing.currency ); println!(""); println!("Final Bid Statuses:"); for bid in &auction_listing.bids { println!( "- User {}: {} {} (Status: {:?})", bid.bidder_id, bid.amount, bid.currency, bid.status ); } println!(""); } Err(e) => println!("Error completing auction: {}", e), } // Create an exchange listing with auto-generated ID let exchange_listing = Listing::new( None, // id (auto-generated) "ETH for BTC Exchange", // title "Looking to exchange ETH for BTC", // description "101", // asset_id (referencing the ETH asset) AssetType::Native, // asset_type "1001", // seller_id 1.0, // amount (1 ETH) "BTC", // currency (what they want in exchange) ListingType::Exchange, // listing_type Some(Utc::now() + Duration::days(14)), // expires_at (14 days from now) vec!["exchange".to_string(), "crypto".to_string()], // tags None::, // image_url ); println!( "Created Exchange Listing: '{}' (ID: {})", exchange_listing.title, exchange_listing.base_data.id ); println!( "Offering: Asset {} ({:?})", exchange_listing.asset_id, exchange_listing.asset_type ); println!( "Wanted: {} {}", exchange_listing.price, exchange_listing.currency ); println!(""); // --- PART 3: DEMONSTRATING EDGE CASES --- println!("\n=== EDGE CASES AND VALIDATIONS ===\n"); // Create a new auction listing for edge case testing with explicit ID let test_auction = Listing::new( Some(205), // id (explicit) "Test Auction", // title "For testing edge cases", // description "101", // asset_id AssetType::Native, // asset_type "1001", // seller_id 10.0, // starting_price "ETH", // currency ListingType::Auction, // listing_type Some(Utc::now() + Duration::days(1)), // expires_at vec![], // tags None::, // image_url ); // Try to add a bid that's too low let low_bid = Bid::new( test_auction.base_data.id.to_string(), // listing_id 2004, // bidder_id 5.0, // amount (lower than starting price) "ETH", // currency ); println!("Attempting to add a bid that's too low (5.0 ETH):"); match test_auction.add_bid(low_bid) { Ok(_) => println!("Bid accepted (This shouldn't happen)"), Err(e) => println!("Error as expected: {}", e), } println!(""); // Try to cancel a completed listing println!("Attempting to cancel a completed listing:"); match auction_listing.clone().cancel() { Ok(_) => println!("Listing cancelled (This shouldn't happen)"), Err(e) => println!("Error as expected: {}", e), } println!(""); // Create a listing that will expire with auto-generated ID let mut expiring_listing = Listing::new( None, // id (auto-generated) "About to Expire", // title "This listing will expire immediately", // description "101", // asset_id AssetType::Native, // asset_type "1001", // seller_id 0.1, // price "ETH", // currency ListingType::FixedPrice, // listing_type Some(Utc::now() - Duration::hours(1)), // expires_at (1 hour ago) vec![], // tags None::, // image_url ); println!( "Created Expiring Listing: '{}' (ID: {})", expiring_listing.title, expiring_listing.base_data.id ); println!("Initial Status: {:?}", expiring_listing.status); // Check expiration expiring_listing = expiring_listing.check_expiration(); println!("After Checking Expiration: {:?}", expiring_listing.status); println!(""); println!("Finance Models Example Completed."); }