Up until now, wallet apps built on Bark didn’t handle their own Lightning pathfinding. Instead, the wallet app would send the BOLT11 invoice, amount, and destination to the Ark server, which would work out the best path on the user’s behalf. That’s simple and works great, but some users prefer more control over their pathfinding, or don’t want to share destination data with the server.

I decided to see if I could offer an alternative and make client-side pathfinding work on Bark wallets. Some of my findings below.

Pathfinding without client-side channels is a challenge

A Bark wallet isn't a Lightning node. It has no channels. When you make a Lightning payment, the link to the Lightning Network is an HTLC VTXO cosigned with the Ark server, which is not a Lightning channel in any sense. The HTLC ensures that any Lightning payment is atomic with the server, and it’s the server that maintains channels with the wider network.

This makes self-pathfinding a challenge for the wallet app because it really only cares about VTXOs and on-chain bitcoin—it’s not aware of the state of the Lightning Network.

LDK to the rescue

Looking through CLN’s toolkit, we didn’t find anything simple that would help us solve the problem client-side (the server’s LN gateway is built on CLN). But Lightning Dev Kit (LDK)’s pathfinding library and Rapid Gossip Sync (RGS) proved to be just the things we needed. 

The trick is to make Bark run LDK’s pathfinding with the gateway's node ID as the source, pull the destination, amount, and route hints out of the invoice, and build the payment onion as though the gateway were the sender. 

Then it needs to hand that finished onion to the gateway to relay to the Lightning Network. CLN already has the exact functionality for this (sendonion) so the gateway-side needs no fundamental changes. It just ships what your Bark wallet hands it.

Cooking with onions

Because the onion is built by the client, the gateway is blinded to what’s inside it. The destination node, the full route, the hop count, the payment secret, and the precise invoice amount now live only inside the onion. The gateway turns into a dumb onion relay.

The payment hash, the amount the gateway fronts on the first hop, which of its own peers it forwards through, and the timelock are the items that have to be available to the gateway for the payment to work. Beyond that, the gateway is completely content being oblivious to the rest of the details.

Diagram showing the Lightning payment onion, including what is and isn't visible to the Ark server

Where the map comes from

You can’t route a Lightning payment without a topology of all the public Lightning channels in the network—the “gossip map”. Your Bark wallet gets the gossip map via a Rapid Gossip Sync (RGS) server over HTTP. 

Diagram of how RGS helps Bark wallets stay informed about Lightning's network map

RGS is another fantastic LDK component that makes it easy for mobile devices to download compact gossip map snapshots on-demand. Once you have an initial snapshot, the RGS server can provide smaller delta updates that cut sync time to a handful of milliseconds.

Proving the concept

I’ve published a proof of concept over on my GitLab. It’s early research, but it runs: payments work end-to-end on regtest for multi-hop routes. You can run a multi-hop regtest-based demo with my fork, nix develop and then just devnet-up. Once the regtest network is stood up and running, copy/paste the command it outputs to start the demo payment.

Areas for further research

There are a few things needing work before client-side pathfinding is ready for mainnet. 

Right now, in the PoC code, payments are a one-off attempt. If a route fails, Bark doesn't try another. The HTLCs revoke, the money comes back, and you start over. A better version would read the encrypted error onion sent back from the Lightning Network to learn which hop failed, then reassess and retry. 

The client also doesn’t know the gateway’s channel balances. This means it can choose a first hop that doesn’t have enough outbound liquidity, and then fail the payment. A future improvement could be to query the gateway’s channel balances, cache that information on-device temporarily, and then be able to choose one of the channels with enough outbound capacity.

One huge potential benefit unlocked by client-side pathfinding is that it could remove the minimum 20-sat fee for Lightning payments. This means micropayment use cases such as tipping or Nostr zaps become more viable.

Get involved

If you’re keen to see this enabled sooner rather than later, we welcome contributions. And once on mainnet, we’d appreciate your help testing it with live payments. Due to the nature of the Lightning Network, nothing beats testing on the real thing!