Skip to content

Commit 7c95dd4

Browse files
authored
Merge pull request #171 from MostroP2P/fix/admsettle-false-success
fix(admin-disputes): confirm Mostro reply before reporting settle/cancel success
2 parents 75154e9 + a339d8e commit 7c95dd4

2 files changed

Lines changed: 95 additions & 12 deletions

File tree

src/cli/take_dispute.rs

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub async fn execute_admin_cancel_dispute(
7373
println!("{table}");
7474
println!("💡 Canceling dispute...\n");
7575

76-
let _admin_keys = get_admin_keys(ctx)?;
76+
let admin_keys = get_admin_keys(ctx)?;
7777

7878
let payload = if slash_seller || slash_buyer {
7979
Some(Payload::BondResolution(BondResolution {
@@ -84,17 +84,56 @@ pub async fn execute_admin_cancel_dispute(
8484
None
8585
};
8686

87-
// Build admin dispute message
88-
let take_dispute_message =
87+
let admin_cancel_message =
8988
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminCancel, payload)
9089
.as_json()
9190
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
9291

93-
admin_send_dm(ctx, take_dispute_message).await?;
92+
// Send the message and await Mostro's reply so the success message is
93+
// only printed when the cancel actually went through. Admin identity
94+
// binds via the seal/rumor signers — the admin role doesn't rotate
95+
// trade keys, so `admin_keys` signs both layers.
96+
let sent_message = send_dm(
97+
&ctx.client,
98+
admin_keys,
99+
admin_keys,
100+
&ctx.mostro_pubkey,
101+
admin_cancel_message,
102+
None,
103+
false,
104+
);
94105

95-
println!("✅ Dispute canceled successfully!");
106+
let recv_event = wait_for_dm(ctx, Some(admin_keys), sent_message)
107+
.await
108+
.map_err(|e| {
109+
anyhow::anyhow!(
110+
"Failed to receive response from Mostro for AdminCancel: {e}. \
111+
The operation may not have completed; verify the order id exists and check backend logs."
112+
)
113+
})?;
96114

97-
Ok(())
115+
let messages = parse_dm_events(recv_event, admin_keys, None).await;
116+
let (message, _, sender_pubkey) = messages
117+
.first()
118+
.ok_or_else(|| anyhow::anyhow!("No response received from Mostro"))?;
119+
120+
if *sender_pubkey != ctx.mostro_pubkey {
121+
return Err(anyhow::anyhow!("Received response from wrong sender"));
122+
}
123+
124+
let message_kind = message.get_inner_message_kind();
125+
if message_kind.action == Action::AdminCanceled {
126+
println!("✅ Dispute canceled successfully!");
127+
Ok(())
128+
} else if message_kind.action == Action::CantDo {
129+
print_commands_results(message_kind, ctx).await
130+
} else {
131+
Err(anyhow::anyhow!(
132+
"Received response with mismatched action. Expected: {:?}, Got: {:?}",
133+
Action::AdminCanceled,
134+
message_kind.action
135+
))
136+
}
98137
}
99138

100139
pub async fn execute_admin_settle_dispute(
@@ -126,7 +165,7 @@ pub async fn execute_admin_settle_dispute(
126165
println!("{table}");
127166
println!("💡 Settling dispute...\n");
128167

129-
let _admin_keys = get_admin_keys(ctx)?;
168+
let admin_keys = get_admin_keys(ctx)?;
130169

131170
let payload = if slash_seller || slash_buyer {
132171
Some(Payload::BondResolution(BondResolution {
@@ -137,15 +176,56 @@ pub async fn execute_admin_settle_dispute(
137176
None
138177
};
139178

140-
// Build admin dispute message
141-
let take_dispute_message =
179+
let admin_settle_message =
142180
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminSettle, payload)
143181
.as_json()
144182
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
145-
admin_send_dm(ctx, take_dispute_message).await?;
146183

147-
println!("✅ Dispute settled successfully!");
148-
Ok(())
184+
// Send the message and await Mostro's reply so the success message is
185+
// only printed when the settle actually went through. Admin identity
186+
// binds via the seal/rumor signers — the admin role doesn't rotate
187+
// trade keys, so `admin_keys` signs both layers.
188+
let sent_message = send_dm(
189+
&ctx.client,
190+
admin_keys,
191+
admin_keys,
192+
&ctx.mostro_pubkey,
193+
admin_settle_message,
194+
None,
195+
false,
196+
);
197+
198+
let recv_event = wait_for_dm(ctx, Some(admin_keys), sent_message)
199+
.await
200+
.map_err(|e| {
201+
anyhow::anyhow!(
202+
"Failed to receive response from Mostro for AdminSettle: {e}. \
203+
The operation may not have completed; verify the order id exists and check backend logs."
204+
)
205+
})?;
206+
207+
let messages = parse_dm_events(recv_event, admin_keys, None).await;
208+
let (message, _, sender_pubkey) = messages
209+
.first()
210+
.ok_or_else(|| anyhow::anyhow!("No response received from Mostro"))?;
211+
212+
if *sender_pubkey != ctx.mostro_pubkey {
213+
return Err(anyhow::anyhow!("Received response from wrong sender"));
214+
}
215+
216+
let message_kind = message.get_inner_message_kind();
217+
if message_kind.action == Action::AdminSettled {
218+
println!("✅ Dispute settled successfully!");
219+
Ok(())
220+
} else if message_kind.action == Action::CantDo {
221+
print_commands_results(message_kind, ctx).await
222+
} else {
223+
Err(anyhow::anyhow!(
224+
"Received response with mismatched action. Expected: {:?}, Got: {:?}",
225+
Action::AdminSettled,
226+
message_kind.action
227+
))
228+
}
149229
}
150230

151231
pub async fn execute_take_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()> {

src/parser/dms.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ pub async fn print_commands_results(message: &MessageKind, ctx: &Context) -> Res
653653
println!("📊 Please use a valid currency");
654654
Err(anyhow::anyhow!("Invalid currency"))
655655
}
656+
Some(Payload::CantDo(Some(CantDoReason::NotFound))) => Err(anyhow::anyhow!(
657+
"Resource not found. Verify the order or dispute id exists."
658+
)),
656659
_ => {
657660
println!("❓ Unknown Error");
658661
println!("💡 An unknown error occurred");

0 commit comments

Comments
 (0)