dpp_domain/transfer/
chain.rs1use serde::{Deserialize, Serialize};
4
5use super::error::TransferError;
6use super::record::TransferRecord;
7use super::status::TransferStatus;
8use crate::operator::ResponsibleOperator;
9use crate::passport::PassportId;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct TransferChain {
18 pub passport_id: PassportId,
20 pub original_operator: ResponsibleOperator,
22 pub transfers: Vec<TransferRecord>,
24}
25
26impl TransferChain {
27 #[must_use]
29 pub fn new(passport_id: PassportId, original_operator: ResponsibleOperator) -> Self {
30 Self {
31 passport_id,
32 original_operator,
33 transfers: Vec::new(),
34 }
35 }
36
37 pub fn current_operator(&self) -> &ResponsibleOperator {
42 self.transfers
43 .iter()
44 .rev()
45 .find(|t| t.is_complete())
46 .map(|t| &t.to_operator)
47 .unwrap_or(&self.original_operator)
48 }
49
50 pub fn transfer_count(&self) -> usize {
52 self.transfers.iter().filter(|t| t.is_complete()).count()
53 }
54
55 pub fn initiate_transfer(&mut self, record: TransferRecord) -> Result<(), TransferError> {
61 let current = self.current_operator();
63 if record.from_operator.did != current.did {
64 return Err(TransferError::OperatorMismatch {
65 expected: current.did.clone(),
66 got: record.from_operator.did.clone(),
67 });
68 }
69
70 let has_pending = self.transfers.iter().any(|t| {
72 t.status() == TransferStatus::Initiated || t.status() == TransferStatus::Accepted
73 });
74 if has_pending {
75 return Err(TransferError::TransferAlreadyPending);
76 }
77
78 self.transfers.push(record);
79 Ok(())
80 }
81}