Liquid Rebalancing of Lightning Channels

Vlad Goryachev
6 min readDec 20, 2023

Running a Lightning node is an exciting journey. Implementations like Umbrel make it look easy and fun, but under the surface lies an endless rabbit hole. Bitcoin evolves every day and motivates its users to evolve with it. My curiosity was piqued after someone on Reddit mentioned that he rebalanced channels over Liquid network with PeerSwap. So I decided to learn it.

Back to the Drawing Board

The basic idea behind Lightning is to open channels when the chain fees are low and use them for payments when they are high. If the fees stay high and a channel is used up, closing it and opening a new one becomes uneconomical. Even splicing — closing and opening a channel in a single transaction — is too costly nowadays. We are forced to keep using the old channels as long as possible without touching the base layer.

Once a channel is depleted, the traditional solution is to do a circular rebalancing via your other channels. An algorithm in LNDg and other scripts keeps searching for routes over and over, until all those nodes also run out of liquidity. A multi-hop route a priori costs more than a single hop— hence the conundrum. The network trends to a state when most of its channels are permanently stuck. Even zero fees do not attract any flows. When all the rivers and creeks flow in one direction, something else needs to carry water uphill. Don’t think channels, think clouds!

Another Layer 2

I heard about Liquid BTC for years, but did not have a reason to use it. It is a Bitcoin sidechain with faster confirmations, cheaper costs, confidential transactions and a token value pegged 1:1 to the regular BTC. Just like Lightning can be looped out, Liquid can be pegged out at any time. But it is a private blockchain governed by the Liquid Federation. However minimal, there is a chance of rug pull, censorship, regulatory crackdown or what not. So L-BTC is not suitable for hodling Bitcoin long term. However, temporary possession of this asset can be beneficial.

Imagine you opened a 10m balanced channel with Alice and a 10m balanced channel with Bob. After some time, liquidity in the first one became all inbound, and in the second all outbound. For months you’ve been trying to rebalance them via other peers, gradually increasing the fee you were willing to spend, to no avail. You don’t want to pay more for the rebalancing than the income you received. This income came from routing 5m to Alice — say, at 200 ppm on average. 1000 sats in total.

The channels are dead. 10m of your sats are stuck with Bob, and 10m of Alice’s sats are stuck with you forever. Both channels need to be closed to get these sats back on chain. Or maybe, you could buy something from Bob for 5m sats, and immediately sell the same thing to Alice? This would balance both channels back to 50/50. What asset would do the trick, so that it is desirable for all and its value will not fluctuate in the mean time? Liquid BTC!

Why should Alice and Bob accept such a deal? Because they undoubtedly have the same problem with some of their channels. Using similar arguments, Alice can convince Charlie to buy L-BTC from her and Bob can convince Dana to sell him one. Holding onto Liquid while talking to peers is not a problem. Worst comes to worst, one can always convert it back into Lighting at SideSwap, Boltz, Bitfinex or some other exchange.

Now the best part: swapping L-BTC for Lightning and back can be done peer-to-peer in a trustless way and for a fixed nominal fee of about 300 sats.

PeerSwap and Elements Core

We get to know submarine swaps when looping Lighting sats into on-chain BTC at the Loop server. The process is atomic and trustless, because the same preimage is used to unlock off-chain and on-chain funds. I long wondered why not just any node can be such a swap partner. The Loop server code is not open source because Lightning Labs is a VC-backed for-profit business, I soon realized. A monopoly? Not anymore.

Meet PeerSwap — a FOSS peer-to-peer submarine swap implementation for CLN and LND. It works at arms length: direct peers must have the software installed on their nodes, and the receiving peer must whitelist the sender. The sender, whether initiating a swap in or out, pays the costs. This is to avoid surprises, because PeerSwap daemon runs in the background and does the swaps automatically. Not only it can do swapping Lightning for BTC, but also for L-BTC!

The latter requires installation of Elements Core on your node. This is a Liquid BTC full node similar to Bitcoin Core (and in fact it was its fork). It can be found in the Umbrel’s App Store or installed from github. Make sure to put trim_headers=1 into elements.conf: this saves some RAM. For Umbrel it was already set.

It took me a couple of days to sync the blockchain, although it is only about 20 Gb on disk. The progress can be monitored in Elements Core Web UI.

8 Gb Raspberry Pi can run this, but make sure to uninstall all RAM-hogging apps. Elements Core is very memory intensive while doing initial block download, getting over 4 Gb at times, so keep an eye on your node’s free RAM. When mine got critically low, restarting Elements helped lower its appetite:

$ ~/umbrel/scripts/app restart elements

Once the IBD is complete, my Elements Core uses very little RAM:

Installing PeerSwap depends on whether you run CLN or LND implementation, but both are well documented.

Update 2024: On Umbrel PeerSwap is now available in App Store, including a beautiful Web UI with some useful features like automatic fee management, auto swap-ins, Liquid peg-ins and Elements wallet backup. Skip the following step if you run Umbrel. For others, PeerSwap Web UI can be installed manually.

To run peerswapd on startup, create a systemd service as follows:

$ sudo nano /etc/systemd/system/peerswapd.service
[Unit]
Description=Peer Swap Daemon
StartLimitBurst=9999999
[Service]
ExecStart=/home/umbrel/go/bin/peerswapd
User=umbrel
Type=simple
KillMode=process
TimeoutSec=180
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

Save with ctrl-S, exit with ctrl-X, then start, check status and enable for reboots:

$ sudo systemctl start peerswapd
$ sudo systemctl status peerswapd
$ sudo systemctl enable peerswapd

Once installed and running, you can find out which of your channel peers can do a swap with you:

$ pscli listpeers
{
“peers”: []
}

Yes, it will likely be nobody :-). This technology is still too new and too advanced for an average node operator. But the peerswap community is growing. I am convinced that selling Bitcoin liquidity retail via Lighting and buying in back wholesale via Liquid is THE scaling solution we are looking for. L2 x L2 = ∞

Very Important: Elements Core uses legacy wallet.dat format to store private keys. Seed words to recover your wallet are not available. It is important to backup “peerswap” wallet file to a secure location, or your Liquid balance can be lost if SSD fails. The best way to do it is with elements-cli backupwallet command. On Umbrel, you can access elements-cli like so:

$ docker exec -it elements_node_1 elements-cli -rpcuser=elements -rpcpassword=<elements password>

Give it a try on Testnet, ask questions on Discord, discuss this idea with your peers. Grow.

Happy routing!

--

--