Skip to main content

privacy_cash/
lib.rs

1//! # Privacy Cash Rust SDK
2//!
3//! **Pure Rust** SDK for [Privacy Cash](https://www.privacycash.org) on Solana.
4//! Privacy-preserving transactions using Zero-Knowledge Proofs.
5//!
6//! ## Features
7//!
8//! - **Private Transactions**: Send SOL and SPL tokens with complete privacy
9//! - **Pure Rust ZK Proofs**: Native Groth16 proof generation
10//! - **Multi-Token Support**: SOL, USDC, USDT, and more
11//! - **Partner Fee Integration**: Earn fees by integrating into your platform
12//!
13//! ## Quick Start - ONE Function
14//!
15//! ```rust,no_run
16//! use privacy_cash::send_privately;
17//!
18//! #[tokio::main]
19//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//!     // Send 0.1 SOL privately - ONE function does everything!
21//!     let result = send_privately(
22//!         "your_base58_private_key",  // Private key
23//!         "recipient_pubkey",          // Recipient address  
24//!         0.1,                         // Amount to send
25//!         "sol",                       // Token: "sol", "usdc", "usdt"
26//!         None,                        // Optional RPC URL
27//!     ).await?;
28//!     
29//!     println!("Deposit TX: {}", result.deposit_signature);
30//!     println!("Withdraw TX: {}", result.withdraw_signature);
31//!     println!("Amount received: {}", result.amount_received);
32//!     Ok(())
33//! }
34//! ```
35
36pub mod client;
37pub mod config;
38pub mod constants;
39pub mod deposit;
40pub mod deposit_spl;
41pub mod encryption;
42pub mod error;
43pub mod get_utxos;
44pub mod get_utxos_spl;
45pub mod keypair;
46pub mod merkle_tree;
47pub mod poseidon;
48pub mod prover;
49pub mod prover_rust;
50pub mod storage;
51pub mod utxo;
52pub mod utils;
53pub mod withdraw;
54pub mod withdraw_spl;
55
56// Re-export main types
57pub use client::PrivacyCash;
58pub use config::{Config, SupportedToken};
59pub use constants::*;
60pub use error::{PrivacyCashError, Result};
61pub use keypair::ZkKeypair;
62pub use utxo::{Utxo, Balance, SplBalance};
63
64// Re-export Solana types for convenience
65pub use solana_sdk::{
66    pubkey::Pubkey,
67    signature::{Keypair, Signer},
68};
69
70// ============================================================================
71// MAIN FUNCTION: send_privately() - ONE function does everything!
72// ============================================================================
73
74use std::str::FromStr;
75
76/// Result of a send_privately operation
77#[derive(Debug, Clone)]
78pub struct SendPrivatelyResult {
79    /// Deposit transaction signature
80    pub deposit_signature: String,
81    /// Withdraw transaction signature  
82    pub withdraw_signature: String,
83    /// Amount deposited (in smallest units)
84    pub amount_deposited: u64,
85    /// Amount received by recipient (after fees)
86    pub amount_received: u64,
87    /// Total fees paid (Privacy Cash + Nova Shield)
88    pub total_fees: u64,
89    /// Recipient address
90    pub recipient: String,
91    /// Token type
92    pub token: String,
93}
94
95/// 🚀 SEND PRIVATELY - The ONE function you need!
96///
97/// This function does EVERYTHING:
98/// 1. Deposits your tokens into Privacy Cash
99/// 2. Waits for confirmation
100/// 3. Withdraws the MAXIMUM amount to the recipient
101///
102/// # Arguments
103/// * `private_key` - Your wallet's private key (base58 encoded)
104/// * `recipient` - Recipient's public key (base58 encoded)
105/// * `amount` - Amount to send (e.g., 0.1 for 0.1 SOL or 10.0 for 10 USDC)
106/// * `token` - Token type: "sol", "usdc", or "usdt"
107/// * `rpc_url` - Optional RPC URL (defaults to mainnet)
108///
109/// # Example
110/// ```rust,no_run
111/// use privacy_cash::send_privately;
112///
113/// #[tokio::main]
114/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
115///     let result = send_privately(
116///         "your_private_key_base58",
117///         "recipient_pubkey",
118///         0.1,     // 0.1 SOL
119///         "sol",
120///         None,    // Use default RPC
121///     ).await?;
122///     
123///     println!("✅ Sent privately!");
124///     println!("Deposit TX: {}", result.deposit_signature);
125///     println!("Withdraw TX: {}", result.withdraw_signature);
126///     println!("Recipient received: {} lamports", result.amount_received);
127///     Ok(())
128/// }
129/// ```
130pub async fn send_privately(
131    private_key: &str,
132    recipient: &str,
133    amount: f64,
134    token: &str,
135    rpc_url: Option<&str>,
136) -> Result<SendPrivatelyResult> {
137    // Parse private key
138    let key_bytes = bs58::decode(private_key)
139        .into_vec()
140        .map_err(|e| PrivacyCashError::InvalidInput(format!("Invalid private key: {}", e)))?;
141    let keypair = Keypair::from_bytes(&key_bytes)
142        .map_err(|e| PrivacyCashError::InvalidInput(format!("Invalid keypair: {}", e)))?;
143
144    // Parse recipient
145    let recipient_pubkey = Pubkey::from_str(recipient)
146        .map_err(|e| PrivacyCashError::InvalidInput(format!("Invalid recipient: {}", e)))?;
147
148    // Create client
149    let rpc = rpc_url.unwrap_or("https://api.mainnet-beta.solana.com");
150    let client = PrivacyCash::new(rpc, keypair)?;
151
152    let token_lower = token.to_lowercase();
153    
154    match token_lower.as_str() {
155        "sol" => {
156            let lamports = (amount * 1_000_000_000.0) as u64;
157            
158            // Step 1: Deposit
159            log::info!("Step 1/3: Depositing {} SOL...", amount);
160            let deposit_result = client.deposit(lamports).await?;
161            log::info!("Deposit TX: {}", deposit_result.signature);
162            
163            // Step 2: Wait for indexer
164            log::info!("Step 2/3: Waiting for indexer (5 seconds)...");
165            tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
166            
167            // Step 3: Withdraw ALL to recipient
168            log::info!("Step 3/3: Withdrawing to recipient...");
169            let withdraw_result = client.withdraw_all(Some(&recipient_pubkey)).await?;
170            log::info!("Withdraw TX: {}", withdraw_result.signature);
171            
172            Ok(SendPrivatelyResult {
173                deposit_signature: deposit_result.signature,
174                withdraw_signature: withdraw_result.signature,
175                amount_deposited: lamports,
176                amount_received: withdraw_result.amount_in_lamports,
177                total_fees: lamports.saturating_sub(withdraw_result.amount_in_lamports),
178                recipient: recipient.to_string(),
179                token: "sol".to_string(),
180            })
181        }
182        "usdc" => {
183            let base_units = (amount * 1_000_000.0) as u64;
184            
185            // Step 1: Deposit
186            log::info!("Step 1/3: Depositing {} USDC...", amount);
187            let deposit_result = client.deposit_usdc(base_units).await?;
188            log::info!("Deposit TX: {}", deposit_result.signature);
189            
190            // Step 2: Wait for indexer
191            log::info!("Step 2/3: Waiting for indexer (5 seconds)...");
192            tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
193            
194            // Step 3: Withdraw ALL to recipient
195            log::info!("Step 3/3: Withdrawing to recipient...");
196            let withdraw_result = client.withdraw_all_usdc(Some(&recipient_pubkey)).await?;
197            log::info!("Withdraw TX: {}", withdraw_result.signature);
198            
199            Ok(SendPrivatelyResult {
200                deposit_signature: deposit_result.signature,
201                withdraw_signature: withdraw_result.signature,
202                amount_deposited: base_units,
203                amount_received: withdraw_result.base_units,
204                total_fees: base_units.saturating_sub(withdraw_result.base_units),
205                recipient: recipient.to_string(),
206                token: "usdc".to_string(),
207            })
208        }
209        "usdt" => {
210            let base_units = (amount * 1_000_000.0) as u64;
211            
212            // Step 1: Deposit
213            log::info!("Step 1/3: Depositing {} USDT...", amount);
214            let deposit_result = client.deposit_usdt(base_units).await?;
215            log::info!("Deposit TX: {}", deposit_result.signature);
216            
217            // Step 2: Wait for indexer
218            log::info!("Step 2/3: Waiting for indexer (5 seconds)...");
219            tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
220            
221            // Step 3: Withdraw ALL to recipient
222            log::info!("Step 3/3: Withdrawing to recipient...");
223            let withdraw_result = client.withdraw_all_spl(&USDT_MINT, Some(&recipient_pubkey)).await?;
224            log::info!("Withdraw TX: {}", withdraw_result.signature);
225            
226            Ok(SendPrivatelyResult {
227                deposit_signature: deposit_result.signature,
228                withdraw_signature: withdraw_result.signature,
229                amount_deposited: base_units,
230                amount_received: withdraw_result.base_units,
231                total_fees: base_units.saturating_sub(withdraw_result.base_units),
232                recipient: recipient.to_string(),
233                token: "usdt".to_string(),
234            })
235        }
236        _ => Err(PrivacyCashError::InvalidInput(format!(
237            "Unsupported token: {}. Use 'sol', 'usdc', or 'usdt'",
238            token
239        ))),
240    }
241}