-
Notifications
You must be signed in to change notification settings - Fork 982
Feature request: getroutes support for circular routes (source == destination) for rebalancing #9032
Description
Summary
getroutes currently requires source != destination. When source == destination, it returns immediately with no routes (and xpay resolves the payment hash locally without sending HTLCs). This makes it impossible to use askrene layers for circular rebalancing — the primary use case for Lightning channel liquidity management.
Use Case
Circular rebalancing moves liquidity between channels by routing a payment from yourself, through the network, back to yourself. This is the most common operation for node operators maintaining channel health.
With askrene layers, plugins can encode rich routing intelligence:
- Fleet/peer group channels at reduced fees (cooperative routing)
- Reputation-based node biases (avoid unreliable peers)
- Capacity constraints from real-time observations (
inform-channel) - Profitability-based channel preferences
All of this intelligence is available via getroutes for A→B payments. But for circular rebalancing (A→...→A), none of it can be used because getroutes doesn't support source == destination.
Current Workaround
We use a two-step approach:
getroutes(with layers) for route discovery — finds optimal path and fee estimategetroute(legacy, no layer support) +sendpayfor execution — computes per-hop amounts and sends HTLCs
This works but means the execution path can't benefit from askrene layers. The legacy getroute uses gossip fees which may differ from layer overrides, and doesn't respect biases, capacity constraints, or disabled nodes from layers.
Proposed Enhancement
Allow getroutes to find circular routes when source == destination. The returned route would be a cycle: source → hop1 → hop2 → ... → source.
This would enable:
getroutes(source=our_id, destination=our_id, amount_msat=X, layers=[...])
→ returns circular route with correct per-hop amounts
→ sendpay(route) executes the circular payment
Alternatively, xpay could detect that when layers are provided and a circular route exists, it should route through the network instead of resolving locally.
Context
We develop cl-hive (fleet coordination) and cl-revenue-ops (fee/rebalance optimization) for Core Lightning. We've built a 5-layer askrene intelligence stack (fleet topology, peer reputation, corridor values, traffic patterns, local profitability) that makes getroutes significantly smarter for our fleet. But all of that intelligence is lost for our most frequent operation — rebalancing — because it requires circular routing.
The current sendpay + getroute workaround works but is fragile (manual first-hop fee calculation, no layer awareness for the execution path, different fee math between getroute and getroutes).
Related
xpayself-payment resolves locally (test_xpay_selfpay) — correct for single-node but prevents multi-hop circular routingsendpaywith explicit routes is the only way to execute circular payments today- Sling plugin implements its own Dijkstra for circular pathfinding, bypassing CLN's routing entirely