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::error::{Error, Result};
use tap_agent::key_manager::{Secret, SecretMaterial, SecretType};
use tap_caip::AssetId;
use tap_msg::message::{Authorize, Reject, Settle, Transfer};
use tap_msg::Party;
fn main() -> Result<()> {
tokio_test::block_on(async {
println!("=== Secure TAIP-3 Transfer Flow with TAIP-4 Authorization ===\n");
println!("Step 1: Setting up agents with proper key management");
let (originator_agent, originator_did) = create_agent(
"did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo",
"nWGxne/9WmC6hEr+BQh+uDpW6n7dZsN4c4C9rFfIz3Yh",
)
.await?;
let (beneficiary_agent, beneficiary_did) = create_agent(
"did:key:z6MkhFvVnYxkqLNEiWQmUwhQuVpXiCfNmRUVi5yZ4Cg9w15k",
"8zYZK2vvsAyVYpNpnYzTnUPjBuWdWpYmPpQmwErV9XQg",
"8zYZK2vvsAyVYpNpnYzTnUPjBuWdWpYmPpQmwErV9XQg",
)
.await?;
println!("Created agents with DIDs:");
println!(" Originator: {}", originator_did);
println!(" Beneficiary: {}\n", beneficiary_did);
println!("Step 2: Creating and validating a transfer request");
let settlement_address = "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb";
let transfer =
match create_transfer_message(&originator_did, &beneficiary_did, settlement_address) {
Ok(transfer) => transfer,
Err(e) => {
println!("Error creating transfer message: {}", e);
return Err(Error::Validation(
"Failed to create transfer message".to_string(),
));
}
};
let transfer_id = uuid::Uuid::new_v4().to_string();
if let Err(e) = transfer.validate() {
println!("Transfer validation failed: {}", e);
return Err(Error::Validation(format!(
"Transfer validation failed: {}",
e
)));
}
println!("Transfer message created and validated successfully");
println!(" Asset: {}", transfer.asset);
println!(" Amount: {}", transfer.amount);
println!(
" From: {}",
transfer
.originator
.as_ref()
.map(|o| o.id.as_str())
.unwrap_or("unknown")
);
println!(" To: {}\n", transfer.beneficiary.as_ref().unwrap().id);
println!("Step 3: Sending the transfer request with proper security");
let (packed_transfer, _delivery_results) = match originator_agent
.send_message(&transfer, vec![&beneficiary_did], false)
.await
{
Ok((packed, delivery_results)) => (packed, delivery_results),
Err(e) => {
println!("Error packing transfer message: {}", e);
return Err(e);
}
};
println!("Transfer message packed and sent successfully\n");
println!("Step 4: Beneficiary receives and validates the transfer request");
let _received_transfer: Transfer = match beneficiary_agent
.receive_message(&packed_transfer)
.await
{
Ok(plain_message) => serde_json::from_value(plain_message.body)
.map_err(|e| Error::Validation(format!("Failed to deserialize transfer: {}", e)))?,
Err(e) => {
println!("Error unpacking transfer message: {}", e);
if let Error::Validation(_) = e {
let reject = Reject {
transaction_id: transfer_id.clone(),
reason: Some(format!("validation.failed: Transfer validation failed: {}. Please correct the validation issues and try again", e)),
};
let _ = beneficiary_agent
.send_message(&reject, vec![&originator_did], false)
.await;
println!("Sent rejection due to validation failure");
}
return Err(e);
}
};
println!("Transfer message received and validated successfully\n");
println!("Step 5: Performing risk assessment");
let risk_score = 20; let risk_threshold = 70;
println!("Risk assessment completed");
println!(
" Risk score: {}/100 (threshold: {})\n",
risk_score, risk_threshold
);
println!("Step 6: Processing authorization decision");
if risk_score >= risk_threshold {
println!("High risk detected, rejecting transfer");
let reject = Reject {
transaction_id: transfer_id.clone(),
reason: Some(format!("risk.threshold.exceeded: Risk score ({}) exceeds threshold ({}). Please contact support for further assistance", risk_score, risk_threshold)),
};
let (packed_reject, _delivery_results) = match beneficiary_agent
.send_message(&reject, vec![&originator_did], false)
.await
{
Ok((packed, delivery_results)) => (packed, delivery_results),
Err(e) => {
println!("Error sending rejection: {}", e);
return Err(e);
}
};
println!("Rejection sent successfully\n");
let received_reject: Reject = match originator_agent
.receive_message(&packed_reject)
.await
{
Ok(plain_message) => serde_json::from_value(plain_message.body).map_err(|e| {
Error::Validation(format!("Failed to deserialize reject: {}", e))
})?,
Err(e) => {
println!("Error receiving rejection: {}", e);
return Err(e);
}
};
println!("Originator received rejection:");
println!(" Transfer ID: {}", received_reject.transaction_id);
println!(" Reason: {:?}", received_reject.reason);
println!("Transfer flow ended with rejection");
return Ok(());
}
println!("Low risk detected, proceeding with authorization");
let authorize = Authorize {
transaction_id: transfer_id.clone(),
settlement_address: None,
expiry: None,
};
let (packed_authorize, _delivery_results) = match beneficiary_agent
.send_message(&authorize, vec![&originator_did], false)
.await
{
Ok((packed, delivery_results)) => (packed, delivery_results),
Err(e) => {
println!("Error sending authorization: {}", e);
return Err(e);
}
};
println!("Authorization sent successfully with expiry time in note\n");
println!("Step 7: Originator receives and validates the authorization");
let received_authorize: Authorize =
match originator_agent.receive_message(&packed_authorize).await {
Ok(plain_message) => serde_json::from_value(plain_message.body).map_err(|e| {
Error::Validation(format!("Failed to deserialize authorize: {}", e))
})?,
Err(e) => {
println!("Error receiving authorization: {}", e);
return Err(e);
}
};
println!("Authorization received and validated successfully");
println!(" Transfer ID: {}", received_authorize.transaction_id);
println!();
println!("Step 8: Originator settles the transfer");
let settlement_id =
"eip155:1:tx/0x3edb98c24d46d148eb926c714f4fbaa117c47b0c0821f38bfce9763604457c33";
let settle = Settle {
transaction_id: transfer_id.clone(),
settlement_id: Some(settlement_id.to_string()),
amount: Some(transfer.amount.clone()),
};
let (packed_settle, _delivery_results) = match originator_agent
.send_message(&settle, vec![&beneficiary_did], false)
.await
{
Ok((packed, delivery_results)) => (packed, delivery_results),
Err(e) => {
println!("Error sending settlement: {}", e);
return Err(e);
}
};
println!("Settlement sent successfully");
println!(" Transaction ID: {}\n", settlement_id);
println!("Step 9: Beneficiary receives and validates the settlement");
let received_settle: Settle = match beneficiary_agent.receive_message(&packed_settle).await
{
Ok(plain_message) => serde_json::from_value(plain_message.body)
.map_err(|e| Error::Validation(format!("Failed to deserialize settle: {}", e)))?,
Err(e) => {
println!("Error receiving settlement: {}", e);
return Err(e);
}
};
println!("Settlement received and validated successfully");
println!(" Transfer ID: {}", received_settle.transaction_id);
println!(" Settlement ID: {:?}", received_settle.settlement_id);
if let Some(amount) = &received_settle.amount {
println!(" Amount: {}", amount);
}
println!();
println!("=== Secure transfer flow completed successfully ===");
Ok(())
})
}
async fn create_agent(
did: &str,
public_key: &str,
private_key: &str,
) -> Result<(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()?;
let agent = TapAgent::new(agent_config, Arc::new(key_manager));
Ok((Arc::new(agent), did.to_string()))
}
fn create_transfer_message(
originator_did: &str,
beneficiary_did: &str,
settlement_address: &str,
) -> Result<Transfer> {
if originator_did.is_empty() || beneficiary_did.is_empty() {
return Err(Error::Validation("Invalid DIDs provided".to_string()));
}
let originator = Party::new(originator_did);
let beneficiary = Party::new(beneficiary_did);
let settlement_agent =
tap_msg::Agent::new(settlement_address, "SettlementAddress", originator_did);
let asset = match AssetId::from_str("eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f")
{
Ok(asset) => asset,
Err(_) => return Err(Error::Validation("Invalid asset ID".to_string())),
};
let transfer = Transfer {
transaction_id: Some(uuid::Uuid::new_v4().to_string()),
asset,
originator: Some(originator),
beneficiary: Some(beneficiary),
amount: "100.0".to_string(),
agents: vec![settlement_agent],
settlement_id: None,
expiry: None,
transaction_value: None,
memo: Some("Secure example transfer".to_string()),
connection_id: None,
metadata: HashMap::new(),
};
Ok(transfer)
}