@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/background.cjs
CHANGED
|
@@ -245,6 +245,22 @@ var isSubmarineFinalStatus = (status) => {
|
|
|
245
245
|
var isSubmarineRefundableStatus = (status) => {
|
|
246
246
|
return ["invoice.failedToPay", "transaction.lockupFailed", "swap.expired"].includes(status);
|
|
247
247
|
};
|
|
248
|
+
var SUBMARINE_STATUS_PROGRESSION = [
|
|
249
|
+
"swap.created",
|
|
250
|
+
"invoice.set",
|
|
251
|
+
"transaction.mempool",
|
|
252
|
+
"transaction.confirmed",
|
|
253
|
+
"invoice.pending",
|
|
254
|
+
"invoice.paid",
|
|
255
|
+
"transaction.claim.pending",
|
|
256
|
+
"transaction.claimed"
|
|
257
|
+
];
|
|
258
|
+
var hasSubmarineStatusReached = (status, target) => {
|
|
259
|
+
const progression = SUBMARINE_STATUS_PROGRESSION;
|
|
260
|
+
const statusIndex = progression.indexOf(status);
|
|
261
|
+
const targetIndex = progression.indexOf(target);
|
|
262
|
+
return statusIndex >= 0 && targetIndex >= 0 && statusIndex >= targetIndex;
|
|
263
|
+
};
|
|
248
264
|
var isSubmarineSuccessStatus = (status) => {
|
|
249
265
|
return status === "transaction.claimed";
|
|
250
266
|
};
|
|
@@ -1291,10 +1307,10 @@ var import_light_bolt11_decoder = __toESM(require("light-bolt11-decoder"), 1);
|
|
|
1291
1307
|
var import_sdk2 = require("@arkade-os/sdk");
|
|
1292
1308
|
var decodeInvoice = (invoice) => {
|
|
1293
1309
|
const decoded = import_light_bolt11_decoder.default.decode(invoice);
|
|
1294
|
-
const millisats =
|
|
1310
|
+
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1295
1311
|
return {
|
|
1296
1312
|
expiry: decoded.expiry ?? 3600,
|
|
1297
|
-
amountSats:
|
|
1313
|
+
amountSats: Number(millisats / 1000n),
|
|
1298
1314
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1299
1315
|
paymentHash: decoded.sections.find((s) => s.name === "payment_hash")?.value ?? ""
|
|
1300
1316
|
};
|
|
@@ -2909,6 +2925,19 @@ var createVHTLCScript = (args) => {
|
|
|
2909
2925
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
2910
2926
|
return { vhtlcScript, vhtlcAddress };
|
|
2911
2927
|
};
|
|
2928
|
+
var candidateServerPubkeys = (arkInfo) => {
|
|
2929
|
+
const current = import_base8.hex.encode(normalizeToXOnlyKey(import_base8.hex.decode(arkInfo.signerPubkey), "server"));
|
|
2930
|
+
const seen = /* @__PURE__ */ new Set([current]);
|
|
2931
|
+
const candidates = [current];
|
|
2932
|
+
for (const deprecated of arkInfo.deprecatedSigners ?? []) {
|
|
2933
|
+
if (!deprecated.pubkey) continue;
|
|
2934
|
+
const key = import_base8.hex.encode(normalizeToXOnlyKey(import_base8.hex.decode(deprecated.pubkey), "server"));
|
|
2935
|
+
if (seen.has(key)) continue;
|
|
2936
|
+
seen.add(key);
|
|
2937
|
+
candidates.push(key);
|
|
2938
|
+
}
|
|
2939
|
+
return candidates;
|
|
2940
|
+
};
|
|
2912
2941
|
var joinBatch = async (arkProvider, identity, input, output, {
|
|
2913
2942
|
forfeitPubkey,
|
|
2914
2943
|
forfeitAddress,
|
|
@@ -3323,6 +3352,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3323
3352
|
...args.description?.trim() ? { description: args.description.trim() } : {}
|
|
3324
3353
|
};
|
|
3325
3354
|
const swapResponse = await this.swapProvider.createReverseSwap(swapRequest);
|
|
3355
|
+
const decodedInvoice = decodeInvoice(swapResponse.invoice);
|
|
3356
|
+
if (decodedInvoice.paymentHash !== preimageHash) {
|
|
3357
|
+
throw new SwapError({ message: "Preimage hash does not match invoice payment hash" });
|
|
3358
|
+
}
|
|
3326
3359
|
const pendingSwap = {
|
|
3327
3360
|
id: swapResponse.id,
|
|
3328
3361
|
type: "reverse",
|
|
@@ -3366,27 +3399,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3366
3399
|
"boltz",
|
|
3367
3400
|
pendingSwap.id
|
|
3368
3401
|
);
|
|
3369
|
-
const serverXOnly =
|
|
3370
|
-
|
|
3371
|
-
"server",
|
|
3372
|
-
pendingSwap.id
|
|
3373
|
-
);
|
|
3374
|
-
const { vhtlcScript, vhtlcAddress } = this.createVHTLCScript({
|
|
3375
|
-
network: arkInfo.network,
|
|
3402
|
+
const { vhtlcScript, serverXOnlyPublicKey: serverXOnly } = this.resolveVHTLCForLockup({
|
|
3403
|
+
arkInfo,
|
|
3376
3404
|
preimageHash: (0, import_sha23.sha256)(preimage),
|
|
3377
3405
|
receiverPubkey: import_base9.hex.encode(receiverXOnly),
|
|
3378
3406
|
senderPubkey: import_base9.hex.encode(senderXOnly),
|
|
3379
|
-
|
|
3380
|
-
|
|
3407
|
+
timeoutBlockHeights: vhtlcTimeouts,
|
|
3408
|
+
lockupAddress,
|
|
3409
|
+
swapId: pendingSwap.id
|
|
3381
3410
|
});
|
|
3382
|
-
if (!vhtlcScript.claimScript)
|
|
3383
|
-
throw new Error(
|
|
3384
|
-
`Swap ${pendingSwap.id}: failed to create VHTLC script for reverse swap`
|
|
3385
|
-
);
|
|
3386
|
-
if (vhtlcAddress !== lockupAddress)
|
|
3387
|
-
throw new Error(
|
|
3388
|
-
`Swap ${pendingSwap.id}: VHTLC address mismatch. Expected ${lockupAddress}, got ${vhtlcAddress}`
|
|
3389
|
-
);
|
|
3390
3411
|
let unspentVtxos = [];
|
|
3391
3412
|
let rawVtxos = [];
|
|
3392
3413
|
for (let attempt = 1; attempt <= CLAIM_VTXO_RETRY_ATTEMPTS; attempt++) {
|
|
@@ -3537,16 +3558,6 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3537
3558
|
this.swapProvider.monitorSwap(pendingSwap.id, onStatusUpdate).catch(reject);
|
|
3538
3559
|
});
|
|
3539
3560
|
}
|
|
3540
|
-
// =========================================================================
|
|
3541
|
-
// Lightning: Submarine swaps (send Arkade -> Lightning)
|
|
3542
|
-
// =========================================================================
|
|
3543
|
-
/**
|
|
3544
|
-
* Sends a Lightning payment via a submarine swap (Arkade → Lightning).
|
|
3545
|
-
* Creates the swap, sends funds, and waits for settlement. Auto-refunds on failure.
|
|
3546
|
-
* @param args.invoice - BOLT11 Lightning invoice to pay.
|
|
3547
|
-
* @returns The amount paid, preimage (proof of payment), and transaction ID.
|
|
3548
|
-
* @throws {TransactionFailedError} If the payment fails (auto-refunds if possible).
|
|
3549
|
-
*/
|
|
3550
3561
|
async sendLightningPayment(args) {
|
|
3551
3562
|
const pendingSwap = await this.createSubmarineSwap(args);
|
|
3552
3563
|
if (!pendingSwap.response.address)
|
|
@@ -3557,6 +3568,18 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3557
3568
|
amount: pendingSwap.response.expectedAmount
|
|
3558
3569
|
});
|
|
3559
3570
|
try {
|
|
3571
|
+
if (args.waitFor === "funded") {
|
|
3572
|
+
if (!this.swapManager) {
|
|
3573
|
+
logger.warn(
|
|
3574
|
+
`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`
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
await this.waitForSwapFunded(pendingSwap);
|
|
3578
|
+
return {
|
|
3579
|
+
amount: pendingSwap.response.expectedAmount,
|
|
3580
|
+
txid
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3560
3583
|
const { preimage } = await this.waitForSwapSettlement(pendingSwap);
|
|
3561
3584
|
return {
|
|
3562
3585
|
amount: pendingSwap.response.expectedAmount,
|
|
@@ -3628,11 +3651,6 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3628
3651
|
"our",
|
|
3629
3652
|
swap.id
|
|
3630
3653
|
);
|
|
3631
|
-
const serverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
3632
|
-
import_base9.hex.decode(resolvedArkInfo.signerPubkey),
|
|
3633
|
-
"server",
|
|
3634
|
-
swap.id
|
|
3635
|
-
);
|
|
3636
3654
|
const { claimPublicKey, timeoutBlockHeights: vhtlcTimeouts } = swap.response;
|
|
3637
3655
|
if (!claimPublicKey || !vhtlcTimeouts)
|
|
3638
3656
|
throw new Error(`Swap ${swap.id}: incomplete submarine swap response`);
|
|
@@ -3641,20 +3659,19 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3641
3659
|
"boltz",
|
|
3642
3660
|
swap.id
|
|
3643
3661
|
);
|
|
3644
|
-
const
|
|
3645
|
-
|
|
3662
|
+
const lockupAddress = swap.response.address;
|
|
3663
|
+
if (!lockupAddress)
|
|
3664
|
+
throw new Error(`Swap ${swap.id}: missing lockup address in submarine swap response`);
|
|
3665
|
+
const { vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
3666
|
+
arkInfo: resolvedArkInfo,
|
|
3646
3667
|
preimageHash: import_base9.hex.decode(preimageHash),
|
|
3647
3668
|
receiverPubkey: import_base9.hex.encode(boltzXOnlyPublicKey),
|
|
3648
3669
|
senderPubkey: import_base9.hex.encode(ourXOnlyPublicKey),
|
|
3649
|
-
|
|
3650
|
-
|
|
3670
|
+
timeoutBlockHeights: vhtlcTimeouts,
|
|
3671
|
+
lockupAddress,
|
|
3672
|
+
swapId: swap.id
|
|
3651
3673
|
});
|
|
3652
|
-
|
|
3653
|
-
throw new Error(`Swap ${swap.id}: failed to create VHTLC script for submarine swap`);
|
|
3654
|
-
if (vhtlcAddress !== swap.response.address)
|
|
3655
|
-
throw new Error(
|
|
3656
|
-
`VHTLC address mismatch for swap ${swap.id}: expected ${swap.response.address}, got ${vhtlcAddress}`
|
|
3657
|
-
);
|
|
3674
|
+
const vhtlcAddress = lockupAddress;
|
|
3658
3675
|
const vhtlcPkScriptHex = import_base9.hex.encode(vhtlcScript.pkScript);
|
|
3659
3676
|
return {
|
|
3660
3677
|
arkInfo: resolvedArkInfo,
|
|
@@ -4064,6 +4081,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4064
4081
|
}
|
|
4065
4082
|
/**
|
|
4066
4083
|
* Waits for a submarine swap's Lightning payment to settle.
|
|
4084
|
+
* Resolves only at the terminal "transaction.claimed" status, once Boltz
|
|
4085
|
+
* has swept the HTLC. To resolve as soon as the payment is in flight, use
|
|
4086
|
+
* {@link waitForSwapFunded} instead.
|
|
4067
4087
|
* @param pendingSwap - The submarine swap to monitor.
|
|
4068
4088
|
* @returns The preimage from the settled Lightning payment (proof of payment).
|
|
4069
4089
|
* @throws {SwapExpiredError} If the swap expires.
|
|
@@ -4071,19 +4091,59 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4071
4091
|
* @throws {TransactionLockupFailedError} If the lockup transaction fails.
|
|
4072
4092
|
*/
|
|
4073
4093
|
async waitForSwapSettlement(pendingSwap) {
|
|
4094
|
+
return this.waitForSubmarineSwap(pendingSwap);
|
|
4095
|
+
}
|
|
4096
|
+
/**
|
|
4097
|
+
* Waits until a submarine swap is funded: resolves as soon as the lockup
|
|
4098
|
+
* transaction is observed ("transaction.mempool" or any later status in
|
|
4099
|
+
* the lifecycle — statuses can be skipped since subscriptions report only
|
|
4100
|
+
* the current one). The sender's funds are committed and the swap is
|
|
4101
|
+
* refundable from this point, which is when most Lightning wallets show
|
|
4102
|
+
* a payment as "sent".
|
|
4103
|
+
*
|
|
4104
|
+
* Monitoring continues in the background until the swap reaches a
|
|
4105
|
+
* terminal status, persisting updates to the repository (the preimage on
|
|
4106
|
+
* claim, the refundable flag on failure), but this promise no longer
|
|
4107
|
+
* rejects once resolved — acting on a late failure is the caller's
|
|
4108
|
+
* responsibility (the SwapManager handles it automatically when enabled).
|
|
4109
|
+
* @param pendingSwap - The submarine swap to monitor.
|
|
4110
|
+
* @throws {SwapExpiredError} If the swap expires before funding.
|
|
4111
|
+
* @throws {InvoiceFailedToPayError} If Boltz fails to route the payment.
|
|
4112
|
+
* @throws {TransactionLockupFailedError} If the lockup transaction fails.
|
|
4113
|
+
*/
|
|
4114
|
+
async waitForSwapFunded(pendingSwap) {
|
|
4115
|
+
await this.waitForSubmarineSwap(pendingSwap, "transaction.mempool");
|
|
4116
|
+
}
|
|
4117
|
+
/**
|
|
4118
|
+
* Shared wait machinery: monitors the swap and resolves at the terminal
|
|
4119
|
+
* "transaction.claimed" status (with the preimage) or, when `resolveAt`
|
|
4120
|
+
* is given, as soon as that status — or any later one in the successful
|
|
4121
|
+
* progression — is observed (without a preimage).
|
|
4122
|
+
*/
|
|
4123
|
+
async waitForSubmarineSwap(pendingSwap, resolveAt) {
|
|
4074
4124
|
return new Promise((resolve, reject) => {
|
|
4075
|
-
let
|
|
4125
|
+
let isFinal = false;
|
|
4126
|
+
let isSettled = false;
|
|
4076
4127
|
const onStatusUpdate = async (status) => {
|
|
4077
|
-
if (
|
|
4078
|
-
const saveStatus = (additionalFields) =>
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4128
|
+
if (isFinal) return;
|
|
4129
|
+
const saveStatus = async (additionalFields) => {
|
|
4130
|
+
try {
|
|
4131
|
+
await updateSubmarineSwapStatus(
|
|
4132
|
+
pendingSwap,
|
|
4133
|
+
status,
|
|
4134
|
+
this.savePendingSubmarineSwap.bind(this),
|
|
4135
|
+
additionalFields
|
|
4136
|
+
);
|
|
4137
|
+
} catch (error) {
|
|
4138
|
+
logger.error(
|
|
4139
|
+
`Swap ${pendingSwap.id}: failed to persist status "${status}": ${error}`
|
|
4140
|
+
);
|
|
4141
|
+
}
|
|
4142
|
+
};
|
|
4084
4143
|
switch (status) {
|
|
4085
4144
|
case "swap.expired":
|
|
4086
|
-
|
|
4145
|
+
isFinal = true;
|
|
4146
|
+
isSettled = true;
|
|
4087
4147
|
await saveStatus({ refundable: true });
|
|
4088
4148
|
reject(
|
|
4089
4149
|
new SwapExpiredError({
|
|
@@ -4093,7 +4153,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4093
4153
|
);
|
|
4094
4154
|
break;
|
|
4095
4155
|
case "invoice.failedToPay":
|
|
4096
|
-
|
|
4156
|
+
isFinal = true;
|
|
4157
|
+
isSettled = true;
|
|
4097
4158
|
await saveStatus({ refundable: true });
|
|
4098
4159
|
reject(
|
|
4099
4160
|
new InvoiceFailedToPayError({
|
|
@@ -4103,7 +4164,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4103
4164
|
);
|
|
4104
4165
|
break;
|
|
4105
4166
|
case "transaction.lockupFailed":
|
|
4106
|
-
|
|
4167
|
+
isFinal = true;
|
|
4168
|
+
isSettled = true;
|
|
4107
4169
|
await saveStatus({ refundable: true });
|
|
4108
4170
|
reject(
|
|
4109
4171
|
new TransactionLockupFailedError({
|
|
@@ -4113,23 +4175,47 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4113
4175
|
);
|
|
4114
4176
|
break;
|
|
4115
4177
|
case "transaction.claimed": {
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4178
|
+
isFinal = true;
|
|
4179
|
+
isSettled = true;
|
|
4180
|
+
try {
|
|
4181
|
+
const { preimage } = await this.swapProvider.getSwapPreimage(
|
|
4182
|
+
pendingSwap.id
|
|
4183
|
+
);
|
|
4184
|
+
await saveStatus({ preimage });
|
|
4185
|
+
resolve({ preimage });
|
|
4186
|
+
} catch (error) {
|
|
4187
|
+
logger.error(
|
|
4188
|
+
`Swap ${pendingSwap.id}: failed to fetch preimage on claim: ${error}`
|
|
4189
|
+
);
|
|
4190
|
+
reject(error);
|
|
4191
|
+
}
|
|
4122
4192
|
break;
|
|
4123
4193
|
}
|
|
4124
4194
|
default:
|
|
4125
4195
|
await saveStatus();
|
|
4196
|
+
if (resolveAt && hasSubmarineStatusReached(status, resolveAt)) {
|
|
4197
|
+
isSettled = true;
|
|
4198
|
+
resolve({ preimage: void 0 });
|
|
4199
|
+
}
|
|
4126
4200
|
break;
|
|
4127
4201
|
}
|
|
4128
4202
|
};
|
|
4129
|
-
this.swapProvider.monitorSwap(pendingSwap.id,
|
|
4130
|
-
|
|
4131
|
-
|
|
4203
|
+
this.swapProvider.monitorSwap(pendingSwap.id, (status) => {
|
|
4204
|
+
onStatusUpdate(status).catch(
|
|
4205
|
+
(error) => logger.error(
|
|
4206
|
+
`Swap ${pendingSwap.id}: error handling status "${status}": ${error}`
|
|
4207
|
+
)
|
|
4208
|
+
);
|
|
4209
|
+
}).catch((error) => {
|
|
4210
|
+
if (!isSettled) {
|
|
4211
|
+
isFinal = true;
|
|
4212
|
+
isSettled = true;
|
|
4132
4213
|
reject(error);
|
|
4214
|
+
} else {
|
|
4215
|
+
isFinal = true;
|
|
4216
|
+
logger.warn(
|
|
4217
|
+
`Swap ${pendingSwap.id}: monitor failed after settlement: ${error}`
|
|
4218
|
+
);
|
|
4133
4219
|
}
|
|
4134
4220
|
});
|
|
4135
4221
|
});
|
|
@@ -4367,29 +4453,26 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4367
4453
|
"user",
|
|
4368
4454
|
pendingSwap.id
|
|
4369
4455
|
);
|
|
4370
|
-
const serverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
4371
|
-
import_base9.hex.decode(arkInfo.signerPubkey),
|
|
4372
|
-
"server",
|
|
4373
|
-
pendingSwap.id
|
|
4374
|
-
);
|
|
4375
4456
|
const boltzXOnlyPublicKey = normalizeToXOnlyKey(
|
|
4376
4457
|
import_base9.hex.decode(pendingSwap.response.lockupDetails.serverPublicKey),
|
|
4377
4458
|
"boltz",
|
|
4378
4459
|
pendingSwap.id
|
|
4379
4460
|
);
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4461
|
+
let vhtlcScript;
|
|
4462
|
+
let serverXOnlyPublicKey;
|
|
4463
|
+
try {
|
|
4464
|
+
({ vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
4465
|
+
arkInfo,
|
|
4466
|
+
preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
|
|
4467
|
+
senderPubkey: import_base9.hex.encode(ourXOnlyPublicKey),
|
|
4468
|
+
receiverPubkey: import_base9.hex.encode(boltzXOnlyPublicKey),
|
|
4469
|
+
timeoutBlockHeights: pendingSwap.response.lockupDetails.timeouts,
|
|
4470
|
+
lockupAddress: pendingSwap.response.lockupDetails.lockupAddress,
|
|
4471
|
+
swapId: pendingSwap.id
|
|
4472
|
+
}));
|
|
4473
|
+
} catch (error) {
|
|
4391
4474
|
throw new SwapError({
|
|
4392
|
-
message: "Unable to
|
|
4475
|
+
message: error instanceof Error ? error.message : "Unable to refund: invalid VHTLC address"
|
|
4393
4476
|
});
|
|
4394
4477
|
}
|
|
4395
4478
|
const { vtxos } = await this.indexerProvider.getVtxos({
|
|
@@ -4648,20 +4731,21 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4648
4731
|
pendingSwap.response.claimDetails.serverPublicKey,
|
|
4649
4732
|
"sender"
|
|
4650
4733
|
);
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4734
|
+
let vhtlcScript;
|
|
4735
|
+
let serverXOnlyPublicKey;
|
|
4736
|
+
try {
|
|
4737
|
+
({ vhtlcScript, serverXOnlyPublicKey } = this.resolveVHTLCForLockup({
|
|
4738
|
+
arkInfo,
|
|
4739
|
+
preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
|
|
4740
|
+
senderPubkey: import_base9.hex.encode(senderXOnlyPublicKey),
|
|
4741
|
+
receiverPubkey: import_base9.hex.encode(receiverXOnlyPublicKey),
|
|
4742
|
+
timeoutBlockHeights: pendingSwap.response.claimDetails.timeouts,
|
|
4743
|
+
lockupAddress: pendingSwap.response.claimDetails.lockupAddress,
|
|
4744
|
+
swapId: pendingSwap.id
|
|
4745
|
+
}));
|
|
4746
|
+
} catch (error) {
|
|
4663
4747
|
throw new SwapError({
|
|
4664
|
-
message: "Unable to claim: invalid VHTLC address"
|
|
4748
|
+
message: error instanceof Error ? error.message : "Unable to claim: invalid VHTLC address"
|
|
4665
4749
|
});
|
|
4666
4750
|
}
|
|
4667
4751
|
let vtxo;
|
|
@@ -5023,6 +5107,55 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
5023
5107
|
createVHTLCScript(args) {
|
|
5024
5108
|
return createVHTLCScript(args);
|
|
5025
5109
|
}
|
|
5110
|
+
/**
|
|
5111
|
+
* Reconstruct a swap's VHTLC by matching the persisted `lockupAddress`
|
|
5112
|
+
* against the current and deprecated server signers, returning the matched
|
|
5113
|
+
* script together with the server key it was minted under.
|
|
5114
|
+
*
|
|
5115
|
+
* Recovery paths (claim/refund/lookup) must use this instead of building the
|
|
5116
|
+
* VHTLC from the current signer alone: a swap created before a planned arkd
|
|
5117
|
+
* signer rotation is locked to a now-deprecated signer, so the current key
|
|
5118
|
+
* would yield the wrong address and strand the funds. The returned
|
|
5119
|
+
* `serverXOnlyPublicKey` is the original (possibly deprecated) key and MUST
|
|
5120
|
+
* be threaded into downstream signing/verification.
|
|
5121
|
+
*
|
|
5122
|
+
* Throws a descriptive mismatch error when no candidate reproduces the
|
|
5123
|
+
* lockup address (e.g. the swap predates an already-pruned deprecated
|
|
5124
|
+
* signer) — replacing the previous current-signer-only equality check.
|
|
5125
|
+
*/
|
|
5126
|
+
resolveVHTLCForLockup(args) {
|
|
5127
|
+
const candidates = candidateServerPubkeys(args.arkInfo);
|
|
5128
|
+
for (const serverPubkey of candidates) {
|
|
5129
|
+
const { vhtlcScript, vhtlcAddress } = this.createVHTLCScript({
|
|
5130
|
+
network: args.arkInfo.network,
|
|
5131
|
+
preimageHash: args.preimageHash,
|
|
5132
|
+
receiverPubkey: args.receiverPubkey,
|
|
5133
|
+
senderPubkey: args.senderPubkey,
|
|
5134
|
+
serverPubkey,
|
|
5135
|
+
timeoutBlockHeights: args.timeoutBlockHeights
|
|
5136
|
+
});
|
|
5137
|
+
if (vhtlcAddress !== args.lockupAddress) continue;
|
|
5138
|
+
if (!vhtlcScript.claimScript && !vhtlcScript.refundScript) {
|
|
5139
|
+
throw new Error(
|
|
5140
|
+
`Swap ${args.swapId}: VHTLC address matched but claim/refund script leaves are empty`
|
|
5141
|
+
);
|
|
5142
|
+
}
|
|
5143
|
+
return {
|
|
5144
|
+
vhtlcScript,
|
|
5145
|
+
// The matched (possibly deprecated) key must flow into downstream
|
|
5146
|
+
// signing/verification: arkd signs a deprecated-signer input with
|
|
5147
|
+
// the deprecated key, so the claim/refund leaf checks use it.
|
|
5148
|
+
serverXOnlyPublicKey: normalizeToXOnlyKey(
|
|
5149
|
+
import_base9.hex.decode(serverPubkey),
|
|
5150
|
+
"server",
|
|
5151
|
+
args.swapId
|
|
5152
|
+
)
|
|
5153
|
+
};
|
|
5154
|
+
}
|
|
5155
|
+
throw new Error(
|
|
5156
|
+
`Swap ${args.swapId}: VHTLC address mismatch. Expected ${args.lockupAddress}; no current or deprecated server signer (${candidates.length} candidate(s) tried) reproduced it`
|
|
5157
|
+
);
|
|
5158
|
+
}
|
|
5026
5159
|
async getFees(from, to) {
|
|
5027
5160
|
if (from && to) {
|
|
5028
5161
|
return this.swapProvider.getChainFees(from, to);
|
|
@@ -5106,13 +5239,28 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
5106
5239
|
for (const swap of await this.getPendingSubmarineSwapsFromStorage()) {
|
|
5107
5240
|
if (isSubmarineFinalStatus(swap.status)) continue;
|
|
5108
5241
|
promises.push(
|
|
5109
|
-
this.getSwapStatus(swap.id).then(
|
|
5110
|
-
|
|
5242
|
+
this.getSwapStatus(swap.id).then(async ({ status }) => {
|
|
5243
|
+
let additionalFields;
|
|
5244
|
+
if (isSubmarineSuccessStatus(status) && !swap.preimage) {
|
|
5245
|
+
try {
|
|
5246
|
+
const { preimage } = await this.swapProvider.getSwapPreimage(
|
|
5247
|
+
swap.id
|
|
5248
|
+
);
|
|
5249
|
+
additionalFields = { preimage };
|
|
5250
|
+
} catch (error) {
|
|
5251
|
+
logger.warn(
|
|
5252
|
+
`Failed to fetch preimage for settled swap ${swap.id}:`,
|
|
5253
|
+
error
|
|
5254
|
+
);
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
await updateSubmarineSwapStatus(
|
|
5111
5258
|
swap,
|
|
5112
5259
|
status,
|
|
5113
|
-
this.savePendingSubmarineSwap.bind(this)
|
|
5114
|
-
|
|
5115
|
-
|
|
5260
|
+
this.savePendingSubmarineSwap.bind(this),
|
|
5261
|
+
additionalFields
|
|
5262
|
+
);
|
|
5263
|
+
}).catch((error) => {
|
|
5116
5264
|
logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
|
|
5117
5265
|
})
|
|
5118
5266
|
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DefineSwapBackgroundTaskOptions } from '../swapsPollProcessor-
|
|
2
|
-
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-
|
|
1
|
+
import { D as DefineSwapBackgroundTaskOptions } from '../swapsPollProcessor-CGMXUKPe.cjs';
|
|
2
|
+
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-CGMXUKPe.cjs';
|
|
3
3
|
import '@arkade-os/sdk/worker/expo';
|
|
4
4
|
import '@arkade-os/sdk';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-8NrCdOpS.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Define the Expo background task handler for swap polling.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DefineSwapBackgroundTaskOptions } from '../swapsPollProcessor-
|
|
2
|
-
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-
|
|
1
|
+
import { D as DefineSwapBackgroundTaskOptions } from '../swapsPollProcessor-CuDM6sxV.js';
|
|
2
|
+
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-CuDM6sxV.js';
|
|
3
3
|
import '@arkade-os/sdk/worker/expo';
|
|
4
4
|
import '@arkade-os/sdk';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-8NrCdOpS.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Define the Expo background task handler for swap polling.
|
package/dist/expo/background.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SWAP_POLL_TASK_TYPE,
|
|
3
3
|
swapsPollProcessor
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-CWY37W4B.js";
|
|
5
5
|
import {
|
|
6
6
|
BoltzSwapProvider
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-UXYHW7KV.js";
|
|
8
8
|
import "../chunk-SJQJQO7P.js";
|
|
9
9
|
|
|
10
10
|
// src/expo/background.ts
|