Skip to main content

chio_settle/evm/
finalize.rs

1//! EVM dispatch finalization and runtime settlement receipt builders.
2
3use super::*;
4
5pub fn finalize_escrow_dispatch(
6    prepared: &PreparedEscrowCreate,
7    receipt: &EvmTransactionReceipt,
8) -> Result<PreparedEscrowCreate, SettlementError> {
9    if !receipt.status {
10        return Err(SettlementError::InvalidDispatch(format!(
11            "transaction {} failed before escrow identity could be finalized",
12            receipt.tx_hash
13        )));
14    }
15    let escrow_id = extract_escrow_created_id(receipt, &prepared.call.to_address)?;
16    let mut finalized = prepared.clone();
17    finalized.expected_escrow_id = escrow_id.clone();
18    finalized.dispatch.escrow_id = escrow_id;
19    Ok(finalized)
20}
21
22pub fn finalize_bond_lock(
23    prepared: &PreparedBondLock,
24    receipt: &EvmTransactionReceipt,
25) -> Result<PreparedBondLock, SettlementError> {
26    if !receipt.status {
27        return Err(SettlementError::InvalidDispatch(format!(
28            "transaction {} failed before bond identity could be finalized",
29            receipt.tx_hash
30        )));
31    }
32    let (vault_id, bond_id_hash, facility_id_hash) =
33        extract_bond_locked_identity(receipt, &prepared.call.to_address)?;
34    if bond_id_hash != prepared.bond_id_hash {
35        return Err(SettlementError::InvalidDispatch(format!(
36            "bond receipt identity mismatch: expected bond {}, observed {}",
37            prepared.bond_id_hash, bond_id_hash
38        )));
39    }
40    if facility_id_hash != prepared.facility_id_hash {
41        return Err(SettlementError::InvalidDispatch(format!(
42            "bond receipt identity mismatch: expected facility {}, observed {}",
43            prepared.facility_id_hash, facility_id_hash
44        )));
45    }
46    let mut finalized = prepared.clone();
47    finalized.vault_id = vault_id;
48    Ok(finalized)
49}
50
51pub fn build_failure_receipt(
52    dispatch: &Web3SettlementDispatchArtifact,
53    execution_receipt_id: String,
54    settlement_reference: String,
55    failure_reference: String,
56    failure_reason: String,
57) -> Result<Web3SettlementExecutionReceiptArtifact, SettlementError> {
58    let amount = dispatch.settlement_amount.clone();
59    let receipt = Web3SettlementExecutionReceiptArtifact {
60        schema: CHIO_WEB3_SETTLEMENT_RECEIPT_SCHEMA.to_string(),
61        execution_receipt_id,
62        issued_at: dispatch.issued_at,
63        dispatch: dispatch.clone(),
64        observed_execution: chio_core::credit::CapitalExecutionObservation {
65            observed_at: dispatch.issued_at,
66            external_reference_id: failure_reference,
67            amount: amount.clone(),
68        },
69        lifecycle_state: Web3SettlementLifecycleState::Failed,
70        settlement_reference,
71        reconciled_anchor_proof: None,
72        identity_registry_evidence: None,
73        identity_registry_evidence_binding: None,
74        oracle_evidence: None,
75        settled_amount: amount,
76        reversal_of: None,
77        failure_reason: Some(failure_reason),
78        note: Some(
79            "Runtime-marked failure after bounded retry or validation exhaustion.".to_string(),
80        ),
81    };
82    validate_web3_settlement_execution_receipt(&receipt)
83        .map_err(|error| SettlementError::Verification(error.to_string()))?;
84    Ok(receipt)
85}
86
87pub fn build_reversal_receipt(
88    dispatch: &Web3SettlementDispatchArtifact,
89    execution_receipt_id: String,
90    settlement_reference: String,
91    tx_hash: String,
92    observed_amount: MonetaryAmount,
93    reversal_of: String,
94    charged_back: bool,
95) -> Result<Web3SettlementExecutionReceiptArtifact, SettlementError> {
96    let receipt = Web3SettlementExecutionReceiptArtifact {
97        schema: CHIO_WEB3_SETTLEMENT_RECEIPT_SCHEMA.to_string(),
98        execution_receipt_id,
99        issued_at: dispatch.issued_at,
100        dispatch: dispatch.clone(),
101        observed_execution: chio_core::credit::CapitalExecutionObservation {
102            observed_at: dispatch.issued_at,
103            external_reference_id: tx_hash,
104            amount: observed_amount.clone(),
105        },
106        lifecycle_state: if charged_back {
107            Web3SettlementLifecycleState::ChargedBack
108        } else {
109            Web3SettlementLifecycleState::Reversed
110        },
111        settlement_reference,
112        reconciled_anchor_proof: None,
113        identity_registry_evidence: None,
114        identity_registry_evidence_binding: None,
115        oracle_evidence: None,
116        settled_amount: observed_amount,
117        reversal_of: Some(reversal_of),
118        failure_reason: None,
119        note: Some(
120            "Runtime-projected compensating settlement after dispute or operator recovery."
121                .to_string(),
122        ),
123    };
124    validate_web3_settlement_execution_receipt(&receipt)
125        .map_err(|error| SettlementError::Verification(error.to_string()))?;
126    Ok(receipt)
127}