use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use tap_agent::agent::{Agent, TapAgent};
use tap_agent::agent_key_manager::AgentKeyManagerBuilder;
use tap_agent::config::AgentConfig;
use tap_agent::key_manager::{Secret, SecretMaterial, SecretType};
use tap_caip::AssetId;
use tap_msg::message::{Authorize, Settle};
use tap_msg::{Party, Payment};
fn main() -> Result<(), Box<dyn std::error::Error>> {
tokio_test::block_on(async {
println!("=== TAIP-14 Payment Flow with TAIP-4 Authorization ===\n");
let (merchant_agent, merchant_did) = create_agent(
"did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo",
"nWGxne/9WmC6hEr+BQh+uDpW6n7dZsN4c4C9rFfIz3Yh",
)
.await;
let (customer_agent, customer_did) = create_agent(
"did:key:z6MkhFvVnYxkqLNEiWQmUwhQuVpXiCfNmRUVi5yZ4Cg9w15k",
"8zYZK2vvsAyVYpNpnYzTnUPjBuWdWpYmPpQmwErV9XQg",
"8zYZK2vvsAyVYpNpnYzTnUPjBuWdWpYmPpQmwErV9XQg",
)
.await;
println!("Created merchant agent with DID: {}", merchant_did);
println!("Created customer agent with DID: {}\n", customer_did);
let settlement_address = "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb";
println!("Step 1: Merchant creates a payment request");
let transaction_id = uuid::Uuid::new_v4().to_string();
let payment = create_payment_message(
&merchant_did,
&customer_did,
settlement_address,
&transaction_id,
);
println!("Payment details:");
println!(" Asset: {}", payment.asset.as_ref().unwrap());
println!(" Amount: {}", payment.amount);
println!(" Merchant: {}", payment.merchant.id);
if let Some(customer) = &payment.customer {
println!(" Customer: {}", customer.id);
}
println!();
let (packed_payment, _delivery_results) = merchant_agent
.send_message(&payment, vec![&customer_did], false)
.await?;
println!("Merchant sends the payment request to the customer\n");
println!("Step 2: Customer receives and processes the payment request");
let plain_message = customer_agent.receive_message(&packed_payment).await?;
let received_payment: Payment = serde_json::from_value(plain_message.body)?;
println!("Customer received payment request:");
println!(" Asset: {}", received_payment.asset.as_ref().unwrap());
println!(" Amount: {}", received_payment.amount);
println!(" Merchant: {}", received_payment.merchant.id);
if let Some(customer) = &received_payment.customer {
println!(" Customer: {}", customer.id);
}
println!();
println!("Step 3: Customer authorizes the payment");
let authorize = Authorize {
transaction_id: transaction_id.clone(),
settlement_address: None,
expiry: None,
};
let (packed_authorize, _delivery_results) = customer_agent
.send_message(&authorize, vec![&merchant_did], false)
.await?;
println!("Customer sends authorization to the merchant\n");
println!("Step 4: Merchant receives the authorization");
let plain_message = merchant_agent.receive_message(&packed_authorize).await?;
let received_authorize: Authorize = serde_json::from_value(plain_message.body)?;
println!("Merchant received authorization:");
println!(" Payment ID: {}", received_authorize.transaction_id);
println!("Step 5: Customer settles the payment");
let settlement_id =
"eip155:1:tx/0x3edb98c24d46d148eb926c714f4fbaa117c47b0c0821f38bfce9763604457c33";
let settle = Settle {
transaction_id: transaction_id.clone(),
settlement_id: Some(settlement_id.to_string()),
amount: Some(payment.amount.clone()),
};
let (packed_settle, _delivery_results) = customer_agent
.send_message(&settle, vec![&merchant_did], false)
.await?;
println!("Customer sends settlement confirmation to the merchant");
println!(" Settlement ID: {}\n", settlement_id);
println!("Step 6: Merchant receives the settlement confirmation");
let plain_message = merchant_agent.receive_message(&packed_settle).await?;
let received_settle: Settle = serde_json::from_value(plain_message.body)?;
println!("Merchant received settlement confirmation:");
println!(" Payment ID: {}", received_settle.transaction_id);
println!(" Settlement ID: {:?}", received_settle.settlement_id);
if let Some(amount) = &received_settle.amount {
println!(" Amount: {}\n", amount);
}
println!("Step 7: Merchant fulfills the order (out of band)");
println!(" Merchant has received the payment and will now fulfill the order.\n");
println!("=== Payment flow completed successfully ===");
Ok(())
})
}
async fn create_agent(did: &str, public_key: &str, private_key: &str) -> (Arc<TapAgent>, String) {
let agent_config = AgentConfig::new(did.to_string());
let mut builder = AgentKeyManagerBuilder::new();
let secret = Secret {
id: format!("{}#keys-1", did),
type_: SecretType::JsonWebKey2020,
secret_material: SecretMaterial::JWK {
private_key_jwk: serde_json::json!({
"kty": "OKP",
"crv": "Ed25519",
"x": public_key,
"d": private_key
}),
},
};
builder = builder.add_secret(did.to_string(), secret);
let key_manager = builder.build().expect("Failed to build key manager");
let agent = TapAgent::new(agent_config, Arc::new(key_manager));
(Arc::new(agent), did.to_string())
}
fn create_payment_message(
merchant_did: &str,
customer_did: &str,
settlement_address: &str,
transaction_id: &str,
) -> Payment {
let merchant = Party::new(merchant_did);
let customer = Party::new(customer_did);
let settlement_agent =
tap_msg::Agent::new(settlement_address, "SettlementAddress", merchant_did);
Payment {
asset: Some(
AssetId::from_str("eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f").unwrap(),
),
currency_code: None,
amount: "100.0".to_string(),
supported_assets: None,
invoice: None,
expiry: None,
merchant,
customer: Some(customer),
agents: vec![settlement_agent],
connection_id: None,
fallback_settlement_addresses: None,
metadata: HashMap::new(),
transaction_id: Some(transaction_id.to_string()),
memo: Some("Payment for goods or services".to_string()),
}
}