@flashnet/sdk 0.5.6 → 0.5.8
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/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/node_modules/@buildonspark/spark-sdk/dist/buffer-C7zVfCZb.d.ts +2 -0
- package/dist/cjs/node_modules/@buildonspark/spark-sdk/dist/buffer-C7zVfCZb.d.ts.map +1 -0
- package/dist/cjs/src/api/typed-endpoints.d.ts +11 -0
- package/dist/cjs/src/api/typed-endpoints.d.ts.map +1 -1
- package/dist/cjs/src/api/typed-endpoints.js +15 -0
- package/dist/cjs/src/api/typed-endpoints.js.map +1 -1
- package/dist/cjs/src/client/FlashnetClient.d.ts +37 -1
- package/dist/cjs/src/client/FlashnetClient.d.ts.map +1 -1
- package/dist/cjs/src/client/FlashnetClient.js +253 -111
- package/dist/cjs/src/client/FlashnetClient.js.map +1 -1
- package/dist/cjs/src/types/index.d.ts +35 -0
- package/dist/cjs/src/types/index.d.ts.map +1 -1
- package/dist/cjs/src/utils/intents.d.ts +13 -0
- package/dist/cjs/src/utils/intents.d.ts.map +1 -1
- package/dist/cjs/src/utils/intents.js +27 -0
- package/dist/cjs/src/utils/intents.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@buildonspark/spark-sdk/dist/buffer-C7zVfCZb.d.ts +2 -0
- package/dist/esm/node_modules/@buildonspark/spark-sdk/dist/buffer-C7zVfCZb.d.ts.map +1 -0
- package/dist/esm/src/api/typed-endpoints.d.ts +11 -0
- package/dist/esm/src/api/typed-endpoints.d.ts.map +1 -1
- package/dist/esm/src/api/typed-endpoints.js +15 -0
- package/dist/esm/src/api/typed-endpoints.js.map +1 -1
- package/dist/esm/src/client/FlashnetClient.d.ts +37 -1
- package/dist/esm/src/client/FlashnetClient.d.ts.map +1 -1
- package/dist/esm/src/client/FlashnetClient.js +254 -112
- package/dist/esm/src/client/FlashnetClient.js.map +1 -1
- package/dist/esm/src/types/index.d.ts +35 -0
- package/dist/esm/src/types/index.d.ts.map +1 -1
- package/dist/esm/src/utils/intents.d.ts +13 -0
- package/dist/esm/src/utils/intents.d.ts.map +1 -1
- package/dist/esm/src/utils/intents.js +27 -1
- package/dist/esm/src/utils/intents.js.map +1 -1
- package/package.json +11 -7
- package/dist/cjs/node_modules/@buildonspark/spark-sdk/dist/buffer-DK3I_h9P.d.ts +0 -2
- package/dist/cjs/node_modules/@buildonspark/spark-sdk/dist/buffer-DK3I_h9P.d.ts.map +0 -1
- package/dist/esm/node_modules/@buildonspark/spark-sdk/dist/buffer-DK3I_h9P.d.ts +0 -2
- package/dist/esm/node_modules/@buildonspark/spark-sdk/dist/buffer-DK3I_h9P.d.ts.map +0 -1
|
@@ -1002,6 +1002,53 @@ class FlashnetClient {
|
|
|
1002
1002
|
}
|
|
1003
1003
|
return response;
|
|
1004
1004
|
}
|
|
1005
|
+
// LP Lock & Transfer Operations
|
|
1006
|
+
/**
|
|
1007
|
+
* Lock an LP position to prevent withdrawal until expiry.
|
|
1008
|
+
* Locks can only be set or extended, never shortened.
|
|
1009
|
+
* @param poolId Pool ID (LP identity public key)
|
|
1010
|
+
* @param lockUntilTimestamp Unix timestamp (seconds). "0" = indefinite lock.
|
|
1011
|
+
*/
|
|
1012
|
+
async lockPosition(poolId, lockUntilTimestamp, opts) {
|
|
1013
|
+
await this.ensureInitialized();
|
|
1014
|
+
await this.ensurePingOk();
|
|
1015
|
+
const nonce = index$2.generateNonce();
|
|
1016
|
+
const intentMessage = intents.generateLockPositionIntentMessage({
|
|
1017
|
+
userPublicKey: this.publicKey,
|
|
1018
|
+
lpIdentityPublicKey: poolId,
|
|
1019
|
+
lockUntilTimestamp,
|
|
1020
|
+
tickLower: opts?.tickLower,
|
|
1021
|
+
tickUpper: opts?.tickUpper,
|
|
1022
|
+
nonce,
|
|
1023
|
+
});
|
|
1024
|
+
const messageHash = sha256__default.default(intentMessage);
|
|
1025
|
+
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1026
|
+
const request = {
|
|
1027
|
+
userPublicKey: this.publicKey,
|
|
1028
|
+
poolId,
|
|
1029
|
+
lockUntilTimestamp,
|
|
1030
|
+
tickLower: opts?.tickLower,
|
|
1031
|
+
tickUpper: opts?.tickUpper,
|
|
1032
|
+
nonce,
|
|
1033
|
+
signature: hex.getHexFromUint8Array(signature),
|
|
1034
|
+
};
|
|
1035
|
+
const response = await this.typedApi.lockPosition(request);
|
|
1036
|
+
if (!response.accepted) {
|
|
1037
|
+
const errorMessage = response.error || "Lock position rejected by the AMM";
|
|
1038
|
+
throw new Error(errorMessage);
|
|
1039
|
+
}
|
|
1040
|
+
return response;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* List LP position locks for a pool. Read-only, no signature required.
|
|
1044
|
+
* @param poolId Pool ID (LP identity public key)
|
|
1045
|
+
* @param ownerPublicKey Optional filter by owner
|
|
1046
|
+
*/
|
|
1047
|
+
async getPositionLocks(poolId, ownerPublicKey) {
|
|
1048
|
+
await this.ensureInitialized();
|
|
1049
|
+
const response = await this.typedApi.getPositionLocks(poolId, ownerPublicKey);
|
|
1050
|
+
return response.locks;
|
|
1051
|
+
}
|
|
1005
1052
|
// Host Operations
|
|
1006
1053
|
/**
|
|
1007
1054
|
* Register as a host
|
|
@@ -2099,8 +2146,16 @@ class FlashnetClient {
|
|
|
2099
2146
|
const assetOutAddress = quote.tokenIsAssetA
|
|
2100
2147
|
? pool.assetBAddress
|
|
2101
2148
|
: pool.assetAAddress;
|
|
2102
|
-
|
|
2103
|
-
|
|
2149
|
+
const effectiveMaxLightningFee = maxLightningFeeSats ?? quote.estimatedLightningFee;
|
|
2150
|
+
// Floor minAmountOut at invoiceAmount + fee so the swap never returns
|
|
2151
|
+
// less BTC than the lightning payment requires.
|
|
2152
|
+
const slippageMin = this.calculateMinAmountOut(quote.btcAmountRequired, maxSlippageBps);
|
|
2153
|
+
const baseBtcNeeded = !quote.isZeroAmountInvoice
|
|
2154
|
+
? BigInt(quote.invoiceAmountSats) + BigInt(effectiveMaxLightningFee)
|
|
2155
|
+
: 0n;
|
|
2156
|
+
const minBtcOut = BigInt(slippageMin) >= baseBtcNeeded
|
|
2157
|
+
? slippageMin
|
|
2158
|
+
: baseBtcNeeded.toString();
|
|
2104
2159
|
// Execute the swap
|
|
2105
2160
|
const swapResponse = await this.executeSwap({
|
|
2106
2161
|
poolId: quote.poolId,
|
|
@@ -2125,138 +2180,158 @@ class FlashnetClient {
|
|
|
2125
2180
|
error: swapResponse.error || "Swap was not accepted",
|
|
2126
2181
|
};
|
|
2127
2182
|
}
|
|
2128
|
-
// Step 5:
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
const effectiveMaxLightningFee = maxLightningFeeSats ?? quote.estimatedLightningFee;
|
|
2133
|
-
const btcNeededForPayment = invoiceAmountSats + effectiveMaxLightningFee;
|
|
2134
|
-
const balance = await this.getBalance();
|
|
2135
|
-
canPayImmediately = balance.balance >= bigint.safeBigInt(btcNeededForPayment);
|
|
2136
|
-
}
|
|
2137
|
-
if (!canPayImmediately) {
|
|
2138
|
-
const transferComplete = await this.waitForTransferCompletion(swapResponse.outboundTransferId, transferTimeoutMs);
|
|
2139
|
-
if (!transferComplete) {
|
|
2140
|
-
return {
|
|
2141
|
-
success: false,
|
|
2142
|
-
poolId: quote.poolId,
|
|
2143
|
-
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2144
|
-
btcAmountReceived: swapResponse.amountOut || "0",
|
|
2145
|
-
swapTransferId: swapResponse.outboundTransferId,
|
|
2146
|
-
ammFeePaid: quote.estimatedAmmFee,
|
|
2147
|
-
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2148
|
-
error: "Transfer did not complete within timeout",
|
|
2149
|
-
};
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
// Step 6: Calculate Lightning fee and payment amount
|
|
2153
|
-
const effectiveMaxLightningFee = maxLightningFeeSats ?? quote.estimatedLightningFee;
|
|
2154
|
-
const btcReceived = swapResponse.amountOut || quote.btcAmountRequired;
|
|
2155
|
-
// Step 7: Pay the Lightning invoice
|
|
2183
|
+
// Step 5: Claim the swap output and refresh wallet state.
|
|
2184
|
+
// Suppress leaf optimization for the entire claim-to-pay window so
|
|
2185
|
+
// the SSP cannot swap away the leaves we need for lightning payment.
|
|
2186
|
+
const restoreOptimization = this.suppressOptimization();
|
|
2156
2187
|
try {
|
|
2157
|
-
let
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
const
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2188
|
+
let canPayImmediately = false;
|
|
2189
|
+
if (!quote.isZeroAmountInvoice && useExistingBtcBalance) {
|
|
2190
|
+
const invoiceAmountSats = await this.decodeInvoiceAmount(invoice);
|
|
2191
|
+
const btcNeededForPayment = invoiceAmountSats + effectiveMaxLightningFee;
|
|
2192
|
+
const balance = await this.getBalance();
|
|
2193
|
+
canPayImmediately =
|
|
2194
|
+
balance.balance >= bigint.safeBigInt(btcNeededForPayment);
|
|
2195
|
+
}
|
|
2196
|
+
if (!canPayImmediately) {
|
|
2197
|
+
const claimed = await this.instaClaimTransfer(swapResponse.outboundTransferId, transferTimeoutMs);
|
|
2198
|
+
if (!claimed) {
|
|
2165
2199
|
return {
|
|
2166
2200
|
success: false,
|
|
2167
2201
|
poolId: quote.poolId,
|
|
2168
2202
|
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2169
|
-
btcAmountReceived:
|
|
2203
|
+
btcAmountReceived: swapResponse.amountOut || "0",
|
|
2170
2204
|
swapTransferId: swapResponse.outboundTransferId,
|
|
2171
2205
|
ammFeePaid: quote.estimatedAmmFee,
|
|
2172
2206
|
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2173
|
-
error:
|
|
2207
|
+
error: "Transfer did not complete within timeout",
|
|
2174
2208
|
};
|
|
2175
2209
|
}
|
|
2176
|
-
invoiceAmountPaid = Number(amountToPay);
|
|
2177
|
-
lightningPayment = await this._wallet.payLightningInvoice({
|
|
2178
|
-
invoice,
|
|
2179
|
-
amountSats: invoiceAmountPaid,
|
|
2180
|
-
maxFeeSats: effectiveMaxLightningFee,
|
|
2181
|
-
preferSpark,
|
|
2182
|
-
});
|
|
2183
2210
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2211
|
+
// Step 6: Calculate payment amount
|
|
2212
|
+
const requestedMaxLightningFee = effectiveMaxLightningFee;
|
|
2213
|
+
const btcReceived = swapResponse.amountOut || quote.btcAmountRequired;
|
|
2214
|
+
// Cap the lightning fee budget to what the wallet can actually cover.
|
|
2215
|
+
// The swap output may be slightly less than quoted due to rounding or
|
|
2216
|
+
// price movement between quote and execution. The Spark SDK requires
|
|
2217
|
+
// invoiceAmount + maxFeeSats <= balance, so we adjust maxFeeSats down
|
|
2218
|
+
// when the actual BTC received is less than expected.
|
|
2219
|
+
let cappedMaxLightningFee = requestedMaxLightningFee;
|
|
2220
|
+
if (!quote.isZeroAmountInvoice) {
|
|
2221
|
+
const actualBtc = bigint.safeBigInt(btcReceived);
|
|
2222
|
+
const invoiceAmount = bigint.safeBigInt(quote.invoiceAmountSats);
|
|
2223
|
+
const available = actualBtc - invoiceAmount;
|
|
2224
|
+
if (available > 0n && available < bigint.safeBigInt(cappedMaxLightningFee)) {
|
|
2225
|
+
cappedMaxLightningFee = Number(available);
|
|
2226
|
+
}
|
|
2191
2227
|
}
|
|
2192
|
-
//
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2202
|
-
btcAmountReceived: btcReceived,
|
|
2203
|
-
swapTransferId: swapResponse.outboundTransferId,
|
|
2204
|
-
lightningPaymentId: lightningPayment.id,
|
|
2205
|
-
ammFeePaid: quote.estimatedAmmFee,
|
|
2206
|
-
lightningFeePaid: effectiveMaxLightningFee,
|
|
2207
|
-
invoiceAmountPaid,
|
|
2208
|
-
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2209
|
-
sparkLightningTransferId,
|
|
2210
|
-
};
|
|
2211
|
-
}
|
|
2212
|
-
catch (lightningError) {
|
|
2213
|
-
// Lightning payment failed after swap succeeded
|
|
2214
|
-
const lightningErrorMessage = lightningError instanceof Error
|
|
2215
|
-
? lightningError.message
|
|
2216
|
-
: String(lightningError);
|
|
2217
|
-
// Attempt rollback if requested
|
|
2218
|
-
if (rollbackOnFailure) {
|
|
2219
|
-
try {
|
|
2220
|
-
const rollbackResult = await this.rollbackSwap(quote.poolId, btcReceived, tokenAddress, maxSlippageBps);
|
|
2221
|
-
if (rollbackResult.success) {
|
|
2228
|
+
// Step 7: Pay the Lightning invoice
|
|
2229
|
+
try {
|
|
2230
|
+
let lightningPayment;
|
|
2231
|
+
let invoiceAmountPaid;
|
|
2232
|
+
if (quote.isZeroAmountInvoice) {
|
|
2233
|
+
const actualBtc = bigint.safeBigInt(btcReceived);
|
|
2234
|
+
const lnFee = bigint.safeBigInt(cappedMaxLightningFee);
|
|
2235
|
+
const amountToPay = actualBtc - lnFee;
|
|
2236
|
+
if (amountToPay <= 0n) {
|
|
2222
2237
|
return {
|
|
2223
2238
|
success: false,
|
|
2224
2239
|
poolId: quote.poolId,
|
|
2225
|
-
tokenAmountSpent:
|
|
2226
|
-
btcAmountReceived:
|
|
2240
|
+
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2241
|
+
btcAmountReceived: btcReceived,
|
|
2227
2242
|
swapTransferId: swapResponse.outboundTransferId,
|
|
2228
2243
|
ammFeePaid: quote.estimatedAmmFee,
|
|
2229
2244
|
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2230
|
-
error: `
|
|
2245
|
+
error: `BTC received (${btcReceived} sats) is not enough to cover lightning fee (${cappedMaxLightningFee} sats).`,
|
|
2231
2246
|
};
|
|
2232
2247
|
}
|
|
2248
|
+
invoiceAmountPaid = Number(amountToPay);
|
|
2249
|
+
lightningPayment = await this._wallet.payLightningInvoice({
|
|
2250
|
+
invoice,
|
|
2251
|
+
amountSats: invoiceAmountPaid,
|
|
2252
|
+
maxFeeSats: cappedMaxLightningFee,
|
|
2253
|
+
preferSpark,
|
|
2254
|
+
});
|
|
2233
2255
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
:
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
poolId: quote.poolId,
|
|
2241
|
-
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2242
|
-
btcAmountReceived: btcReceived,
|
|
2243
|
-
swapTransferId: swapResponse.outboundTransferId,
|
|
2244
|
-
ammFeePaid: quote.estimatedAmmFee,
|
|
2245
|
-
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2246
|
-
error: `Lightning payment failed: ${lightningErrorMessage}. Rollback also failed: ${rollbackErrorMessage}. BTC remains in wallet.`,
|
|
2247
|
-
};
|
|
2256
|
+
else {
|
|
2257
|
+
lightningPayment = await this._wallet.payLightningInvoice({
|
|
2258
|
+
invoice,
|
|
2259
|
+
maxFeeSats: cappedMaxLightningFee,
|
|
2260
|
+
preferSpark,
|
|
2261
|
+
});
|
|
2248
2262
|
}
|
|
2263
|
+
// Extract the Spark transfer ID from the lightning payment result.
|
|
2264
|
+
// payLightningInvoice returns LightningSendRequest | WalletTransfer:
|
|
2265
|
+
// - LightningSendRequest has .transfer?.sparkId (the Sparkscan-visible transfer ID)
|
|
2266
|
+
// - WalletTransfer (Spark-to-Spark) has .id directly as the transfer ID
|
|
2267
|
+
// Note: lightningPayment.id (the SSP request ID) is already returned as lightningPaymentId
|
|
2268
|
+
const sparkLightningTransferId = lightningPayment.transfer?.sparkId;
|
|
2269
|
+
return {
|
|
2270
|
+
success: true,
|
|
2271
|
+
poolId: quote.poolId,
|
|
2272
|
+
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2273
|
+
btcAmountReceived: btcReceived,
|
|
2274
|
+
swapTransferId: swapResponse.outboundTransferId,
|
|
2275
|
+
lightningPaymentId: lightningPayment.id,
|
|
2276
|
+
ammFeePaid: quote.estimatedAmmFee,
|
|
2277
|
+
lightningFeePaid: cappedMaxLightningFee,
|
|
2278
|
+
invoiceAmountPaid,
|
|
2279
|
+
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2280
|
+
sparkLightningTransferId,
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
2283
|
+
catch (lightningError) {
|
|
2284
|
+
// Lightning payment failed after swap succeeded
|
|
2285
|
+
const lightningErrorMessage = lightningError instanceof Error
|
|
2286
|
+
? lightningError.message
|
|
2287
|
+
: String(lightningError);
|
|
2288
|
+
// Attempt rollback if requested
|
|
2289
|
+
if (rollbackOnFailure) {
|
|
2290
|
+
try {
|
|
2291
|
+
const rollbackResult = await this.rollbackSwap(quote.poolId, btcReceived, tokenAddress, maxSlippageBps);
|
|
2292
|
+
if (rollbackResult.success) {
|
|
2293
|
+
return {
|
|
2294
|
+
success: false,
|
|
2295
|
+
poolId: quote.poolId,
|
|
2296
|
+
tokenAmountSpent: "0", // Rolled back
|
|
2297
|
+
btcAmountReceived: "0",
|
|
2298
|
+
swapTransferId: swapResponse.outboundTransferId,
|
|
2299
|
+
ammFeePaid: quote.estimatedAmmFee,
|
|
2300
|
+
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2301
|
+
error: `Lightning payment failed: ${lightningErrorMessage}. Funds rolled back to ${rollbackResult.tokenAmount} tokens.`,
|
|
2302
|
+
};
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
catch (rollbackError) {
|
|
2306
|
+
const rollbackErrorMessage = rollbackError instanceof Error
|
|
2307
|
+
? rollbackError.message
|
|
2308
|
+
: String(rollbackError);
|
|
2309
|
+
return {
|
|
2310
|
+
success: false,
|
|
2311
|
+
poolId: quote.poolId,
|
|
2312
|
+
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2313
|
+
btcAmountReceived: btcReceived,
|
|
2314
|
+
swapTransferId: swapResponse.outboundTransferId,
|
|
2315
|
+
ammFeePaid: quote.estimatedAmmFee,
|
|
2316
|
+
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2317
|
+
error: `Lightning payment failed: ${lightningErrorMessage}. Rollback also failed: ${rollbackErrorMessage}. BTC remains in wallet.`,
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
return {
|
|
2322
|
+
success: false,
|
|
2323
|
+
poolId: quote.poolId,
|
|
2324
|
+
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2325
|
+
btcAmountReceived: btcReceived,
|
|
2326
|
+
swapTransferId: swapResponse.outboundTransferId,
|
|
2327
|
+
ammFeePaid: quote.estimatedAmmFee,
|
|
2328
|
+
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2329
|
+
error: `Lightning payment failed: ${lightningErrorMessage}. BTC (${btcReceived} sats) remains in wallet.`,
|
|
2330
|
+
};
|
|
2249
2331
|
}
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
tokenAmountSpent: quote.tokenAmountRequired,
|
|
2254
|
-
btcAmountReceived: btcReceived,
|
|
2255
|
-
swapTransferId: swapResponse.outboundTransferId,
|
|
2256
|
-
ammFeePaid: quote.estimatedAmmFee,
|
|
2257
|
-
sparkTokenTransferId: swapResponse.inboundSparkTransferId,
|
|
2258
|
-
error: `Lightning payment failed: ${lightningErrorMessage}. BTC (${btcReceived} sats) remains in wallet.`,
|
|
2259
|
-
};
|
|
2332
|
+
}
|
|
2333
|
+
finally {
|
|
2334
|
+
restoreOptimization();
|
|
2260
2335
|
}
|
|
2261
2336
|
}
|
|
2262
2337
|
catch (error) {
|
|
@@ -2777,6 +2852,73 @@ class FlashnetClient {
|
|
|
2777
2852
|
}
|
|
2778
2853
|
return false;
|
|
2779
2854
|
}
|
|
2855
|
+
/**
|
|
2856
|
+
* Suppress leaf optimization on the wallet. Sets the internal
|
|
2857
|
+
* optimizationInProgress flag so optimizeLeaves() returns immediately.
|
|
2858
|
+
* Returns a restore function that clears the flag.
|
|
2859
|
+
* @private
|
|
2860
|
+
*/
|
|
2861
|
+
suppressOptimization() {
|
|
2862
|
+
const w = this._wallet;
|
|
2863
|
+
const was = w.optimizationInProgress;
|
|
2864
|
+
w.optimizationInProgress = true;
|
|
2865
|
+
return () => {
|
|
2866
|
+
w.optimizationInProgress = was;
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Insta-claim: listen for the wallet's stream event that fires when
|
|
2871
|
+
* the coordinator broadcasts the transfer. The stream auto-claims
|
|
2872
|
+
* incoming transfers, so no polling is needed.
|
|
2873
|
+
*
|
|
2874
|
+
* After claim, refreshes the leaf cache from the coordinator to
|
|
2875
|
+
* ensure the balance is current.
|
|
2876
|
+
*
|
|
2877
|
+
* Caller is responsible for suppressing optimization around this call
|
|
2878
|
+
* if the claimed leaves must not be swapped before spending.
|
|
2879
|
+
* @private
|
|
2880
|
+
*/
|
|
2881
|
+
async instaClaimTransfer(transferId, timeoutMs) {
|
|
2882
|
+
const w = this._wallet;
|
|
2883
|
+
const claimed = await new Promise((resolve) => {
|
|
2884
|
+
let done = false;
|
|
2885
|
+
const finish = (value) => {
|
|
2886
|
+
if (done) {
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
done = true;
|
|
2890
|
+
clearTimeout(timer);
|
|
2891
|
+
try {
|
|
2892
|
+
w.removeListener?.("transfer:claimed", handler);
|
|
2893
|
+
}
|
|
2894
|
+
catch {
|
|
2895
|
+
// Ignore
|
|
2896
|
+
}
|
|
2897
|
+
resolve(value);
|
|
2898
|
+
};
|
|
2899
|
+
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
2900
|
+
const handler = (claimedId) => {
|
|
2901
|
+
if (claimedId === transferId) {
|
|
2902
|
+
finish(true);
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2905
|
+
// The wallet's background gRPC stream auto-claims transfers.
|
|
2906
|
+
// We just listen for the event.
|
|
2907
|
+
if (typeof w.on === "function") {
|
|
2908
|
+
w.on("transfer:claimed", handler);
|
|
2909
|
+
}
|
|
2910
|
+
else {
|
|
2911
|
+
// No event support, fall back to passive polling
|
|
2912
|
+
clearTimeout(timer);
|
|
2913
|
+
this.pollForTransferCompletion(transferId, timeoutMs).then(resolve);
|
|
2914
|
+
}
|
|
2915
|
+
});
|
|
2916
|
+
if (claimed) {
|
|
2917
|
+
const leaves = await this._wallet.getLeaves(true);
|
|
2918
|
+
w.leaves = leaves;
|
|
2919
|
+
}
|
|
2920
|
+
return claimed;
|
|
2921
|
+
}
|
|
2780
2922
|
/**
|
|
2781
2923
|
* Get Lightning fee estimate for an invoice
|
|
2782
2924
|
* @private
|