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 estimate
getroute (legacy, no layer support) + sendpay for 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
xpay self-payment resolves locally (test_xpay_selfpay) — correct for single-node but prevents multi-hop circular routing
sendpay with 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
Summary
getroutescurrently requiressource != destination. Whensource == destination, it returns immediately with no routes (andxpayresolves 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:
inform-channel)All of this intelligence is available via
getroutesfor A→B payments. But for circular rebalancing (A→...→A), none of it can be used becausegetroutesdoesn't supportsource == 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 HTLCsThis works but means the execution path can't benefit from askrene layers. The legacy
getrouteuses gossip fees which may differ from layer overrides, and doesn't respect biases, capacity constraints, or disabled nodes from layers.Proposed Enhancement
Allow
getroutesto find circular routes whensource == destination. The returned route would be a cycle:source → hop1 → hop2 → ... → source.This would enable:
Alternatively,
xpaycould 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
getroutessignificantly 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+getrouteworkaround 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