use rust_x402::{
blockchain::{BlockchainClientFactory, TransactionStatus},
blockchain_facilitator::{BlockchainFacilitatorClient, BlockchainFacilitatorFactory},
client::X402Client,
error::X402Error,
types::{PaymentPayload, PaymentRequirements},
wallet::{Wallet, WalletFactory},
Result,
};
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
println!("🚀 x402 Real Implementation Demo");
println!("=================================");
println!("\n1️⃣ Setting up real wallet...");
let wallet = setup_real_wallet()?;
println!("✅ Wallet configured for network: {}", wallet.network());
println!("\n2️⃣ Setting up real facilitator...");
let facilitator = setup_real_facilitator()?;
println!("✅ Facilitator configured");
println!("\n3️⃣ Setting up blockchain client...");
let blockchain_client = BlockchainClientFactory::base_sepolia();
let network_info = blockchain_client.get_network_info().await?;
println!(
"✅ Connected to network: {} (Chain ID: {})",
network_info.network_name, network_info.chain_id
);
println!("\n4️⃣ Creating payment requirements...");
let payment_req = create_payment_requirements();
println!("✅ Payment requirements created");
println!(" Amount: {} USDC", payment_req.max_amount_required);
println!(" Network: {}", payment_req.network);
println!(" Pay to: {}", payment_req.pay_to);
println!("\n5️⃣ Creating real payment payload...");
let payment_payload =
wallet.create_signed_payment_payload(&payment_req, &get_payer_address())?;
println!("✅ Real payment payload created with EIP-712 signature");
println!("\n6️⃣ Verifying payment with real facilitator...");
let verification = facilitator.verify(&payment_payload, &payment_req).await?;
if verification.is_valid {
println!("✅ Payment verification successful");
println!(" Payer: {:?}", verification.payer);
} else {
println!(
"❌ Payment verification failed: {:?}",
verification.invalid_reason
);
return Ok(());
}
println!("\n7️⃣ Checking payer balance...");
let balance_info = blockchain_client
.get_usdc_balance(&get_payer_address())
.await?;
if let Some(token_balance) = balance_info.token_balance {
let balance: u128 = u128::from_str_radix(token_balance.trim_start_matches("0x"), 16)
.map_err(|_| X402Error::InvalidAmount {
expected: "hex string".to_string(),
got: "invalid format".to_string(),
})?;
println!(
"✅ Payer USDC balance: {} ({} wei)",
balance / 1_000_000,
balance
);
} else {
println!("⚠️ Could not retrieve token balance");
}
println!("\n8️⃣ Settling payment with real facilitator...");
let settlement = facilitator.settle(&payment_payload, &payment_req).await?;
if settlement.success {
println!("✅ Payment settlement successful!");
println!(" Transaction: {}", settlement.transaction);
println!(" Network: {}", settlement.network);
println!(" Payer: {:?}", settlement.payer);
} else {
println!(
"❌ Payment settlement failed: {:?}",
settlement.error_reason
);
return Ok(());
}
println!("\n9️⃣ Monitoring transaction confirmation...");
monitor_transaction_confirmation(&blockchain_client, &settlement.transaction).await?;
println!("\n🔟 Making real HTTP request with payment...");
make_real_http_request(&payment_payload).await?;
println!("\n🎉 Real implementation demo completed successfully!");
println!("\n📝 Key Features Demonstrated:");
println!(" ✅ Real EIP-712 signature creation and verification");
println!(" ✅ Real blockchain network interaction");
println!(" ✅ Real USDC balance checking");
println!(" ✅ Real transaction monitoring");
println!(" ✅ Real facilitator integration");
println!(" ✅ Real HTTP client with payment headers");
Ok(())
}
fn setup_real_wallet() -> Result<Wallet> {
let private_key = std::env::var("X402_PRIVATE_KEY").unwrap_or_else(|_| {
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string()
});
let network = std::env::var("X402_NETWORK").unwrap_or_else(|_| "base-sepolia".to_string());
WalletFactory::from_private_key(&private_key, &network)
}
fn setup_real_facilitator() -> Result<BlockchainFacilitatorClient> {
BlockchainFacilitatorFactory::base_sepolia()
}
fn create_payment_requirements() -> PaymentRequirements {
PaymentRequirements::new(
"exact",
"base-sepolia",
"1000000", "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", "https://api.example.com/premium",
"Premium API access with real implementation",
)
}
fn get_payer_address() -> String {
std::env::var("X402_PAYER_ADDRESS")
.unwrap_or_else(|_| "0x857b06519E91e3A54538791bDbb0E22373e36b66".to_string())
}
async fn monitor_transaction_confirmation(
blockchain_client: &rust_x402::blockchain::BlockchainClient,
transaction_hash: &str,
) -> Result<()> {
let mut attempts = 0;
let max_attempts = 30;
println!(" Monitoring transaction: {}", transaction_hash);
while attempts < max_attempts {
match blockchain_client
.get_transaction_status(transaction_hash)
.await
{
Ok(tx_info) => match tx_info.status {
TransactionStatus::Confirmed => {
println!("✅ Transaction confirmed!");
println!(" Block number: {:?}", tx_info.block_number);
println!(" Gas used: {:?}", tx_info.gas_used);
return Ok(());
}
TransactionStatus::Failed => {
println!("❌ Transaction failed on blockchain");
return Err(X402Error::PaymentSettlementFailed {
reason: "Transaction failed".to_string(),
});
}
TransactionStatus::Pending => {
println!(
" ⏳ Transaction pending... (attempt {}/{})",
attempts + 1,
max_attempts
);
}
TransactionStatus::Unknown => {
println!(
" 🔍 Transaction not found yet... (attempt {}/{})",
attempts + 1,
max_attempts
);
}
},
Err(e) => {
println!(" ⚠️ Error checking transaction: {}", e);
}
}
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
attempts += 1;
}
println!("⚠️ Transaction confirmation timeout");
Ok(())
}
async fn make_real_http_request(payment_payload: &PaymentPayload) -> Result<()> {
let client = X402Client::new()?;
match client
.get("http://localhost:4021/premium")
.payment(payment_payload)?
.send()
.await
{
Ok(response) => {
if response.status().is_success() {
println!("✅ HTTP request successful!");
let data: serde_json::Value = response.json().await?;
println!(" Response: {}", serde_json::to_string_pretty(&data)?);
} else {
println!("⚠️ HTTP request returned status: {}", response.status());
}
}
Err(e) => {
println!(
"⚠️ HTTP request failed (expected if no server is running): {}",
e
);
println!(
" This is normal for the demo - in production, you would have a real server"
);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wallet_setup() {
let wallet = setup_real_wallet();
assert!(wallet.is_ok());
}
#[test]
fn test_facilitator_setup() {
let facilitator = setup_real_facilitator();
assert!(facilitator.is_ok());
}
#[test]
fn test_payment_requirements_creation() {
let req = create_payment_requirements();
assert_eq!(req.scheme, "exact");
assert_eq!(req.network, "base-sepolia");
}
}