@@ -67,6 +67,129 @@ val createChannelResult = channelManager.create_channel(
67
67
</template >
68
68
</CodeSwitcher >
69
69
70
+ # FundingGenerationReady Event Handling
71
+
72
+ 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.
73
+
74
+
75
+ <CodeSwitcher :languages =" {rust:'Rust', java:'Java', kotlin:'Kotlin'} " >
76
+ <template v-slot:rust >
77
+
78
+ ``` rust
79
+ // In the event handler passed to BackgroundProcessor::start
80
+ match event {
81
+ Event :: FundingGenerationReady {
82
+ temporary_channel_id ,
83
+ channel_value_satoshis ,
84
+ output_script ,
85
+ user_channel_id ,
86
+ } => {
87
+ // This is the same channel created earler.
88
+ assert_eq! (event . user_channel_id, 42 );
89
+
90
+ // Construct the raw transaction with one output, that is paid the amount of the
91
+ // channel.
92
+ let network = bitcoin_bech32 :: constants :: Network :: Testnet ;
93
+ let address = WitnessProgram :: from_scriptpubkey (& output_script [.. ], network )
94
+ . unwrap (). to_address;
95
+ let mut outputs = vec! [HashMap :: with_capacity (1 )];
96
+ outputs [0 ]. insert (address , channel_value_satoshis as f64 / 100_000_000.0 );
97
+ let raw_tx = bitcoind_client . create_raw_transaction (outputs ). await ;
98
+
99
+ // Have your wallet put the inputs into the transaction such that the output is
100
+ // satisfied.
101
+ let funded_tx = bitcoind_client . fund_raw_transaction (raw_tx ). await ;
102
+ assert! (funded_tx . changepos == 0 || funded_tx . changepos == 1 );
103
+
104
+ // Sign the funding transaction and give it to ChannelManager to broadcast.
105
+ let signed_tx = bitcoind_client . sign_raw_transaction_with_wallet (funded_tx . hex). await ;
106
+ assert_eq! (signed_tx . complete, true );
107
+ let final_tx : Transaction =
108
+ encode :: deserialize (& hex_utils :: to_vec (& signed_tx . hex). unwrap ()). unwrap ();
109
+ channel_manager . funding_transaction_generated (& temporary_channel_id , final_tx ). unwrap ();
110
+ }
111
+ // ...
112
+ }
113
+ ```
114
+
115
+ </template >
116
+
117
+ <template v-slot:java >
118
+
119
+ ``` java
120
+ // After the peer responds with an `accept_channel` message, an
121
+ // Event.FundingGenerationReady event will be generated.
122
+
123
+ // In the `handle_event` method of ChannelManagerPersister implementation
124
+ if (e instanceof Event . FundingGenerationReady ) {
125
+ Event . FundingGenerationReady event = (Event . FundingGenerationReady ) e;
126
+ byte [] funding_scriptpubkey = event. output_script;
127
+ long output_value = event. channel_value_satoshis;
128
+
129
+ // This is the same channel created earler
130
+ assert event. user_channel_id == 42 ;
131
+
132
+ // The output is always a P2WSH:
133
+ assert funding_scriptpubkey. length == 34 && funding_scriptpubkey[0 ] == 0 &&
134
+ funding_scriptpubkey[1 ] == 32 ;
135
+
136
+ // Generate the funding transaction for the channel based on the channel amount
137
+ // The following uses the bitcoinj library to do so, but you can use any
138
+ // standard Bitcoin library for on-chain logic.
139
+ NetworkParameters bitcoinj_net =
140
+ NetworkParameters . fromID(NetworkParameters . ID_MAINNET );
141
+ Transaction funding_tx = new Transaction (bitcoinj_net);
142
+ funding_tx. addInput(new TransactionInput (bitcoinj_net, funding, new byte [0 ]));
143
+ // Note that all inputs in the funding transaction MUST spend SegWit outputs
144
+ // (and have witnesses)
145
+ funding_tx. getInputs(). get(0 ). setWitness(new TransactionWitness (2 ));
146
+ funding_tx. getInput(0 ). getWitness(). setPush(0 , new byte []{0x1 });
147
+ funding_tx. addOutput(Coin . SATOSHI. multiply(output_value),
148
+ new Script (funding_scriptpubkey));
149
+
150
+ // Give the funding transaction back to the ChannelManager.
151
+ Result_NoneAPIErrorZ funding_res = channel_manager. funding_transaction_generated(
152
+ event. temporary_channel_id, funding_tx. bitcoinSerialize());
153
+ // funding_transaction_generated should only generate an error if the
154
+ // transaction didn't meet the required format (or the counterparty already
155
+ // closed the channel on us):
156
+ assert funding_res instanceof Result_NoneAPIErrorZ . Result_NoneAPIErrorZ_OK ;
157
+ }
158
+ ```
159
+
160
+ </template >
161
+
162
+ <template v-slot:kotlin >
163
+
164
+ ``` kotlin
165
+ // After the peer responds with an `accept_channel` message, an
166
+ // Event.FundingGenerationReady event will be generated.
167
+
168
+ if (event is Event .FundingGenerationReady ) {
169
+ val funding_spk = event.output_script
170
+
171
+ if (funding_spk.size == 34 && funding_spk[0 ].toInt() == 0 && funding_spk[1 ].toInt() == 32 ) {
172
+ // Generate the funding transaction for the channel based on the channel amount
173
+ // The following uses BDK for on-chain logic
174
+ val rawTx = OnchainWallet .buildFundingTx(event.channel_value_satoshis, event.output_script)
175
+
176
+ channelManager.funding_transaction_generated(
177
+ event.temporary_channel_id,
178
+ event.counterparty_node_id,
179
+ rawTx
180
+ )
181
+ }
182
+ }
183
+ ```
184
+
185
+ </template >
186
+
187
+
188
+
189
+
190
+ </CodeSwitcher >
191
+
192
+
70
193
71
194
72
195
0 commit comments