Setting Up Liquidity Ads in c-lightning

Blockstream
Blockstream Engineering Blog
7 min readAug 12, 2021

--

by Lisa Neigut

⚡️

The v0.10.0 version of c-lightning introduced the dual-funding protocol, which allows either channel peer to put funds into the channel funding transaction. This is a great addition to the Lightning protocol, as it cuts down on the number of on-chain transactions required to deploy capital into Lightning contracts.

However, dual-funding introduces a coordination problem. This is because it’s impossible to know if a peer will put funds into a channel with you unless you ask them. You can explicitly signal that your node is setup to automatically dual-fund a channel, like this tweet I put out. But, that requires node operators to agree to use the same centralized communication network.

Solving the Dual-Funding Coordination Problem

Liquidity ads solve the coordination problem by allowing your node to advertise its willingness to contribute funds to a channel open request from a peer directly over the Lightning gossip network. This means that every node on the Lightning Network can broadcast their intention to contribute funds to a channel, as well as see all the nodes that are currently offering up liquidity directly, without any added services or software.

With c-lightning, you can see these advertisements via the node information returned in listnodes .

Here’s the node listing for my node, 02cca6c5966fcf61d121e3a70e03a1cd9eeeea024b2626ea666ce974d43b242e636 , which is currently advertising that it will lease you funds.

$ lightning-cli listnodes 02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636
{
"nodes": [
{
"nodeid": "02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636",
"alias": "the_holy_cheese_grater",
"color": "cc0099",
"last_timestamp": 1628537935,
"features": "80000028226aa2",
"addresses": [
{
"type": "ipv4",
"address": "104.131.77.55",
"port": 6666
},
{
"type": "torv3",
"address": "oen54qzoyk47zs5alrkii5zjblyyubgjbkpx56ida24gk3mm5pabxuqd.onion",
"port": 6767
}
],
"option_will_fund": {
"lease_fee_base_msat": "1000000msat",
"lease_fee_basis": 10,
"funding_weight": 666,
"channel_fee_max_base_msat": "5000000msat",
"channel_fee_max_proportional_thousandths": 100,
"compact_lease": "029a000a0064000003e84c4b40"
}
}
]
}

Note: You can filter for nodes that are just advertising liquidity with the following grep addition:

lightning-cli listnodes | grep -B20 -A7 option_will_fund

Let’s walk through the information that this liquidity ad is displaying, show how to setup your node (running c-lightning v0.10.1 or later) to advertise this information, and finally walk through leasing some liquidity from a peer that’s advertising it.

Dissecting a Liquidity Ad

The node entry for a liquidity ad shows six fields.

"option_will_fund": {
"lease_fee_base_msat": "1000000msat",
"lease_fee_basis": 10,
"funding_weight": 666,
"channel_fee_max_base_msat": "5000000msat",
"channel_fee_max_proportional_thousandths": 100,
"compact_lease": "029a000a0064000003e84c4b40"
}
  • lease_fee_base_msat : This is the base fee that my node will charge for a liquidity lease; in this example it’s set to 1k sats.
  • lease_fee_basis : This is the basis points that my node will charge for a liquidity lease. It’s calculated as “sats you’d like to lease” * “lease_fee_basis” * 1 / 10,000. For example, if you’d like to lease 1M sats, I’m going to charge you 1M * 10 / 10k, or 1k sats. This plus the lease_base_fee_msat is the total amount you’ll be compensated for the funds lease.
  • funding_weight : This is the weight that I’ll expect your node to pay for in the opening transaction. The opener picks the feerate that the funding transaction uses, so the total satoshi charge for this funding_weight will be calculated using the rate the opener chooses. For example, if the opener uses a 50 sat/vbyte rate, then they’ll need to pay my node 666 / 4 * 50, or 8,325 sats, to cover my cost of contributing inputs to the funding transaction. In c-lightning, this value defaults to the expected weight of 2 P2WPKH inputs and a P2WPKH output.
  • channel_fee_max_base_msat + chanel_fee_max_proportional_thousandths : These are promises. Specifically, the leasing node promises not to charge users rates greater than these values when routing payments through the leased channel. In effect, these fields are a cap on the routing fees the leasing node will collect on the leased funds. Note that ‘thousandths’ is quite large — it’s a 1,000 times larger than the typical ‘ppm’ number that fee rates are expressed in. In this example, my node is currently advertising that the max fee_per_millionth it will charge is 100,000. This is really high (10%)! (A value of 1 for the channel_fee_max_proportional_thousandths is equal to 1,000ppm ).
  • compact_lease : This is a compact representation of the above five fields. It’s used for signaling the rates you expect when you call fundchannel to take advantage of a lease, so make note of it.

Given the current settings, a channel lease of 1M sats opened at a feerate of 50 sats/vbyte would cost an opening peer a total of 10,325 sats. (1k sats for the base fee, 1k sats for the basis fee, and 8,325 for the on-chain fees for the funding transaction).

Setting up Your c-lightning Node to Advertise Liquidity

The v0.10.1 release of c-lightning introduces a new plugin, funder . Funder gives you some knobs for setting up a policy for fudning incoming channel requests, as well as a way to set the rates that you want to charge for liquidity. It allos you to both contribute funds to v2 opens without advertising liquidity as well as charging for the liquidity that you provide.

By default, it only hands out liquidity to opens that offer to pay for a lease.

Also, note that you’ll need to enable --experimental-dual-fund to be able to actually fund any advertisement that you offer.

You can see the current settings of funder using the funderupdate command. Here’s what my node is currently set to.

$ lightning-cli funderupdate
{
"summary": "match (100%)",
"policy": "match",
"policy_mod": 100,
"leases_only": true,
"min_their_funding_msat": "50000000msat",
"max_their_funding_msat": "4294967295000msat",
"per_channel_min_msat": "10000000msat",
"per_channel_max_msat": "10000000000msat",
"reserve_tank_msat": "0msat",
"fuzz_percent": 0,
"fund_probability": 100,
"lease_fee_base_msat": "1000000msat",
"lease_fee_basis": 10,
"funding_weight": 666,
"channel_fee_max_base_msat": "5000000msat",
"channel_fee_max_proportional_thousandths": 100,
"compact_lease": "029a000a0064000003e84c4b40"
}

Note that you won’t see the lease parameters until you set at least one of them.

Funder Policy

For funding liquidity offers, you’re most likely going to want to set your policy and the accompanying modifier to match (100%). This will provide as much liquidity as the peer requests, no more no less. You’ll also want to turn off the fuzzing, as c-lightning clients who are requesting liquidity currently fail the open if the node offering the liquidity doesn’t match or exceed the requested funding amount.

Here’s how you’d set these parameters using the funderupdate command.

$ lightning-cli funderupdate -k policy=match policy_mod=100
{
"summary": "match (100%)",
"policy": "match",
"policy_mod": 100,
"leases_only": true,
"min_their_funding_msat": "10000000msat",
"max_their_funding_msat": "4294967295000msat",
"per_channel_min_msat": "10000000msat",
"per_channel_max_msat": "4294967295000msat",
"reserve_tank_msat": "0msat",
"fuzz_percent": 0,
"fund_probability": 100
}

Setting Up Your Liquidity Ad

OK, our policy is set to match (100%). Let’s go ahead and add a liquidity ad that will be broadcast to the network.

I’m going to set the fees for the lease, the rest of the parameters will be the default.

$ lightning-cli funderupdate -k lease_fee_base_msat=500sat lease_fee_basis=50
{
"summary": "match (100%)",
"policy": "match",
"policy_mod": 100,
"leases_only": true,
"min_their_funding_msat": "10000000msat",
"max_their_funding_msat": "4294967295000msat",
"per_channel_min_msat": "10000000msat",
"per_channel_max_msat": "4294967295000msat",
"reserve_tank_msat": "0msat",
"fuzz_percent": 0,
"fund_probability": 100,
"lease_fee_base_msat": "500000msat",
"lease_fee_basis": 50,
"funding_weight": 666,
"channel_fee_max_base_msat": "5000000msat",
"channel_fee_max_proportional_thousandths": 100,
"compact_lease": "029a00320064000001f44c4b40"
}

Those channel_fee parameters look a bit high to me (5000sats base, 100,000ppm), so I’ll adjust them downwards to 100sat base and 2000ppm.

$ lightning-cli funderupdate -k channel_fee_max_base_msat=100sat channel_fee_max_proportional_thousandths=2
{
"summary": "match (100%)",
"policy": "match",
"policy_mod": 100,
"leases_only": true,
"min_their_funding_msat": "10000000msat",
"max_their_funding_msat": "4294967295000msat",
"per_channel_min_msat": "10000000msat",
"per_channel_max_msat": "4294967295000msat",
"reserve_tank_msat": "0msat",
"fuzz_percent": 0,
"fund_probability": 100,
"lease_fee_base_msat": "500000msat",
"lease_fee_basis": 50,
"funding_weight": 666,
"channel_fee_max_base_msat": "100000msat",
"channel_fee_max_proportional_thousandths": 2,
"compact_lease": "029a00320002000001f40186a0"
}

If you want to check what you’re currently advertising, run listnodes <your_node_id>. It might take a few minutes for any recent changes to be reflected here, as we rate limit how frequently node_announcements can be updated. (Since I updated it twice in a row, it took a moment for the second set of changes to appear.)

Configs

To make these settings persist across a restart, you’ll need to set them in your lightning configs. You can do this by adding the following lines to your config file.

experimental-dual-fund
funder-policy=match
funder-policy-mod=100
lease-fee-base-msat=500sat
lease-fee-basis=50
channel-fee-max-base-msat=100sat
channel-fee-max-proportional-thousandths=2

Leasing Funds

Now that you’ve got a channel lease set up, it’s a matter of waiting for a peer to take you up on the offer. You might check that your on-chain funds balance is large enough to accept any incoming requests, with listfunds. The funds in outputs will be what’s used to fund the requests.

Let’s try being the other side of the trade now, and request to lease funds from a node that’s advertising liquidity.

Here’s how you’d request a 1M sat channel from my node on mainnet. Note that we’re also putting in 1M sats, which means this channel will be balanced to start (provided the open happens without issue).

$ lightning-cli fundchannel -k id=02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636 amount=0.01btc request_amt=0.01btc compact_lease=029a000a0002000003e80186a0

Note that you’ll need to connect to my node before you can open a channel, which you can accomplish with the following:

$ lightning-cli connect 02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636@104.131.77.55:6666

And that should be it!

A few caveats. If the lease terms have changed, the open should fail. You’ll need to get the latest compact_lease from listnodes before trying again. If the peer doesn’t have enough capital available, or if your request doesn’t pass the parameters they’ve set for peers (see the other options available on funderupdate), then your open request will fail.

Please note that as with all `experimental` features, leases are to be considered a #reckless.

Want to learn more?

If you’d like to take a look at the draft spec proposal, it can be found on Github. Be sure to check out the c-lightning Github repo if you’re interested in contributing! You can also chat with us on Libera IRC in #c-lightning and in the c-lightning Telegram group.

--

--

Blockstream
Blockstream Engineering Blog

Blockstream is the global leader in Bitcoin & blockchain technology, making financial markets more efficient by reducing reliance on trust.