Loop Out In-depth

15 Apr 2019
on Technical and Posts

by Joost Jager

In a previous blog
post we
announced Loop Out, a
non-custodial service to obtain inbound liquidity by offloading funds to a
regular on-chain address. This post goes deeper into some of the technical
details of Loop Out and assumes knowledge of Bitcoin, Lightning and hash locked
contracts.

Inbound Liquidity

The general way of obtaining inbound liquidity in the Lightning Network is to
send out a payment through the channel you would like to receive on. This in
itself is a unique aspect of Lightning and not like any other payment system. A
way to look at a channel is as a closed tube between you and your channel peer
that contains marbles. Marbles represent money. By sending a payment (for
example to buy goods from a supplier), marbles move to your peer’s side of the
tube. A subsequent payment to you (your customer buying the goods) moves the
marbles back to your side.

In an ideal future where everyone uses Lightning, this system is self-balanced.
You pay to others as much as you receive from them and the marbles just keep
rolling back and forth. However, with the state of Lightning today, this is not
necessarily true. A merchant for example who sells products via Lightning but
pays its suppliers via another payment method will likely accumulate more and
more balance in its Lightning channels until customers can no longer make
payments. All the marbles have moved to the merchant’s side of the channels.

The solution that Loop Out offers in this situation is to make a payment (push
the marbles away from you) and receive the money back at an on-chain address.
You are effectively looping the payment back to yourself, hence the name
Lightning Loop.

Any channel can be Looped out over and over again. There is no need to open new
channels and the user can pick the peer they want to loop out through. This is
an advantage over existing services that “sell” a channel between the service
and the user. With those services, any incoming payment to the user will be
subjected to the routing fees that the service charges. They are bound to the
routing policy of their target service. In addition to that, many users opening
channels with the same service creates a single point of failure.

We wanted to offer the Loop Out service in a way that minimizes the amount of
trust required. It would definitely have been much easier to build a full
custodial service, but we believe there is value for the user in not having
that counterparty risk. And fortunately the bitcoin blockchain offers the tools
to do so.

Mechanism

The basic mechanism that is used in Loop Out is also known as a
submarine swap. There are multiple variations of the submarine swap, but the
process we use consists of the following high level steps:

The user of the service generates a secret hash preimage.

The user sends a payment tied to this hash to the Lightning Loop server. The
server is not yet able to settle this payment because it doesn’t know the
preimage yet. Instead, it holds on to the payment until it discovers the
preimage. This part is implemented using a hodl
invoice.

The server publishes an on-chain transaction to an output that can be spent
by disclosing the secret preimage (a hash locked output).

The user sweeps that output to his wallet. He can only do this by disclosing
the preimage in the spending transaction.

The server picks up the preimage from the spending transaction and uses it
to settle the Lightning payment that it is still holding on to. This last
step completes the swap.

If the server holds onto the Lightning payment and never publishes the on-chain
transaction, the payment will time out and the funds will be returned to the
user. This forms the non-custodial characteristic of the service. There is a
slight penalty though for the user in the time out case, because it will lock
up their funds until the time out.

Prepayment

The Loop server needs to spend money on publishing an HTLC on-chain. In case
the user doesn’t follow through with the swap, we would lose that money. Left
unchecked, this could introduce a DoS vector tying up the spare UTXOs of the
Loop System. To prevent this the server requires a second Lightning payment
called the prepayment to be made along with the swap payment. The idea is that
if the swap doesn’t succeed, but the server did publish the on-chain HTLC, the
server keeps the prepayment as a compensation for the loss in miner fees.

Sweeping Back to the Wallet

The preimage is revealed when the user’s sweep transaction enters the mempool
(step 4 above). From that point onwards, the preimage is to be considered
public knowledge and the user should expect their Lightning payment to be
settled at any time. It is for that reason that the user needs to make sure
that the transaction confirms. One thing that can get in the way of this is
publishing the sweep transaction with a too low miner fee. However, the user
can leverage fee bumping tools such as RBF and CPFP to ensure a timely
confirmation.

The risk of the sweep transaction not confirming is dealt with in Lightning
Loop by publishing with RBF enabled and trying to replace the sweep transaction
in every block with a new transaction that is based on the latest fee estimate.
The transaction fee is capped by the maximum miner fee that the user specified
when the swap was initiated to avoid overpaying on-chain.

Time Pressure

Unfortunately for the user, there is not an endless amount of time to get that
sweep transaction confirmed. The server does not publish the hash locked output
without having a way to reclaim the funds in case the user doesn’t follow
through. There is a second spending path that requires a certain block height
to be reached. At that expiry height the server can reclaim the funds. So the
on-chain swap output is locked by both a hash and a time, which makes it a
hash-time locked contract (HTLC) similar to HTLCs used in regular Lightning
payments.

The actual expiry height of the HTLC is picked by the server when the swap is
initiated and checked against an acceptable minimum by the Loop client
implementation. If the server proposes an expiry height that is too soon, the
off-chain swap payment will not be paid and the swap will be aborted. The
reason for this is that the user needs to have a reasonable opportunity to get
the sweep transaction confirmed.

When the user discloses the preimage by inserting the sweep transaction in the
mempool, the timer starts ticking. The users needs to get that transaction
confirmed before the expiry height is reached and server reclaim path opens up.

This timer ticking complicates the situation around getting the sweep
transaction confirmed. Possibly the user needs to become more aggressive with
fee bumping when getting closer to the expiry height. He might even want to
exceed the maximum set miner fee then, because the alternative may be to lose
the full swap amount.

Fair Server

For the Loop client, our goal has been to implement it in a way that makes no
assumptions about the server behaviour. It should be prepared for an adversary
server that does all it can to steal from the user. An example of this is that
all values received from the server and the parameters of the on-chain HTLC are
checked locally by the client. If anything exceeds acceptable ranges, the swap
is aborted.

Despite those preparations, we did implement a ‘fair’ server. Wherever we could
choose between different behaviours, we chose the behaviour that is most
beneficial for the user. This differs from an adversary server that would seize
any opportunity to maximize profit. Because the swaps are non-custodial, there
are fortunately not many of those opportunities. They mostly arise around
non-happy flows and mistakes on the part of the user.

An illustration of this is cancellation of swap payments. When the server needs
to reclaim funds after the HTLC expiry and the timeout transaction is confirmed
sufficiently, it cancels back the held off-chain payment immediately. It could
hold on to it longer, hoping that for some reason the preimage would still pop
up in the mempool, but doesn’t do so.

Channel Tricks with Loop

Recursive Loop Out

With Loop Out it is possible to use an amount of money X to obtain far greater
inbound liquidity than X. The idea here is to open a channel and loop all funds
out. With the received on-chain funds another channel can be opened and this
channel can be Looped out too. This process can be continued as long as there
are funds left, because of course with every step fees need to be paid to
miners, routing nodes and the Loop service. Some engineers on our team have
taken to calling this method a “LoopDeLoop”.

The end result of this is that routing nodes will have a lot of funds committed
to the user’s node. And hopefully for them, they will earn some routing fees in
exchange for that commitment.

This also underlines the need for routing nodes to monitor their channels and
close the ones that don’t yield any returns.

Loop Out to External Address

The default Loop Out behaviour is to Loop out to a wallet address of the user.
But it is also possible to specify an external address. It allows an on-chain
payment to be made from a node that has all of its funds committed in channels.

Similarly a channel can be Looped out directly to an exchange. This can for
example be valuable for merchants that need to pay out suppliers or employees
via fiat.

Conclusion

The added DoS defense of the pre-payment allows the service to operate in a
manner where we’re compensated for any failed on-chain swaps. The pre-payment
amount is nominal and is at most a few thousands satoshis. Within the API and
on the CLI, the user executing the swap is shown the prepayment amount up front
where they can agree to it.

Aside from that, standard timeout handling with respect to incoming and
outgoing CLTV outputs with HTLCs are required. This is no different from the
level of time lock management required in Lightning. However, with good fee
selection heuristics the impact of this can be brought down to a minimum.

We think the points above are marginal compared to the unique advantages that
Loop Out offers. It gives users the flexibility to obtain inbound liquidity
from anyone. It does not push towards a centralized network topology and
provides a way to re-use existing channels thereby extending their lifetime.

The next step for us is the release of Loop In. With Loop In, any channel can
be topped up with an on-chain payment. There is no more need to close an
otherwise good channel and reopen a new one.