1
1
# Closing a Channel
2
2
3
- Close Channel
3
+ Close Channel.
4
4
5
5
<CodeSwitcher :languages =" {rust:'Rust', java:'Java', swift:'Swift'} " >
6
6
<template v-slot:rust >
@@ -32,7 +32,7 @@ if res!.isOk() {
32
32
</CodeSwitcher >
33
33
34
34
35
- Claim Funds using Custom KeysManager. (Single Fees)
35
+ Claim Funds directly into the BDK wallet using Custom KeysManager.
36
36
37
37
<CodeSwitcher :languages =" {rust:'Rust', java:'Java', swift:'Swift'} " >
38
38
<template v-slot:rust >
@@ -52,41 +52,58 @@ Claim Funds using Custom KeysManager. (Single Fees)
52
52
<template v-slot:swift >
53
53
54
54
``` Swift
55
- // Custom KeysManager to get funds directly back to the BDK wallet after Channel Close
55
+ import Foundation
56
+ import LightningDevKit
57
+ import BitcoinDevKit
58
+
56
59
class MyKeysManager {
57
- let keysManager: KeysManager
58
- let signerProvider: MySignerProvider
60
+ let inner: KeysManager
59
61
let wallet: BitcoinDevKit.Wallet
62
+ let signerProvider: MySignerProvider
60
63
61
64
init (seed : [UInt8 ], startingTimeSecs : UInt64 , startingTimeNanos : UInt32 , wallet : BitcoinDevKit.Wallet) {
62
- self .keysManager = KeysManager (seed : seed, startingTimeSecs : startingTimeSecs, startingTimeNanos : startingTimeNanos)
65
+ self .inner = KeysManager (seed : seed, startingTimeSecs : startingTimeSecs, startingTimeNanos : startingTimeNanos)
63
66
self .wallet = wallet
64
67
signerProvider = MySignerProvider ()
65
68
signerProvider.myKeysManager = self
66
69
}
70
+
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
83
+ }
84
+ return true
85
+ }
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
+ }
67
95
}
68
96
69
- // Custom SignerProvider to override getDestinationScript() and getShutdownScriptpubkey()
70
97
class MySignerProvider : SignerProvider {
71
98
weak var myKeysManager: MyKeysManager?
72
- override func deriveChannelSigner (channelValueSatoshis : UInt64 , channelKeysId : [UInt8 ]) -> Bindings.WriteableEcdsaChannelSigner {
73
- return myKeysManager! .keysManager .asSignerProvider ().deriveChannelSigner (channelValueSatoshis : channelValueSatoshis, channelKeysId : channelKeysId)
74
- }
75
-
76
- override func generateChannelKeysId (inbound : Bool , channelValueSatoshis : UInt64 , userChannelId : [UInt8 ]) -> [UInt8 ] {
77
- return myKeysManager! .keysManager .asSignerProvider ().generateChannelKeysId (inbound : inbound, channelValueSatoshis : channelValueSatoshis, userChannelId : userChannelId)
78
- }
79
-
80
- override func readChanSigner (reader : [UInt8 ]) -> Bindings.Result_WriteableEcdsaChannelSignerDecodeErrorZ {
81
- return myKeysManager! .keysManager .asSignerProvider ().readChanSigner (reader : reader)
82
- }
83
99
100
+ // We return the destination and shutdown scripts derived by the BDK wallet.
84
101
override func getDestinationScript () -> Bindings.Result_ScriptNoneZ {
85
102
do {
86
103
let address = try myKeysManager! .wallet .getAddress (addressIndex : .new )
87
104
return Bindings.Result_ScriptNoneZ .initWithOk (o : address.address .scriptPubkey ().toBytes ())
88
105
} catch {
89
- return myKeysManager ! . keysManager . asSignerProvider (). getDestinationScript ()
106
+ return . initWithErr ()
90
107
}
91
108
}
92
109
@@ -137,19 +154,38 @@ class MySignerProvider: SignerProvider {
137
154
return Bindings.Result_ShutdownScriptNoneZ .initWithOk (o : res.getValue ()! )
138
155
}
139
156
}
140
- return myKeysManager ! . keysManager . asSignerProvider (). getShutdownScriptpubkey ()
157
+ return . initWithErr ()
141
158
} catch {
142
- return myKeysManager ! . keysManager . asSignerProvider (). getShutdownScriptpubkey ()
159
+ return . initWithErr ()
143
160
}
144
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)
181
+ }
145
182
}
146
-
147
183
```
148
184
149
185
</template >
150
186
</CodeSwitcher >
151
187
152
- Claim Funds using Events. (Double Fees)
188
+ Handle Spendable Outputs event.
153
189
154
190
<CodeSwitcher :languages =" {rust:'Rust', java:'Java', swift:'Swift'} " >
155
191
<template v-slot:rust >
@@ -171,21 +207,21 @@ Claim Funds using Events. (Double Fees)
171
207
``` Swift
172
208
func handleEvent (event : Event) {
173
209
if let event = event.getValueAsSpendableOutputs () {
210
+ print (" handleEvent: trying to spend output" )
174
211
let outputs = event.getOutputs ()
175
212
do {
176
- let address = // Get an address to transfer the funds
213
+ let address = ldkManager ! . bdkManager . getAddress ( addressIndex : . new ) !
177
214
let script = try Address (address : address).scriptPubkey ().toBytes ()
178
- let res = ldkManager. keysManager .spendSpendableOutputs (
215
+ let res = ldkManager! . myKeysManager .spendSpendableOutputs (
179
216
descriptors : outputs,
180
217
outputs : [],
181
218
changeDestinationScript : script,
182
219
feerateSatPer1000Weight : 1000 ,
183
- locktime : nil
184
- )
220
+ locktime : nil )
185
221
if res.isOk () {
186
222
var txs: [[UInt8 ]] = []
187
223
txs.append (res.getValue ()! )
188
- ldkManager.broadcaster .broadcastTransactions (txs : txs)
224
+ ldkManager! .broadcaster .broadcastTransactions (txs : txs)
189
225
}
190
226
} catch {
191
227
print (error.localizedDescription )
0 commit comments