Skip to main content

max_affordable_send_amount

Function max_affordable_send_amount 

pub async fn max_affordable_send_amount<GrossUp, Quote, Fut>(
    balance: Amount,
    min_amount: Amount,
    max_amount: Amount,
    gross_up: GrossUp,
    fee_quote: Quote,
) -> Option<Amount>
where GrossUp: Fn(Amount) -> Amount, Quote: Fn(Amount) -> Fut, Fut: Future<Output = Result<FeeQuote, Error>>,
Expand description

Finds the largest send amount payable in full out of balance when the payment carries both an external per-amount fee (e.g. a Lightning gateway routing fee) and the on-federation transaction fee.

Sending an amount x requires funding a value gross_up(x) on the federation — the external fee grosses the amount up, e.g. the outgoing Lightning contract is x + gateway_fee(x) — and funding that value costs an additional federation fee reported by fee_quote (the module’s output fee plus the primary module’s funding input fees, change output fees and dust). This returns the largest x in min_amount..=max_amount satisfying

gross_up(x) + fee_quote(gross_up(x)).total().get_bitcoin() <= balance

or None if even min_amount is unaffordable.

The cost is not a closed form of x: the federation fee is charged per note, so note selection, denomination rounding, change and dust move it in steps as x crosses thresholds. Rather than invert an analytic formula this evaluates the real quote via a monotonic binary search — each step a single, non-committing fee_quote dry-run over the current inventory — and only ever advances the lower bound to a verified-affordable amount, so the result never overestimates. A fee_quote error (e.g. the balance cannot fund a value that large) is treated as unaffordable.

To keep those dry-runs cheap the search is seeded near the top: a first pass binary-searches gross_up alone (pure arithmetic, no quotes) for the largest fundable amount, peeling off the gateway fee for free, so the real fee quotes only probe the small window the federation fee leaves — a handful of dry-runs rather than one per bit of the balance.

The LNv2 and LNv1 send-all flows share this solver; they differ only in gross_up (the gateway fee model) and which fee_quote they pass.