# Opening a Channel

Channels are the basic building blocks of the Lightning Network. With channels, you can transact not only with your immediate peers but with others on the network. Let's explore how to open a channel with LDK.

Now that you have a peer, you can open a channel with them using ChannelManager. You'll need the peer's pubkey as before along with:

  • the amount in sats to use when funding the channel,
  • any msats to push to your peer,
  • an id which is given back in the FundingGenerationReady event,
  • an optional UserConfig for overriding ChannelManager defaults

Channels can be announced to the network or can remain private, which is controlled via UserConfig::announced_channel.

  • Rust
  • Kotlin
  • Swift
let amount = 10_000;
let push_msat = 1_000;
let user_id = 42;
let config = UserConfig {
  channel_options: ChannelConfig { announced_channel: true, ..Default::default() },
  ..Default::default()
};
match channel_manager.create_channel(pubkey, amount, push_msat, user_id, Some(config)) {
  Ok(_) => println!("EVENT: initiated channel with peer {}", pubkey),
  Err(e) => panic!("ERROR: failed to open channel: {:?}", e),
}

# FundingGenerationReady Event Handling

At this point, an outbound channel has been initiated with your peer and it will appear in ChannelManager::list_channels. However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a FundingGenerationReady event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.

Note

Remember that the funding transaction must only spend SegWit (opens new window) inputs.

  • Rust
  • Kotlin
  • Swift
// After the peer responds with an `accept_channel` message, an
// Event.FundingGenerationReady event will be generated.
match event {
	Event::FundingGenerationReady {
		temporary_channel_id,
		channel_value_satoshis,
		output_script,
		user_channel_id,
	} => {
	   // Generate the funding transaction for the channel based on the channel amount
      // The following uses BDK (Bitcoin Dev Kit) for on-chain logic
		let (psbt, _) = {
		let mut builder = wallet.build_tx();
			builder
				.add_recipient(output_script, channel_value_satoshis)
				.fee_rate(fee_rate)
				.enable_rbf()
			builder.finish()?
	  	};
		let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
		let raw_tx = finalized.extract_tx()

	}
	// ...
}

References: Rust FundingGenerationReady docs (opens new window), Java FundingGenerationReady bindings (opens new window)

# Broadcasting the Funding Transaction

After crafting the funding transaction you'll need to send it to the Bitcoin network where it will hopefully be mined and added to the blockchain. You'll need to watch this transaction and wait for a minimum of 6 confirmations before the channel is ready to use.

  • Rust
  • Kotlin
  • Swift
// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client
impl BroadcasterInterface for YourTxBroadcaster {
	fn broadcast_transactions(&self, txs: &[&Transaction]) {
		let server_url = DEFAULT_ESPLORA_SERVER_URL.to_string();
		let tx_sync = Arc::new(EsploraSyncClient::new(server_url, Arc::clone(&logger)));
		let blockchain = EsploraBlockchain::from_client(tx_sync.client().clone(), BDK_CLIENT_STOP_GAP)
						.with_concurrency(BDK_CLIENT_CONCURRENCY);
		(blockchain, tx_sync)

		let res = tokio::task::block_in_place(move || {
			locked_runtime
				.as_ref()
				.unwrap()
				.block_on(async move { blockchain.broadcast(tx).await })
		});

		match res {
			Ok(_) => {}
			Err(err) => {
				log_error!(self.logger, "Failed to broadcast transaction: {}", err);
			}
		}
	}
}

References: Rust BroadcasterInterface docs (opens new window), Java/Kotlin BroadcasterInterface bindings (opens new window)

Keep LDK in sync

Remember if you are restarting and have open channels then you should let LDK know about the latest channel state.

Last Updated: 11/18/2024, 6:18:24 PM