@breeztech/breez-sdk-spark 0.27.0-dev2 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/breez-sdk-spark.tgz +0 -0
- package/bundler/breez_sdk_spark_wasm.d.ts +347 -95
- package/bundler/breez_sdk_spark_wasm_bg.js +210 -92
- package/bundler/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/bundler/breez_sdk_spark_wasm_bg.wasm.d.ts +28 -14
- package/bundler/storage/index.js +251 -20
- package/bundler/tree-store/index.js +39 -6
- package/deno/breez_sdk_spark_wasm.d.ts +347 -95
- package/deno/breez_sdk_spark_wasm.js +210 -92
- package/deno/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/deno/breez_sdk_spark_wasm_bg.wasm.d.ts +28 -14
- package/itest/database-drivers.test.js +45 -0
- package/nodejs/breez_sdk_spark_wasm.d.ts +347 -95
- package/nodejs/breez_sdk_spark_wasm.js +210 -92
- package/nodejs/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/nodejs/breez_sdk_spark_wasm_bg.wasm.d.ts +28 -14
- package/nodejs/index.js +6 -0
- package/nodejs/mysql-session-store/index.cjs +3 -1
- package/nodejs/mysql-storage/index.cjs +238 -20
- package/nodejs/mysql-storage/migrations.cjs +49 -1
- package/nodejs/mysql-token-store/index.cjs +3 -7
- package/nodejs/mysql-tree-store/index.cjs +26 -1
- package/nodejs/postgres-session-store/index.cjs +3 -1
- package/nodejs/postgres-storage/index.cjs +228 -19
- package/nodejs/postgres-storage/migrations.cjs +49 -0
- package/nodejs/postgres-token-store/index.cjs +3 -1
- package/nodejs/postgres-tree-store/index.cjs +25 -1
- package/nodejs/postgres-tree-store/migrations.cjs +10 -0
- package/nodejs/storage/index.cjs +210 -19
- package/nodejs/storage/migrations.cjs +38 -0
- package/nodejs/tree-store/index.cjs +35 -0
- package/package.json +1 -1
- package/web/breez_sdk_spark_wasm.d.ts +375 -109
- package/web/breez_sdk_spark_wasm.js +210 -92
- package/web/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/web/breez_sdk_spark_wasm_bg.wasm.d.ts +28 -14
- package/web/storage/index.js +251 -20
- package/web/tree-store/index.js +39 -6
|
@@ -22,16 +22,20 @@ export const bitcoinchainservicehandle_tipHeight: (a: number) => any;
|
|
|
22
22
|
export const breezsdk_addContact: (a: number, b: any) => any;
|
|
23
23
|
export const breezsdk_addEventListener: (a: number, b: any) => any;
|
|
24
24
|
export const breezsdk_authorizeLightningAddressTransfer: (a: number, b: any) => any;
|
|
25
|
+
export const breezsdk_bridgeFromCashApp: (a: number, b: any) => any;
|
|
26
|
+
export const breezsdk_bridgeToCashApp: (a: number, b: any) => any;
|
|
25
27
|
export const breezsdk_buildUnsignedBatchPackage: (a: number, b: any) => any;
|
|
26
28
|
export const breezsdk_buildUnsignedLnurlPayPackage: (a: number, b: any) => any;
|
|
29
|
+
export const breezsdk_buildUnsignedPullPackage: (a: number, b: any) => any;
|
|
27
30
|
export const breezsdk_buildUnsignedTransferPackage: (a: number, b: any) => any;
|
|
28
31
|
export const breezsdk_buyBitcoin: (a: number, b: any) => any;
|
|
29
32
|
export const breezsdk_checkLightningAddressAvailable: (a: number, b: any) => any;
|
|
30
33
|
export const breezsdk_checkMessage: (a: number, b: any) => any;
|
|
31
|
-
export const
|
|
34
|
+
export const breezsdk_checkRecoverFunds: (a: number, b: any) => any;
|
|
32
35
|
export const breezsdk_claimDeposit: (a: number, b: any) => any;
|
|
33
36
|
export const breezsdk_claimHtlcPayment: (a: number, b: any) => any;
|
|
34
37
|
export const breezsdk_claimLightningAddressTransfer: (a: number, b: any) => any;
|
|
38
|
+
export const breezsdk_createTokenAllowance: (a: number, b: any) => any;
|
|
35
39
|
export const breezsdk_deleteContact: (a: number, b: number, c: number) => any;
|
|
36
40
|
export const breezsdk_deleteLightningAddress: (a: number) => any;
|
|
37
41
|
export const breezsdk_disconnect: (a: number) => any;
|
|
@@ -50,6 +54,7 @@ export const breezsdk_listContacts: (a: number, b: any) => any;
|
|
|
50
54
|
export const breezsdk_listFiatCurrencies: (a: number) => any;
|
|
51
55
|
export const breezsdk_listFiatRates: (a: number) => any;
|
|
52
56
|
export const breezsdk_listPayments: (a: number, b: any) => any;
|
|
57
|
+
export const breezsdk_listTokenAllowances: (a: number, b: any) => any;
|
|
53
58
|
export const breezsdk_listUnclaimedDeposits: (a: number, b: any) => any;
|
|
54
59
|
export const breezsdk_listWebhooks: (a: number) => any;
|
|
55
60
|
export const breezsdk_lnurlAuth: (a: number, b: any) => any;
|
|
@@ -59,23 +64,27 @@ export const breezsdk_optimizeLeaves: (a: number, b: any) => any;
|
|
|
59
64
|
export const breezsdk_parse: (a: number, b: number, c: number) => any;
|
|
60
65
|
export const breezsdk_prepareLnurlPay: (a: number, b: any) => any;
|
|
61
66
|
export const breezsdk_preparePaymentLink: (a: number, b: any) => any;
|
|
67
|
+
export const breezsdk_preparePullPayment: (a: number, b: any) => any;
|
|
68
|
+
export const breezsdk_prepareRecoverFunds: (a: number, b: any) => any;
|
|
62
69
|
export const breezsdk_prepareSendBatch: (a: number, b: any) => any;
|
|
63
70
|
export const breezsdk_prepareSendPayment: (a: number, b: any) => any;
|
|
64
|
-
export const breezsdk_prepareUnilateralExit: (a: number, b: any) => any;
|
|
65
71
|
export const breezsdk_publishSignedLnurlPayPackage: (a: number, b: any) => any;
|
|
72
|
+
export const breezsdk_publishSignedPullPackage: (a: number, b: any) => any;
|
|
66
73
|
export const breezsdk_publishSignedTransferPackage: (a: number, b: any) => any;
|
|
74
|
+
export const breezsdk_pullPayment: (a: number, b: any) => any;
|
|
67
75
|
export const breezsdk_receivePayment: (a: number, b: any) => any;
|
|
68
76
|
export const breezsdk_recommendedFees: (a: number) => any;
|
|
77
|
+
export const breezsdk_recoverFunds: (a: number, b: any, c: number) => any;
|
|
69
78
|
export const breezsdk_refundDeposit: (a: number, b: any) => any;
|
|
70
79
|
export const breezsdk_refundPendingConversions: (a: number) => any;
|
|
71
80
|
export const breezsdk_registerLightningAddress: (a: number, b: any) => any;
|
|
72
81
|
export const breezsdk_registerWebhook: (a: number, b: any) => any;
|
|
73
82
|
export const breezsdk_removeEventListener: (a: number, b: number, c: number) => any;
|
|
83
|
+
export const breezsdk_revokeTokenAllowance: (a: number, b: any) => any;
|
|
74
84
|
export const breezsdk_sendBatch: (a: number, b: any) => any;
|
|
75
85
|
export const breezsdk_sendPayment: (a: number, b: any) => any;
|
|
76
86
|
export const breezsdk_signMessage: (a: number, b: any) => any;
|
|
77
87
|
export const breezsdk_syncWallet: (a: number, b: any) => any;
|
|
78
|
-
export const breezsdk_unilateralExit: (a: number, b: any, c: any) => any;
|
|
79
88
|
export const breezsdk_unregisterWebhook: (a: number, b: any) => any;
|
|
80
89
|
export const breezsdk_updateContact: (a: number, b: any) => any;
|
|
81
90
|
export const breezsdk_updateUserSettings: (a: number, b: any) => any;
|
|
@@ -110,6 +119,7 @@ export const externalsigningsignerhandle_signHashSchnorr: (a: number, b: number,
|
|
|
110
119
|
export const externalsparksignerhandle_getIdentityPublicKey: (a: number) => any;
|
|
111
120
|
export const externalsparksignerhandle_getPublicKeyForLeaf: (a: number, b: any) => any;
|
|
112
121
|
export const externalsparksignerhandle_getStaticDepositPublicKey: (a: number, b: number) => any;
|
|
122
|
+
export const externalsparksignerhandle_isRemote: (a: number) => number;
|
|
113
123
|
export const externalsparksignerhandle_prepareClaim: (a: number, b: any) => any;
|
|
114
124
|
export const externalsparksignerhandle_prepareLightningReceive: (a: number, b: any) => any;
|
|
115
125
|
export const externalsparksignerhandle_prepareStaticDeposit: (a: number, b: any) => any;
|
|
@@ -122,7 +132,9 @@ export const externalsparksignerhandle_signLeafRefundSpend: (a: number, b: any,
|
|
|
122
132
|
export const externalsparksignerhandle_signMessage: (a: number, b: number, c: number) => any;
|
|
123
133
|
export const externalsparksignerhandle_signSparkInvoice: (a: number, b: any) => any;
|
|
124
134
|
export const externalsparksignerhandle_signStaticDepositRefund: (a: number, b: any) => any;
|
|
135
|
+
export const externalsparksignerhandle_signWatchtowerExitRecovery: (a: number, b: any) => any;
|
|
125
136
|
export const externalsparksignerhandle_startStaticDepositRefund: (a: number, b: any) => any;
|
|
137
|
+
export const externalsparksignerhandle_startWatchtowerExitRecovery: (a: number, b: any) => any;
|
|
126
138
|
export const getSparkStatus: () => any;
|
|
127
139
|
export const initLogging: (a: any, b: number, c: number) => any;
|
|
128
140
|
export const mysqlStorage: (a: any) => number;
|
|
@@ -185,21 +197,23 @@ export const intounderlyingsource_cancel: (a: number) => void;
|
|
|
185
197
|
export const intounderlyingsource_pull: (a: number, b: any) => any;
|
|
186
198
|
export const __wbg_externalbreezsignerhandle_free: (a: number, b: number) => void;
|
|
187
199
|
export const __wbg_defaultsessionstore_free: (a: number, b: number) => void;
|
|
188
|
-
export const __wbg_externalsigningsignerhandle_free: (a: number, b: number) => void;
|
|
189
200
|
export const __wbg_externalsparksignerhandle_free: (a: number, b: number) => void;
|
|
201
|
+
export const __wbg_externalsigningsignerhandle_free: (a: number, b: number) => void;
|
|
190
202
|
export const __wbg_signingonlyexternalsigners_free: (a: number, b: number) => void;
|
|
191
203
|
export const signingonlyexternalsigners_breezSigner: (a: number) => number;
|
|
192
204
|
export const signingonlyexternalsigners_sparkSigner: (a: number) => number;
|
|
193
|
-
export const
|
|
194
|
-
export const
|
|
195
|
-
export const
|
|
196
|
-
export const
|
|
197
|
-
export const
|
|
198
|
-
export const
|
|
199
|
-
export const
|
|
200
|
-
export const
|
|
201
|
-
export const
|
|
202
|
-
export const
|
|
205
|
+
export const wasm_bindgen__convert__closures_____invoke__h6a948436da8c8a31: (a: number, b: number, c: any) => [number, number];
|
|
206
|
+
export const wasm_bindgen__convert__closures_____invoke__h6a948436da8c8a31_6: (a: number, b: number, c: any) => [number, number];
|
|
207
|
+
export const wasm_bindgen__convert__closures_____invoke__h6a948436da8c8a31_7: (a: number, b: number, c: any) => [number, number];
|
|
208
|
+
export const wasm_bindgen__convert__closures_____invoke__h6a948436da8c8a31_8: (a: number, b: number, c: any) => [number, number];
|
|
209
|
+
export const wasm_bindgen__convert__closures_____invoke__h6a948436da8c8a31_9: (a: number, b: number, c: any) => [number, number];
|
|
210
|
+
export const wasm_bindgen__convert__closures_____invoke__h118cfc65b353d9fd: (a: number, b: number, c: any, d: any) => void;
|
|
211
|
+
export const wasm_bindgen__convert__closures_____invoke__h06397208c6d2b4ed: (a: number, b: number, c: any) => void;
|
|
212
|
+
export const wasm_bindgen__convert__closures_____invoke__h06397208c6d2b4ed_2: (a: number, b: number, c: any) => void;
|
|
213
|
+
export const wasm_bindgen__convert__closures_____invoke__h06397208c6d2b4ed_3: (a: number, b: number, c: any) => void;
|
|
214
|
+
export const wasm_bindgen__convert__closures_____invoke__h06397208c6d2b4ed_4: (a: number, b: number, c: any) => void;
|
|
215
|
+
export const wasm_bindgen__convert__closures_____invoke__h06397208c6d2b4ed_5: (a: number, b: number, c: any) => void;
|
|
216
|
+
export const wasm_bindgen__convert__closures_____invoke__h02848814aa3937de: (a: number, b: number) => void;
|
|
203
217
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
204
218
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
205
219
|
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
package/nodejs/index.js
CHANGED
|
@@ -35,6 +35,9 @@ try {
|
|
|
35
35
|
if (error.code !== 'MODULE_NOT_FOUND') {
|
|
36
36
|
console.warn('Breez SDK: Failed to load PostgreSQL storage:', error.message);
|
|
37
37
|
}
|
|
38
|
+
// The WASM bridge builds every PostgreSQL store from a pool, so a caller that asks
|
|
39
|
+
// for PostgreSQL storage gets this load error.
|
|
40
|
+
global.createPostgresPool = () => { throw error; };
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
// Automatically import and set up the PostgreSQL tree store for Node.js
|
|
@@ -80,6 +83,9 @@ try {
|
|
|
80
83
|
if (error.code !== 'MODULE_NOT_FOUND') {
|
|
81
84
|
console.warn('Breez SDK: Failed to load MySQL storage:', error.message);
|
|
82
85
|
}
|
|
86
|
+
// The WASM bridge builds every MySQL store from a pool, so a caller that asks
|
|
87
|
+
// for MySQL storage gets this load error.
|
|
88
|
+
global.createMysqlPool = () => { throw error; };
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
// Automatically import and set up the MySQL tree store for Node.js
|
|
@@ -16,10 +16,12 @@ try {
|
|
|
16
16
|
try {
|
|
17
17
|
mysql = require("mysql2/promise");
|
|
18
18
|
} catch (fallbackError) {
|
|
19
|
-
|
|
19
|
+
const loadError = new Error(
|
|
20
20
|
`mysql2 not found. Please install it in your project: npm install mysql2@^3.11.0\n` +
|
|
21
21
|
`Original error: ${error.message}\nFallback error: ${fallbackError.message}`
|
|
22
22
|
);
|
|
23
|
+
loadError.code = fallbackError.code;
|
|
24
|
+
throw loadError;
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -30,16 +30,26 @@ try {
|
|
|
30
30
|
try {
|
|
31
31
|
mysql = require("mysql2/promise");
|
|
32
32
|
} catch (fallbackError) {
|
|
33
|
-
|
|
33
|
+
const loadError = new Error(
|
|
34
34
|
`mysql2 not found. Please install it in your project: npm install mysql2@^3.11.0\n` +
|
|
35
35
|
`Original error: ${error.message}\nFallback error: ${fallbackError.message}`
|
|
36
36
|
);
|
|
37
|
+
loadError.code = fallbackError.code;
|
|
38
|
+
throw loadError;
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
const { StorageError } = require("./errors.cjs");
|
|
41
43
|
const { MysqlMigrationManager } = require("./migrations.cjs");
|
|
42
44
|
|
|
45
|
+
// JSON has no BigInt, so u128 amounts are stored as decimal strings, which the
|
|
46
|
+
// SDK reads back as BigInts.
|
|
47
|
+
function toJson(value) {
|
|
48
|
+
return JSON.stringify(value, (_key, v) =>
|
|
49
|
+
typeof v === "bigint" ? v.toString() : v
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
const PAYMENT_UPDATE_LOCK_TIMEOUT_SECS = 10;
|
|
44
54
|
|
|
45
55
|
/**
|
|
@@ -120,6 +130,58 @@ function crossChainSwapFromRow(row) {
|
|
|
120
130
|
};
|
|
121
131
|
}
|
|
122
132
|
|
|
133
|
+
/**
|
|
134
|
+
* A row holds a leaf recovery and one of its watchtower exit recoveries, so
|
|
135
|
+
* a leaf recovery with several of them spans several rows.
|
|
136
|
+
*/
|
|
137
|
+
function leafRecoveriesFromRows(rows) {
|
|
138
|
+
const leafRecoveries = [];
|
|
139
|
+
for (const row of rows) {
|
|
140
|
+
let leafRecovery = leafRecoveries[leafRecoveries.length - 1];
|
|
141
|
+
if (leafRecovery?.leafId !== row.leaf_id) {
|
|
142
|
+
leafRecovery = {
|
|
143
|
+
leafId: row.leaf_id,
|
|
144
|
+
chainCheckedAt:
|
|
145
|
+
row.chain_checked_at != null ? BigInt(row.chain_checked_at) : null,
|
|
146
|
+
watchtowerExitOutput:
|
|
147
|
+
row.output_block_height != null
|
|
148
|
+
? {
|
|
149
|
+
txid: row.output_txid,
|
|
150
|
+
vout: Number(row.output_vout),
|
|
151
|
+
amountSats: BigInt(row.output_amount_sats),
|
|
152
|
+
scriptPubkey: row.output_script_pubkey,
|
|
153
|
+
blockHeight: Number(row.output_block_height),
|
|
154
|
+
}
|
|
155
|
+
: null,
|
|
156
|
+
watchtowerExitRecoveries: [],
|
|
157
|
+
watchtowerExitSpend:
|
|
158
|
+
row.spend_block_height != null
|
|
159
|
+
? {
|
|
160
|
+
txid: row.spend_txid,
|
|
161
|
+
blockHeight: Number(row.spend_block_height),
|
|
162
|
+
}
|
|
163
|
+
: null,
|
|
164
|
+
unilateralExitSweep:
|
|
165
|
+
row.sweep_block_height != null
|
|
166
|
+
? {
|
|
167
|
+
txid: row.sweep_txid,
|
|
168
|
+
blockHeight: Number(row.sweep_block_height),
|
|
169
|
+
}
|
|
170
|
+
: null,
|
|
171
|
+
};
|
|
172
|
+
leafRecoveries.push(leafRecovery);
|
|
173
|
+
}
|
|
174
|
+
if (row.recovery_txid != null) {
|
|
175
|
+
leafRecovery.watchtowerExitRecoveries.push({
|
|
176
|
+
txid: row.recovery_txid,
|
|
177
|
+
transactionHex: row.recovery_transaction_hex,
|
|
178
|
+
outputAmountSats: BigInt(row.recovery_output_amount_sats),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return leafRecoveries;
|
|
183
|
+
}
|
|
184
|
+
|
|
123
185
|
class MysqlStorage {
|
|
124
186
|
/**
|
|
125
187
|
* @param {import('mysql2/promise').Pool} pool - Connection pool (may be shared with other tenants).
|
|
@@ -403,7 +465,7 @@ class MysqlStorage {
|
|
|
403
465
|
} catch (error) {
|
|
404
466
|
if (error instanceof StorageError) throw error;
|
|
405
467
|
throw new StorageError(
|
|
406
|
-
`Failed to list payments (request: ${
|
|
468
|
+
`Failed to list payments (request: ${toJson(request)}): ${error.message}`,
|
|
407
469
|
error
|
|
408
470
|
);
|
|
409
471
|
}
|
|
@@ -528,7 +590,7 @@ class MysqlStorage {
|
|
|
528
590
|
payment.amount.toString(),
|
|
529
591
|
payment.fees.toString(),
|
|
530
592
|
payment.timestamp,
|
|
531
|
-
payment.method ?
|
|
593
|
+
payment.method ? toJson(payment.method) : null,
|
|
532
594
|
withdrawTxId,
|
|
533
595
|
spark,
|
|
534
596
|
]
|
|
@@ -560,10 +622,10 @@ class MysqlStorage {
|
|
|
560
622
|
this.identity,
|
|
561
623
|
payment.id,
|
|
562
624
|
payment.details.invoiceDetails
|
|
563
|
-
?
|
|
625
|
+
? toJson(payment.details.invoiceDetails)
|
|
564
626
|
: null,
|
|
565
627
|
payment.details.htlcDetails
|
|
566
|
-
?
|
|
628
|
+
? toJson(payment.details.htlcDetails)
|
|
567
629
|
: null,
|
|
568
630
|
]
|
|
569
631
|
);
|
|
@@ -609,11 +671,11 @@ class MysqlStorage {
|
|
|
609
671
|
[
|
|
610
672
|
this.identity,
|
|
611
673
|
payment.id,
|
|
612
|
-
|
|
674
|
+
toJson(payment.details.metadata),
|
|
613
675
|
payment.details.txHash,
|
|
614
676
|
payment.details.txType,
|
|
615
677
|
payment.details.invoiceDetails
|
|
616
|
-
?
|
|
678
|
+
? toJson(payment.details.invoiceDetails)
|
|
617
679
|
: null,
|
|
618
680
|
]
|
|
619
681
|
);
|
|
@@ -746,14 +808,14 @@ class MysqlStorage {
|
|
|
746
808
|
paymentId,
|
|
747
809
|
metadata.parentPaymentId,
|
|
748
810
|
metadata.lnurlPayInfo
|
|
749
|
-
?
|
|
811
|
+
? toJson(metadata.lnurlPayInfo)
|
|
750
812
|
: null,
|
|
751
813
|
metadata.lnurlWithdrawInfo
|
|
752
|
-
?
|
|
814
|
+
? toJson(metadata.lnurlWithdrawInfo)
|
|
753
815
|
: null,
|
|
754
816
|
metadata.lnurlDescription,
|
|
755
817
|
metadata.conversionInfo
|
|
756
|
-
?
|
|
818
|
+
? toJson(metadata.conversionInfo)
|
|
757
819
|
: null,
|
|
758
820
|
metadata.conversionStatus ?? null,
|
|
759
821
|
]
|
|
@@ -833,7 +895,7 @@ class MysqlStorage {
|
|
|
833
895
|
`UPDATE brz_unclaimed_deposits
|
|
834
896
|
SET claim_error = ?
|
|
835
897
|
WHERE user_id = ? AND txid = ? AND vout = ?`,
|
|
836
|
-
[
|
|
898
|
+
[toJson(payload.error), this.identity, txid, vout]
|
|
837
899
|
);
|
|
838
900
|
} else if (payload.type === "refund") {
|
|
839
901
|
await this.pool.query(
|
|
@@ -843,7 +905,7 @@ class MysqlStorage {
|
|
|
843
905
|
[
|
|
844
906
|
payload.refundTx,
|
|
845
907
|
payload.refundTxid,
|
|
846
|
-
|
|
908
|
+
toJson(payload.state),
|
|
847
909
|
this.identity,
|
|
848
910
|
txid,
|
|
849
911
|
vout,
|
|
@@ -854,7 +916,7 @@ class MysqlStorage {
|
|
|
854
916
|
`UPDATE brz_unclaimed_deposits
|
|
855
917
|
SET instant_claim_status = ?
|
|
856
918
|
WHERE user_id = ? AND txid = ? AND vout = ?`,
|
|
857
|
-
[
|
|
919
|
+
[toJson(payload.status), this.identity, txid, vout]
|
|
858
920
|
);
|
|
859
921
|
} else if (payload.type === "refundBroadcastState") {
|
|
860
922
|
await this.pool.query(
|
|
@@ -862,7 +924,7 @@ class MysqlStorage {
|
|
|
862
924
|
SET refund_state = ?
|
|
863
925
|
WHERE user_id = ? AND txid = ? AND vout = ? AND refund_tx_id = ?`,
|
|
864
926
|
[
|
|
865
|
-
|
|
927
|
+
toJson(payload.state),
|
|
866
928
|
this.identity,
|
|
867
929
|
txid,
|
|
868
930
|
vout,
|
|
@@ -875,7 +937,7 @@ class MysqlStorage {
|
|
|
875
937
|
SET max_claim_fee = ?
|
|
876
938
|
WHERE user_id = ? AND txid = ? AND vout = ?`,
|
|
877
939
|
[
|
|
878
|
-
payload.maxFee ?
|
|
940
|
+
payload.maxFee ? toJson(payload.maxFee) : null,
|
|
879
941
|
this.identity,
|
|
880
942
|
txid,
|
|
881
943
|
vout,
|
|
@@ -946,6 +1008,163 @@ class MysqlStorage {
|
|
|
946
1008
|
}
|
|
947
1009
|
}
|
|
948
1010
|
|
|
1011
|
+
async listLeafRecoveries() {
|
|
1012
|
+
try {
|
|
1013
|
+
const [rows] = await this.pool.query(
|
|
1014
|
+
`SELECT l.leaf_id,
|
|
1015
|
+
l.chain_checked_at,
|
|
1016
|
+
o.txid AS output_txid,
|
|
1017
|
+
o.vout AS output_vout,
|
|
1018
|
+
o.amount_sats AS output_amount_sats,
|
|
1019
|
+
o.script_pubkey AS output_script_pubkey,
|
|
1020
|
+
ot.block_height AS output_block_height,
|
|
1021
|
+
s.txid AS spend_txid,
|
|
1022
|
+
st.block_height AS spend_block_height,
|
|
1023
|
+
w.txid AS sweep_txid,
|
|
1024
|
+
wt.block_height AS sweep_block_height,
|
|
1025
|
+
r.txid AS recovery_txid,
|
|
1026
|
+
r.transaction_hex AS recovery_transaction_hex,
|
|
1027
|
+
r.output_amount_sats AS recovery_output_amount_sats
|
|
1028
|
+
FROM brz_leaf_recoveries l
|
|
1029
|
+
LEFT JOIN brz_watchtower_exit_outputs o
|
|
1030
|
+
ON o.user_id = l.user_id AND o.leaf_id = l.leaf_id
|
|
1031
|
+
LEFT JOIN brz_chain_transactions ot
|
|
1032
|
+
ON ot.user_id = o.user_id AND ot.txid = o.txid
|
|
1033
|
+
LEFT JOIN brz_watchtower_exit_spends s
|
|
1034
|
+
ON s.user_id = l.user_id AND s.leaf_id = l.leaf_id
|
|
1035
|
+
LEFT JOIN brz_chain_transactions st
|
|
1036
|
+
ON st.user_id = s.user_id AND st.txid = s.txid
|
|
1037
|
+
LEFT JOIN brz_unilateral_exit_sweeps w
|
|
1038
|
+
ON w.user_id = l.user_id AND w.leaf_id = l.leaf_id
|
|
1039
|
+
LEFT JOIN brz_chain_transactions wt
|
|
1040
|
+
ON wt.user_id = w.user_id AND wt.txid = w.txid
|
|
1041
|
+
LEFT JOIN brz_watchtower_exit_recoveries r
|
|
1042
|
+
ON r.user_id = l.user_id AND r.leaf_id = l.leaf_id
|
|
1043
|
+
WHERE l.user_id = ?
|
|
1044
|
+
ORDER BY l.leaf_id, r.txid`,
|
|
1045
|
+
[this.identity]
|
|
1046
|
+
);
|
|
1047
|
+
return leafRecoveriesFromRows(rows);
|
|
1048
|
+
} catch (error) {
|
|
1049
|
+
throw new StorageError(
|
|
1050
|
+
`Failed to list leaf recoveries: ${error.message}`,
|
|
1051
|
+
error
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
async updateLeafRecovery(update) {
|
|
1057
|
+
try {
|
|
1058
|
+
const leafId = update.leafId;
|
|
1059
|
+
await this._withTransaction(async (conn) => {
|
|
1060
|
+
const setChainTransaction = (txid, blockHeight) =>
|
|
1061
|
+
conn.query(
|
|
1062
|
+
`INSERT INTO brz_chain_transactions (user_id, txid, block_height)
|
|
1063
|
+
VALUES (?, ?, ?)
|
|
1064
|
+
ON DUPLICATE KEY UPDATE block_height = VALUES(block_height)`,
|
|
1065
|
+
[this.identity, txid, blockHeight]
|
|
1066
|
+
);
|
|
1067
|
+
|
|
1068
|
+
// MySQL locks the leaf's row, so writers of one leaf do not interleave.
|
|
1069
|
+
await conn.query(
|
|
1070
|
+
`INSERT INTO brz_leaf_recoveries (user_id, leaf_id) VALUES (?, ?)
|
|
1071
|
+
ON DUPLICATE KEY UPDATE leaf_id = leaf_id`,
|
|
1072
|
+
[this.identity, leafId]
|
|
1073
|
+
);
|
|
1074
|
+
if (update.chainCheckedAt != null) {
|
|
1075
|
+
// The parameter is a string, and MySQL would compare it with the
|
|
1076
|
+
// stored time as strings. CAST makes MySQL compare them as numbers.
|
|
1077
|
+
await conn.query(
|
|
1078
|
+
`UPDATE brz_leaf_recoveries
|
|
1079
|
+
SET chain_checked_at =
|
|
1080
|
+
GREATEST(COALESCE(chain_checked_at, 0), CAST(? AS SIGNED))
|
|
1081
|
+
WHERE user_id = ? AND leaf_id = ?`,
|
|
1082
|
+
[String(update.chainCheckedAt), this.identity, leafId]
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
if (update.watchtowerExitOutput != null) {
|
|
1086
|
+
const output = update.watchtowerExitOutput;
|
|
1087
|
+
for (const table of [
|
|
1088
|
+
"brz_watchtower_exit_recoveries",
|
|
1089
|
+
"brz_watchtower_exit_spends",
|
|
1090
|
+
]) {
|
|
1091
|
+
await conn.query(
|
|
1092
|
+
`DELETE FROM ${table}
|
|
1093
|
+
WHERE user_id = ? AND leaf_id = ? AND EXISTS (
|
|
1094
|
+
SELECT 1 FROM brz_watchtower_exit_outputs
|
|
1095
|
+
WHERE user_id = ? AND leaf_id = ? AND (txid <> ? OR vout <> ?))`,
|
|
1096
|
+
[
|
|
1097
|
+
this.identity,
|
|
1098
|
+
leafId,
|
|
1099
|
+
this.identity,
|
|
1100
|
+
leafId,
|
|
1101
|
+
output.txid,
|
|
1102
|
+
output.vout,
|
|
1103
|
+
]
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
await setChainTransaction(output.txid, output.blockHeight);
|
|
1107
|
+
await conn.query(
|
|
1108
|
+
`INSERT INTO brz_watchtower_exit_outputs
|
|
1109
|
+
(user_id, leaf_id, txid, vout, amount_sats, script_pubkey)
|
|
1110
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
1111
|
+
ON DUPLICATE KEY UPDATE
|
|
1112
|
+
txid = VALUES(txid),
|
|
1113
|
+
vout = VALUES(vout),
|
|
1114
|
+
amount_sats = VALUES(amount_sats),
|
|
1115
|
+
script_pubkey = VALUES(script_pubkey)`,
|
|
1116
|
+
[
|
|
1117
|
+
this.identity,
|
|
1118
|
+
leafId,
|
|
1119
|
+
output.txid,
|
|
1120
|
+
output.vout,
|
|
1121
|
+
String(output.amountSats),
|
|
1122
|
+
output.scriptPubkey,
|
|
1123
|
+
]
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
if (update.watchtowerExitRecovery != null) {
|
|
1127
|
+
const recovery = update.watchtowerExitRecovery;
|
|
1128
|
+
await conn.query(
|
|
1129
|
+
`INSERT INTO brz_watchtower_exit_recoveries
|
|
1130
|
+
(user_id, leaf_id, txid, transaction_hex, output_amount_sats)
|
|
1131
|
+
VALUES (?, ?, ?, ?, ?)
|
|
1132
|
+
ON DUPLICATE KEY UPDATE txid = txid`,
|
|
1133
|
+
[
|
|
1134
|
+
this.identity,
|
|
1135
|
+
leafId,
|
|
1136
|
+
recovery.txid,
|
|
1137
|
+
recovery.transactionHex,
|
|
1138
|
+
String(recovery.outputAmountSats),
|
|
1139
|
+
]
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
for (const [table, chainTransaction] of [
|
|
1143
|
+
["brz_watchtower_exit_spends", update.watchtowerExitSpend],
|
|
1144
|
+
["brz_unilateral_exit_sweeps", update.unilateralExitSweep],
|
|
1145
|
+
]) {
|
|
1146
|
+
if (chainTransaction == null) {
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
await setChainTransaction(
|
|
1150
|
+
chainTransaction.txid,
|
|
1151
|
+
chainTransaction.blockHeight
|
|
1152
|
+
);
|
|
1153
|
+
await conn.query(
|
|
1154
|
+
`INSERT INTO ${table} (user_id, leaf_id, txid) VALUES (?, ?, ?)
|
|
1155
|
+
ON DUPLICATE KEY UPDATE txid = VALUES(txid)`,
|
|
1156
|
+
[this.identity, leafId, chainTransaction.txid]
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
throw new StorageError(
|
|
1162
|
+
`Failed to update leaf recovery '${update.leafId}': ${error.message}`,
|
|
1163
|
+
error
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
949
1168
|
async setLnurlMetadata(metadata) {
|
|
950
1169
|
try {
|
|
951
1170
|
await this._withTransaction(async (conn) => {
|
|
@@ -1268,7 +1487,7 @@ class MysqlStorage {
|
|
|
1268
1487
|
record.id.dataId,
|
|
1269
1488
|
record.schemaVersion,
|
|
1270
1489
|
Math.floor(Date.now() / 1000),
|
|
1271
|
-
|
|
1490
|
+
toJson(record.updatedFields),
|
|
1272
1491
|
revision.toString(),
|
|
1273
1492
|
]
|
|
1274
1493
|
);
|
|
@@ -1297,7 +1516,6 @@ class MysqlStorage {
|
|
|
1297
1516
|
if (this.logger && typeof this.logger.log === "function") {
|
|
1298
1517
|
this.logger.log({ line: msg, level: "warn" });
|
|
1299
1518
|
} else {
|
|
1300
|
-
// eslint-disable-next-line no-console
|
|
1301
1519
|
console.warn(`[MysqlStorage] ${msg}`);
|
|
1302
1520
|
}
|
|
1303
1521
|
}
|
|
@@ -1324,7 +1542,7 @@ class MysqlStorage {
|
|
|
1324
1542
|
record.revision.toString(),
|
|
1325
1543
|
record.schemaVersion,
|
|
1326
1544
|
Math.floor(Date.now() / 1000),
|
|
1327
|
-
|
|
1545
|
+
toJson(record.data),
|
|
1328
1546
|
]
|
|
1329
1547
|
);
|
|
1330
1548
|
|
|
@@ -1441,7 +1659,7 @@ class MysqlStorage {
|
|
|
1441
1659
|
record.id.dataId,
|
|
1442
1660
|
record.schemaVersion,
|
|
1443
1661
|
Math.floor(Date.now() / 1000),
|
|
1444
|
-
|
|
1662
|
+
toJson(record.data),
|
|
1445
1663
|
record.revision.toString(),
|
|
1446
1664
|
]
|
|
1447
1665
|
);
|
|
@@ -1604,7 +1822,7 @@ class MysqlStorage {
|
|
|
1604
1822
|
record.revision.toString(),
|
|
1605
1823
|
record.schemaVersion,
|
|
1606
1824
|
Math.floor(Date.now() / 1000),
|
|
1607
|
-
|
|
1825
|
+
toJson(record.data),
|
|
1608
1826
|
]
|
|
1609
1827
|
);
|
|
1610
1828
|
|
|
@@ -149,7 +149,6 @@ class MysqlMigrationManager {
|
|
|
149
149
|
if (this.logger && typeof this.logger.log === "function") {
|
|
150
150
|
this.logger.log({ line: message, level });
|
|
151
151
|
} else if (level === "error") {
|
|
152
|
-
// eslint-disable-next-line no-console
|
|
153
152
|
console.error(`[MysqlMigrationManager] ${message}`);
|
|
154
153
|
}
|
|
155
154
|
}
|
|
@@ -607,6 +606,55 @@ class MysqlMigrationManager {
|
|
|
607
606
|
`ALTER TABLE brz_unclaimed_deposits ADD COLUMN max_claim_fee JSON NULL`,
|
|
608
607
|
],
|
|
609
608
|
},
|
|
609
|
+
{
|
|
610
|
+
// Leaf recoveries. What the chain service reported about leaves with
|
|
611
|
+
// funds to recover on-chain, and the recoveries the operators co-signed.
|
|
612
|
+
// Every block height is in brz_chain_transactions, keyed by txid.
|
|
613
|
+
name: "Add leaf recovery tables",
|
|
614
|
+
sql: [
|
|
615
|
+
`CREATE TABLE IF NOT EXISTS brz_leaf_recoveries (
|
|
616
|
+
user_id VARBINARY(33) NOT NULL,
|
|
617
|
+
leaf_id VARCHAR(255) NOT NULL,
|
|
618
|
+
chain_checked_at BIGINT,
|
|
619
|
+
PRIMARY KEY (user_id, leaf_id)
|
|
620
|
+
)`,
|
|
621
|
+
`CREATE TABLE IF NOT EXISTS brz_chain_transactions (
|
|
622
|
+
user_id VARBINARY(33) NOT NULL,
|
|
623
|
+
txid VARCHAR(255) NOT NULL,
|
|
624
|
+
block_height BIGINT NOT NULL,
|
|
625
|
+
PRIMARY KEY (user_id, txid)
|
|
626
|
+
)`,
|
|
627
|
+
`CREATE TABLE IF NOT EXISTS brz_watchtower_exit_outputs (
|
|
628
|
+
user_id VARBINARY(33) NOT NULL,
|
|
629
|
+
leaf_id VARCHAR(255) NOT NULL,
|
|
630
|
+
txid VARCHAR(255) NOT NULL,
|
|
631
|
+
vout BIGINT NOT NULL,
|
|
632
|
+
amount_sats BIGINT NOT NULL,
|
|
633
|
+
script_pubkey TEXT NOT NULL,
|
|
634
|
+
PRIMARY KEY (user_id, leaf_id)
|
|
635
|
+
)`,
|
|
636
|
+
`CREATE TABLE IF NOT EXISTS brz_watchtower_exit_recoveries (
|
|
637
|
+
user_id VARBINARY(33) NOT NULL,
|
|
638
|
+
leaf_id VARCHAR(255) NOT NULL,
|
|
639
|
+
txid VARCHAR(255) NOT NULL,
|
|
640
|
+
transaction_hex TEXT NOT NULL,
|
|
641
|
+
output_amount_sats BIGINT NOT NULL,
|
|
642
|
+
PRIMARY KEY (user_id, leaf_id, txid)
|
|
643
|
+
)`,
|
|
644
|
+
`CREATE TABLE IF NOT EXISTS brz_watchtower_exit_spends (
|
|
645
|
+
user_id VARBINARY(33) NOT NULL,
|
|
646
|
+
leaf_id VARCHAR(255) NOT NULL,
|
|
647
|
+
txid VARCHAR(255) NOT NULL,
|
|
648
|
+
PRIMARY KEY (user_id, leaf_id)
|
|
649
|
+
)`,
|
|
650
|
+
`CREATE TABLE IF NOT EXISTS brz_unilateral_exit_sweeps (
|
|
651
|
+
user_id VARBINARY(33) NOT NULL,
|
|
652
|
+
leaf_id VARCHAR(255) NOT NULL,
|
|
653
|
+
txid VARCHAR(255) NOT NULL,
|
|
654
|
+
PRIMARY KEY (user_id, leaf_id)
|
|
655
|
+
)`,
|
|
656
|
+
],
|
|
657
|
+
},
|
|
610
658
|
];
|
|
611
659
|
}
|
|
612
660
|
}
|
|
@@ -17,10 +17,12 @@ try {
|
|
|
17
17
|
try {
|
|
18
18
|
mysql = require("mysql2/promise");
|
|
19
19
|
} catch (fallbackError) {
|
|
20
|
-
|
|
20
|
+
const loadError = new Error(
|
|
21
21
|
`mysql2 not found. Please install it in your project: npm install mysql2@^3.11.0\n` +
|
|
22
22
|
`Original error: ${error.message}\nFallback error: ${fallbackError.message}`
|
|
23
23
|
);
|
|
24
|
+
loadError.code = fallbackError.code;
|
|
25
|
+
throw loadError;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -50,12 +52,6 @@ function _identityLockName(prefix, identity) {
|
|
|
50
52
|
return prefix + hash.digest("hex").slice(0, 16);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
function parseJson(value) {
|
|
54
|
-
if (value == null) return null;
|
|
55
|
-
if (typeof value === "string") return JSON.parse(value);
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
55
|
function toBool(value) {
|
|
60
56
|
if (value == null) return null;
|
|
61
57
|
if (typeof value === "boolean") return value;
|
|
@@ -22,10 +22,12 @@ try {
|
|
|
22
22
|
try {
|
|
23
23
|
mysql = require("mysql2/promise");
|
|
24
24
|
} catch (fallbackError) {
|
|
25
|
-
|
|
25
|
+
const loadError = new Error(
|
|
26
26
|
`mysql2 not found. Please install it in your project: npm install mysql2@^3.11.0\n` +
|
|
27
27
|
`Original error: ${error.message}\nFallback error: ${fallbackError.message}`
|
|
28
28
|
);
|
|
29
|
+
loadError.code = fallbackError.code;
|
|
30
|
+
throw loadError;
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -516,6 +518,29 @@ class MysqlTreeStore {
|
|
|
516
518
|
}
|
|
517
519
|
}
|
|
518
520
|
|
|
521
|
+
/**
|
|
522
|
+
* Return the leaves, reserved or not, whose status is one of `statuses`.
|
|
523
|
+
* @param {Array<string>} statuses
|
|
524
|
+
* @returns {Promise<Array<object>>}
|
|
525
|
+
*/
|
|
526
|
+
async getLeavesWithStatus(statuses) {
|
|
527
|
+
try {
|
|
528
|
+
if (!statuses || statuses.length === 0) return [];
|
|
529
|
+
const [rows] = await this.pool.query(
|
|
530
|
+
`SELECT data FROM brz_tree_leaves
|
|
531
|
+
WHERE user_id = ? AND status IN (${buildPlaceholders(statuses.length)})`,
|
|
532
|
+
[this.identity, ...statuses]
|
|
533
|
+
);
|
|
534
|
+
return rows.map((row) => parseJson(row.data));
|
|
535
|
+
} catch (error) {
|
|
536
|
+
if (error instanceof TreeStoreError) throw error;
|
|
537
|
+
throw new TreeStoreError(
|
|
538
|
+
`Failed to get leaves with status: ${error.message}`,
|
|
539
|
+
error
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
519
544
|
/**
|
|
520
545
|
* Set leaves from a refresh operation.
|
|
521
546
|
* @param {Array} leaves - Available leaves from operators
|