@@ -68,9 +68,9 @@ userConfig.setChannelHandshakeConfig(val: channelConfig)
6868
6969let createChannelResults = channelManager.createChannel (
7070 theirNetworkKey : pubKey,
71- channelValueSatoshis : amount,
72- pushMsat : pushMsat,
73- userChannelId : userId,
71+ channelValueSatoshis : amount,
72+ pushMsat : pushMsat,
73+ userChannelId : userId,
7474 overrideConfig : userConfig
7575)
7676```
@@ -81,49 +81,40 @@ let createChannelResults = channelManager.createChannel(
8181
8282# FundingGenerationReady Event Handling
8383
84- 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.
84+ 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.
8585
8686::: tip Note
8787
88- Remember that the funding transaction must only spend SegWit inputs.
88+ Remember that the funding transaction must only spend [ SegWit] ( https://bitcoinops.org/en/topics/segregated-witness/ ) inputs.
8989
9090:::
9191
9292<CodeSwitcher :languages =" {rust:'Rust', kotlin:'Kotlin', swift:'Swift'} " >
9393<template v-slot:rust >
9494
9595``` rust
96- // In the event handler passed to BackgroundProcessor::start
96+ // After the peer responds with an `accept_channel` message, an
97+ // Event.FundingGenerationReady event will be generated.
9798match event {
9899 Event :: FundingGenerationReady {
99100 temporary_channel_id ,
100101 channel_value_satoshis ,
101102 output_script ,
102103 user_channel_id ,
103104 } => {
104- // This is the same channel created earler.
105- assert_eq! (event . user_channel_id, 42 );
106-
107- // Construct the raw transaction with one output, that is paid the amount of the
108- // channel.
109- let network = bitcoin_bech32 :: constants :: Network :: Testnet ;
110- let address = WitnessProgram :: from_scriptpubkey (& output_script [.. ], network )
111- . unwrap (). to_address;
112- let mut outputs = vec! [HashMap :: with_capacity (1 )];
113- outputs [0 ]. insert (address , channel_value_satoshis as f64 / 100_000_000.0 );
114- let raw_tx = bitcoind_client . create_raw_transaction (outputs ). await ;
115-
116- // Have your wallet put the inputs into the transaction such that the output is
117- // satisfied.
118- let funded_tx = bitcoind_client . fund_raw_transaction (raw_tx ). await ;
119- assert! (funded_tx . changepos == 0 || funded_tx . changepos == 1 );
120-
121- // Sign the funding transaction and give it to ChannelManager to broadcast.
122- let signed_tx = bitcoind_client . sign_raw_transaction_with_wallet (funded_tx . hex). await ;
123- assert_eq! (signed_tx . complete, true );
124- let final_tx : Transaction =
125- encode :: deserialize (& hex_utils :: to_vec (& signed_tx . hex). unwrap ()). unwrap ();
126- channel_manager . funding_transaction_generated (& temporary_channel_id , final_tx ). unwrap ();
105+ // Generate the funding transaction for the channel based on the channel amount
106+ // The following uses BDK (Bitcoin Dev Kit) for on-chain logic
107+ let (psbt , _ ) = {
108+ let mut builder = wallet . build_tx ();
109+ builder
110+ . add_recipient (output_script , channel_value_satoshis )
111+ . fee_rate (fee_rate )
112+ . enable_rbf ()
113+ builder . finish ()?
114+ };
115+ let finalized = wallet . sign (& mut psbt , SignOptions :: default ())? ;
116+ let raw_tx = finalized . extract_tx ()
117+
127118 }
128119 // ...
129120}
@@ -136,13 +127,10 @@ match event {
136127``` java
137128// After the peer responds with an `accept_channel` message, an
138129// Event.FundingGenerationReady event will be generated.
139-
140130if (event is Event . FundingGenerationReady ) {
141- val funding_spk = event. output_script
131+ val fundingSpk = event. output_script
142132
143- if (funding_spk. size == 34 && funding_spk[0 ]. toInt() == 0 && funding_spk[1 ]. toInt() == 32 ) {
144- // Generate the funding transaction for the channel based on the channel amount
145- // The following uses BDK (Bitcoin Dev Kit) for on-chain logic
133+ if (fundingSpk. size == 34 && fundingSpk[0 ]. toInt() == 0 && fundingSpk[1 ]. toInt() == 32 ) {
146134 val rawTx = buildFundingTx(event. channel_value_satoshis, event. output_script)
147135
148136 channelManager. funding_transaction_generated(
@@ -153,6 +141,8 @@ if (event is Event.FundingGenerationReady) {
153141 }
154142 }
155143
144+ // Generate the funding transaction for the channel based on the channel amount
145+ // The following uses BDK (Bitcoin Dev Kit) for on-chain logic
156146fun buildFundingTx(value: Long , script: ByteArray ): Transaction {
157147 val scriptListUByte: List<UByte > = script. toUByteArray(). asList()
158148 val outputScript = Script(scriptListUByte)
@@ -173,21 +163,21 @@ fun buildFundingTx(value: Long, script: ByteArray): Transaction {
173163``` Swift
174164// After the peer responds with an `accept_channel` message, an
175165// Event.FundingGenerationReady event will be generated.
176-
177166if let event = event.getValueAsFundingGenerationReady () {
178167 let script = Script (rawOutputScript : event.getOutputScript ())
179168 let channelValue = event.getChannelValueSatoshis ()
180169 let rawTx = buildFundingTx (script : script, amount : channelValue)
181170 if let rawTx = rawTx {
182171 channelManager.fundingTransactionGenerated (
183- temporaryChannelId : event.getTemporaryChannelId (),
184- counterpartyNodeId : event.getCounterpartyNodeId (),
172+ temporaryChannelId : event.getTemporaryChannelId (),
173+ counterpartyNodeId : event.getCounterpartyNodeId (),
185174 fundingTransaction : rawTx.serialize ()
186175 )
187176 }
188177}
189178
190- // Building transaction using BDK
179+ // Generate the funding transaction for the channel based on the channel amount
180+ // The following uses BDK (Bitcoin Dev Kit) for on-chain logic
191181func buildFundingTx (script : Script, amount : UInt64 ) -> Transaction? {
192182 do {
193183 let transaction = try TxBuilder ().addRecipient (
@@ -208,6 +198,7 @@ func buildFundingTx(script: Script, amount: UInt64) -> Transaction? {
208198</CodeSwitcher >
209199
210200** References:** [ Rust ` FundingGenerationReady ` docs] ( https://docs.rs/lightning/*/lightning/util/events/enum.Event.html#variant.FundingGenerationReady ) , [ Java ` FundingGenerationReady ` bindings] ( https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L95 )
201+
211202# Broadcasting the Funding Transaction
212203
213204After 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.
@@ -218,18 +209,18 @@ After crafting the funding transaction you'll need to send it to the Bitcoin net
218209``` rust
219210// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client
220211impl BroadcasterInterface for YourTxBroadcaster {
221- fn broadcast_transaction (& self , tx : & Transaction ) {
222- let locked_runtime = self . tokio_runtime . read () . unwrap ();
223- if locked_runtime . as_ref () . is_none () {
224- log_error! ( self . logger, " Failed to broadcast transaction: No runtime. " );
225- return ;
226- }
212+ fn broadcast_transactions (& self , txs : & [ & Transaction ] ) {
213+ let server_url = DEFAULT_ESPLORA_SERVER_URL . to_string ();
214+ let tx_sync = Arc :: new ( EsploraSyncClient :: new ( server_url , Arc :: clone ( & logger )));
215+ let blockchain = EsploraBlockchain :: from_client ( tx_sync . client () . clone (), BDK_CLIENT_STOP_GAP )
216+ . with_concurrency ( BDK_CLIENT_CONCURRENCY ) ;
217+ ( blockchain , tx_sync )
227218
228219 let res = tokio :: task :: block_in_place (move || {
229220 locked_runtime
230221 . as_ref ()
231222 . unwrap ()
232- . block_on (async move { self . blockchain. broadcast (tx ). await })
223+ . block_on (async move { blockchain . broadcast (tx ). await })
233224 });
234225
235226 match res {
@@ -251,20 +242,22 @@ impl BroadcasterInterface for YourTxBroadcaster {
251242
252243// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client
253244object YourTxBroadcaster : BroadcasterInterface . BroadcasterInterfaceInterface {
254- override fun broadcast_transaction(tx : ByteArray ? ) {
255- val esploraURL = " esploraUrl "
245+ override fun broadcast_transactions(txs : Array<out ByteArray > ? ? ) {
246+ val esploraURL = " esplora url "
256247 val blockchainConfig = BlockchainConfig . Esplora(EsploraConfig(esploraURL, null , 5u, 20u, null ))
257- val blockchain = Blockchain(blockchainConfig)
248+ val blockchain = Blockchain(blockchainConfig)
258249
259- val uByteArray = UByteArray(tx. size) { tx[it]. toUByte() }
260- val transaction = Transaction(uByteArray. toList())
250+ txs? . let { transactions - >
251+ CoroutineScope(Dispatchers . IO ). launch {
252+ transactions. forEach { txByteArray - >
253+ val uByteArray = txByteArray. toUByteArray()
254+ val transaction = Transaction(uByteArray. toList())
261255
262- tx ? . let {
263- CoroutineScope( Dispatchers . IO ) . launch {
264- blockchain . broadcast(transaction)
265- }
256+ blockchain . broadcast(transaction)
257+ Log . i( LDKTAG , " The raw transaction broadcast is: ${txByteArray.toHex()} " )
258+ }
259+ }
266260 } ?: throw (IllegalStateException(" Broadcaster attempted to broadcast a null transaction" ))
267-
268261 }
269262}
270263
0 commit comments