Skip to content
This repository was archived by the owner on Feb 9, 2026. It is now read-only.

Commit 699b548

Browse files
committed
fix: save addresses only when used for closing a channel
1 parent 7902df4 commit 699b548

9 files changed

Lines changed: 62 additions & 14 deletions

File tree

lib/android/src/main/java/com/reactnativeldk/LdkModule.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ enum class EventTypes {
5454
network_graph_updated,
5555
channel_manager_restarted,
5656
backup_state_update,
57-
lsp_log
57+
lsp_log,
58+
used_close_address
5859
}
5960
//*****************************************************************
6061

@@ -242,7 +243,7 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
242243
}
243244

244245
@ReactMethod
245-
fun initKeysManager(seed: String, destinationScriptPublicKey: String, witnessProgram: String, witnessProgramVersion: Double, promise: Promise) {
246+
fun initKeysManager(seed: String, address: String, destinationScriptPublicKey: String, witnessProgram: String, witnessProgramVersion: Double, promise: Promise) {
246247
if (keysManager != null) {
247248
return handleResolve(promise, LdkCallbackResponses.keys_manager_init_success)
248249
}
@@ -259,11 +260,11 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
259260
seedBytes,
260261
seconds,
261262
nanoSeconds.toInt(),
263+
address,
262264
destinationScriptPublicKey.hexa(),
263265
witnessProgram.hexa(),
264266
witnessProgramVersion.toInt().toByte()
265267
)
266-
//keysManager = KeysManager.of(seedBytes, seconds, nanoSeconds.toInt())
267268

268269
handleResolve(promise, LdkCallbackResponses.keys_manager_init_success)
269270
}

lib/android/src/main/java/com/reactnativeldk/classes/CustomKeysManager.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class CustomKeysManager(
2222
seed: ByteArray,
2323
startingTimeSecs: Long,
2424
startingTimeNanos: Int,
25+
val address: String,
2526
val destinationScriptPublicKey: ByteArray,
2627
val witnessProgram: ByteArray,
2728
val witnessProgramVersion: Byte
@@ -68,6 +69,7 @@ class CustomSignerProvider : SignerProviderInterface {
6869
val res = ShutdownScript.new_witness_program(witness)
6970

7071
return if (res.is_ok) {
72+
LdkEventEmitter.send(EventTypes.used_close_address, customKeysManager.address)
7173
Result_ShutdownScriptNoneZ.ok((res as Result_ShutdownScriptInvalidShutdownScriptZ.Result_ShutdownScriptInvalidShutdownScriptZ_OK).res)
7274
} else {
7375
Result_ShutdownScriptNoneZ.err()

lib/ios/Classes/CustomKeysManager.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import LightningDevKit
1111
class CustomKeysManager {
1212
let inner: KeysManager
1313
let signerProvider: CustomSignerProvider
14+
let address: String
1415
let destinationScriptPublicKey: [UInt8]
1516
let witnessProgram: [UInt8]
1617
let witnessProgramVersion: UInt8
1718

18-
init(seed: [UInt8], startingTimeSecs: UInt64, startingTimeNanos: UInt32, destinationScriptPublicKey: [UInt8], witnessProgram: [UInt8], witnessProgramVersion: UInt8) {
19+
init(seed: [UInt8], startingTimeSecs: UInt64, startingTimeNanos: UInt32, address: String, destinationScriptPublicKey: [UInt8], witnessProgram: [UInt8], witnessProgramVersion: UInt8) {
1920
self.inner = KeysManager(seed: seed, startingTimeSecs: startingTimeSecs, startingTimeNanos: startingTimeNanos)
21+
self.address = address
2022
self.destinationScriptPublicKey = destinationScriptPublicKey
2123
self.witnessProgram = witnessProgram
2224
self.witnessProgramVersion = witnessProgramVersion
@@ -61,6 +63,8 @@ class CustomSignerProvider: SignerProvider {
6163
override func getShutdownScriptpubkey() -> Bindings.Result_ShutdownScriptNoneZ {
6264
let res = ShutdownScript.newWitnessProgram(witnessProgram: .init(version: customKeysManager!.witnessProgramVersion, program: customKeysManager!.witnessProgram))
6365
if res.isOk() {
66+
//To record which addresses should be watched for close channel funds
67+
LdkEventEmitter.shared.send(withEvent: .used_close_address, body: customKeysManager!.address)
6468
return Bindings.Result_ShutdownScriptNoneZ.initWithOk(o: res.getValue()!)
6569
}
6670

lib/ios/Ldk.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ @interface RCT_EXTERN_MODULE(Ldk, NSObject)
1616
RCT_EXTERN_METHOD(initChainMonitor:(RCTPromiseResolveBlock)resolve
1717
reject:(RCTPromiseRejectBlock)reject)
1818
RCT_EXTERN_METHOD(initKeysManager:(NSString *)seed
19+
address:(NSString *)address
1920
destinationScriptPublicKey:(NSString *)destinationScriptPublicKey
2021
witnessProgram:(NSString *)witnessProgram
2122
witnessProgramVersion:(NSInteger *)witnessProgramVersion

lib/ios/Ldk.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum EventTypes: String, CaseIterable {
2626
case channel_manager_restarted = "channel_manager_restarted"
2727
case backup_state_update = "backup_state_update"
2828
case lsp_log = "lsp_log"
29+
case used_close_address = "used_close_address"
2930
}
3031
//*****************************************************************
3132

@@ -210,7 +211,7 @@ class Ldk: NSObject {
210211
}
211212

212213
@objc
213-
func initKeysManager(_ seed: NSString, destinationScriptPublicKey: NSString, witnessProgram: NSString, witnessProgramVersion: NSInteger, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
214+
func initKeysManager(_ seed: NSString, address: NSString, destinationScriptPublicKey: NSString, witnessProgram: NSString, witnessProgramVersion: NSInteger, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
214215
if keysManager != nil {
215216
//If previously started with the same key (by backup client) return success.
216217
return handleResolve(resolve, .keys_manager_init_success)
@@ -228,6 +229,7 @@ class Ldk: NSObject {
228229
seed: String(seed).hexaBytes,
229230
startingTimeSecs: seconds,
230231
startingTimeNanos: nanoSeconds,
232+
address: String(address),
231233
destinationScriptPublicKey: String(destinationScriptPublicKey).hexaBytes,
232234
witnessProgram: String(witnessProgram).hexaBytes,
233235
witnessProgramVersion: UInt8(witnessProgramVersion)

lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@synonymdev/react-native-ldk",
33
"title": "React Native LDK",
4-
"version": "0.0.143",
4+
"version": "0.0.145",
55
"description": "React Native wrapper for LDK",
66
"main": "./dist/index.js",
77
"types": "./dist/index.d.ts",

lib/src/ldk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,15 @@ class LDK {
9595
*/
9696
async initKeysManager({
9797
seed,
98+
address,
9899
channelCloseDestinationScriptPublicKey,
99100
channelCloseWitnessProgram,
100101
channelCloseWitnessProgramVersion,
101102
}: TInitKeysManager): Promise<Result<string>> {
102103
try {
103104
const res = await NativeLDK.initKeysManager(
104105
seed,
106+
address,
105107
channelCloseDestinationScriptPublicKey,
106108
channelCloseWitnessProgram,
107109
channelCloseWitnessProgramVersion,

lib/src/lightning-manager.ts

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ class LightningManager {
232232
this.onChannelManagerRestarted.bind(this),
233233
);
234234
ldk.onEvent(EEventTypes.lsp_log, this.onLspLogEvent.bind(this));
235+
ldk.onEvent(EEventTypes.used_close_address, (address: string) => {
236+
this.saveAddressToFile(address).catch(console.error);
237+
});
235238
}
236239

237240
/**
@@ -364,14 +367,7 @@ class LightningManager {
364367
this.account = account;
365368
this.network = network;
366369
this.addresses = await this.readAddressesFromFile();
367-
this.getAddress = async () => {
368-
const addressObj = await getAddress();
369-
const address = addressObj?.address;
370-
if (address) {
371-
this.saveAddressToFile(address).then();
372-
}
373-
return addressObj;
374-
};
370+
this.getAddress = getAddress;
375371
this.getScriptPubKeyHistory = getScriptPubKeyHistory;
376372
this.getFees = getFees;
377373
this.broadcastTransaction = broadcastTransaction;
@@ -452,6 +448,7 @@ class LightningManager {
452448
// ldk.setLogLevel(ELdkLogLevels.trace, true),
453449
ldk.initKeysManager({
454450
seed: this.account.seed,
451+
address: closeAddress.address,
455452
channelCloseDestinationScriptPublicKey: closeAddress.publicKey,
456453
channelCloseWitnessProgram: witnessProgram,
457454
channelCloseWitnessProgramVersion: witnessProgramVersion,
@@ -513,6 +510,7 @@ class LightningManager {
513510
ldk.nodeStateDump().catch(console.error);
514511

515512
this.cleanupBroadcastedTxs().catch(console.error);
513+
this.resetAddressFileIfUnused().catch(console.error);
516514

517515
this.isStarting = false;
518516
const result = ok('Node started');
@@ -769,6 +767,37 @@ class LightningManager {
769767
return ok('Watch transactions checked');
770768
};
771769

770+
/*
771+
* Previously we were writing all addresses to file even
772+
* if they may not have been used in a channel shutdown script or
773+
* force close sweeping. So reset the file if there is no evidence of prior channels.
774+
* */
775+
resetAddressFileIfUnused = async (): Promise<void> => {
776+
//If no channel files found and no addresses are being used, reset the address file.
777+
const channelFilesRes = await ldk.listChannelFiles();
778+
if (channelFilesRes.isErr()) {
779+
return;
780+
}
781+
782+
if (channelFilesRes.value.length > 0) {
783+
return;
784+
}
785+
786+
const accountPath = appendPath(this.baseStoragePath, this.account.name);
787+
const writeRes = await ldk.writeToFile({
788+
fileName: ELdkFiles.addresses,
789+
path: accountPath,
790+
content: JSON.stringify([]),
791+
remotePersist: false,
792+
});
793+
794+
this.addresses = [];
795+
796+
if (writeRes.isErr()) {
797+
console.error(writeRes.error);
798+
}
799+
};
800+
772801
saveAddressToFile = async (address: string): Promise<Result<boolean>> => {
773802
if (!address) {
774803
return err('No address provided');
@@ -1822,6 +1851,7 @@ class LightningManager {
18221851
changeDestinationScript: changeDestinationScript,
18231852
};
18241853
const res = await ldk.reconstructAndSpendOutputs(req);
1854+
await this.saveAddressToFile(address.address);
18251855

18261856
if (res.isOk()) {
18271857
reconstructedTxs++;
@@ -2127,6 +2157,7 @@ class LightningManager {
21272157
res: TChannelManagerSpendableOutputs,
21282158
): Promise<void> {
21292159
const spendableOutputs = await this.getLdkSpendableOutputs();
2160+
21302161
res.outputsSerialized.forEach((o) => {
21312162
if (!spendableOutputs.includes(o)) {
21322163
spendableOutputs.push(o);
@@ -2172,6 +2203,9 @@ class LightningManager {
21722203
return;
21732204
}
21742205

2206+
//Address was used to sweep to so wallet needs to watch it
2207+
await this.saveAddressToFile(address.address);
2208+
21752209
await ldk.writeToLogFile(
21762210
'info',
21772211
`Created tx spending outputs: ${spendRes.value}`,

lib/src/utils/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export enum EEventTypes {
3535
channel_manager_restarted = 'channel_manager_restarted',
3636
backup_state_update = 'backup_state_update',
3737
lsp_log = 'lsp_log',
38+
used_close_address = 'used_close_address',
3839
}
3940

4041
//LDK event responses
@@ -326,6 +327,7 @@ export type TDownloadScorer = {
326327

327328
export type TInitKeysManager = {
328329
seed: string;
330+
address: string;
329331
channelCloseDestinationScriptPublicKey: string;
330332
channelCloseWitnessProgram: string;
331333
channelCloseWitnessProgramVersion: number;

0 commit comments

Comments
 (0)