-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexecute_finalize_dispute.rs
More file actions
138 lines (127 loc) · 4.06 KB
/
Copy pathexecute_finalize_dispute.rs
File metadata and controls
138 lines (127 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Execute admin finalize dispute functionality (settle or cancel)
use anyhow::Result;
use nostr_sdk::prelude::*;
use sqlx::SqlitePool;
use uuid::Uuid;
use crate::models::AdminDispute;
use crate::util::mostro_info::MostroInstanceInfo;
use super::{execute_admin_cancel, execute_admin_settle, BondSlashChoice};
/// Finalize a dispute by either settling (paying buyer) or canceling (refunding seller).
///
/// This function handles both AdminSettle and AdminCancel actions, sends the message
/// to Mostro, and updates the dispute status in the database.
///
/// **Post-Finalization Protection**: This function checks if the dispute is already
/// finalized before attempting any action. If the dispute status is Settled,
/// SellerRefunded, or Released, the action is blocked and an error is returned.
///
/// Requires admin privileges (admin_privkey must be configured)
///
/// # Arguments
///
/// * `dispute_id` - The UUID of the dispute to finalize
/// * `bond` - Anti-abuse bond slash choice for the wire payload
/// * `client` - The Nostr client for sending messages
/// * `mostro_pubkey` - The public key of the Mostro daemon
/// * `pool` - The database connection pool for updating dispute status
/// * `is_settle` - If true, executes AdminSettle (pay buyer), otherwise AdminCancel (refund seller)
///
/// # Returns
///
/// Returns `Ok(())` if the finalization message was successfully sent and the database
/// was updated, or an error if the operation failed.
///
/// # Errors
///
/// This function will return an error if:
/// - Dispute is already finalized (Settled, SellerRefunded, or Released)
/// - Dispute not found in database
/// - Settings are not initialized
/// - Admin private key is not configured
/// - Failed to serialize the message
/// - Failed to send the DM
/// - Failed to update dispute status in database
#[allow(clippy::too_many_arguments)]
pub async fn execute_finalize_dispute(
dispute_id: &Uuid,
bond: BondSlashChoice,
admin_keys: &Keys,
client: &Client,
mostro_pubkey: PublicKey,
pool: &SqlitePool,
is_settle: bool,
mostro_instance: Option<&MostroInstanceInfo>,
) -> Result<()> {
let dispute_id_str = dispute_id.to_string();
let dispute: AdminDispute = sqlx::query_as::<_, AdminDispute>(
r#"SELECT * FROM admin_disputes WHERE dispute_id = ? LIMIT 1"#,
)
.bind(&dispute_id_str)
.fetch_one(pool)
.await?;
if dispute.is_finalized() {
let action_name = if is_settle {
"AdminSettle"
} else {
"AdminCancel"
};
return Err(anyhow::anyhow!(
"Cannot execute {}: dispute {} is already finalized (status: {})",
action_name,
dispute_id,
dispute.status.as_deref().unwrap_or("unknown")
));
}
if is_settle && !dispute.can_settle() {
return Err(anyhow::anyhow!(
"Cannot settle dispute {}: action not allowed in current state",
dispute_id
));
}
if !is_settle && !dispute.can_cancel() {
return Err(anyhow::anyhow!(
"Cannot cancel dispute {}: action not allowed in current state",
dispute_id
));
}
let order_id = Uuid::parse_str(&dispute.id)?;
let result = if is_settle {
execute_admin_settle(
&order_id,
bond,
admin_keys,
client,
mostro_pubkey,
mostro_instance,
)
.await
} else {
execute_admin_cancel(
&order_id,
bond,
admin_keys,
client,
mostro_pubkey,
mostro_instance,
)
.await
};
result?;
if is_settle {
AdminDispute::set_status_settled(pool, &dispute.id).await?;
} else {
AdminDispute::set_status_seller_refunded(pool, &dispute.id).await?;
}
let action_name = if is_settle {
"settled (buyer paid)"
} else {
"canceled (seller refunded)"
};
log::info!(
"✅ Dispute {} {} ({})!",
dispute_id,
action_name,
bond.log_context()
);
Ok(())
}