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>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() <= balanceor 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.