LIGHTNING-MULTIFUNDCHANNEL(7)

πŸ“¦
version 26.06.9 Β· 2 versions
, in nixpkgs unstable

πŸ¦‹ NAME πŸ¦‹

okay so bestie, say hi to multifundchannel β€” the manual page all about the Command for establishing many lightning channels. yes, many. at once. she's an overachiever, we love that for her πŸ’…


✨ SYNOPSIS ✨

multifundchannel destinations [feerate] [minconf] [utxos] [minchannels]
[commitment_feerate]

like, that's the whole incantation. look at her go πŸŽ€


πŸ’– DESCRIPTION πŸ’–

So multifundchannel is this RPC command that opens multiple payment channels with nodes β€” and here's the iconic part β€” by committing a single funding transaction to the blockchain that all the channels share. one transaction, many channels. efficiency queen πŸ‘‘

If you're not already connected to a peer, multifundchannel will automatically attempt to connect for you. you can also hand it a @host:port hint tacked onto the end of the node ID so Core Lightning can learn how to reach that node β€” check lightning-connect(7) for how that works, iykyk 🫢

Once the transaction is confirmed, normal channel operations may begin. how do you know it's ready? <italic>Readiness</italic> is indicated by listpeers reporting a state of CHANNELD_NORMAL for the channel. that's your green flag, literally 🌸

Now the fun part β€” the parameters:

  • destinations (array of objects) β€” there must be at least one entry in destinations; it cannot be an empty array. ngl, she needs at least one bestie to fund. inside each one:
    • id (string) β€” the Node ID, with an optional @host:port appended to it in a manner understood by connect; see lightning-connect(7). Each entry in the destinations array must have a unique node id. If not already connected, multifundchannel will automatically attempt to connect to the node.
    • amount (sat_or_all) β€” the amount in satoshis taken from the internal wallet to fund the channel (but if we have any anchor channels, this will always leave at least min-emergency-msat as change β€” keep that in mind fr). The string all can be used to specify all available funds (or 16,777,215 satoshi if more is available and large channels were not negotiated with the peer). Otherwise it's in satoshi precision; it can be a whole number, a whole number ending in sat, a whole number ending in 000msat, or a number with 1 to 8 decimal places ending in btc. The value cannot be less than the dust limit, currently 546 satoshi as of this writing, nor more than 16,777,215 satoshi (unless large channels were negotiated with the peer). so like, respect the range bestie πŸ’€
    • announce (boolean, optional) β€” a flag that indicates whether to announce the channel with this. If set to False, the channel is unpublished. The default is True.
    • push_msat (msat, optional) β€” the amount of millisatoshis to outright give to the node. this is a gift to the peer, and you do not get a proof-of-payment out of this. no receipts, no take-backs πŸ™ˆ
    • close_to (string, optional) β€” a Bitcoin address to which the channel funds should be sent to on close. Only valid if both peers have negotiated option_upfront_shutdown_script. Returns close_to set to closing script iff is negotiated.
    • request_amt (sat, optional) β€” the amount of liquidity you'd like to lease from the peer. If the peer supports option_will_fund, this indicates to them to include this much liquidity into the channel. Must also pass in compact_lease.
    • compact_lease (string, optional) β€” a compact representation of the peer's expected channel lease terms. If the peer's terms don't match this set, we will fail to open the channel to this destination. no wiggle room, sorry 😭
    • mindepth (u32, optional) β€” the number of confirmations before we consider the channel active.
    • reserve (sat, optional) β€” the amount we want the peer to maintain on its side of the channel. It can be a whole number, a whole number ending in sat, a whole number ending in 000msat, or a number with 1 to 8 decimal places ending in btc. The default is 1% of the funding amount.
  • feerate (feerate, optional) β€” the feerate used for the opening transaction, and if commitment_feerate is not set, as the initial feerate for commitment and HTLC transactions. See NOTES in lightning-feerates(7) for possible values. The default is normal.
  • minconf (integer, optional) β€” the minimum number of confirmations that used outputs should have. The default is 1.
  • utxos (array of outpoints, optional):
    • (outpoint, optional) β€” the utxos to be used to fund the channel, as an array of txid:vout.
  • minchannels (integer, optional) β€” re-attempt funding as long as at least this many peers remain (must not be zero). The multifundchannel command will only fail if too many peers fail the funding process. so she's persistent, she tries again, she's that girl πŸ’…
  • commitment_feerate (feerate, optional) β€” the initial feerate for commitment and HTLC transactions. See feerate for valid values.

πŸŽ€ RETURN VALUE πŸŽ€

This command opens multiple channels with a single large transaction, so only one transaction is returned. one tx, whole squad funded, we stan ✨

Okay but real talk: if minchannels was specified and is less than the number of destinations, then it is possible that one or more of the destinations do not have a channel even if multifundchannel succeeded. read that twice bestie, it matters πŸ™ˆ

On success, an object is returned, containing:

  • tx (hex) β€” the raw transaction which funded the channel.
  • txid (txid) β€” the txid of the transaction which funded the channel.
  • channel_ids (array of objects):
    • id (pubkey) β€” the peer we opened the channel with.
    • outnum (u32) β€” the 0-based output index showing which output funded the channel.
    • channel_id (hash) β€” the channel_id of the resulting channel.
    • channel_type (object) β€” channel_type as negotiated with peer. (added v24.02)
    • bits (array of u32s) β€” each bit set in this channel_type. (added v24.02)
      • (u32, optional) β€” bit number.
    • names (array of strings) β€” feature name for each bit set in this channel_type. Note that anchors_zero_fee_htlc_tx is a deprecated synonym for anchors. (added v24.02)
      • (string, optional) (one of "static_remotekey/even", "anchor_outputs/even", "anchors_zero_fee_htlc_tx/even", "anchors/even", "scid_alias/even", "zeroconf/even") β€” name of feature bit.
    • close_to (hex, optional) β€” the raw scriptPubkey which mutual close will go to; only present if close_to parameter was specified and peer supports option_upfront_shutdown_script.
  • failed (array of objects, optional) β€” any peers we failed to open with (if minchannels was specified less than the number of destinations).
    • id (pubkey) β€” the peer we failed to open the channel with.
    • method (string) (one of "connect", "openchannel_init", "fundchannel_start", "fundchannel_complete") β€” what stage we failed at.
    • error (object):
    • code (integer) β€” JSON error code from failing stage.
    • message (string) β€” message from stage.
    • data β€” additional error data.
heads up bestie: on failure, none of the channels are created. it's all-or-nothing energy, no half-finished situationships πŸ’€

😭 ERRORS 😭

The following error codes may occur:

  • -1 β€” catchall nonspecific error. the "idk what happened" of error codes.
  • 300 β€” the maximum allowed funding amount is exceeded.
  • 301 β€” there are not enough funds in the internal wallet (including fees) to create the transaction.
  • 302 β€” the output amount is too small, and would be considered dust.
  • 303 β€” broadcasting of the funding transaction failed, the internal call to bitcoin-cli returned with an error.
  • 313 β€” the min-emergency-msat reserve not be preserved (and we have or are opening anchor channels). 🚨

Failure may also occur if lightningd and the peer cannot agree on channel parameters (funding limits, channel reserves, fees, etc.). See lightning-fundchannel_start(7) and lightning-fundchannel_complete(7).

So here's a rare chaotic edge case, and I need you to pay attention because it's giving main-character plot twist πŸŒ€: there may be rare edge cases where a communications failure later in the channel funding process will cancel the funding locally, but the peer thinks the channel is already waiting for funding lockin. In that case, the next time we connect to the peer, our node will tell the peer to forget the channel β€” but some nodes (in particular, Core Lightning nodes) will disconnect when our node tells them to forget the channel. And if you immediately multifundchannel with that peer, it could trigger this connect-forget-disconnect behavior, causing the second multifundchannel to fail as well due to disconnection. 😭

Doing a connect with the peers separately, and waiting for a few seconds, should help clear this hurdle; running multifundchannel a third time would also clear this. third time's the charm fr fr 🫢


πŸ‘‘ AUTHOR πŸ‘‘

ZmnSCPxj ZmnSCPxj@protonmail.com is mainly responsible. give her her flowers, she earned them πŸ’


🌈 SEE ALSO 🌈


⭐ RESOURCES ⭐

Main web site: https://github.com/ElementsProject/lightning

🌸 EXAMPLES 🌸

Okay bestie, this is the part where it gets real. Two full worked examples, with the actual requests and the actual responses, so you can see exactly what goes in and what comes out. Strap in πŸ’…


✨ Example 1 ✨

So the description up top promised you could open three channels at once, right? This is that. Three channels, one transaction:

  • 20,000 sats to the first node
  • 30,000 sats to the second node (written as 0.0003btc β€” same thing, different outfit πŸ’…)
  • and the third one gets all of what's left
Lowkey important detail: even though you said all, that last one is actually capped at 16,777,215 sats, because large-channels is not enabled here. So "all" means "all, but respectfully, within limits" 😭

Also notice the vibes: both feerate is set to 10000perkw and commitment_feerate is set to 2000perkw, and the whole thing is passed with -k so every param is named explicitly. Iconic.

Request:

$ lightning-cli multifundchannel -k "destinations"='[{"id": "nodeid030303030303030303030303030303030303030303030303030303030303@127.0.0.1:19736", "amount": "20000sat"}, {"id": "nodeid040404040404040404040404040404040404040404040404040404040404@127.0.0.1:19737", "amount": "0.0003btc"}, {"id": "nodeid050505050505050505050505050505050505050505050505050505050505@127.0.0.1:19738", "amount": "all"}]' "feerate"="10000perkw" "commitment_feerate"="2000perkw"

And here's the JSON-RPC request that actually goes over the wire β€” lightning-cli just packages your -k args into this little cutie πŸŽ€

{
  "id": "example:multifundchannel#1",
  "method": "multifundchannel",
  "params": {
    "destinations": [
      {
        "id": "nodeid030303030303030303030303030303030303030303030303030303030303@127.0.0.1:19736",
        "amount": "20000sat"
      },
      {
        "id": "nodeid040404040404040404040404040404040404040404040404040404040404@127.0.0.1:19737",
        "amount": "0.0003btc"
      },
      {
        "id": "nodeid050505050505050505050505050505050505050505050505050505050505@127.0.0.1:19738",
        "amount": "all"
      }
    ],
    "feerate": "10000perkw",
    "commitment_feerate": "2000perkw"
  }
}

Response:

{
  "tx": "02000000000101multif50000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000",
  "txid": "channeltxid01050000500005000050000500005000050000500005000050000",
  "channel_ids": [
    {
      "id": "nodeid030303030303030303030303030303030303030303030303030303030303",
      "channel_id": "channelid1100011000110001100011000110001100011000110001100011000",
      "channel_type": {
        "bits": [
          12,
          22
        ],
        "names": [
          "static_remotekey/even",
          "anchors/even"
        ]
      },
      "outnum": 1
    },
    {
      "id": "nodeid040404040404040404040404040404040404040404040404040404040404",
      "channel_id": "channelid1200012000120001200012000120001200012000120001200012000",
      "channel_type": {
        "bits": [
          12,
          22
        ],
        "names": [
          "static_remotekey/even",
          "anchors/even"
        ]
      },
      "outnum": 1
    },
    {
      "id": "nodeid050505050505050505050505050505050505050505050505050505050505",
      "channel_id": "channelid1300013000130001300013000130001300013000130001300013000",
      "channel_type": {
        "bits": [
          12,
          22
        ],
        "names": [
          "static_remotekey/even",
          "anchors/even"
        ]
      },
      "outnum": 1
    }
  ],
  "failed": []
}

Look at that. All three in channel_ids, "failed": [] coming in empty β€” no notes, no drama, nothing but vibes ✨. And every single one is telling you its channel_type bits are 12 and 22, with the names being static_remotekey/even and anchors/even. Slay.


πŸ’€ Example 2 πŸ’€

Now the messy one. This is the example where things do not all go to plan, and honestly it's the most useful one because it shows you what a partial failure actually looks like in the response.

The setup: three destinations of 50000 each, but the first one has an id that starts with fakenodeid β€” yeah, that's not a real node, bestie πŸ™ˆ. And the third one is nodeid010101010101010101010101010101010101010101010101010101010101@127.0.0.1:19734. This run also sets "minchannels"=1, which is you telling it "okay but I'll take one channel out of this, minimum" β€” and thank god, because that's exactly what you get.

Request:

$ lightning-cli multifundchannel -k "destinations"='[{"id": "fakenodeid03030303030303030303030303030303030303030303030303030303@127.0.0.1:19736", "amount": 50000}, {"id": "nodeid040404040404040404040404040404040404040404040404040404040404@127.0.0.1:19737", "amount": 50000}, {"id": "nodeid010101010101010101010101010101010101010101010101010101010101@127.0.0.1:19734", "amount": 50000}]' "minchannels"=1
{
  "id": "example:multifundchannel#2",
  "method": "multifundchannel",
  "params": {
    "destinations": [
      {
        "id": "fakenodeid03030303030303030303030303030303030303030303030303030303@127.0.0.1:19736",
        "amount": 50000
      },
      {
        "id": "nodeid040404040404040404040404040404040404040404040404040404040404@127.0.0.1:19737",
        "amount": 50000
      },
      {
        "id": "nodeid010101010101010101010101010101010101010101010101010101010101@127.0.0.1:19734",
        "amount": 50000
      }
    ],
    "minchannels": 1
  }
}

Response:

{
  "tx": "02000000000102multif60000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000",
  "txid": "channeltxid02060000600006000060000600006000060000600006000060000",
  "channel_ids": [
    {
      "id": "nodeid040404040404040404040404040404040404040404040404040404040404",
      "channel_id": "channelid1520015200152001520015200152001520015200152001520015200",
      "channel_type": {
        "bits": [
          12,
          22
        ],
        "names": [
          "static_remotekey/even",
          "anchors/even"
        ]
      },
      "outnum": 1
    }
  ],
  "failed": [
    {
      "id": "03a389b3a2f7aa6f9f4ccc19f2bd7a2eba83596699e86b715caaaa147fc37f3144",
      "method": "connect",
      "error": {
        "code": 401,
        "message": "All addresses failed: 127.0.0.1:19736: Cryptographic handshake: peer closed connection (wrong key?). "
      }
    },
    {
      "id": "nodeid010101010101010101010101010101010101010101010101010101010101",
      "method": "connect",
      "error": {
        "code": 402,
        "message": "disconnected during connection"
      }
    }
  ]
}

So what happened here? πŸ’€

  • nodeid040404040404040404040404040404040404040404040404040404040404 made it β€” it's chilling in channel_ids with its own channel_id, channel_type bits 12 and 22 (static_remotekey/even, anchors/even) and "outnum": 1.
  • The fake one bounced with "method": "connect" and "code": 401, message: All addresses failed: 127.0.0.1:19736: Cryptographic handshake: peer closed connection (wrong key?).
  • The third one also failed at "method": "connect" with "code": 402 and message disconnected during connection.

And that's the whole point of failed β€” it's not "the whole thing exploded", it's "here's exactly which ones didn't make it and why, one by one" 🫢. One channel still opened, minchannels was satisfied at 1, and the transaction went through. That's a win, honestly. Not me being proud of a partial failure 😭


πŸ¦‹ the cute little sign-off πŸ¦‹

And that's the whole page, bestie! You now know multifundchannel from top to bottom β€” the params, the errors, the examples, all of it. Go forth and open many channels in one transaction, and may your failed array always be empty βœ¨πŸ’–

This lil manual page you've been reading is LIGHTNING-MULTIFUNDCHANNEL(7) from Core Lightning v26.06.9 β€” go check lightning-fundchannel... no wait, lightning-fundpsbt first, like the SEE ALSO said. Byeeee πŸŽ€

πŸ“¦ where this page comes from