use crate::config::AntiAbuseBondSettings;
pub fn compute_bond_amount(order_amount_sats: i64, cfg: &AntiAbuseBondSettings) -> i64 {
let base = cfg.base_amount_sats.max(0);
if order_amount_sats <= 0 || cfg.amount_pct <= 0.0 {
return base;
}
let pct_raw = (order_amount_sats as f64) * cfg.amount_pct;
let pct_rounded = pct_raw.round();
let pct_sats: i64 = if pct_rounded >= i64::MAX as f64 {
i64::MAX
} else if pct_rounded <= 0.0 {
0
} else {
pct_rounded as i64
};
pct_sats.max(base)
}
pub fn compute_node_share(amount_sats: i64, pct: f64) -> i64 {
if amount_sats <= 0 {
return 0;
}
let pct = pct.clamp(0.0, 1.0);
let raw = (amount_sats as f64) * pct;
let floored = raw.floor();
if floored <= 0.0 {
0
} else if floored >= amount_sats as f64 {
amount_sats
} else {
floored as i64
}
}
#[cfg(test)]
mod tests {
use super::*;
fn cfg_with(pct: f64, floor: i64) -> AntiAbuseBondSettings {
AntiAbuseBondSettings {
enabled: true,
amount_pct: pct,
base_amount_sats: floor,
..AntiAbuseBondSettings::default()
}
}
#[test]
fn floor_dominates_on_tiny_orders() {
let cfg = cfg_with(0.01, 1_000);
assert_eq!(compute_bond_amount(50_000, &cfg), 1_000);
}
#[test]
fn percentage_dominates_on_large_orders() {
let cfg = cfg_with(0.01, 1_000);
assert_eq!(compute_bond_amount(10_000_000, &cfg), 100_000);
}
#[test]
fn floor_and_percentage_equal_at_threshold() {
let cfg = cfg_with(0.01, 1_000);
assert_eq!(compute_bond_amount(100_000, &cfg), 1_000);
}
#[test]
fn zero_percentage_returns_floor() {
let cfg = cfg_with(0.0, 500);
assert_eq!(compute_bond_amount(1_000_000, &cfg), 500);
}
#[test]
fn zero_order_returns_floor() {
let cfg = cfg_with(0.01, 250);
assert_eq!(compute_bond_amount(0, &cfg), 250);
}
#[test]
fn negative_order_returns_floor() {
let cfg = cfg_with(0.01, 250);
assert_eq!(compute_bond_amount(-5_000, &cfg), 250);
}
#[test]
fn negative_floor_clamped_to_zero() {
let cfg = cfg_with(0.01, -10);
assert_eq!(compute_bond_amount(10_000, &cfg), 100);
}
#[test]
fn rounds_to_nearest_sat() {
let cfg = cfg_with(0.007, 0);
assert_eq!(compute_bond_amount(333, &cfg), 2);
let cfg = cfg_with(0.007, 0);
assert_eq!(compute_bond_amount(500, &cfg), 4);
}
#[test]
fn saturates_on_absurd_percentage() {
let cfg = cfg_with(1e18, 0);
assert_eq!(compute_bond_amount(i64::MAX, &cfg), i64::MAX);
}
#[test]
fn node_share_half_default() {
assert_eq!(compute_node_share(10_000, 0.5), 5_000);
}
#[test]
fn node_share_zero_pct_goes_to_counterparty() {
assert_eq!(compute_node_share(10_000, 0.0), 0);
}
#[test]
fn node_share_one_pct_keeps_all() {
assert_eq!(compute_node_share(10_000, 1.0), 10_000);
}
#[test]
fn node_share_floors_no_rounding_leak() {
let share = compute_node_share(333, 0.5);
assert_eq!(share, 166);
assert_eq!(333 - share, 167);
}
#[test]
fn node_share_zero_or_negative_amount() {
assert_eq!(compute_node_share(0, 0.5), 0);
assert_eq!(compute_node_share(-100, 0.5), 0);
}
#[test]
fn node_share_clamps_out_of_range_pct() {
assert_eq!(compute_node_share(10_000, -0.1), 0);
assert_eq!(compute_node_share(10_000, 1.5), 10_000);
}
}