### Install Dependencies and Serve Locally Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/README.md Use these commands to install project dependencies and start a local development server. Ensure Node.js is installed. ```bash npm install ``` ```bash npm start ``` -------------------------------- ### Swift KeysManager and SignerProvider Setup Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/key_management.md Sets up a Swift KeysManager and its associated SignerProvider, integrating with a BitcoinDevKit Wallet. This snippet shows the initialization and the start of the `spend_spendable_outputs` method. ```swift class MyKeysManager { let inner: KeysManager let wallet: BitcoinDevKit.Wallet let signerProvider: MySignerProvider init(seed: [UInt8], startingTimeSecs: UInt64, startingTimeNanos: UInt32, wallet: BitcoinDevKit.Wallet) { self.inner = KeysManager(seed: seed, startingTimeSecs: startingTimeSecs, startingTimeNanos: startingTimeNanos) self.wallet = wallet signerProvider = MySignerProvider() signerProvider.myKeysManager = self } // We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be // spendable by the BDK wallet) and forward any other descriptors to // `KeysManager::spend_spendable_outputs`. // ``` -------------------------------- ### Basic LDK Node Setup and Usage in Rust Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/_blog/announcing-ldk-node.md Demonstrates how to initialize, configure, start, and use the LDK Node for basic Lightning operations like opening channels and sending payments. Requires setting network, Esplora server, and gossip source. Ensure the funding address is funded before opening a channel. ```rust use ldk_node::{Builder, NetAddress}; use ldk_node::lightning_invoice::Invoice; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::bitcoin::Network; use std::str::FromStr; fn main() { let mut builder = Builder::new(); builder.set_network(Network::Testnet); builder.set_esplora_server("https://blockstream.info/testnet/api".to_string()); builder.set_gossip_source_rgs("https://rapidsync.lightningdevkit.org/testnet/snapshot".to_string()); let node = builder.build().unwrap(); node.start().unwrap(); let funding_address = node.new_onchain_address(); // .. fund address .. let node_id = PublicKey::from_str("NODE_ID").unwrap(); let node_addr = NetAddress::from_str("IP_ADDR:PORT").unwrap(); node.connect_open_channel(node_id, node_addr, 10000, None, false).unwrap(); let event = node.wait_next_event(); println!("EVENT: {:?}", event); node.event_handled(); let invoice = Invoice::from_str("INVOICE_STR").unwrap(); node.send_payment(&invoice).unwrap(); node.stop().unwrap(); } ``` -------------------------------- ### Get Inbound Liquidity via JIT Channel with ldk-node Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/_blog/unleashing-liquidity-on-the-lightning-network-with-lightning-liquidity.md This example demonstrates how to configure and use ldk-node to source inbound liquidity using the LSPS2 protocol. It shows how to set up the LSP connection details and request an invoice for a payment via a JIT channel. ```rust use ldk_node::Builder; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::bitcoin::Network; use std::str::FromStr; fn main() { let lsp_node_id = PublicKey::from_str("LSP_NODE_ID").unwrap(); let lsp_node_addr = SocketAddress::from_str("LSP_IP_ADDR:LSP_PORT").unwrap(); let lsp_token = Some("LSP_TOKEN".to_string()); let mut builder = Builder::new(); // tell ldk-node we want to source liquidity using LSPS2 builder.set_liquidity_source_lsps2(lsp_node_addr, lsp_node_id, lsp_token) let node = builder.build().unwrap(); node.start().unwrap(); // how much I want to receive let invoice_amount_msat = 500_000_000; // the maximum I’m willing to pay in fees for the channel from the LSP let max_total_fee_limit_msat = 5_000_000; // the invoice I receive will be valid for this many seconds let invoice_expiry_seconds = 3600; // get an invoice I can have paid without needing to set up any channels let invoice = node.receive_payment_via_jit_channel(invoice_amount_msat, "invoice description", invoice_expiry_seconds, Some(max_total_fee_limit_msat)).unwrap(); } ``` -------------------------------- ### Main Function for Fee Estimator Demo Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/fee_estimation.md This `main` function demonstrates how to initialize and use the `MyAppFeeEstimator`. It updates the fees from the API and then prints example fee rates for different confirmation targets. ```rust #[tokio::main] async fn main() { let mut fee_estimator = MyAppFeeEstimator::new(); if let Err(e) = fee_estimator.update_fees().await { eprintln!("Failed to update fees: {}", e); } // Example of calling 'get_est_sat_per_1000_weight' with a specific confirmation target let high_fee_target = ConfirmationTarget::UrgentOnChainSweep; let low_fee_target = ConfirmationTarget::MinAllowedAnchorChannelRemoteFee; println!("Feerate for {:?}: {:?}", high_fee_target, fee_estimator.get_est_sat_per_1000_weight(high_fee_target)); } ``` -------------------------------- ### Create a Public Channel (Kotlin) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/opening-a-channel.md Opens a new public Lightning channel using Kotlin. This example demonstrates setting up `UserConfig` and `ChannelHandshakeConfig` to ensure the channel is announced. It requires the peer's public key, funding amount, push msats, and a unique user channel ID. ```kotlin val amount = 100_000L val pushMsat = 1_000L val userChannelId = UInt128(Random.nextLong()) // public aka announced channel val userConfig = UserConfig.with_default() val channelHandshakeConfig = ChannelHandshakeConfig.with_default() channelHandshakeConfig._announced_channel = true userConfig._channel_handshake_config = channelHandshakeConfig val createChannelResult = channelManager.create_channel( pubKey.toByteArray(), amount, pushMsat, userChannelId, userConfig ) ``` -------------------------------- ### Install Latest Rust Toolchain Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/running-a-sample-ldk-node.md Ensures the latest stable Rust toolchain is installed using rustup. This is a prerequisite for building and running Rust projects. ```bash rustup default stable ``` -------------------------------- ### Create MyAppFeeEstimator Instance (Rust) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/fee_estimation.md Initializes a new MyAppFeeEstimator by populating its fee_rate_cache with default feerates for various ConfirmationTarget values. This ensures the application can start without waiting for network operations. ```rust pub fn new() -> Self { let mut fee_rate_cache = HashMap::new(); use ConfirmationTarget::*; for target in &[ MinAllowedAnchorChannelRemoteFee, MinAllowedNonAnchorChannelRemoteFee, ChannelCloseMinimum, AnchorChannelFee, NonAnchorChannelFee, UrgentOnChainSweep, OutputSpendingFee, MaximumFeeEstimate, ] { let default_fee = Self::default_fee_from_conf_target(*target); fee_rate_cache.insert(*target, default_fee); } MyAppFeeEstimator { fee_rate_cache } } ``` -------------------------------- ### Initialize ChannelManager in Swift Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Provides Swift code for initializing the ChannelManager, handling both scenarios: restarting from serialized data and a fresh initialization. Correct parameters are crucial for successful setup. ```swift if serializedChannelManager != nil && !serializedChannelManager!.isEmpty { do { let channelManagerConstructor = try ChannelManagerConstructor( channelManagerSerialized: serializedChannelManager!, channelMonitorsSerialized: serializedChannelMonitors, networkGraph: NetworkGraphArgument.instance(netGraph), filter: filter, params: channelManagerConstructionParameters ) } catch { let channelManagerConstructor = ChannelManagerConstructor( network: network, currentBlockchainTipHash: latestBlockHash!, currentBlockchainTipHeight: latestBlockHeight!, netGraph: netGraph, params: channelManagerConstructionParameters ) } } else { let channelManagerConstructor = ChannelManagerConstructor( network: network, currentBlockchainTipHash: latestBlockHash!, currentBlockchainTipHeight: latestBlockHeight!, netGraph: netGraph, params: channelManagerConstructionParameters ) } ``` -------------------------------- ### Initialize ChannelManager in Kotlin Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Shows how to initialize the ChannelManager in Kotlin, differentiating between loading from serialized data (restarting) and a fresh start. Ensure all required parameters are provided. ```kotlin if (serializedChannelManager != null && serializedChannelManager.isNotEmpty()) { // Loading from disk (restarting) val channelManagerConstructor = ChannelManagerConstructor( serializedChannelManager, serializedChannelMonitors, userConfig, keysManager!!.inner.as_EntropySource(), keysManager!!.inner.as_NodeSigner(), SignerProvider.new_impl(keysManager!!.signerProvider), feeEstimator, chainMonitor, txFilter, networkGraph!!.write(), ProbabilisticScoringDecayParameters.with_default(), ProbabilisticScoringFeeParameters.with_default(), scorer!!.write(), null, txBroadcaster, logger ) } else { // Fresh start val channelManagerConstructor = ChannelManagerConstructor( Network.LDKNetwork_Regtest, userConfig, latestBlockHash.toByteArray(), latestBlockHeight, keysManager!!.inner.as_EntropySource(), keysManager!!.inner.as_NodeSigner(), SignerProvider.new_impl(keysManager!!.signerProvider), feeEstimator, chainMonitor, networkGraph, ProbabilisticScoringDecayParameters.with_default(), ProbabilisticScoringFeeParameters.with_default(), null, txBroadcaster, logger ) } ``` -------------------------------- ### Initialize KeysManager in Swift Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initializes the KeysManager in Swift using a byte array for the seed and current system time for starting seconds and nanoseconds. ```swift let seed: [UInt8] = // secure random bytes or reload from disk let timestampSeconds = UInt64(NSDate().timeIntervalSince1970) let timestampNanos = UInt32(truncating: NSNumber(value: timestampSeconds * 1000 * 1000)) let keysManager = KeysManager(seed: seed, startingTimeSecs: timestampSeconds, startingTimeNanos: timestampNanos) ``` -------------------------------- ### Initialize KeysManager in Kotlin Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initializes the KeysManager in Kotlin using a provided byte array for the seed and current system time for starting seconds and nanoseconds. ```kotlin val keySeed = ByteArray(32) // fill with secure random bytes or reload from disk val keysManager = KeysManager.of( keySeed, System.currentTimeMillis() / 1000, (System.currentTimeMillis() * 1000).toInt() ) ``` -------------------------------- ### Create Invoice and Register Pending Payment (Kotlin) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/receiving-payments.md Creates a BOLT 11 invoice and encodes it to a string. This example uses a hardcoded description and amount for demonstration. ```kotlin val description = "description" val amtMsat: Long = 3000000 val invoice = UtilMethods.create_invoice_from_channelmanager( channelManager, keysManager.inner.as_NodeSigner(), logger, Currency.LDKCurrency_Regtest, Option_u64Z.some(amtMsat), description, 300, Option_u16Z.some(144) ) val invoiceResult = (invoice as Result_Bolt11InvoiceSignOrCreationErrorZ.Result_Bolt11InvoiceSignOrCreationErrorZ_OK).res val encodedInvoice = invoiceResult.to_str() ``` -------------------------------- ### Spending Spendable Outputs to Wallet in Kotlin Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/closing-a-channel.md This Kotlin example demonstrates how to handle the SpendableOutputs event by spending the outputs directly to a new address in a BDK-based wallet. It includes error handling for the spending process. ```kotlin // Example where we spend straight to our BDK based wallet if (event is Event.SpendableOutputs) { val outputs = event.outputs try { val address = OnchainWallet.getNewAddress() val script = Address(address).scriptPubkey().toBytes().toUByteArray().toByteArray() val txOut: Array = arrayOf() val res = keysManager?.spend_spendable_outputs( outputs, txOut, script, 1000, Option_u32Z.None.none() ) if (res != null) { if (res.is_ok) { val tx = (res as Result_TransactionNoneZ.Result_TransactionNoneZ_OK).res val txs: Array = arrayOf() txs.plus(tx) LDKBroadcaster.broadcast_transactions(txs) } } } catch (e: Exception) { Log.i(LDKTAG, "Error: ${e.message}") } } ``` -------------------------------- ### Spending Spendable Outputs to Wallet in Swift Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/closing-a-channel.md This Swift example shows how to handle the SpendableOutputs event by spending the outputs directly to a new address in a BDK-based wallet. It retrieves a new address, constructs the script, and broadcasts the resulting transaction. ```swift // Example where we spend straight to our BDK based wallet func handleEvent(event: Event) { if let event = event.getValueAsSpendableOutputs() { let outputs = event.getOutputs() do { let address = ldkManager!.bdkManager.getAddress(addressIndex: .new)! let network = ldkManager!.network == .Testnet ? BitcoinDevKit.Network.testnet : BitcoinDevKit.Network.regtest let script = try Address(address: address, network: network).scriptPubkey().toBytes() let res = ldkManager!.myKeysManager.spendSpendableOutputs( descriptors: outputs, outputs: [], changeDestinationScript: script, feerateSatPer1000Weight: 1000, locktime: nil) if res.isOk() { var txs: [[UInt8]] = [] txs.append(res.getValue()!) ldkManager!.broadcaster.broadcastTransactions(txs: txs) } } catch { print(error.localizedDescription) } } } ``` -------------------------------- ### LDK Sample Node Command Reference Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/running-a-sample-ldk-node.md Provides a general template for running the LDK sample node with custom bitcoind RPC credentials and network parameters. Use this when not using Polar or for different configurations. ```bash cargo run :@: [] [] [] [] ``` -------------------------------- ### Initialize Default KeysManager Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/key_management.md Constructs the default KeysManager with a 32-byte seed and unique starting time values. Ensure the seed is securely generated or reloaded on restart. The starting time values must be unique across restarts. ```rust // Fill in random_32_bytes with secure random data, or, on restart, reload the seed from disk. let mut random_32_bytes = [0; 32]; let start_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); let keys_interface_impl = lightning::sign::KeysManager::new(&random_32_bytes, start_time.as_secs(), start_time.subsec_nanos()); ``` ```kotlin // Fill in key_seed with secure random data, or, on restart, reload the seed from disk. val key_seed = ByteArray(32) val keys_manager = KeysManager.of( key_seed, System.currentTimeMillis() / 1000, (System.currentTimeMillis() * 1000).toInt() ) ``` ```swift // Fill in seed with secure random data, or, on restart, reload the seed from disk. let seed = [UInt8](repeating: 0, count: 32) let timestampSeconds = UInt64(NSDate().timeIntervalSince1970) let timestampNanos = UInt32(truncating: NSNumber(value: timestampSeconds * 1000 * 1000)) self.myKeysManager = KeysManager( seed: seed, startingTimeSecs: timestampSeconds, startingTimeNanos: timestampNanos ) ``` -------------------------------- ### Open a Channel with Configuration (Rust) Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initiate a new channel with a peer using `ChannelManager::create_channel`. Configure channel handshake settings like announcement and other parameters. ```rust use lightning::ln::channelmanager::UserConfig; use lightning::util::config::{ChannelConfig, ChannelHandshakeConfig}; let config = UserConfig { channel_handshake_config: ChannelHandshakeConfig { announced_channel: true, // public channel ..Default::default() }, ..Default::default() }; // Initiate channel open (amount in satoshis, push in millisatoshis) match channel_manager.create_channel(peer_pubkey, 100_000, 1_000, 42u128, None, Some(config)) { Ok(_) => println!("Channel initiated with peer {}", peer_pubkey), Err(e) => eprintln!("Failed to open channel: {:?}", e), } // Handle the FundingGenerationReady event (in your event handler) Event::FundingGenerationReady { temporary_channel_id, counterparty_node_id, channel_value_satoshis, output_script, .. } => { // Build a SegWit funding transaction using BDK or your wallet let raw_tx = build_funding_tx(output_script, channel_value_satoshis); channel_manager.funding_transaction_generated( &temporary_channel_id, &counterparty_node_id, raw_tx, ).unwrap(); } ``` -------------------------------- ### Get Estimated Fee Rate Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/fee_estimation.md Retrieves the estimated sat/1000 weight for a given fee target. Ensure the fee estimator is initialized. ```rust println!("Feerate for {:?}: {:?}", low_fee_target, fee_estimator.get_est_sat_per_1000_weight(low_fee_target)); ``` -------------------------------- ### Broadcast Transactions with EsploraBroadcaster Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Implement the BroadcasterInterface to publish on-chain transactions. This example uses Esplora for broadcasting and logs the transaction hex. ```rust use lightning::chain::chaininterface::BroadcasterInterface; use bitcoin::Transaction; struct EsploraBroadcaster { server_url: String } impl BroadcasterInterface for EsploraBroadcaster { fn broadcast_transactions(&self, txs: &[&Transaction]) { for tx in txs { // POST tx to Esplora /tx endpoint let raw = bitcoin::consensus::serialize(tx); let hex_tx = hex::encode(&raw); // e.g.: reqwest::blocking::Client::new() // .post(&format!("{}/tx", self.server_url)) // .body(hex_tx).send().unwrap(); println!("Broadcasting tx: {}", hex_tx); } } } let broadcaster = Arc::new(EsploraBroadcaster { server_url: "https://blockstream.info/api".into() }); ``` -------------------------------- ### Clone and Navigate LDK Sample Directory Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/running-a-sample-ldk-node.md Clones the LDK sample node repository from GitHub and changes the current directory to the cloned repository. This is the first step to running the sample node. ```bash git clone https://github.com/lightningdevkit/ldk-sample cd ldk-sample ``` -------------------------------- ### Initialize ChannelManager in Rust Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Demonstrates initializing the ChannelManager in Rust, covering both loading from disk (restarting) and creating a fresh instance. Ensure all dependencies are correctly provided. ```rust let user_config = UserConfig::default(); /* RESTARTING */ let (channel_manager_blockhash, mut channel_manager) = { let channel_manager_file = fs::File::open(format!("{}/manager", ldk_data_dir.clone())).unwrap(); // Use the `ChannelMonitors` we read from disk. let mut channel_monitor_mut_references = Vec::new(); for (_, channel_monitor) in channel_monitors.iter_mut() { channel_monitor_mut_references.push(channel_monitor); } let read_args = ChannelManagerReadArgs::new( &keys_manager, &fee_estimator, &chain_monitor, &broadcaster, &logger, user_config, channel_monitor_mut_references, ); <(BlockHash, ChannelManager)>::read(&mut channel_manager_file, read_args).unwrap() }; /* FRESH CHANNELMANAGER */ let (channel_manager_blockhash, mut channel_manager) = { let best_blockhash = // insert the best blockhash you know of let best_chain_height = // insert the height corresponding to best_blockhash let chain_params = ChainParameters { network: Network::Testnet, // substitute this with your network best_block: BestBlock::new(best_blockhash, best_chain_height), }; let fresh_channel_manager = ChannelManager::new( &fee_estimator, &chain_monitor, &broadcaster, &router, &logger, &entropy_source, &node_signer, &signer_provider, user_config, chain_params, current_timestamp ); (best_blockhash, fresh_channel_manager) }; ``` -------------------------------- ### MySignerProvider: Get Destination Script Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/key_management.md Implement `getDestinationScript` to return the destination script derived by the BDK wallet. This is crucial for on-chain fund management. ```swift // We return the destination and shutdown scripts derived by the BDK wallet. override func getDestinationScript() -> Bindings.Result_ScriptNoneZ { do { let address = try myKeysManager!.wallet.getAddress(addressIndex: .new) return Bindings.Result_ScriptNoneZ.initWithOk(o: address.address.scriptPubkey().toBytes()) } catch { return .initWithErr() } } ``` -------------------------------- ### Use LDK Sample Filesystem Persistence Crate (Rust) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Utilize the `FilesystemPersister` from the `lightning-persister` crate for a convenient way to handle `ChannelMonitor` persistence to the filesystem. Initialize it with the path to your LDK data directory. ```Rust use lightning_persister::FilesystemPersister; // import LDK sample persist crate let persister = FilesystemPersister::new(ldk_data_dir_path); ``` -------------------------------- ### Set up Inbound Peer Connections (Rust) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/connect-to-peers.md Configures a TCP listener to accept incoming peer connections using `lightning_net_tokio`. Ensure `peer_manager` is initialized before use. ```rust use lightning_net_tokio; // use LDK's sample networking module let listen_port = 9735; let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", listen_port)) .await.unwrap() loop { let tcp_stream = listener.accept().await.unwrap().0; tokio::spawn(async move { // Use LDK's supplied networking battery to facilitate inbound // connections. lightning_net_tokio::setup_inbound( &peer_manager, tcp_stream.into_std().unwrap(), ) .await; }); } ``` -------------------------------- ### Connect to Peers Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Use `lightning-net-tokio` (Rust) or `NioPeerHandler` (Kotlin) to accept inbound connections and initiate outbound ones. ```APIDOC ## Connect to Peers — Inbound and Outbound Connections Use `lightning-net-tokio` (Rust) or `NioPeerHandler` (Kotlin) to accept inbound connections and initiate outbound ones. ### Rust Example ```rust use lightning_net_tokio; // Accept inbound connections on port 9735 let listener = tokio::net::TcpListener::bind("0.0.0.0:9735").await.unwrap(); loop { let tcp_stream = listener.accept().await.unwrap().0; let peer_mgr = Arc::clone(&peer_manager); tokio::spawn(async move { lightning_net_tokio::setup_inbound(&peer_mgr, tcp_stream.into_std().unwrap()).await; }); } // Connect outbound to a peer match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, address).await { Some(conn_closed_future) => { let mut fut = Box::pin(conn_closed_future); loop { if futures::poll!(&mut fut).is_ready() { panic!("Peer disconnected before handshake completed"); } if peer_manager.get_peer_node_ids().iter().any(|id| *id == pubkey) { break; // Handshake complete } tokio::time::sleep(std::time::Duration::from_millis(10)).await; } } None => panic!("Failed to connect to peer"), } ``` ### Kotlin Example ```kotlin val nioPeerHandler = channelManagerConstructor.nio_peer_handler nioPeerHandler.bind_listener(InetSocketAddress("0.0.0.0", 9735)) // Outbound connection nioPeerHandler.connect(pubkeyHex.toByteArray(), InetSocketAddress(hostname, port), 5000) ``` ``` -------------------------------- ### Get Default Fee from Confirmation Target (Rust) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/fee_estimation.md Provides a hard-coded feerate for a given ConfirmationTarget. Feerates are presented as sats/vByte * 250 for readability, but stored as sats/KW. ```rust pub fn default_fee_from_conf_target(confirmation_target: ConfirmationTarget) -> u32 { match confirmation_target { ConfirmationTarget::MaximumFeeEstimate => 75 * 250, ConfirmationTarget::MinAllowedAnchorChannelRemoteFee => 10 * 250, ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => 10 * 250, ConfirmationTarget::ChannelCloseMinimum => 20 * 250, ConfirmationTarget::AnchorChannelFee => 20 * 250, ConfirmationTarget::NonAnchorChannelFee => 30 * 250, ConfirmationTarget::UrgentOnChainSweep => 50 * 250, ConfirmationTarget::OutputSpendingFee => 10 * 250, } } ``` -------------------------------- ### Initialize P2PGossipSync in Rust Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Initializes P2PGossipSync using a pre-existing network graph read from disk. Requires a logger and optionally chain access. ```rust let genesis = genesis_block(Network::Testnet).header.block_hash(); let network_graph_path = format!("{}/network_graph", ldk_data_dir.clone()); let network_graph = Arc::new(disk::read_network(Path::new(&network_graph_path), genesis, logger.clone())); let gossip_sync = Arc::new(P2PGossipSync::new( Arc::clone(&network_graph), None::>, logger.clone(), )); ``` -------------------------------- ### MySignerProvider: Get Shutdown Scriptpubkey Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/key_management.md Implement `getShutdownScriptpubkey` to provide the shutdown script. This method handles different witness versions and ensures correct script construction. ```swift override func getShutdownScriptpubkey() -> Bindings.Result_ShutdownScriptNoneZ { do { let address = try myKeysManager!.wallet.getAddress(addressIndex: .new).address let payload = address.payload() if case let .witnessProgram(`version`, `program`) = payload { let ver: UInt8 switch version { case .v0: ver = 0 case .v1: ver = 1 case .v2: ver = 2 case .v3: ver = 3 case .v4: ver = 4 case .v5: ver = 5 case .v6: ver = 6 case .v7: ver = 7 case .v8: ver = 8 case .v9: ver = 9 case .v10: ver = 10 case .v11: ver = 11 case .v12: ver = 12 case .v13: ver = 13 case .v14: ver = 14 case .v15: ver = 15 case .v16: ver = 16 } let res = ShutdownScript.newWitnessProgram(version: ver, program: program) if res.isOk() { return Bindings.Result_ShutdownScriptNoneZ.initWithOk(o: res.getValue()!) } } return .initWithErr() } catch { return .initWithErr() } } ``` -------------------------------- ### Broadcast Transaction with BDK (Kotlin) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/opening-a-channel.md Implement the `BroadcasterInterface` in Kotlin using BDK to broadcast transactions via an Esplora client. This example uses CoroutineScope for asynchronous broadcasting. ```java // Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client object YourTxBroadcaster : BroadcasterInterface.BroadcasterInterfaceInterface { override fun broadcast_transactions(txs: Array??) { val esploraURL = "esplora url" val blockchainConfig = BlockchainConfig.Esplora(EsploraConfig(esploraURL, null, 5u, 20u, null)) val blockchain = Blockchain(blockchainConfig) txs?.let { transactions -> CoroutineScope(Dispatchers.IO).launch { transactions.forEach { txByteArray -> val uByteArray = txByteArray.toUByteArray() val transaction = Transaction(uByteArray.toList()) blockchain.broadcast(transaction) Log.i(LDKTAG, "The raw transaction broadcast is: ${txByteArray.toHex()}") } } } ?: throw(IllegalStateException("Broadcaster attempted to broadcast a null transaction")) } } ``` -------------------------------- ### Initialize Probabilistic Scorer (Rust) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Initializes the network graph and scorer from disk in Rust. Ensure the LDK data directory and logger are properly configured. ```rust let network_graph_path = format!("{}/network_graph", ldk_data_dir.clone()); let network_graph = Arc::new(disk::read_network(Path::new(&network_graph_path), args.network, logger.clone())); let scorer_path = format!("{}/scorer", ldk_data_dir.clone()); let scorer = Arc::new(RwLock::new(disk::read_scorer( Path::new(&scorer_path), Arc::clone(&network_graph), Arc::clone(&logger), ))); ``` -------------------------------- ### YAML Frontmatter for SEO Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/README.md Add SEO metadata like description and tags to a page using YAML frontmatter. This example shows how to configure meta attributes for a page. ```text --- description: How to integrate LDK tags: - WooCommerce - WordPress - Plugin - eCommerce --- # LDK integration This document explains how to **integrate LDK into your stack**. ``` -------------------------------- ### Initialize KeysManager with a Persisted Seed Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initialize the KeysManager with a 32-byte seed, persisting it to disk on first start and reloading it on subsequent restarts. Uses current system time for uniqueness. ```rust use lightning::sign::KeysManager; use std::time::SystemTime; use std::fs; // On first start: generate and persist a random 32-byte seed let keys_seed_path = format!("{}/keys_seed", ldk_data_dir); let keys_seed: [u8; 32] = if let Ok(seed) = fs::read(&keys_seed_path) { let mut key = [0u8; 32]; key.copy_from_slice(&seed); key } else { let mut key = [0u8; 32]; rand::thread_rng().fill_bytes(&mut key); fs::write(&keys_seed_path, &key).expect("Failed to persist seed"); key }; let cur = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); let keys_manager = Arc::new(KeysManager::new(&keys_seed, cur.as_secs(), cur.subsec_nanos())); ``` -------------------------------- ### Create and Configure Rust Project Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/fee_estimation.md Use cargo to create a new Rust project and then add the required LDK and other dependencies to your Cargo.toml file. ```bash $ cargo new ldk-fee-estimator $ cd ldk-fee-estimator ``` ```toml [package] name = "ldk-fee-estimator" version = "0.1.0" edition = "2024" [dependencies] lightning = { version = "0.0.124", features = ["max_level_trace"] } lightning-block-sync = { version = "0.0.124", features = [ "rpc-client" ] } lightning-invoice = { version = "0.31.0" } lightning-net-tokio = { version = "0.0.124" } lightning-persister = { version = "0.0.124" } lightning-background-processor = { version = "0.0.124" } lightning-rapid-gossip-sync = { version = "0.0.124" } reqwest = { version = "0.11", features = ["json", "blocking"] } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1", features = ["full"]} # Async runtime, required for reqwest ``` -------------------------------- ### Implement LDK Logging with FilesystemLogger Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Implement the Logger trait to route structured log records to your application's logging backend. This example shows writing logs to stdout. ```rust use lightning::util::logger::{Logger, Record}; use time::OffsetDateTime; struct FilesystemLogger { data_dir: String } impl Logger for FilesystemLogger { fn log(&self, record: &Record) { let log = format!( "{} {:<5} [{}:{}] \n", OffsetDateTime::now_utc().format("%F %T"), record.level.to_string(), record.module_path, record.line, record.args ); // Write `log` to a file at self.data_dir, or print to stdout print!("{}", log); } } let logger = Arc::new(FilesystemLogger { data_dir: "/path/to/ldk_data".to_string() }); ``` -------------------------------- ### Accept Inbound and Connect Outbound Peers (Rust) Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Use `lightning-net-tokio` to accept incoming TCP connections and initiate outbound connections to peers. Ensure proper handling of connection futures and peer manager state. ```rust use lightning_net_tokio; // Accept inbound connections on port 9735 let listener = tokio::net::TcpListener::bind("0.0.0.0:9735").await.unwrap(); loop { let tcp_stream = listener.accept().await.unwrap().0; let peer_mgr = Arc::clone(&peer_manager); tokio::spawn(async move { lightning_net_tokio::setup_inbound(&peer_mgr, tcp_stream.into_std().unwrap()).await; }); } // Connect outbound to a peer match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, address).await { Some(conn_closed_future) => { let mut fut = Box::pin(conn_closed_future); loop { if futures::poll!(&mut fut).is_ready() { panic!("Peer disconnected before handshake completed"); } if peer_manager.get_peer_node_ids().iter().any(|id| *id == pubkey) { break; // Handshake complete } tokio::time::sleep(std::time::Duration::from_millis(10)).await; } } None => panic!("Failed to connect to peer"), } ``` -------------------------------- ### Initialize ProbabilisticScorer for Route Selection Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initialize ProbabilisticScorer to estimate channel liquidity and historical payment success rates for optimal route selection. It can be loaded from disk or created fresh. ```rust use lightning::routing::scoring::{ ProbabilisticScorer, ProbabilisticScoringDecayParameters, ProbabilisticScoringFeeParameters, }; use std::sync::RwLock; // Load from disk or create fresh let scorer_path = format!("{}/scorer", ldk_data_dir); let scorer = Arc::new(RwLock::new( if let Ok(file) = std::fs::File::open(&scorer_path) { let args = (ProbabilisticScoringDecayParameters::default(), Arc::clone(&network_graph), logger.clone()); ProbabilisticScorer::read(&mut std::io::BufReader::new(file), args) .unwrap_or_else(|_| ProbabilisticScorer::new( ProbabilisticScoringDecayParameters::default(), Arc::clone(&network_graph), logger.clone() )) } else { ProbabilisticScorer::new( ProbabilisticScoringDecayParameters::default(), Arc::clone(&network_graph), logger.clone() ) } )); // Scorer is updated automatically by BackgroundProcessor on PaymentPathSuccessful/PaymentPathFailed events ``` -------------------------------- ### Broadcast Transaction with BDK (Swift) Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/opening-a-channel.md Implement the `BroadcasterInterface` in Swift using BDK to broadcast transactions via an Esplora client. This example demonstrates error handling for the broadcast operation. ```swift // Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client import BitcoinDevKit class MyBroacaster: BroadcasterInterface { override func broadcastTransactions(txs: [[UInt8]]) { let esploraURL = "esploraUrl" let esploraConfig = EsploraConfig(baseUrl: esploraURL, proxy: nil, concurrency: 5, stopGap: 20, timeout: nil) let blockchainConfig = BlockchainConfig.esplora(config: esploraConfig) do { let blockchain = try Blockchain(config: blockchainConfig) for tx in txs { let transaction = try Transaction(transactionBytes: tx) try blockchain.broadcast(transaction: transaction) } } catch { print("Failed to broadcast transaction: \(error.localizedDescription)") } } } ``` -------------------------------- ### Instantiate ChannelManager in Swift Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Sets up ChannelManagerConstructionParameters and then instantiates the ChannelManagerConstructor in Swift. This involves providing network parameters, blockchain tip information, and various LDK components. ```swift import LightningDevKit let channelManagerConstructionParameters = ChannelManagerConstructionParameters( config: userConfig, entropySource: keysManager.asEntropySource(), nodeSigner: keysManager.asNodeSigner(), signerProvider: keysManager.asSignerProvider(), feeEstimator: feeEstimator, chainMonitor: chainMonitor, txBroadcaster: broadcaster, logger: logger, enableP2PGossip: true, scorer: scorer ) let channelManagerConstructor = ChannelManagerConstructor( network: network, currentBlockchainTipHash: latestBlockHash, currentBlockchainTipHeight: latestBlockHeight, netGraph: netGraph, params: channelManagerConstructionParameters ) ``` -------------------------------- ### Initialize NetworkGraph with RapidGossipSync Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initialize a NetworkGraph and populate it using Rapid Gossip Sync (RGS). This is efficient for bandwidth-constrained environments like mobile devices. ```rust use lightning_rapid_gossip_sync::RapidGossipSync; use bitcoin::network::constants::Network; // Rapid Gossip Sync (mobile / bandwidth-constrained) let rgs = RapidGossipSync::new(Arc::clone(&network_graph), logger.clone()); let last_sync_timestamp: u32 = network_graph.get_last_rapid_gossip_sync_timestamp().unwrap_or(0); let snapshot_url = format!("https://rapidsync.lightningdevkit.org/snapshot/{}", last_sync_timestamp); // Fetch snapshot bytes, then: let result = rgs.update_network_graph_no_std(&snapshot_bytes, Some(current_time_unix)); if result.is_ok() { println!("Network graph updated via RGS"); } ``` -------------------------------- ### Persisting Spendable Outputs in Rust Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/closing-a-channel.md In Rust, the SpendableOutputs event provides a vector of SpendableOutputDescriptor. These descriptors must be persisted as LDK will not regenerate them. This example shows persisting them to disk for later spending. ```rust Event::SpendableOutputs { outputs, channel_id: _ } => { // SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track // of! While a `StaticOutput` descriptor is just an output to a static, well-known key, // other descriptors are not currently ever regenerated for you by LDK. Once we return // from this method, the descriptor will be gone, and you may lose track of some funds. // // Here we simply persist them to disk, with a background task running which will try // to spend them regularly (possibly duplicatively/RBF'ing them). These can just be // treated as normal funds where possible - they are only spendable by us and there is // no rush to claim them. for output in outputs { let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes()); // Note that if the type here changes our read code needs to change as well. let output: SpendableOutputDescriptor = output; fs_store.write(PENDING_SPENDABLE_OUTPUT_DIR, "", &key, &output.encode()).unwrap(); } } ``` -------------------------------- ### Initialize ChannelManager for Channel State Management Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt ChannelManager is central to LDK, managing channel state, payments, and component coordination. Provide chain parameters for a fresh start or deserialize from disk on restart. ```rust use lightning::ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, ChainParameters, UserConfig}; use lightning::chain::BestBlock; use bitcoin::network::constants::Network; let user_config = UserConfig::default(); // Fresh start let chain_params = ChainParameters { network: Network::Testnet, best_block: BestBlock::new(best_blockhash, best_chain_height), }; let channel_manager = Arc::new(ChannelManager::new( &fee_estimator, &chain_monitor, &broadcaster, &router, &logger, &entropy_source, // from keys_manager.as_entropy_source() &node_signer, // from keys_manager.as_node_signer() &signer_provider, // from keys_manager.as_signer_provider() user_config, chain_params, current_timestamp, )); ``` ```rust use std::fs; use lightning::chain::BlockHash; // Restart from disk let channel_manager_file = fs::File::open(format!("{}/manager", ldk_data_dir)).unwrap(); let read_args = ChannelManagerReadArgs::new( &keys_manager, &fee_estimator, &chain_monitor, &broadcaster, &logger, user_config, channel_monitors, // loaded from persister.read_channelmonitors() ); let (_, channel_manager) = <(BlockHash, ChannelManager)>::read(&mut channel_manager_file, read_args).unwrap(); ``` -------------------------------- ### Initialize ProbabilisticScorer Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/probing.md Initializes the Logger, Network Graph, and Scorer. Assumes Logger and ChannelManager are already set up. Reads the scorer from disk if available, otherwise creates a new one. ```rust // Initialize the Logger. let logger = Arc::new(FilesystemLogger::new(ldk_data_dir.clone())); // Initialize the Network Graph. let network_graph_path = format!("{}/network_graph", ldk_data_dir.clone()); let network_graph = Arc::new(disk::read_network(Path::new(&network_graph_path), args.network, logger.clone())); // Initialize the Scorer. let scorer_path = format!("{}/scorer", ldk_data_dir.clone()); let scorer = Arc::new(RwLock::new(disk::read_scorer( Path::new(&scorer_path), Arc::clone(&network_graph), Arc::clone(&logger), ))); ``` -------------------------------- ### Start Background Processing for LDK Source: https://github.com/lightningdevkit/lightningdevkit.org/blob/main/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md Initiate the `BackgroundProcessor` to manage periodic background tasks essential for LDK's operation. This requires instances of `Persist`, `InvoicePayer`, `ChainMonitor`, `ChannelManager`, `NetGraphMsgHandler`, `PeerManager`, and `Logger`. ```Rust let background_processor = BackgroundProcessor::start( persister, Arc::clone(&invoice_payer), Arc::clone(&chain_monitor), Arc::clone(&channel_manager), Arc::clone(&net_graph_msg_handler), Arc::clone(&peer_manager), Arc::clone(&logger), ); ``` -------------------------------- ### Initialize NetworkGraph with P2PGossipSync Source: https://context7.com/lightningdevkit/lightningdevkit.org/llms.txt Initialize a NetworkGraph and populate it using P2P gossip synchronization. This is suitable for always-online nodes that can maintain a full peer-to-peer connection. ```rust use lightning::routing::gossip::{NetworkGraph, P2PGossipSync}; use bitcoin::network::constants::Network; // P2P gossip (full node / always-online) let genesis = genesis_block(Network::Testnet).header.block_hash(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, logger.clone())); let gossip_sync = Arc::new(P2PGossipSync::new( Arc::clone(&network_graph), None::>, logger.clone(), )); ```