@@ -6,7 +6,7 @@ However, LDK also allows to customize the way key material and entropy are sourc
66
77A ` KeysManager ` can be constructed simply with only a 32-byte seed and some random integers which ensure uniqueness across restarts (defined as ` starting_time_secs ` and ` starting_time_nanos ` ):
88
9- <CodeSwitcher :languages =" {rust:'Rust', java:'Java', kotlin:'Kotlin', swift:'Swift'} " >
9+ <CodeSwitcher :languages =" {rust:'Rust', kotlin:'Kotlin', swift:'Swift'} " >
1010 <template v-slot:rust >
1111
1212``` rust
@@ -18,19 +18,6 @@ let keys_interface_impl = lightning::sign::KeysManager::new(&random_32_bytes, st
1818
1919 </template >
2020
21- <template v-slot:java >
22-
23- ``` java
24- // Fill in key_seed with secure random data, or, on restart, reload the seed from disk.
25- byte [] key_seed = new byte [32 ];
26- KeysManager keys_manager = KeysManager . of(key_seed,
27- System . currentTimeMillis() / 1000 ,
28- (int ) (System . currentTimeMillis() * 1000 )
29- );
30- ```
31-
32- </template >
33-
3421 <template v-slot:kotlin >
3522
3623``` kotlin
@@ -52,8 +39,8 @@ let seed = [UInt8](repeating: 0, count: 32)
5239let timestampSeconds = UInt64 (NSDate ().timeIntervalSince1970 )
5340let timestampNanos = UInt32 (truncating : NSNumber (value : timestampSeconds * 1000 * 1000 ))
5441self .myKeysManager = KeysManager (
55- seed : seed,
56- startingTimeSecs : timestampSeconds,
42+ seed : seed,
43+ startingTimeSecs : timestampSeconds,
5744 startingTimeNanos : timestampNanos
5845)
5946```
@@ -73,7 +60,7 @@ Using a [BDK](https://bitcoindevkit.org/)-based wallet the steps would be as fol
73603 . Derive the private key at ` m/535h ` (or some other custom path). That's 32 bytes and is your starting entropy for your LDK wallet.
74614 . Optional: use a custom ` SignerProvider ` implementation to have the BDK wallet provide the destination and shutdown scripts (see [ Spending On-Chain Funds] ( #spending-on-chain-funds ) ).
7562
76- <CodeSwitcher :languages =" {rust:'Rust', java:'Java', kotlin:'Kotlin', swift:'Swift'} " >
63+ <CodeSwitcher :languages =" {rust:'Rust', kotlin:'Kotlin', swift:'Swift'} " >
7764 <template v-slot:rust >
7865
7966``` rust
@@ -96,36 +83,6 @@ let keys_manager = KeysManager::new(&ldk_seed, cur.as_secs(), cur.subsec_nanos()
9683
9784 </template >
9885
99- <template v-slot:java >
100-
101- ``` java
102- // Use BDK to create and build the HD wallet
103- Mnemonic mnemonic = Mnemonic . Companion . fromString(" sock lyrics " +
104- " village put galaxy " +
105- " famous pass act ship second diagram pull" );
106-
107- // Other supported networks include mainnet (Bitcoin), Regtest, Signet
108- DescriptorSecretKey bip32RootKey = new DescriptorSecretKey (Network . TESTNET , mnemonic, null );
109-
110- DerivationPath ldkDerivationPath = new DerivationPath (" m/535h" );
111- DescriptorSecretKey ldkChild = bip32RootKey. derive(ldkDerivationPath);
112-
113- ByteArrayOutputStream bos = new ByteArrayOutputStream ();
114- ObjectOutputStream oos = new ObjectOutputStream (bos);
115- oos. writeObject(ldkChild. secretBytes());
116- byte [] entropy = bos. toByteArray();
117-
118- // Seed the LDK KeysManager with the private key at m/535h
119- var startupTime = System . currentTimeMillis();
120- KeysManager keysManager = KeysManager . of(
121- entropy,
122- startupTime / 1000 ,
123- (int ) (startupTime * 1000 )
124- );
125- ```
126-
127- </template >
128-
12986 <template v-slot:kotlin >
13087
13188``` kotlin
@@ -164,8 +121,8 @@ let timestampNanos = UInt32(truncating: NSNumber(value: timestampSeconds * 1000
164121
165122// Seed the LDK KeysManager with the private key at m/535h
166123let keysManager = KeysManager (
167- seed : ldkSeed,
168- startingTimeSecs : timestampSeconds,
124+ seed : ldkSeed,
125+ startingTimeSecs : timestampSeconds,
169126 startingTimeNanos : timestampNanos
170127)
171128```
@@ -192,7 +149,7 @@ In order to make the outputs from channel closing spendable by a third-party wal
192149
193150For example, a wrapper based on BDK's [ ` Wallet ` ] ( https://docs.rs/bdk/*/bdk/wallet/struct.Wallet.html ) could look like this:
194151
195- <CodeSwitcher :languages =" {rust:'Rust', swift:'Swift'} " >
152+ <CodeSwitcher :languages =" {rust:'Rust', kotlin: 'Kotlin', swift:'Swift'} " >
196153<template v-slot:rust >
197154
198155``` rust
@@ -312,6 +269,96 @@ where
312269// ... snip
313270}
314271
272+ ```
273+
274+ </template >
275+
276+ <template v-slot:kotlin >
277+
278+ ``` kotlin
279+ class LDKKeysManager (seed : ByteArray , startTimeSecs : Long , startTimeNano : Int , wallet : Wallet ) {
280+ var inner: KeysManager
281+ var wallet: Wallet
282+ var signerProvider: LDKSignerProvider
283+
284+ init {
285+ this .inner = KeysManager .of(seed, startTimeSecs, startTimeNano)
286+ this .wallet = wallet
287+ signerProvider = LDKSignerProvider ()
288+ signerProvider.ldkkeysManager = this
289+ }
290+
291+ // We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be
292+ // spendable by the BDK wallet) and forward any other descriptors to
293+ // `KeysManager::spend_spendable_outputs`.
294+ //
295+ // Note you should set `locktime` to the current block height to mitigate fee sniping.
296+ // See https://bitcoinops.org/en/topics/fee-sniping/ for more information.
297+ fun spend_spendable_outputs (
298+ descriptors : Array <SpendableOutputDescriptor >,
299+ outputs : Array <TxOut >,
300+ changeDestinationScript : ByteArray ,
301+ feerateSatPer1000Weight : Int ,
302+ locktime : Option_u32Z
303+ ): Result_TransactionNoneZ {
304+ val onlyNonStatic: Array <SpendableOutputDescriptor > = descriptors.filter { it !is SpendableOutputDescriptor .StaticOutput }.toTypedArray()
305+
306+ return inner.spend_spendable_outputs(
307+ onlyNonStatic,
308+ outputs,
309+ changeDestinationScript,
310+ feerateSatPer1000Weight,
311+ locktime,
312+ )
313+ }
314+ }
315+
316+ class LDKSignerProvider : SignerProvider .SignerProviderInterface {
317+ var ldkkeysManager: LDKKeysManager ? = null
318+
319+ override fun generate_channel_keys_id (inbound : Boolean , channelValueSatoshis : Long , userChannelId : UInt128 ? ): ByteArray {
320+ return ldkkeysManager!! .inner.as_SignerProvider().generate_channel_keys_id(inbound, channelValueSatoshis, userChannelId)
321+ }
322+
323+ override fun derive_channel_signer (channelValueSatoshis : Long , channelKeysId : ByteArray? ): WriteableEcdsaChannelSigner {
324+ return ldkkeysManager!! .inner.as_SignerProvider().derive_channel_signer(channelValueSatoshis, channelKeysId)
325+ }
326+
327+ override fun read_chan_signer (reader : ByteArray? ): Result_WriteableEcdsaChannelSignerDecodeErrorZ {
328+ return ldkkeysManager!! .inner.as_SignerProvider().read_chan_signer(reader)
329+ }
330+
331+ // We return the destination and shutdown scripts derived by the BDK wallet.
332+ @OptIn(ExperimentalUnsignedTypes ::class )
333+ override fun get_destination_script (): Result_CVec_u8ZNoneZ {
334+ val address = ldkkeysManager!! .wallet.getAddress(AddressIndex .New )
335+ return Result_CVec_u8ZNoneZ .ok(address.address.scriptPubkey().toBytes().toUByteArray().toByteArray())
336+ }
337+
338+ // Only applies to cooperative close transactions.
339+ override fun get_shutdown_scriptpubkey (): Result_ShutdownScriptNoneZ {
340+ val address = ldkkeysManager!! .wallet.getAddress(AddressIndex .New ).address
341+
342+ return when (val payload: Payload = address.payload()) {
343+ is Payload .WitnessProgram -> {
344+ val ver = when (payload.version.name) {
345+ in " V0" .. " V16" -> payload.version.name.substring(1 ).toIntOrNull() ? : 0
346+ else -> 0 // Default to 0 if it doesn't match any "V0" to "V16"
347+ }
348+
349+ val result = ShutdownScript .new_witness_program(
350+ WitnessVersion (ver.toByte()),
351+ payload.program.toUByteArray().toByteArray()
352+ )
353+ Result_ShutdownScriptNoneZ .ok((result as Result_ShutdownScriptInvalidShutdownScriptZ .Result_ShutdownScriptInvalidShutdownScriptZ_OK ).res)
354+ }
355+ else -> {
356+ Result_ShutdownScriptNoneZ .err()
357+ }
358+ }
359+ }
360+ }
361+
315362```
316363
317364 </template >
@@ -323,7 +370,7 @@ class MyKeysManager {
323370 let inner: KeysManager
324371 let wallet: BitcoinDevKit.Wallet
325372 let signerProvider: MySignerProvider
326-
373+
327374 init (seed : [UInt8 ], startingTimeSecs : UInt64 , startingTimeNanos : UInt32 , wallet : BitcoinDevKit.Wallet) {
328375 self .inner = KeysManager (seed : seed, startingTimeSecs : startingTimeSecs, startingTimeNanos : startingTimeNanos)
329376 self .wallet = wallet
@@ -359,7 +406,7 @@ class MyKeysManager {
359406
360407class MySignerProvider : SignerProvider {
361408 weak var myKeysManager: MyKeysManager?
362-
409+
363410 // We return the destination and shutdown scripts derived by the BDK wallet.
364411 override func getDestinationScript () -> Bindings.Result_ScriptNoneZ {
365412 do {
@@ -369,7 +416,7 @@ class MySignerProvider: SignerProvider {
369416 return .initWithErr ()
370417 }
371418 }
372-
419+
373420 override func getShutdownScriptpubkey () -> Bindings.Result_ShutdownScriptNoneZ {
374421 do {
375422 let address = try myKeysManager! .wallet .getAddress (addressIndex : .new ).address
@@ -422,27 +469,28 @@ class MySignerProvider: SignerProvider {
422469 return .initWithErr ()
423470 }
424471 }
425-
472+
426473 // ... and redirect all other trait method implementations to the `inner` `KeysManager`.
427474 override func deriveChannelSigner (channelValueSatoshis : UInt64 , channelKeysId : [UInt8 ]) -> Bindings.WriteableEcdsaChannelSigner {
428475 return myKeysManager! .inner .asSignerProvider ().deriveChannelSigner (
429476 channelValueSatoshis : channelValueSatoshis,
430477 channelKeysId : channelKeysId
431478 )
432479 }
433-
480+
434481 override func generateChannelKeysId (inbound : Bool , channelValueSatoshis : UInt64 , userChannelId : [UInt8 ]) -> [UInt8 ] {
435482 return myKeysManager! .inner .asSignerProvider ().generateChannelKeysId (
436483 inbound : inbound,
437484 channelValueSatoshis : channelValueSatoshis,
438485 userChannelId : userChannelId
439486 )
440487 }
441-
488+
442489 override func readChanSigner (reader : [UInt8 ]) -> Bindings.Result_WriteableEcdsaChannelSignerDecodeErrorZ {
443490 return myKeysManager! .inner .asSignerProvider ().readChanSigner (reader : reader)
444491 }
445492}
446493```
494+
447495 </template >
448496</CodeSwitcher >
0 commit comments