@arkade-os/boltz-swap 0.3.39 → 0.3.41
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/README.md +29 -0
- package/dist/{arkade-swaps-Uet3tgN6.d.ts → arkade-swaps-C3sUFr5f.d.cts} +76 -5
- package/dist/{arkade-swaps-DG9UepoS.d.cts → arkade-swaps-LvsGHtre.d.ts} +76 -5
- package/dist/{chunk-DNCIVDU5.js → chunk-CWY37W4B.js} +1 -1
- package/dist/{chunk-CFB2NNGT.js → chunk-UXYHW7KV.js} +248 -99
- package/dist/expo/background.cjs +247 -99
- package/dist/expo/background.d.cts +3 -3
- package/dist/expo/background.d.ts +3 -3
- package/dist/expo/background.js +2 -2
- package/dist/expo/index.cjs +250 -99
- package/dist/expo/index.d.cts +9 -5
- package/dist/expo/index.d.ts +9 -5
- package/dist/expo/index.js +5 -2
- package/dist/index.cjs +266 -99
- package/dist/index.d.cts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +20 -1
- package/dist/repositories/realm/index.d.cts +1 -1
- package/dist/repositories/realm/index.d.ts +1 -1
- package/dist/repositories/sqlite/index.d.cts +1 -1
- package/dist/repositories/sqlite/index.d.ts +1 -1
- package/dist/{swapsPollProcessor-BlyUrhtO.d.cts → swapsPollProcessor-CGMXUKPe.d.cts} +1 -1
- package/dist/{swapsPollProcessor-Bv4Z2R7g.d.ts → swapsPollProcessor-CuDM6sxV.d.ts} +1 -1
- package/dist/{types-D97i1LFu.d.cts → types-8NrCdOpS.d.cts} +51 -1
- package/dist/{types-D97i1LFu.d.ts → types-8NrCdOpS.d.ts} +51 -1
- package/package.json +2 -2
package/dist/expo/index.cjs
CHANGED
|
@@ -239,6 +239,22 @@ var isSubmarineFinalStatus = (status) => {
|
|
|
239
239
|
var isSubmarineRefundableStatus = (status) => {
|
|
240
240
|
return ["invoice.failedToPay", "transaction.lockupFailed", "swap.expired"].includes(status);
|
|
241
241
|
};
|
|
242
|
+
var SUBMARINE_STATUS_PROGRESSION = [
|
|
243
|
+
"swap.created",
|
|
244
|
+
"invoice.set",
|
|
245
|
+
"transaction.mempool",
|
|
246
|
+
"transaction.confirmed",
|
|
247
|
+
"invoice.pending",
|
|
248
|
+
"invoice.paid",
|
|
249
|
+
"transaction.claim.pending",
|
|
250
|
+
"transaction.claimed"
|
|
251
|
+
];
|
|
252
|
+
var hasSubmarineStatusReached = (status, target) => {
|
|
253
|
+
const progression = SUBMARINE_STATUS_PROGRESSION;
|
|
254
|
+
const statusIndex = progression.indexOf(status);
|
|
255
|
+
const targetIndex = progression.indexOf(target);
|
|
256
|
+
return statusIndex >= 0 && targetIndex >= 0 && statusIndex >= targetIndex;
|
|
257
|
+
};
|
|
242
258
|
var isSubmarineSuccessStatus = (status) => {
|
|
243
259
|
return status === "transaction.claimed";
|
|
244
260
|
};
|
|
@@ -1281,10 +1297,10 @@ var import_light_bolt11_decoder = __toESM(require("light-bolt11-decoder"), 1);
|
|
|
1281
1297
|
var import_sdk2 = require("@arkade-os/sdk");
|
|
1282
1298
|
var decodeInvoice = (invoice) => {
|
|
1283
1299
|
const decoded = import_light_bolt11_decoder.default.decode(invoice);
|
|
1284
|
-
const millisats =
|
|
1300
|
+
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1285
1301
|
return {
|
|
1286
1302
|
expiry: decoded.expiry ?? 3600,
|
|
1287
|
-
amountSats:
|
|
1303
|
+
amountSats: Number(millisats / 1000n),
|
|
1288
1304
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1289
1305
|
paymentHash: decoded.sections.find((s) => s.name === "payment_hash")?.value ?? ""
|
|
1290
1306
|
};
|
|
@@ -2899,6 +2915,19 @@ var createVHTLCScript = (args) => {
|
|
|
2899
2915
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
2900
2916
|
return { vhtlcScript, vhtlcAddress };
|
|
2901
2917
|
};
|
|
2918
|
+
var candidateServerPubkeys = (arkInfo) => {
|
|
2919
|
+
const current = import_base8.hex.encode(normalizeToXOnlyKey(import_base8.hex.decode(arkInfo.signerPubkey), "server"));
|
|
2920
|
+
const seen = /* @__PURE__ */ new Set([current]);
|
|
2921
|
+
const candidates = [current];
|
|
2922
|
+
for (const deprecated of arkInfo.deprecatedSigners ?? []) {
|
|
2923
|
+
if (!deprecated.pubkey) continue;
|
|
2924
|
+
const key = import_base8.hex.encode(normalizeToXOnlyKey(import_base8.hex.decode(deprecated.pubkey), "server"));
|
|
2925
|
+
if (seen.has(key)) continue;
|
|
2926
|
+
seen.add(key);
|
|
2927
|
+
candidates.push(key);
|
|
2928
|
+
}
|
|
2929
|
+
return candidates;
|
|
2930
|
+
};
|
|
2902
2931
|
var joinBatch = async (arkProvider, identity, input, output, {
|
|
2903
2932
|
forfeitPubkey,
|
|
2904
2933
|
forfeitAddress,
|
|
@@ -3313,6 +3342,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3313
3342
|
...args.description?.trim() ? { description: args.description.trim() } : {}
|
|
3314
3343
|
};
|
|
3315
3344
|
const swapResponse = await this.swapProvider.createReverseSwap(swapRequest);
|
|
3345
|
+
const decodedInvoice = decodeInvoice(swapResponse.invoice);
|
|
3346
|
+
if (decodedInvoice.paymentHash !== preimageHash) {
|
|
3347
|
+
throw new SwapError({ message: "Preimage hash does not match invoice payment hash" });
|
|
3348
|
+
}
|
|
3316
3349
|
const pendingSwap = {
|
|
3317
3350
|
id: swapResponse.id,
|
|
3318
3351
|
type: "reverse",
|
|
@@ -3356,27 +3389,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3356
3389
|
"boltz",
|
|
3357
3390
|
pendingSwap.id
|
|
3358
3391
|
);
|
|
3359
|
-
const serverXOnly =
|
|
3360
|
-
|
|
3361
|
-
"server",
|
|
3362
|
-
pendingSwap.id
|
|
3363
|
-
);
|
|
3364
|
-
const { vhtlcScript, vhtlcAddress } = this.createVHTLCScript({
|
|
3365
|
-
network: arkInfo.network,
|
|
3392
|
+
const { vhtlcScript, serverXOnlyPublicKey: serverXOnly } = this.resolveVHTLCForLockup({
|
|
3393
|
+
arkInfo,
|
|
3366
3394
|
preimageHash: (0, import_sha23.sha256)(preimage),
|
|
3367
3395
|
receiverPubkey: import_base9.hex.encode(receiverXOnly),
|
|
3368
3396
|
senderPubkey: import_base9.hex.encode(senderXOnly),
|
|
3369
|
-
|
|
3370
|
-
|
|
3397
|
+
timeoutBlockHeights: vhtlcTimeouts,
|
|
3398
|
+
lockupAddress,
|
|
3399
|
+
swapId: pendingSwap.id
|
|
3371
3400
|
});
|
|
3372
|
-
if (!vhtlcScript.claimScript)
|
|
3373
|
-
throw new Error(
|
|
3374
|
-
`Swap ${pendingSwap.id}: failed to create VHTLC script for reverse swap`
|
|
3375
|
-
);
|
|
3376
|
-
if (vhtlcAddress !== lockupAddress)
|
|
3377
|
-
throw new Error(
|
|
3378
|
-
`Swap ${pendingSwap.id}: VHTLC address mismatch. Expected ${lockupAddress}, got ${vhtlcAddress}`
|
|
3379
|
-
);
|
|
3380
3401
|
let unspentVtxos = [];
|
|
3381
3402
|
let rawVtxos = [];
|
|
3382
3403
|
for (let attempt = 1; attempt <= CLAIM_VTXO_RETRY_ATTEMPTS; attempt++) {
|
|
@@ -3527,16 +3548,6 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3527
3548
|
this.swapProvider.monitorSwap(pendingSwap.id, onStatusUpdate).catch(reject);
|
|
3528
3549
|
});
|
|
3529
3550
|
}
|
|
3530
|
-
// =========================================================================
|
|
3531
|
-
// Lightning: Submarine swaps (send Arkade -> Lightning)
|
|
3532
|
-
// =========================================================================
|
|
3533
|
-
/**
|
|
3534
|
-
* Sends a Lightning payment via a submarine swap (Arkade → Lightning).
|
|
3535
|
-
* Creates the swap, sends funds, and waits for settlement. Auto-refunds on failure.
|
|
3536
|
-
* @param args.invoice - BOLT11 Lightning invoice to pay.
|
|
3537
|
-
* @returns The amount paid, preimage (proof of payment), and transaction ID.
|
|
3538
|
-
* @throws {TransactionFailedError} If the payment fails (auto-refunds if possible).
|
|
3539
|
-
*/
|
|
3540
3551
|
async sendLightningPayment(args) {
|
|
3541
3552
|
const pendingSwap = await this.createSubmarineSwap(args);
|
|
3542
3553
|
if (!pendingSwap.response.address)
|
|
@@ -3547,6 +3558,18 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3547
3558
|
amount: pendingSwap.response.expectedAmount
|
|
3548
3559
|
});
|
|
3549
3560
|
try {
|
|
3561
|
+
if (args.waitFor === "funded") {
|
|
3562
|
+
if (!this.swapManager) {
|
|
3563
|
+
logger.warn(
|
|
3564
|
+
`Swap ${pendingSwap.id}: sendLightningPayment with waitFor "funded" but SwapManager is disabled \u2014 a failure after this promise resolves is only persisted as refundable, not auto-refunded; recover via restoreSwaps/recoverSubmarineFunds`
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
await this.waitForSwapFunded(pendingSwap);
|
|
3568
|
+
return {
|
|
3569
|
+
amount: pendingSwap.response.expectedAmount,
|
|
3570
|
+
txid
|
|
3571
|
+
};
|
|
3572
|
+
}
|
|
3550
3573
|
const { preimage } = await this.waitForSwapSettlement(pendingSwap);
|
|
3551
3574
|
return {
|
|
3552
3575
|
amount: pendingSwap.response.expectedAmount,
|
|
@@ -3618,11 +3641,6 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3618
3641
|
"our",
|
|
3619
3642
|
swap.id
|
|
3620
3643
|
);
|
|
3621
|
-
const serverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
3622
|
-
import_base9.hex.decode(resolvedArkInfo.signerPubkey),
|
|
3623
|
-
"server",
|
|
3624
|
-
swap.id
|
|
3625
|
-
);
|
|
3626
3644
|
const { claimPublicKey, timeoutBlockHeights: vhtlcTimeouts } = swap.response;
|
|
3627
3645
|
if (!claimPublicKey || !vhtlcTimeouts)
|
|
3628
3646
|
throw new Error(`Swap ${swap.id}: incomplete submarine swap response`);
|
|
@@ -3631,20 +3649,19 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3631
3649
|
"boltz",
|
|
3632
3650
|
swap.id
|
|
3633
3651
|
);
|
|
3634
|
-
const
|
|
3635
|
-
|
|
3652
|
+
const lockupAddress = swap.response.address;
|
|
3653
|
+
if (!lockupAddress)
|
|
3654
|
+
throw new Error(`Swap ${swap.id}: missing lockup address in submarine swap response`);
|
|
3655
|
+
const { vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
3656
|
+
arkInfo: resolvedArkInfo,
|
|
3636
3657
|
preimageHash: import_base9.hex.decode(preimageHash),
|
|
3637
3658
|
receiverPubkey: import_base9.hex.encode(boltzXOnlyPublicKey),
|
|
3638
3659
|
senderPubkey: import_base9.hex.encode(ourXOnlyPublicKey),
|
|
3639
|
-
|
|
3640
|
-
|
|
3660
|
+
timeoutBlockHeights: vhtlcTimeouts,
|
|
3661
|
+
lockupAddress,
|
|
3662
|
+
swapId: swap.id
|
|
3641
3663
|
});
|
|
3642
|
-
|
|
3643
|
-
throw new Error(`Swap ${swap.id}: failed to create VHTLC script for submarine swap`);
|
|
3644
|
-
if (vhtlcAddress !== swap.response.address)
|
|
3645
|
-
throw new Error(
|
|
3646
|
-
`VHTLC address mismatch for swap ${swap.id}: expected ${swap.response.address}, got ${vhtlcAddress}`
|
|
3647
|
-
);
|
|
3664
|
+
const vhtlcAddress = lockupAddress;
|
|
3648
3665
|
const vhtlcPkScriptHex = import_base9.hex.encode(vhtlcScript.pkScript);
|
|
3649
3666
|
return {
|
|
3650
3667
|
arkInfo: resolvedArkInfo,
|
|
@@ -4054,6 +4071,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4054
4071
|
}
|
|
4055
4072
|
/**
|
|
4056
4073
|
* Waits for a submarine swap's Lightning payment to settle.
|
|
4074
|
+
* Resolves only at the terminal "transaction.claimed" status, once Boltz
|
|
4075
|
+
* has swept the HTLC. To resolve as soon as the payment is in flight, use
|
|
4076
|
+
* {@link waitForSwapFunded} instead.
|
|
4057
4077
|
* @param pendingSwap - The submarine swap to monitor.
|
|
4058
4078
|
* @returns The preimage from the settled Lightning payment (proof of payment).
|
|
4059
4079
|
* @throws {SwapExpiredError} If the swap expires.
|
|
@@ -4061,19 +4081,59 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4061
4081
|
* @throws {TransactionLockupFailedError} If the lockup transaction fails.
|
|
4062
4082
|
*/
|
|
4063
4083
|
async waitForSwapSettlement(pendingSwap) {
|
|
4084
|
+
return this.waitForSubmarineSwap(pendingSwap);
|
|
4085
|
+
}
|
|
4086
|
+
/**
|
|
4087
|
+
* Waits until a submarine swap is funded: resolves as soon as the lockup
|
|
4088
|
+
* transaction is observed ("transaction.mempool" or any later status in
|
|
4089
|
+
* the lifecycle — statuses can be skipped since subscriptions report only
|
|
4090
|
+
* the current one). The sender's funds are committed and the swap is
|
|
4091
|
+
* refundable from this point, which is when most Lightning wallets show
|
|
4092
|
+
* a payment as "sent".
|
|
4093
|
+
*
|
|
4094
|
+
* Monitoring continues in the background until the swap reaches a
|
|
4095
|
+
* terminal status, persisting updates to the repository (the preimage on
|
|
4096
|
+
* claim, the refundable flag on failure), but this promise no longer
|
|
4097
|
+
* rejects once resolved — acting on a late failure is the caller's
|
|
4098
|
+
* responsibility (the SwapManager handles it automatically when enabled).
|
|
4099
|
+
* @param pendingSwap - The submarine swap to monitor.
|
|
4100
|
+
* @throws {SwapExpiredError} If the swap expires before funding.
|
|
4101
|
+
* @throws {InvoiceFailedToPayError} If Boltz fails to route the payment.
|
|
4102
|
+
* @throws {TransactionLockupFailedError} If the lockup transaction fails.
|
|
4103
|
+
*/
|
|
4104
|
+
async waitForSwapFunded(pendingSwap) {
|
|
4105
|
+
await this.waitForSubmarineSwap(pendingSwap, "transaction.mempool");
|
|
4106
|
+
}
|
|
4107
|
+
/**
|
|
4108
|
+
* Shared wait machinery: monitors the swap and resolves at the terminal
|
|
4109
|
+
* "transaction.claimed" status (with the preimage) or, when `resolveAt`
|
|
4110
|
+
* is given, as soon as that status — or any later one in the successful
|
|
4111
|
+
* progression — is observed (without a preimage).
|
|
4112
|
+
*/
|
|
4113
|
+
async waitForSubmarineSwap(pendingSwap, resolveAt) {
|
|
4064
4114
|
return new Promise((resolve, reject) => {
|
|
4065
|
-
let
|
|
4115
|
+
let isFinal = false;
|
|
4116
|
+
let isSettled = false;
|
|
4066
4117
|
const onStatusUpdate = async (status) => {
|
|
4067
|
-
if (
|
|
4068
|
-
const saveStatus = (additionalFields) =>
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4118
|
+
if (isFinal) return;
|
|
4119
|
+
const saveStatus = async (additionalFields) => {
|
|
4120
|
+
try {
|
|
4121
|
+
await updateSubmarineSwapStatus(
|
|
4122
|
+
pendingSwap,
|
|
4123
|
+
status,
|
|
4124
|
+
this.savePendingSubmarineSwap.bind(this),
|
|
4125
|
+
additionalFields
|
|
4126
|
+
);
|
|
4127
|
+
} catch (error) {
|
|
4128
|
+
logger.error(
|
|
4129
|
+
`Swap ${pendingSwap.id}: failed to persist status "${status}": ${error}`
|
|
4130
|
+
);
|
|
4131
|
+
}
|
|
4132
|
+
};
|
|
4074
4133
|
switch (status) {
|
|
4075
4134
|
case "swap.expired":
|
|
4076
|
-
|
|
4135
|
+
isFinal = true;
|
|
4136
|
+
isSettled = true;
|
|
4077
4137
|
await saveStatus({ refundable: true });
|
|
4078
4138
|
reject(
|
|
4079
4139
|
new SwapExpiredError({
|
|
@@ -4083,7 +4143,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4083
4143
|
);
|
|
4084
4144
|
break;
|
|
4085
4145
|
case "invoice.failedToPay":
|
|
4086
|
-
|
|
4146
|
+
isFinal = true;
|
|
4147
|
+
isSettled = true;
|
|
4087
4148
|
await saveStatus({ refundable: true });
|
|
4088
4149
|
reject(
|
|
4089
4150
|
new InvoiceFailedToPayError({
|
|
@@ -4093,7 +4154,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4093
4154
|
);
|
|
4094
4155
|
break;
|
|
4095
4156
|
case "transaction.lockupFailed":
|
|
4096
|
-
|
|
4157
|
+
isFinal = true;
|
|
4158
|
+
isSettled = true;
|
|
4097
4159
|
await saveStatus({ refundable: true });
|
|
4098
4160
|
reject(
|
|
4099
4161
|
new TransactionLockupFailedError({
|
|
@@ -4103,23 +4165,47 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4103
4165
|
);
|
|
4104
4166
|
break;
|
|
4105
4167
|
case "transaction.claimed": {
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4168
|
+
isFinal = true;
|
|
4169
|
+
isSettled = true;
|
|
4170
|
+
try {
|
|
4171
|
+
const { preimage } = await this.swapProvider.getSwapPreimage(
|
|
4172
|
+
pendingSwap.id
|
|
4173
|
+
);
|
|
4174
|
+
await saveStatus({ preimage });
|
|
4175
|
+
resolve({ preimage });
|
|
4176
|
+
} catch (error) {
|
|
4177
|
+
logger.error(
|
|
4178
|
+
`Swap ${pendingSwap.id}: failed to fetch preimage on claim: ${error}`
|
|
4179
|
+
);
|
|
4180
|
+
reject(error);
|
|
4181
|
+
}
|
|
4112
4182
|
break;
|
|
4113
4183
|
}
|
|
4114
4184
|
default:
|
|
4115
4185
|
await saveStatus();
|
|
4186
|
+
if (resolveAt && hasSubmarineStatusReached(status, resolveAt)) {
|
|
4187
|
+
isSettled = true;
|
|
4188
|
+
resolve({ preimage: void 0 });
|
|
4189
|
+
}
|
|
4116
4190
|
break;
|
|
4117
4191
|
}
|
|
4118
4192
|
};
|
|
4119
|
-
this.swapProvider.monitorSwap(pendingSwap.id,
|
|
4120
|
-
|
|
4121
|
-
|
|
4193
|
+
this.swapProvider.monitorSwap(pendingSwap.id, (status) => {
|
|
4194
|
+
onStatusUpdate(status).catch(
|
|
4195
|
+
(error) => logger.error(
|
|
4196
|
+
`Swap ${pendingSwap.id}: error handling status "${status}": ${error}`
|
|
4197
|
+
)
|
|
4198
|
+
);
|
|
4199
|
+
}).catch((error) => {
|
|
4200
|
+
if (!isSettled) {
|
|
4201
|
+
isFinal = true;
|
|
4202
|
+
isSettled = true;
|
|
4122
4203
|
reject(error);
|
|
4204
|
+
} else {
|
|
4205
|
+
isFinal = true;
|
|
4206
|
+
logger.warn(
|
|
4207
|
+
`Swap ${pendingSwap.id}: monitor failed after settlement: ${error}`
|
|
4208
|
+
);
|
|
4123
4209
|
}
|
|
4124
4210
|
});
|
|
4125
4211
|
});
|
|
@@ -4357,29 +4443,26 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4357
4443
|
"user",
|
|
4358
4444
|
pendingSwap.id
|
|
4359
4445
|
);
|
|
4360
|
-
const serverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
4361
|
-
import_base9.hex.decode(arkInfo.signerPubkey),
|
|
4362
|
-
"server",
|
|
4363
|
-
pendingSwap.id
|
|
4364
|
-
);
|
|
4365
4446
|
const boltzXOnlyPublicKey = normalizeToXOnlyKey(
|
|
4366
4447
|
import_base9.hex.decode(pendingSwap.response.lockupDetails.serverPublicKey),
|
|
4367
4448
|
"boltz",
|
|
4368
4449
|
pendingSwap.id
|
|
4369
4450
|
);
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4451
|
+
let vhtlcScript;
|
|
4452
|
+
let serverXOnlyPublicKey;
|
|
4453
|
+
try {
|
|
4454
|
+
({ vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
4455
|
+
arkInfo,
|
|
4456
|
+
preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
|
|
4457
|
+
senderPubkey: import_base9.hex.encode(ourXOnlyPublicKey),
|
|
4458
|
+
receiverPubkey: import_base9.hex.encode(boltzXOnlyPublicKey),
|
|
4459
|
+
timeoutBlockHeights: pendingSwap.response.lockupDetails.timeouts,
|
|
4460
|
+
lockupAddress: pendingSwap.response.lockupDetails.lockupAddress,
|
|
4461
|
+
swapId: pendingSwap.id
|
|
4462
|
+
}));
|
|
4463
|
+
} catch (error) {
|
|
4381
4464
|
throw new SwapError({
|
|
4382
|
-
message: "Unable to
|
|
4465
|
+
message: error instanceof Error ? error.message : "Unable to refund: invalid VHTLC address"
|
|
4383
4466
|
});
|
|
4384
4467
|
}
|
|
4385
4468
|
const { vtxos } = await this.indexerProvider.getVtxos({
|
|
@@ -4638,20 +4721,21 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4638
4721
|
pendingSwap.response.claimDetails.serverPublicKey,
|
|
4639
4722
|
"sender"
|
|
4640
4723
|
);
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4724
|
+
let vhtlcScript;
|
|
4725
|
+
let serverXOnlyPublicKey;
|
|
4726
|
+
try {
|
|
4727
|
+
({ vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
4728
|
+
arkInfo,
|
|
4729
|
+
preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
|
|
4730
|
+
senderPubkey: import_base9.hex.encode(senderXOnlyPublicKey),
|
|
4731
|
+
receiverPubkey: import_base9.hex.encode(receiverXOnlyPublicKey),
|
|
4732
|
+
timeoutBlockHeights: pendingSwap.response.claimDetails.timeouts,
|
|
4733
|
+
lockupAddress: pendingSwap.response.claimDetails.lockupAddress,
|
|
4734
|
+
swapId: pendingSwap.id
|
|
4735
|
+
}));
|
|
4736
|
+
} catch (error) {
|
|
4653
4737
|
throw new SwapError({
|
|
4654
|
-
message: "Unable to claim: invalid VHTLC address"
|
|
4738
|
+
message: error instanceof Error ? error.message : "Unable to claim: invalid VHTLC address"
|
|
4655
4739
|
});
|
|
4656
4740
|
}
|
|
4657
4741
|
let vtxo;
|
|
@@ -5013,6 +5097,55 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
5013
5097
|
createVHTLCScript(args) {
|
|
5014
5098
|
return createVHTLCScript(args);
|
|
5015
5099
|
}
|
|
5100
|
+
/**
|
|
5101
|
+
* Reconstruct a swap's VHTLC by matching the persisted `lockupAddress`
|
|
5102
|
+
* against the current and deprecated server signers, returning the matched
|
|
5103
|
+
* script together with the server key it was minted under.
|
|
5104
|
+
*
|
|
5105
|
+
* Recovery paths (claim/refund/lookup) must use this instead of building the
|
|
5106
|
+
* VHTLC from the current signer alone: a swap created before a planned arkd
|
|
5107
|
+
* signer rotation is locked to a now-deprecated signer, so the current key
|
|
5108
|
+
* would yield the wrong address and strand the funds. The returned
|
|
5109
|
+
* `serverXOnlyPublicKey` is the original (possibly deprecated) key and MUST
|
|
5110
|
+
* be threaded into downstream signing/verification.
|
|
5111
|
+
*
|
|
5112
|
+
* Throws a descriptive mismatch error when no candidate reproduces the
|
|
5113
|
+
* lockup address (e.g. the swap predates an already-pruned deprecated
|
|
5114
|
+
* signer) — replacing the previous current-signer-only equality check.
|
|
5115
|
+
*/
|
|
5116
|
+
resolveVHTLCForLockup(args) {
|
|
5117
|
+
const candidates = candidateServerPubkeys(args.arkInfo);
|
|
5118
|
+
for (const serverPubkey of candidates) {
|
|
5119
|
+
const { vhtlcScript, vhtlcAddress } = this.createVHTLCScript({
|
|
5120
|
+
network: args.arkInfo.network,
|
|
5121
|
+
preimageHash: args.preimageHash,
|
|
5122
|
+
receiverPubkey: args.receiverPubkey,
|
|
5123
|
+
senderPubkey: args.senderPubkey,
|
|
5124
|
+
serverPubkey,
|
|
5125
|
+
timeoutBlockHeights: args.timeoutBlockHeights
|
|
5126
|
+
});
|
|
5127
|
+
if (vhtlcAddress !== args.lockupAddress) continue;
|
|
5128
|
+
if (!vhtlcScript.claimScript && !vhtlcScript.refundScript) {
|
|
5129
|
+
throw new Error(
|
|
5130
|
+
`Swap ${args.swapId}: VHTLC address matched but claim/refund script leaves are empty`
|
|
5131
|
+
);
|
|
5132
|
+
}
|
|
5133
|
+
return {
|
|
5134
|
+
vhtlcScript,
|
|
5135
|
+
// The matched (possibly deprecated) key must flow into downstream
|
|
5136
|
+
// signing/verification: arkd signs a deprecated-signer input with
|
|
5137
|
+
// the deprecated key, so the claim/refund leaf checks use it.
|
|
5138
|
+
serverXOnlyPublicKey: normalizeToXOnlyKey(
|
|
5139
|
+
import_base9.hex.decode(serverPubkey),
|
|
5140
|
+
"server",
|
|
5141
|
+
args.swapId
|
|
5142
|
+
)
|
|
5143
|
+
};
|
|
5144
|
+
}
|
|
5145
|
+
throw new Error(
|
|
5146
|
+
`Swap ${args.swapId}: VHTLC address mismatch. Expected ${args.lockupAddress}; no current or deprecated server signer (${candidates.length} candidate(s) tried) reproduced it`
|
|
5147
|
+
);
|
|
5148
|
+
}
|
|
5016
5149
|
async getFees(from, to) {
|
|
5017
5150
|
if (from && to) {
|
|
5018
5151
|
return this.swapProvider.getChainFees(from, to);
|
|
@@ -5096,13 +5229,28 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
5096
5229
|
for (const swap of await this.getPendingSubmarineSwapsFromStorage()) {
|
|
5097
5230
|
if (isSubmarineFinalStatus(swap.status)) continue;
|
|
5098
5231
|
promises.push(
|
|
5099
|
-
this.getSwapStatus(swap.id).then(
|
|
5100
|
-
|
|
5232
|
+
this.getSwapStatus(swap.id).then(async ({ status }) => {
|
|
5233
|
+
let additionalFields;
|
|
5234
|
+
if (isSubmarineSuccessStatus(status) && !swap.preimage) {
|
|
5235
|
+
try {
|
|
5236
|
+
const { preimage } = await this.swapProvider.getSwapPreimage(
|
|
5237
|
+
swap.id
|
|
5238
|
+
);
|
|
5239
|
+
additionalFields = { preimage };
|
|
5240
|
+
} catch (error) {
|
|
5241
|
+
logger.warn(
|
|
5242
|
+
`Failed to fetch preimage for settled swap ${swap.id}:`,
|
|
5243
|
+
error
|
|
5244
|
+
);
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
await updateSubmarineSwapStatus(
|
|
5101
5248
|
swap,
|
|
5102
5249
|
status,
|
|
5103
|
-
this.savePendingSubmarineSwap.bind(this)
|
|
5104
|
-
|
|
5105
|
-
|
|
5250
|
+
this.savePendingSubmarineSwap.bind(this),
|
|
5251
|
+
additionalFields
|
|
5252
|
+
);
|
|
5253
|
+
}).catch((error) => {
|
|
5106
5254
|
logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
|
|
5107
5255
|
})
|
|
5108
5256
|
);
|
|
@@ -5412,6 +5560,9 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
|
|
|
5412
5560
|
waitForSwapSettlement(pendingSwap) {
|
|
5413
5561
|
return this.inner.waitForSwapSettlement(pendingSwap);
|
|
5414
5562
|
}
|
|
5563
|
+
waitForSwapFunded(pendingSwap) {
|
|
5564
|
+
return this.inner.waitForSwapFunded(pendingSwap);
|
|
5565
|
+
}
|
|
5415
5566
|
restoreSwaps(boltzFees) {
|
|
5416
5567
|
return this.inner.restoreSwaps(boltzFees);
|
|
5417
5568
|
}
|
package/dist/expo/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IArkadeSwaps, A as ArkadeSwaps, Q as QuoteSwapOptions, V as VhtlcTimeouts } from '../arkade-swaps-
|
|
2
|
-
import {
|
|
3
|
-
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-
|
|
4
|
-
export { D as DefineSwapBackgroundTaskOptions, b as ExpoArkadeLightningConfig, c as ExpoSwapBackgroundConfig, P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies } from '../swapsPollProcessor-
|
|
1
|
+
import { I as IArkadeSwaps, A as ArkadeSwaps, Q as QuoteSwapOptions, V as VhtlcTimeouts } from '../arkade-swaps-C3sUFr5f.cjs';
|
|
2
|
+
import { n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, b as BoltzReverseSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, F as FeesResponse, a as BoltzChainSwap, j as ArkToBtcResponse, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from '../types-8NrCdOpS.cjs';
|
|
3
|
+
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-CGMXUKPe.cjs';
|
|
4
|
+
export { D as DefineSwapBackgroundTaskOptions, b as ExpoArkadeLightningConfig, c as ExpoSwapBackgroundConfig, P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies } from '../swapsPollProcessor-CGMXUKPe.cjs';
|
|
5
5
|
import { ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
|
|
6
6
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
|
7
7
|
import '@arkade-os/sdk/worker/expo';
|
|
@@ -84,7 +84,10 @@ declare class ExpoArkadeSwaps implements IArkadeSwaps {
|
|
|
84
84
|
stopSwapManager(): Promise<void>;
|
|
85
85
|
getSwapManager(): SwapManagerClient | null;
|
|
86
86
|
createLightningInvoice(args: CreateLightningInvoiceRequest): Promise<CreateLightningInvoiceResponse>;
|
|
87
|
-
sendLightningPayment(args: SendLightningPaymentRequest
|
|
87
|
+
sendLightningPayment(args: SendLightningPaymentRequest & {
|
|
88
|
+
waitFor?: "settled";
|
|
89
|
+
}): Promise<SendLightningPaymentResponse>;
|
|
90
|
+
sendLightningPayment(args: SendLightningPaymentRequest): Promise<OptimisticSendLightningPaymentResponse>;
|
|
88
91
|
createSubmarineSwap(args: SendLightningPaymentRequest): Promise<BoltzSubmarineSwap>;
|
|
89
92
|
createReverseSwap(args: CreateLightningInvoiceRequest): Promise<BoltzReverseSwap>;
|
|
90
93
|
claimVHTLC(pendingSwap: BoltzReverseSwap): Promise<void>;
|
|
@@ -99,6 +102,7 @@ declare class ExpoArkadeSwaps implements IArkadeSwaps {
|
|
|
99
102
|
waitForSwapSettlement(pendingSwap: BoltzSubmarineSwap): Promise<{
|
|
100
103
|
preimage: string;
|
|
101
104
|
}>;
|
|
105
|
+
waitForSwapFunded(pendingSwap: BoltzSubmarineSwap): Promise<void>;
|
|
102
106
|
restoreSwaps(boltzFees?: FeesResponse): Promise<{
|
|
103
107
|
chainSwaps: BoltzChainSwap[];
|
|
104
108
|
reverseSwaps: BoltzReverseSwap[];
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IArkadeSwaps, A as ArkadeSwaps, Q as QuoteSwapOptions, V as VhtlcTimeouts } from '../arkade-swaps-
|
|
2
|
-
import {
|
|
3
|
-
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-
|
|
4
|
-
export { D as DefineSwapBackgroundTaskOptions, b as ExpoArkadeLightningConfig, c as ExpoSwapBackgroundConfig, P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies } from '../swapsPollProcessor-
|
|
1
|
+
import { I as IArkadeSwaps, A as ArkadeSwaps, Q as QuoteSwapOptions, V as VhtlcTimeouts } from '../arkade-swaps-LvsGHtre.js';
|
|
2
|
+
import { n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, b as BoltzReverseSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, F as FeesResponse, a as BoltzChainSwap, j as ArkToBtcResponse, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from '../types-8NrCdOpS.js';
|
|
3
|
+
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-CuDM6sxV.js';
|
|
4
|
+
export { D as DefineSwapBackgroundTaskOptions, b as ExpoArkadeLightningConfig, c as ExpoSwapBackgroundConfig, P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies } from '../swapsPollProcessor-CuDM6sxV.js';
|
|
5
5
|
import { ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
|
|
6
6
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
|
7
7
|
import '@arkade-os/sdk/worker/expo';
|
|
@@ -84,7 +84,10 @@ declare class ExpoArkadeSwaps implements IArkadeSwaps {
|
|
|
84
84
|
stopSwapManager(): Promise<void>;
|
|
85
85
|
getSwapManager(): SwapManagerClient | null;
|
|
86
86
|
createLightningInvoice(args: CreateLightningInvoiceRequest): Promise<CreateLightningInvoiceResponse>;
|
|
87
|
-
sendLightningPayment(args: SendLightningPaymentRequest
|
|
87
|
+
sendLightningPayment(args: SendLightningPaymentRequest & {
|
|
88
|
+
waitFor?: "settled";
|
|
89
|
+
}): Promise<SendLightningPaymentResponse>;
|
|
90
|
+
sendLightningPayment(args: SendLightningPaymentRequest): Promise<OptimisticSendLightningPaymentResponse>;
|
|
88
91
|
createSubmarineSwap(args: SendLightningPaymentRequest): Promise<BoltzSubmarineSwap>;
|
|
89
92
|
createReverseSwap(args: CreateLightningInvoiceRequest): Promise<BoltzReverseSwap>;
|
|
90
93
|
claimVHTLC(pendingSwap: BoltzReverseSwap): Promise<void>;
|
|
@@ -99,6 +102,7 @@ declare class ExpoArkadeSwaps implements IArkadeSwaps {
|
|
|
99
102
|
waitForSwapSettlement(pendingSwap: BoltzSubmarineSwap): Promise<{
|
|
100
103
|
preimage: string;
|
|
101
104
|
}>;
|
|
105
|
+
waitForSwapFunded(pendingSwap: BoltzSubmarineSwap): Promise<void>;
|
|
102
106
|
restoreSwaps(boltzFees?: FeesResponse): Promise<{
|
|
103
107
|
chainSwaps: BoltzChainSwap[];
|
|
104
108
|
reverseSwaps: BoltzReverseSwap[];
|
package/dist/expo/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SWAP_POLL_TASK_TYPE
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-CWY37W4B.js";
|
|
4
4
|
import {
|
|
5
5
|
ArkadeSwaps
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-UXYHW7KV.js";
|
|
7
7
|
import "../chunk-SJQJQO7P.js";
|
|
8
8
|
|
|
9
9
|
// src/expo/arkade-lightning.ts
|
|
@@ -162,6 +162,9 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
|
|
|
162
162
|
waitForSwapSettlement(pendingSwap) {
|
|
163
163
|
return this.inner.waitForSwapSettlement(pendingSwap);
|
|
164
164
|
}
|
|
165
|
+
waitForSwapFunded(pendingSwap) {
|
|
166
|
+
return this.inner.waitForSwapFunded(pendingSwap);
|
|
167
|
+
}
|
|
165
168
|
restoreSwaps(boltzFees) {
|
|
166
169
|
return this.inner.restoreSwaps(boltzFees);
|
|
167
170
|
}
|