use rust_x402::{
client::{DiscoveryClient, X402Client},
types::{PaymentPayload, PaymentRequirements},
wallet::WalletFactory,
Result,
};
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
println!("🔍 Discovering x402 resources...");
let discovery = DiscoveryClient::default_client();
let resources = discovery.get_all_resources().await?;
println!("Found {} discoverable resources", resources.items.len());
let client = X402Client::new()?;
println!("\n📡 Making request to protected resource without payment...");
let response = client.get("http://localhost:4021/joke").send().await?;
if response.status() == 402 {
println!("💰 Payment required! Status: {}", response.status());
let payment_req: PaymentRequirements = response.json().await?;
println!("Payment requirements:");
println!(
" Amount: {} {}",
payment_req.max_amount_required, payment_req.asset
);
println!(" Network: {}", payment_req.network);
println!(" Description: {}", payment_req.description);
let payment_payload = create_real_payment_payload(&payment_req)?;
println!("\n💳 Retrying request with payment...");
let final_response = client
.get("http://localhost:4021/joke")
.payment(&payment_payload)?
.send()
.await?;
if final_response.status().is_success() {
let settlement_header = final_response.headers().get("X-PAYMENT-RESPONSE").cloned();
let joke: serde_json::Value = final_response.json().await?;
println!("✅ Success! Response: {}", joke);
if let Some(settlement_header) = settlement_header {
println!(
"🎉 Payment settled! Transaction: {}",
settlement_header.to_str().unwrap()
);
}
} else {
println!("❌ Request failed with status: {}", final_response.status());
}
} else {
println!(
"✅ No payment required. Response: {}",
response.text().await?
);
}
println!("\n🏥 Testing health endpoint...");
let health_response = client.get("http://localhost:4021/health").send().await?;
if health_response.status().is_success() {
let health: serde_json::Value = health_response.json().await?;
println!("✅ Health check passed: {}", health);
}
println!("\n🔍 Discovering HTTP resources...");
let http_resources = discovery.get_resources_by_type("http").await?;
println!("Found {} HTTP resources", http_resources.items.len());
for resource in &http_resources.items[..3] {
println!(" 📍 {} - {}", resource.resource, resource.r#type);
if let Some(metadata) = &resource.metadata {
println!(" Metadata: {}", metadata);
}
}
Ok(())
}
fn create_real_payment_payload(requirements: &PaymentRequirements) -> Result<PaymentPayload> {
let private_key = std::env::var("X402_PRIVATE_KEY").unwrap_or_else(|_| {
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string()
});
let payer_address = std::env::var("X402_PAYER_ADDRESS")
.unwrap_or_else(|_| "0x857b06519E91e3A54538791bDbb0E22373e36b66".to_string());
let wallet = WalletFactory::from_private_key(&private_key, &requirements.network)?;
let payment_payload = wallet.create_signed_payment_payload(requirements, &payer_address)?;
println!("✅ Created real payment payload with EIP-712 signature");
println!(" Payer: {}", payer_address);
println!(" Network: {}", requirements.network);
println!(
" Amount: {} {}",
requirements.max_amount_required, requirements.asset
);
Ok(payment_payload)
}