1
1
# Closing a Channel
2
2
3
- Close Channel .
3
+ Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs will be accepted on the given channel, and after additional timeout/the closing of all pending HTLCs, the channel will be closed on chain .
4
4
5
- <CodeSwitcher :languages =" {rust:'Rust', java:'Java ', swift:'Swift'} " >
5
+ <CodeSwitcher :languages =" {rust:'Rust', kotlin:'Kotlin ', swift:'Swift'} " >
6
6
<template v-slot:rust >
7
7
8
8
``` rust
9
- // TODO: Add Rust Code Here
9
+ let channel_id = channel_manager
10
+ . list_channels ()
11
+ . iter ()
12
+ . find (| channel | channel . user_id == user_id )
13
+ . expect (" ERROR: Channel not found" )
14
+ . channel_id;
15
+
16
+ // Example: Cooperative close
17
+ channel_manager . close_channel (& channel_id ). expect (" ERROR: Failed to close channel" );
18
+
19
+ // Example: Unilateral close
20
+ channel_manager . force_close_channel (& channel_id ). expect (" ERROR: Failed to close channel" );
10
21
```
11
-
12
22
</template >
13
- <template v-slot:java >
23
+ <template v-slot:kotlin >
24
+
25
+ ``` kotlin
26
+ val res = channelManager!! .close_channel(channelId, pubKey)
27
+
28
+ if (res is Result_NoneAPIErrorZ .Result_NoneAPIErrorZ_Err ) {
29
+ // Handle error
30
+ }
14
31
15
- ``` java
16
- // TODO: Add Java Code Here
32
+ if (res.is_ok) {
33
+ // Handle successful close
34
+ }
17
35
```
18
36
19
37
</template >
@@ -32,182 +50,78 @@ if res!.isOk() {
32
50
</CodeSwitcher >
33
51
34
52
35
- Claim Funds directly into the BDK wallet using Custom KeysManager.
53
+ To claim Funds directly into a custom wallet like BDK wallet using a custom ` KeysManager ` see the [ Key Management] ( /key_management.md ) guide for more info.
54
+
55
+ # SpendableOutputs Event Handling
36
56
37
- <CodeSwitcher :languages =" {rust:'Rust', java:'Java ', swift:'Swift'} " >
57
+ <CodeSwitcher :languages =" {rust:'Rust', kotlin:'Kotlin ', swift:'Swift'} " >
38
58
<template v-slot:rust >
39
59
40
60
``` rust
41
- // TODO: Add Rust Code Here
42
- ```
43
-
44
- </template >
45
- <template v-slot:java >
61
+ Event :: SpendableOutputs { outputs , channel_id : _ } => {
62
+ // SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track
63
+ // of! While a `StaticOutput` descriptor is just an output to a static, well-known key,
64
+ // other descriptors are not currently ever regenerated for you by LDK. Once we return
65
+ // from this method, the descriptor will be gone, and you may lose track of some funds.
66
+ //
67
+ // Here we simply persist them to disk, with a background task running which will try
68
+ // to spend them regularly (possibly duplicatively/RBF'ing them). These can just be
69
+ // treated as normal funds where possible - they are only spendable by us and there is
70
+ // no rush to claim them.
71
+ for output in outputs {
72
+ let key = hex_utils :: hex_str (& keys_manager . get_secure_random_bytes ());
73
+ // Note that if the type here changes our read code needs to change as well.
74
+ let output : SpendableOutputDescriptor = output ;
75
+ fs_store . write (PENDING_SPENDABLE_OUTPUT_DIR , "" , & key , & output . encode ()). unwrap ();
76
+ }
77
+ }
46
78
47
- ``` java
48
- // TODO: Add Java Code Here
49
79
```
50
80
51
81
</template >
52
- <template v-slot:swift >
82
+ <template v-slot:kotlin >
83
+
84
+ ``` kotlin
85
+ // Example where we spend straight to our BDK based wallet
86
+ if (event is Event .SpendableOutputs ) {
87
+ val outputs = event.outputs
88
+ try {
89
+ val address = OnchainWallet .getNewAddress()
90
+ val script = Address (address).scriptPubkey().toBytes().toUByteArray().toByteArray()
91
+ val txOut: Array <TxOut > = arrayOf()
92
+ val res = keysManager?.spend_spendable_outputs(
93
+ outputs,
94
+ txOut,
95
+ script,
96
+ 1000 ,
97
+ Option_u32Z .None .none()
98
+ )
53
99
54
- ``` Swift
55
- import Foundation
56
- import LightningDevKit
57
- import BitcoinDevKit
58
-
59
- class MyKeysManager {
60
- let inner: KeysManager
61
- let wallet: BitcoinDevKit.Wallet
62
- let signerProvider: MySignerProvider
63
-
64
- init (seed : [UInt8 ], startingTimeSecs : UInt64 , startingTimeNanos : UInt32 , wallet : BitcoinDevKit.Wallet) {
65
- self .inner = KeysManager (seed : seed, startingTimeSecs : startingTimeSecs, startingTimeNanos : startingTimeNanos)
66
- self .wallet = wallet
67
- signerProvider = MySignerProvider ()
68
- signerProvider.myKeysManager = self
69
- }
100
+ if (res != null ) {
101
+ if (res.is_ok) {
102
+ val tx = (res as Result_TransactionNoneZ .Result_TransactionNoneZ_OK ).res
103
+ val txs: Array <ByteArray > = arrayOf()
104
+ txs.plus(tx)
70
105
71
- // We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be
72
- // spendable by the BDK wallet) and forward any other descriptors to
73
- // `KeysManager::spend_spendable_outputs`.
74
- //
75
- // Note you should set `locktime` to the current block height to mitigate fee sniping.
76
- // See https://bitcoinops.org/en/topics/fee-sniping/ for more information.
77
- func spendSpendableOutputs (descriptors : [SpendableOutputDescriptor], outputs : [Bindings.TxOut],
78
- changeDestinationScript : [UInt8 ], feerateSatPer1000Weight : UInt32 ,
79
- locktime : UInt32 ? ) -> Result_TransactionNoneZ {
80
- let onlyNonStatic: [SpendableOutputDescriptor] = descriptors.filter { desc in
81
- if desc.getValueType () == .StaticOutput {
82
- return false
106
+ LDKBroadcaster .broadcast_transactions(txs)
83
107
}
84
- return true
85
108
}
86
- let res = self .inner .spendSpendableOutputs (
87
- descriptors : onlyNonStatic,
88
- outputs : outputs,
89
- changeDestinationScript : changeDestinationScript,
90
- feerateSatPer1000Weight : feerateSatPer1000Weight,
91
- locktime : locktime
92
- )
93
- return res
94
- }
95
- }
96
109
97
- class MySignerProvider : SignerProvider {
98
- weak var myKeysManager: MyKeysManager?
99
-
100
- // We return the destination and shutdown scripts derived by the BDK wallet.
101
- override func getDestinationScript () -> Bindings.Result_ScriptNoneZ {
102
- do {
103
- let address = try myKeysManager! .wallet .getAddress (addressIndex : .new )
104
- return Bindings.Result_ScriptNoneZ .initWithOk (o : address.address .scriptPubkey ().toBytes ())
105
- } catch {
106
- return .initWithErr ()
107
- }
108
- }
109
-
110
- override func getShutdownScriptpubkey () -> Bindings.Result_ShutdownScriptNoneZ {
111
- do {
112
- let address = try myKeysManager! .wallet .getAddress (addressIndex : .new ).address
113
- let payload = address.payload ()
114
- if case let .witnessProgram (`version`, `program`) = payload {
115
- let ver: UInt8
116
- switch version {
117
- case .v0 :
118
- ver = 0
119
- case .v1 :
120
- ver = 1
121
- case .v2 :
122
- ver = 2
123
- case .v3 :
124
- ver = 3
125
- case .v4 :
126
- ver = 4
127
- case .v5 :
128
- ver = 5
129
- case .v6 :
130
- ver = 6
131
- case .v7 :
132
- ver = 7
133
- case .v8 :
134
- ver = 8
135
- case .v9 :
136
- ver = 9
137
- case .v10 :
138
- ver = 10
139
- case .v11 :
140
- ver = 11
141
- case .v12 :
142
- ver = 12
143
- case .v13 :
144
- ver = 13
145
- case .v14 :
146
- ver = 14
147
- case .v15 :
148
- ver = 15
149
- case .v16 :
150
- ver = 16
151
- }
152
- let res = ShutdownScript.newWitnessProgram (version : ver, program : program)
153
- if res.isOk () {
154
- return Bindings.Result_ShutdownScriptNoneZ .initWithOk (o : res.getValue ()! )
155
- }
156
- }
157
- return .initWithErr ()
158
- } catch {
159
- return .initWithErr ()
160
- }
161
- }
162
-
163
- // ... and redirect all other trait method implementations to the `inner` `KeysManager`.
164
- override func deriveChannelSigner (channelValueSatoshis : UInt64 , channelKeysId : [UInt8 ]) -> Bindings.WriteableEcdsaChannelSigner {
165
- return myKeysManager! .inner .asSignerProvider ().deriveChannelSigner (
166
- channelValueSatoshis : channelValueSatoshis,
167
- channelKeysId : channelKeysId
168
- )
169
- }
170
-
171
- override func generateChannelKeysId (inbound : Bool , channelValueSatoshis : UInt64 , userChannelId : [UInt8 ]) -> [UInt8 ] {
172
- return myKeysManager! .inner .asSignerProvider ().generateChannelKeysId (
173
- inbound : inbound,
174
- channelValueSatoshis : channelValueSatoshis,
175
- userChannelId : userChannelId
176
- )
177
- }
178
-
179
- override func readChanSigner (reader : [UInt8 ]) -> Bindings.Result_WriteableEcdsaChannelSignerDecodeErrorZ {
180
- return myKeysManager! .inner .asSignerProvider ().readChanSigner (reader : reader)
110
+ } catch (e: Exception ) {
111
+ Log .i(LDKTAG , " Error: ${e.message} " )
181
112
}
182
113
}
183
- ```
184
114
185
- </template >
186
- </CodeSwitcher >
187
-
188
- Handle Spendable Outputs event.
189
-
190
- <CodeSwitcher :languages =" {rust:'Rust', java:'Java', swift:'Swift'} " >
191
- <template v-slot:rust >
192
-
193
- ``` rust
194
- // TODO: Add Rust Code Here
195
- ```
196
-
197
- </template >
198
- <template v-slot:java >
199
-
200
- ``` java
201
- // TODO: Add Java Code Here
202
115
```
203
116
204
117
</template >
205
118
<template v-slot:swift >
206
119
207
120
``` Swift
121
+ // Example where we spend straight to our BDK based wallet
122
+
208
123
func handleEvent (event : Event) {
209
124
if let event = event.getValueAsSpendableOutputs () {
210
- print (" handleEvent: trying to spend output" )
211
125
let outputs = event.getOutputs ()
212
126
do {
213
127
let address = ldkManager! .bdkManager .getAddress (addressIndex : .new )!
0 commit comments