use crate::didcomm::PlainMessage;
use crate::error::Result;
use crate::message::{
policy::{Policy, RequireAuthorization, RequirePresentation, RequireProofOfControl},
tap_message_trait::{Authorizable, TapMessageBody, Transaction},
Agent, Authorize, Party, Transfer, UpdatePolicies,
};
use std::collections::HashMap;
use std::str::FromStr;
use tap_caip::AssetId;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Participant {
pub id: String,
pub role: Option<String>,
pub policies: Option<Vec<Policy>>,
#[serde(rename = "leiCode")]
pub leiCode: Option<String>,
pub name: Option<String>,
}
pub fn create_participant_with_policies_example() -> Result<Participant> {
let auth_policy = RequireAuthorization {
from: Some(vec!["did:example:alice".to_string()]),
from_role: None,
from_agent: None,
purpose: Some("Authorization required from Alice".to_string()),
};
let presentation_policy = RequirePresentation {
context: Some(vec![
"https://www.w3.org/2018/credentials/v1".to_string(),
"https://w3id.org/security/suites/ed25519-2020/v1".to_string(),
]),
from: Some(vec!["did:example:bob".to_string()]),
from_role: None,
from_agent: None,
about_party: Some("originator".to_string()),
about_agent: None,
purpose: Some("Please provide KYC credentials".to_string()),
presentation_definition: Some("https://example.com/presentations/kyc".to_string()),
credentials: None,
};
let participant = Participant {
id: "did:example:charlie".to_string(),
role: Some("beneficiary".to_string()),
leiCode: None,
name: None,
policies: Some(vec![
Policy::RequireAuthorization(auth_policy),
Policy::RequirePresentation(presentation_policy),
]),
};
Ok(participant)
}
pub fn update_policies_example(
transaction_id: &str,
creator_did: &str,
recipients: &[&str],
) -> Result<PlainMessage> {
let proof_policy = RequireProofOfControl {
from: Some(vec!["did:example:dave".to_string()]),
from_role: None,
from_agent: None,
address_id: "eip155:1:0x1234567890123456789012345678901234567890".to_string(),
purpose: Some("Please prove control of your account".to_string()),
};
let update = UpdatePolicies {
transaction_id: transaction_id.to_string(),
policies: vec![Policy::RequireProofOfControl(proof_policy)],
};
let participants = recipients
.iter()
.filter(|&&did| did != creator_did)
.copied()
.collect::<Vec<_>>();
let mut message = update.to_didcomm_with_route(creator_did, participants)?;
message.thid = Some(transaction_id.to_string());
Ok(message)
}
pub fn policy_workflow_example() -> Result<()> {
println!("=== Starting Policy Workflow Example ===");
let originator_did = "did:example:originator";
let beneficiary_did = "did:example:beneficiary";
let sender_vaspd_did = "did:example:sender_vasp";
let receiver_vaspd_did = "did:example:receiver_vasp";
println!("Step 1: Creating beneficiary with policies");
let auth_policy = RequireAuthorization {
from: Some(vec![originator_did.to_string()]),
from_role: None,
from_agent: None,
purpose: Some("Authorization required from originator".to_string()),
};
let beneficiary = Participant {
id: beneficiary_did.to_string(),
role: Some("beneficiary".to_string()),
leiCode: None,
name: None,
policies: Some(vec![Policy::RequireAuthorization(auth_policy)]),
};
println!(" Created beneficiary with policies: {:?}", beneficiary);
let transfer_id = "transfer_12345";
println!("Step 2: Created transfer ID: {}", transfer_id);
println!("Step 3: Sender VASP adds a presentation requirement");
let presentation_policy = RequirePresentation {
context: Some(vec!["https://www.w3.org/2018/credentials/v1".to_string()]),
from: Some(vec![beneficiary_did.to_string()]),
from_role: None,
from_agent: None,
about_party: Some("beneficiary".to_string()),
about_agent: None,
purpose: Some("Please provide identity credentials".to_string()),
presentation_definition: None,
credentials: Some(HashMap::from([(
"type".to_string(),
vec!["IdentityCredential".to_string()],
)])),
};
let update_message = UpdatePolicies {
transaction_id: transfer_id.to_string(),
policies: vec![Policy::RequirePresentation(presentation_policy)],
};
let participants = [
originator_did,
beneficiary_did,
sender_vaspd_did,
receiver_vaspd_did,
];
let to = participants
.iter()
.filter(|&&did| did != sender_vaspd_did)
.copied()
.collect::<Vec<_>>();
let mut message = update_message.to_didcomm_with_route(sender_vaspd_did, to)?;
message.thid = Some(transfer_id.to_string());
println!(" Created UpdatePolicies message: {:?}", message);
println!(" This message will be routed to all participants");
println!("=== Policy Workflow Example Completed ===");
Ok(())
}
pub fn create_update_policies_using_authorizable_example(
original_message: &Result<PlainMessage>,
policies: Vec<Policy>,
_transaction_id: &str,
creator_did: &str,
participant_dids: &[String],
) -> Result<PlainMessage> {
let body_json = original_message
.as_ref()
.map_err(Clone::clone)?
.body
.clone();
let transfer_body: Transfer = serde_json::from_value(body_json.clone())
.map_err(|e| crate::error::Error::SerializationError(e.to_string()))?;
let update_policies_message = transfer_body.update_policies(creator_did, policies);
let mut update_policies_reply = update_policies_message;
update_policies_reply.thid = Some(original_message.as_ref().map_err(Clone::clone)?.id.clone());
update_policies_reply.to = participant_dids.iter().map(|s| s.to_string()).collect();
update_policies_reply.to_plain_message()
}
pub fn policy_workflow_with_authorizable_example() -> Result<()> {
println!("=== Starting Policy Workflow with Authorizable Example ===");
let originator_did = "did:example:originator";
let beneficiary_did = "did:example:beneficiary";
let sender_vasp_did = "did:example:sender_vasp";
let receiver_vasp_did = "did:example:receiver_vasp";
let originator = Party::new(originator_did);
let beneficiary = Party::new(beneficiary_did);
let sender_agent = Agent::new(sender_vasp_did, "sender_vasp", originator_did);
let receiver_agent = Agent::new(receiver_vasp_did, "receiver_vasp", beneficiary_did);
let transfer = Transfer::builder()
.asset(AssetId::from_str("eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap())
.originator(originator)
.beneficiary(beneficiary)
.amount("100.00".to_string())
.add_agent(sender_agent)
.add_agent(receiver_agent)
.transaction_id(uuid::Uuid::new_v4().to_string())
.build();
let transfer_message = transfer.to_didcomm_with_route(
originator_did,
[beneficiary_did, sender_vasp_did, receiver_vasp_did]
.iter()
.copied(),
)?;
println!("Transfer message created: {:?}", transfer_message);
let participants = [
originator_did.to_string(),
beneficiary_did.to_string(),
sender_vasp_did.to_string(),
receiver_vasp_did.to_string(),
];
let cloned_transfer_id = transfer_message.id.clone();
let update_policies_message = create_update_policies_using_authorizable_example(
&Ok(transfer_message),
vec![],
&cloned_transfer_id,
sender_vasp_did,
&participants,
)?;
println!(
"Update policies message created: {:?}",
update_policies_message
);
let authorize_body = transfer.authorize(beneficiary_did, None, None);
let mut authorize_reply = authorize_body;
authorize_reply.thid = Some(update_policies_message.id.clone());
authorize_reply.to = participants.iter().map(|s| s.to_string()).collect();
println!("Authorization message created: {:?}", authorize_reply);
Ok(())
}
pub fn create_authorize_example() -> Result<()> {
let authorize_message = Authorize {
transaction_id: "transfer_12345".to_string(),
settlement_address: None,
expiry: None,
};
println!("Authorize message: {:#?}", authorize_message);
Ok(())
}