Skip to content

Commit 75a0311

Browse files
grunchclaude
andcommitted
feat(admin): expose BondResolution payload on adm-settle / adm-cancel
Add --slash-seller and --slash-buyer flags to the AdmSettle and AdmCancel subcommands so QA / solvers can exercise the anti-abuse-bond Phase 2 flow shipped in MostroP2P/mostro#737. When either flag is set, the dispute message now carries a Payload::BondResolution; with no flags the payload stays None to preserve Phase 1 behaviour. The slash decisions are also surfaced in the printed action table. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 010b5bf commit 75a0311

2 files changed

Lines changed: 66 additions & 6 deletions

File tree

src/cli.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,24 @@ pub enum Commands {
266266
/// Order id
267267
#[arg(short, long)]
268268
order_id: Uuid,
269+
/// Slash the seller's bond (anti-abuse-bond Phase 2)
270+
#[arg(long, default_value_t = false)]
271+
slash_seller: bool,
272+
/// Slash the buyer's bond (anti-abuse-bond Phase 2)
273+
#[arg(long, default_value_t = false)]
274+
slash_buyer: bool,
269275
},
270276
/// Settle a seller's hold invoice (only admin)
271277
AdmSettle {
272278
/// Order id
273279
#[arg(short, long)]
274280
order_id: Uuid,
281+
/// Slash the seller's bond (anti-abuse-bond Phase 2)
282+
#[arg(long, default_value_t = false)]
283+
slash_seller: bool,
284+
/// Slash the buyer's bond (anti-abuse-bond Phase 2)
285+
#[arg(long, default_value_t = false)]
286+
slash_buyer: bool,
275287
},
276288
/// Requests open disputes from Mostro pubkey
277289
ListDisputes {},
@@ -583,8 +595,16 @@ impl Commands {
583595
// Admin commands
584596
Commands::ListDisputes {} => execute_list_disputes(ctx).await,
585597
Commands::AdmAddSolver { npubkey } => execute_admin_add_solver(npubkey, ctx).await,
586-
Commands::AdmSettle { order_id } => execute_admin_settle_dispute(order_id, ctx).await,
587-
Commands::AdmCancel { order_id } => execute_admin_cancel_dispute(order_id, ctx).await,
598+
Commands::AdmSettle {
599+
order_id,
600+
slash_seller,
601+
slash_buyer,
602+
} => execute_admin_settle_dispute(order_id, *slash_seller, *slash_buyer, ctx).await,
603+
Commands::AdmCancel {
604+
order_id,
605+
slash_seller,
606+
slash_buyer,
607+
} => execute_admin_cancel_dispute(order_id, *slash_seller, *slash_buyer, ctx).await,
588608
Commands::AdmTakeDispute { dispute_id } => execute_take_dispute(dispute_id, ctx).await,
589609

590610
// Simple commands

src/cli/take_dispute.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ pub async fn execute_admin_add_solver(npubkey: &str, ctx: &Context) -> Result<()
4444
Ok(())
4545
}
4646

47-
pub async fn execute_admin_cancel_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()> {
47+
pub async fn execute_admin_cancel_dispute(
48+
dispute_id: &Uuid,
49+
slash_seller: bool,
50+
slash_buyer: bool,
51+
ctx: &Context,
52+
) -> Result<()> {
4853
println!("👑 Admin Cancel Dispute");
4954
println!("═══════════════════════════════════════");
5055
let mut table = create_standard_table();
@@ -54,6 +59,12 @@ pub async fn execute_admin_cancel_dispute(dispute_id: &Uuid, ctx: &Context) -> R
5459
"Dispute ID",
5560
&dispute_id.to_string(),
5661
));
62+
if slash_seller {
63+
table.add_row(create_emoji_field_row("⚔️ ", "Slash", "seller bond"));
64+
}
65+
if slash_buyer {
66+
table.add_row(create_emoji_field_row("⚔️ ", "Slash", "buyer bond"));
67+
}
5768
table.add_row(create_emoji_field_row(
5869
"🎯 ",
5970
"Mostro PubKey",
@@ -64,9 +75,18 @@ pub async fn execute_admin_cancel_dispute(dispute_id: &Uuid, ctx: &Context) -> R
6475

6576
let _admin_keys = get_admin_keys(ctx)?;
6677

78+
let payload = if slash_seller || slash_buyer {
79+
Some(Payload::BondResolution(BondResolution {
80+
slash_seller,
81+
slash_buyer,
82+
}))
83+
} else {
84+
None
85+
};
86+
6787
// Build admin dispute message
6888
let take_dispute_message =
69-
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminCancel, None)
89+
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminCancel, payload)
7090
.as_json()
7191
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
7292

@@ -77,7 +97,12 @@ pub async fn execute_admin_cancel_dispute(dispute_id: &Uuid, ctx: &Context) -> R
7797
Ok(())
7898
}
7999

80-
pub async fn execute_admin_settle_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()> {
100+
pub async fn execute_admin_settle_dispute(
101+
dispute_id: &Uuid,
102+
slash_seller: bool,
103+
slash_buyer: bool,
104+
ctx: &Context,
105+
) -> Result<()> {
81106
println!("👑 Admin Settle Dispute");
82107
println!("═══════════════════════════════════════");
83108
let mut table = create_standard_table();
@@ -87,6 +112,12 @@ pub async fn execute_admin_settle_dispute(dispute_id: &Uuid, ctx: &Context) -> R
87112
"Dispute ID",
88113
&dispute_id.to_string(),
89114
));
115+
if slash_seller {
116+
table.add_row(create_emoji_field_row("⚔️ ", "Slash", "seller bond"));
117+
}
118+
if slash_buyer {
119+
table.add_row(create_emoji_field_row("⚔️ ", "Slash", "buyer bond"));
120+
}
90121
table.add_row(create_emoji_field_row(
91122
"🎯 ",
92123
"Mostro PubKey",
@@ -97,9 +128,18 @@ pub async fn execute_admin_settle_dispute(dispute_id: &Uuid, ctx: &Context) -> R
97128

98129
let _admin_keys = get_admin_keys(ctx)?;
99130

131+
let payload = if slash_seller || slash_buyer {
132+
Some(Payload::BondResolution(BondResolution {
133+
slash_seller,
134+
slash_buyer,
135+
}))
136+
} else {
137+
None
138+
};
139+
100140
// Build admin dispute message
101141
let take_dispute_message =
102-
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminSettle, None)
142+
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminSettle, payload)
103143
.as_json()
104144
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
105145
admin_send_dm(ctx, take_dispute_message).await?;

0 commit comments

Comments
 (0)