I started out writing this answer while trying to do it myself, but then found out that we don't yet have tools to manually edit partially signed Bitcoin transactions (PSBTs) which is the very last step before we finalize the double-spend. So this answer is currently incomplete, but I'm planning on building out that tooling and write a plugin that automates all of this, so it get much easier 😉


Given that you're asking for c-lightning let me walk you through the options you have:

Wait and rebroadcast

If the fee is not way too low, and the peer hasn't given up yet, you could have a chance of still establishing the channel, by confirming the original funding transaction. It might require you to rebroadcast the transaction from time to time when it drops out of the mempool. To do so take note of the funding transaction that was returned when calling fundchannel or retrieve it from the database by looking its ID up:

CHANID=$(lightning-cli listpeers [peer_id] | jq '.peers[].channel_id') sqlite3 $HOME/.lightning/bitcoin/lightningd.sqlite3 \ "SELECT hex(rawtx) FROM transactions WHERE hex(id) LIKE '$CHANID'"

This will get you the funding tx for that particular peer. You can use bitcoin-cli decoderawtransaction to decode the transactions and verify that the txid matches the funding_txid in the lightning-cli listpeers output.

You can then rebroadcast using the bitcoin-cli sendrawtransaction or lightning-cli sendrawtransaction methods.

I suggest waiting at least over the weekend, since fees drop considerably, increasing chances of the tx confirming anyway.

Double-spending the funding transaction

If you need the funds somewhere else, or decided the channel isn't worth waiting for you can also double-spend any of the inputs and the funding transaction will never be able to confirm.

🚧 Notice that you wont be able to open a new channel with that specific peer until both sides have given up, as from c-lightning's point of view it may still happen and we need to be ready if it does 🚧

To do this look up the funding transaction like above, then use the following to list the inputs of the funding transaction:

bitcoin-cli decoderawtransaction [tx] | jq '.vin[] | [.txid, .vout]'

Next we synchronize the UTXO status with bitcoind, since we marked the outputs spent by the funding transaction as spent (note that you need to have c-lightning compiled with DEVELOPER=1 for this to be available):

lightning-cli dev-rescan-outputs

Now pick a subset of the inputs and create a new transaction, that collides with the funding transaction on purpose to double-spend it:

lightning-cli utxopsbt satoshi=all feerate=normal startweight=756 utxos=["ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB:0"]

This gives you a partially signed Bitcoin transaction (PSBT), which has one input ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB:0 (matching the result from the decoderawtransaction results above) and no output. Notice the startweight is 756sipa, which is approximately the size of a single-input-single-output transaction which we're trying to build.

This isn't a valid transaction yet, so we need to add an output that goes back into your wallet. To do this we first generate an address to send to your wallet:

lightning-cli newaddr

And now we need to amend the PSBT to include an output with all funds (minus the fee) going to that new address.

... but we don't have tools in place yet to manually edit a PSBT, or at least I'm no aware of any. I'll follow up once we have.