-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexecute_admin_settle.rs
More file actions
118 lines (110 loc) · 3.83 KB
/
Copy pathexecute_admin_settle.rs
File metadata and controls
118 lines (110 loc) · 3.83 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
// Execute admin settle dispute functionality (pays buyer)
use anyhow::Result;
use mostro_core::prelude::*;
use nostr_sdk::prelude::*;
use uuid::Uuid;
use super::BondSlashChoice;
use crate::util::dm_utils::{parse_dm_events, send_dm, wait_for_dm, FETCH_EVENTS_TIMEOUT};
use crate::util::mostro_info::MostroInstanceInfo;
use crate::util::order_utils::helper::handle_mostro_response;
/// Settle a dispute in favor of the buyer (AdminSettle action).
/// This pays the full escrow amount to the buyer.
///
/// **Important**: This is a low-level function that sends the message to Mostro.
/// Callers should use `execute_finalize_dispute()` instead, which includes
/// finalization state checks and database updates. Direct calls to this function
/// should only be made after verifying `AdminDispute::can_settle()` returns true.
///
/// Requires admin privileges (admin_privkey must be configured)
///
/// # Arguments
///
/// * `order_id` - The UUID of the order associated with this dispute (Mostro expects this ID)
/// * `bond` - Anti-abuse bond slash choice (`to_optional_payload()` on the wire)
/// * `client` - The Nostr client for sending messages
/// * `mostro_pubkey` - The public key of the Mostro daemon
///
/// # Returns
///
/// Returns `Ok(())` if Mostro confirms with `AdminSettled`, or an error
/// if the operation failed (including `CantDo` from the daemon).
///
/// # Errors
///
/// This function will return an error if:
/// - Settings are not initialized
/// - Admin private key is not configured
/// - Failed to serialize the message
/// - Failed to send or receive the DM
/// - Mostro replies with `CantDo`
/// - Unexpected response action or sender
pub async fn execute_admin_settle(
order_id: &Uuid,
bond: BondSlashChoice,
admin_keys: &Keys,
client: &Client,
mostro_pubkey: PublicKey,
mostro_instance: Option<&MostroInstanceInfo>,
) -> Result<()> {
let request_id = Uuid::new_v4().as_u128() as u64;
let payload = bond.to_optional_payload();
let settle_message = Message::new_dispute(
Some(*order_id),
Some(request_id),
None,
Action::AdminSettle,
payload,
)
.as_json()
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
let sent_message = send_dm(
client,
Some(admin_keys),
admin_keys,
&mostro_pubkey,
settle_message,
None,
mostro_instance,
);
let recv_event = wait_for_dm(admin_keys, FETCH_EVENTS_TIMEOUT, sent_message).await?;
let messages = parse_dm_events(recv_event, admin_keys, None).await;
let Some((response_message, _, sender_pubkey)) = messages.first() else {
return Err(anyhow::anyhow!("No response received from Mostro"));
};
if *sender_pubkey != mostro_pubkey {
return Err(anyhow::anyhow!("Received response from wrong sender"));
}
let inner_message = handle_mostro_response(response_message, request_id)?;
if inner_message.action != Action::AdminSettled {
return Err(anyhow::anyhow!(
"Unexpected action in response: {:?}",
inner_message.action
));
}
log::info!(
"✅ Admin settle (pay buyer) confirmed for order {} ({})",
order_id,
bond.log_context()
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use uuid::uuid;
#[test]
fn admin_settle_slash_buyer_serializes_bond_resolution() {
let order_id = uuid!("308e1272-d5f4-47e6-bd97-3504baea9c23");
let msg = Message::new_dispute(
Some(order_id),
None,
None,
Action::AdminSettle,
BondSlashChoice::SlashBuyer.to_optional_payload(),
);
assert!(msg.verify());
let json = msg.as_json().expect("serialize");
assert!(json.contains("\"bond_resolution\""));
assert!(json.contains("\"slash_buyer\":true"));
}
}