@arkade-os/boltz-swap 0.3.45 → 0.3.47
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/{arkade-swaps-C8CmzknM.d.cts → arkade-swaps-A180YN8g.d.ts} +11 -1
- package/dist/{arkade-swaps-gXHRbR09.d.ts → arkade-swaps-BG3xEK31.d.cts} +11 -1
- package/dist/{chunk-WPAI2ECT.js → chunk-HIG2OOAN.js} +1 -1
- package/dist/{chunk-5GBBRBFS.js → chunk-VKHFXGKL.js} +78 -19
- package/dist/expo/background.cjs +80 -18
- package/dist/expo/background.d.cts +3 -3
- package/dist/expo/background.d.ts +3 -3
- package/dist/expo/background.js +9 -4
- package/dist/expo/index.cjs +73 -16
- package/dist/expo/index.d.cts +4 -4
- package/dist/expo/index.d.ts +4 -4
- package/dist/expo/index.js +2 -2
- package/dist/index.cjs +74 -17
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- 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-Ov-wp17v.d.ts → swapsPollProcessor-C4HQHP9Z.d.ts} +1 -1
- package/dist/{swapsPollProcessor-B98F6MQF.d.cts → swapsPollProcessor-CIqTFkV1.d.cts} +1 -1
- package/dist/{types-CS62-oEy.d.cts → types-BKEkNZxK.d.cts} +5 -1
- package/dist/{types-CS62-oEy.d.ts → types-BKEkNZxK.d.ts} +5 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IWallet, ArkProvider, IndexerProvider, ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
|
|
2
|
-
import { r as BoltzSwapProvider, y as SwapManager, m as SwapRepository, q as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, j as ArkToBtcResponse, a as BoltzChainSwap, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, F as FeesResponse, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-
|
|
2
|
+
import { r as BoltzSwapProvider, y as SwapManager, m as SwapRepository, q as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, j as ArkToBtcResponse, a as BoltzChainSwap, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, F as FeesResponse, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-BKEkNZxK.js';
|
|
3
3
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -313,6 +313,9 @@ declare class ArkadeSwaps {
|
|
|
313
313
|
}>;
|
|
314
314
|
/**
|
|
315
315
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
316
|
+
*
|
|
317
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
318
|
+
*
|
|
316
319
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
317
320
|
* @returns The BTC transaction ID of the claim.
|
|
318
321
|
*/
|
|
@@ -415,6 +418,13 @@ declare class ArkadeSwaps {
|
|
|
415
418
|
swap: BoltzChainSwap;
|
|
416
419
|
arkInfo: ArkInfo;
|
|
417
420
|
}): Promise<boolean>;
|
|
421
|
+
/**
|
|
422
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
423
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
424
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
425
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
426
|
+
*/
|
|
427
|
+
private verifyBtcChainHtlc;
|
|
418
428
|
/**
|
|
419
429
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
420
430
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IWallet, ArkProvider, IndexerProvider, ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
|
|
2
|
-
import { r as BoltzSwapProvider, y as SwapManager, m as SwapRepository, q as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, j as ArkToBtcResponse, a as BoltzChainSwap, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, F as FeesResponse, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-
|
|
2
|
+
import { r as BoltzSwapProvider, y as SwapManager, m as SwapRepository, q as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, o as SendLightningPaymentResponse, O as OptimisticSendLightningPaymentResponse, c as BoltzSubmarineSwap, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, j as ArkToBtcResponse, a as BoltzChainSwap, l as ChainArkRefundOutcome, k as BtcToArkResponse, d as Chain, F as FeesResponse, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-BKEkNZxK.cjs';
|
|
3
3
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -313,6 +313,9 @@ declare class ArkadeSwaps {
|
|
|
313
313
|
}>;
|
|
314
314
|
/**
|
|
315
315
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
316
|
+
*
|
|
317
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
318
|
+
*
|
|
316
319
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
317
320
|
* @returns The BTC transaction ID of the claim.
|
|
318
321
|
*/
|
|
@@ -415,6 +418,13 @@ declare class ArkadeSwaps {
|
|
|
415
418
|
swap: BoltzChainSwap;
|
|
416
419
|
arkInfo: ArkInfo;
|
|
417
420
|
}): Promise<boolean>;
|
|
421
|
+
/**
|
|
422
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
423
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
424
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
425
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
426
|
+
*/
|
|
427
|
+
private verifyBtcChainHtlc;
|
|
418
428
|
/**
|
|
419
429
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
420
430
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
|
@@ -1001,6 +1001,9 @@ var decodeInvoice = (invoice) => {
|
|
|
1001
1001
|
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1002
1002
|
return {
|
|
1003
1003
|
expiry: decoded.expiry ?? 3600,
|
|
1004
|
+
// The timestamp fallback to 0 is just to satisfy the type checker.
|
|
1005
|
+
// In practice, the timestamp is always present in well-formatted BOLT11 invoices.
|
|
1006
|
+
timestamp: decoded.sections.find((s) => s.name === "timestamp")?.value ?? 0,
|
|
1004
1007
|
amountSats: Number(millisats / 1000n),
|
|
1005
1008
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1006
1009
|
// description_hash (BOLT11 `h`) is missing from light-bolt11-decoder's
|
|
@@ -2376,14 +2379,16 @@ var IndexedDbSwapRepository = class {
|
|
|
2376
2379
|
// src/arkade-swaps.ts
|
|
2377
2380
|
import {
|
|
2378
2381
|
ArkAddress as ArkAddress2,
|
|
2379
|
-
isRecoverable
|
|
2382
|
+
isRecoverable,
|
|
2383
|
+
getNetwork as getNetwork2
|
|
2380
2384
|
} from "@arkade-os/sdk";
|
|
2381
2385
|
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
2386
|
+
import { ripemd160 as ripemd1602 } from "@noble/hashes/legacy.js";
|
|
2382
2387
|
import { hex as hex8 } from "@scure/base";
|
|
2383
2388
|
import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
|
|
2384
2389
|
import { randomBytes } from "@noble/hashes/utils.js";
|
|
2385
2390
|
import { Address as Address2, OutScript as OutScript2, SigHash as SigHash2, Transaction as Transaction6 } from "@scure/btc-signer";
|
|
2386
|
-
import {
|
|
2391
|
+
import { equalBytes as equalBytes3 } from "@scure/btc-signer/utils.js";
|
|
2387
2392
|
|
|
2388
2393
|
// src/utils/musig.ts
|
|
2389
2394
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
@@ -2605,21 +2610,9 @@ var create = (privateKey, publicKeys) => {
|
|
|
2605
2610
|
// src/utils/boltz-swap-tx.ts
|
|
2606
2611
|
import { schnorr } from "@noble/curves/secp256k1.js";
|
|
2607
2612
|
import { hex as hex4 } from "@scure/base";
|
|
2608
|
-
import { Script, Transaction as Transaction2 } from "@scure/btc-signer";
|
|
2613
|
+
import { Script, ScriptNum, Transaction as Transaction2 } from "@scure/btc-signer";
|
|
2609
2614
|
import { tapLeafHash } from "@scure/btc-signer/payment.js";
|
|
2610
2615
|
import { compareBytes, equalBytes as equalBytes2 } from "@scure/btc-signer/utils.js";
|
|
2611
|
-
var REGTEST_NETWORK = {
|
|
2612
|
-
bech32: "bcrt",
|
|
2613
|
-
pubKeyHash: 111,
|
|
2614
|
-
scriptHash: 196,
|
|
2615
|
-
wif: 239
|
|
2616
|
-
};
|
|
2617
|
-
var MUTINYNET_NETWORK = {
|
|
2618
|
-
bech32: "tb",
|
|
2619
|
-
pubKeyHash: 111,
|
|
2620
|
-
scriptHash: 196,
|
|
2621
|
-
wif: 239
|
|
2622
|
-
};
|
|
2623
2616
|
var deserializeLeaf = (leaf) => ({
|
|
2624
2617
|
version: leaf.version,
|
|
2625
2618
|
output: hex4.decode(leaf.output)
|
|
@@ -2653,6 +2646,19 @@ var deserializeSwapTree = (tree) => {
|
|
|
2653
2646
|
])
|
|
2654
2647
|
};
|
|
2655
2648
|
};
|
|
2649
|
+
var TAPLEAF_V1 = 192;
|
|
2650
|
+
var PUSH_32 = Uint8Array.of(32);
|
|
2651
|
+
var decodeScriptNum = (data) => data instanceof Uint8Array && data.length > 0 ? Number(ScriptNum(5, true).decode(data)) : void 0;
|
|
2652
|
+
var assertChainHtlcLeaves = (tree, expected) => {
|
|
2653
|
+
if (tree.claimLeaf.version !== TAPLEAF_V1 || tree.refundLeaf.version !== TAPLEAF_V1)
|
|
2654
|
+
throw new Error("unexpected leaf version");
|
|
2655
|
+
const claim = Script.decode(tree.claimLeaf.output);
|
|
2656
|
+
if (claim.length !== 8 || claim[0] !== "SIZE" || !(claim[1] instanceof Uint8Array) || !equalBytes2(claim[1], PUSH_32) || claim[2] !== "EQUALVERIFY" || claim[3] !== "HASH160" || !(claim[4] instanceof Uint8Array) || !equalBytes2(claim[4], expected.preimageHash160) || claim[5] !== "EQUALVERIFY" || !(claim[6] instanceof Uint8Array) || !equalBytes2(claim[6], expected.claimXOnly) || claim[7] !== "CHECKSIG")
|
|
2657
|
+
throw new Error("unexpected claim leaf");
|
|
2658
|
+
const refund = Script.decode(tree.refundLeaf.output);
|
|
2659
|
+
if (refund.length !== 4 || !(refund[0] instanceof Uint8Array) || !equalBytes2(refund[0], expected.refundXOnly) || refund[1] !== "CHECKSIGVERIFY" || decodeScriptNum(refund[2]) !== expected.timeoutBlockHeight || refund[3] !== "CHECKLOCKTIMEVERIFY")
|
|
2660
|
+
throw new Error("unexpected refund leaf");
|
|
2661
|
+
};
|
|
2656
2662
|
var taprootHashTree = (tree) => {
|
|
2657
2663
|
if (!Array.isArray(tree)) {
|
|
2658
2664
|
return {
|
|
@@ -2720,8 +2726,8 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
|
|
|
2720
2726
|
return tx;
|
|
2721
2727
|
};
|
|
2722
2728
|
var targetFee = (satPerVbyte, constructTx) => {
|
|
2723
|
-
const
|
|
2724
|
-
return constructTx(BigInt(Math.ceil(
|
|
2729
|
+
const probe = constructTx(BigInt(1));
|
|
2730
|
+
return constructTx(BigInt(Math.ceil(probe.vsize * satPerVbyte)));
|
|
2725
2731
|
};
|
|
2726
2732
|
|
|
2727
2733
|
// src/utils/restoration.ts
|
|
@@ -2804,6 +2810,7 @@ import {
|
|
|
2804
2810
|
buildOffchainTx,
|
|
2805
2811
|
getSequence as getSequence2,
|
|
2806
2812
|
Intent,
|
|
2813
|
+
getNetwork,
|
|
2807
2814
|
networks,
|
|
2808
2815
|
VHTLC,
|
|
2809
2816
|
VtxoScript as VtxoScript2,
|
|
@@ -2990,7 +2997,7 @@ var createVHTLCScript = (args) => {
|
|
|
2990
2997
|
)
|
|
2991
2998
|
});
|
|
2992
2999
|
if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
|
|
2993
|
-
const hrp = network
|
|
3000
|
+
const hrp = getNetwork(network).hrp;
|
|
2994
3001
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
2995
3002
|
return { vhtlcScript, vhtlcAddress };
|
|
2996
3003
|
};
|
|
@@ -3425,6 +3432,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3425
3432
|
return {
|
|
3426
3433
|
amount: pendingSwap.response.onchainAmount,
|
|
3427
3434
|
expiry: decodedInvoice.expiry,
|
|
3435
|
+
timestamp: decodedInvoice.timestamp,
|
|
3428
3436
|
invoice: pendingSwap.response.invoice,
|
|
3429
3437
|
paymentHash: decodedInvoice.paymentHash,
|
|
3430
3438
|
pendingSwap,
|
|
@@ -4392,6 +4400,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4392
4400
|
}
|
|
4393
4401
|
/**
|
|
4394
4402
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
4403
|
+
*
|
|
4404
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
4405
|
+
*
|
|
4395
4406
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
4396
4407
|
* @returns The BTC transaction ID of the claim.
|
|
4397
4408
|
*/
|
|
@@ -4407,7 +4418,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4407
4418
|
throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
|
|
4408
4419
|
const lockupTx = Transaction6.fromRaw(hex8.decode(swapStatus.transaction.hex));
|
|
4409
4420
|
const arkInfo = await this.arkProvider.getInfo();
|
|
4410
|
-
const network = arkInfo.network
|
|
4421
|
+
const network = getNetwork2(arkInfo.network);
|
|
4411
4422
|
const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
|
|
4412
4423
|
const musig = tweakMusig(
|
|
4413
4424
|
create(hex8.decode(pendingSwap.ephemeralKey), [
|
|
@@ -4947,8 +4958,56 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4947
4958
|
message: "Boltz is trying to scam us (invalid address)"
|
|
4948
4959
|
});
|
|
4949
4960
|
}
|
|
4961
|
+
this.verifyBtcChainHtlc({ to, swap, arkNetwork: arkInfo.network });
|
|
4950
4962
|
return true;
|
|
4951
4963
|
}
|
|
4964
|
+
/**
|
|
4965
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
4966
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
4967
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
4968
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
4969
|
+
*/
|
|
4970
|
+
verifyBtcChainHtlc(args) {
|
|
4971
|
+
const { to, swap, arkNetwork } = args;
|
|
4972
|
+
const btcDetails = to === "ARK" ? swap.response.lockupDetails : swap.response.claimDetails;
|
|
4973
|
+
if (!btcDetails.swapTree)
|
|
4974
|
+
throw new SwapError({ message: `Swap ${swap.id}: missing swap tree in BTC details` });
|
|
4975
|
+
if (!btcDetails.serverPublicKey)
|
|
4976
|
+
throw new SwapError({
|
|
4977
|
+
message: `Swap ${swap.id}: missing server public key in BTC details`
|
|
4978
|
+
});
|
|
4979
|
+
if (typeof btcDetails.timeoutBlockHeight !== "number")
|
|
4980
|
+
throw new SwapError({
|
|
4981
|
+
message: `Swap ${swap.id}: missing timeout block height in BTC details`
|
|
4982
|
+
});
|
|
4983
|
+
const network = getNetwork2(arkNetwork);
|
|
4984
|
+
const swapTree = deserializeSwapTree(btcDetails.swapTree);
|
|
4985
|
+
const ephemeralPub = secp256k12.getPublicKey(hex8.decode(swap.ephemeralKey));
|
|
4986
|
+
const musig = tweakMusig(
|
|
4987
|
+
create(hex8.decode(swap.ephemeralKey), [
|
|
4988
|
+
hex8.decode(btcDetails.serverPublicKey),
|
|
4989
|
+
ephemeralPub
|
|
4990
|
+
]),
|
|
4991
|
+
swapTree.tree
|
|
4992
|
+
);
|
|
4993
|
+
const expectedScript = OutScript2.encode(Address2(network).decode(btcDetails.lockupAddress));
|
|
4994
|
+
if (!equalBytes3(p2trScript(musig.aggPubkey), expectedScript))
|
|
4995
|
+
throw new SwapError({ message: "Boltz is trying to scam us (invalid BTC address)" });
|
|
4996
|
+
const boltzXOnly = toXOnly(hex8.decode(btcDetails.serverPublicKey));
|
|
4997
|
+
const userXOnly = toXOnly(ephemeralPub);
|
|
4998
|
+
try {
|
|
4999
|
+
assertChainHtlcLeaves(swapTree, {
|
|
5000
|
+
preimageHash160: ripemd1602(hex8.decode(swap.request.preimageHash)),
|
|
5001
|
+
claimXOnly: to === "ARK" ? boltzXOnly : userXOnly,
|
|
5002
|
+
refundXOnly: to === "ARK" ? userXOnly : boltzXOnly,
|
|
5003
|
+
timeoutBlockHeight: btcDetails.timeoutBlockHeight
|
|
5004
|
+
});
|
|
5005
|
+
} catch (err) {
|
|
5006
|
+
throw new SwapError({
|
|
5007
|
+
message: `Boltz is trying to scam us (invalid BTC HTLC: ${err.message})`
|
|
5008
|
+
});
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
4952
5011
|
/**
|
|
4953
5012
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
4954
5013
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
package/dist/expo/background.cjs
CHANGED
|
@@ -969,6 +969,7 @@ var BoltzSwapProvider = class {
|
|
|
969
969
|
// src/arkade-swaps.ts
|
|
970
970
|
var import_sdk8 = require("@arkade-os/sdk");
|
|
971
971
|
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
972
|
+
var import_legacy2 = require("@noble/hashes/legacy.js");
|
|
972
973
|
var import_base9 = require("@scure/base");
|
|
973
974
|
var import_secp256k13 = require("@noble/curves/secp256k1.js");
|
|
974
975
|
var import_utils3 = require("@noble/hashes/utils.js");
|
|
@@ -1192,18 +1193,6 @@ var import_base3 = require("@scure/base");
|
|
|
1192
1193
|
var import_btc_signer = require("@scure/btc-signer");
|
|
1193
1194
|
var import_payment = require("@scure/btc-signer/payment.js");
|
|
1194
1195
|
var import_utils2 = require("@scure/btc-signer/utils.js");
|
|
1195
|
-
var REGTEST_NETWORK = {
|
|
1196
|
-
bech32: "bcrt",
|
|
1197
|
-
pubKeyHash: 111,
|
|
1198
|
-
scriptHash: 196,
|
|
1199
|
-
wif: 239
|
|
1200
|
-
};
|
|
1201
|
-
var MUTINYNET_NETWORK = {
|
|
1202
|
-
bech32: "tb",
|
|
1203
|
-
pubKeyHash: 111,
|
|
1204
|
-
scriptHash: 196,
|
|
1205
|
-
wif: 239
|
|
1206
|
-
};
|
|
1207
1196
|
var deserializeLeaf = (leaf) => ({
|
|
1208
1197
|
version: leaf.version,
|
|
1209
1198
|
output: import_base3.hex.decode(leaf.output)
|
|
@@ -1237,6 +1226,19 @@ var deserializeSwapTree = (tree) => {
|
|
|
1237
1226
|
])
|
|
1238
1227
|
};
|
|
1239
1228
|
};
|
|
1229
|
+
var TAPLEAF_V1 = 192;
|
|
1230
|
+
var PUSH_32 = Uint8Array.of(32);
|
|
1231
|
+
var decodeScriptNum = (data) => data instanceof Uint8Array && data.length > 0 ? Number((0, import_btc_signer.ScriptNum)(5, true).decode(data)) : void 0;
|
|
1232
|
+
var assertChainHtlcLeaves = (tree, expected) => {
|
|
1233
|
+
if (tree.claimLeaf.version !== TAPLEAF_V1 || tree.refundLeaf.version !== TAPLEAF_V1)
|
|
1234
|
+
throw new Error("unexpected leaf version");
|
|
1235
|
+
const claim = import_btc_signer.Script.decode(tree.claimLeaf.output);
|
|
1236
|
+
if (claim.length !== 8 || claim[0] !== "SIZE" || !(claim[1] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[1], PUSH_32) || claim[2] !== "EQUALVERIFY" || claim[3] !== "HASH160" || !(claim[4] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[4], expected.preimageHash160) || claim[5] !== "EQUALVERIFY" || !(claim[6] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[6], expected.claimXOnly) || claim[7] !== "CHECKSIG")
|
|
1237
|
+
throw new Error("unexpected claim leaf");
|
|
1238
|
+
const refund = import_btc_signer.Script.decode(tree.refundLeaf.output);
|
|
1239
|
+
if (refund.length !== 4 || !(refund[0] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(refund[0], expected.refundXOnly) || refund[1] !== "CHECKSIGVERIFY" || decodeScriptNum(refund[2]) !== expected.timeoutBlockHeight || refund[3] !== "CHECKLOCKTIMEVERIFY")
|
|
1240
|
+
throw new Error("unexpected refund leaf");
|
|
1241
|
+
};
|
|
1240
1242
|
var taprootHashTree = (tree) => {
|
|
1241
1243
|
if (!Array.isArray(tree)) {
|
|
1242
1244
|
return {
|
|
@@ -1304,8 +1306,8 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
|
|
|
1304
1306
|
return tx;
|
|
1305
1307
|
};
|
|
1306
1308
|
var targetFee = (satPerVbyte, constructTx) => {
|
|
1307
|
-
const
|
|
1308
|
-
return constructTx(BigInt(Math.ceil(
|
|
1309
|
+
const probe = constructTx(BigInt(1));
|
|
1310
|
+
return constructTx(BigInt(Math.ceil(probe.vsize * satPerVbyte)));
|
|
1309
1311
|
};
|
|
1310
1312
|
|
|
1311
1313
|
// src/utils/decoding.ts
|
|
@@ -1316,6 +1318,9 @@ var decodeInvoice = (invoice) => {
|
|
|
1316
1318
|
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1317
1319
|
return {
|
|
1318
1320
|
expiry: decoded.expiry ?? 3600,
|
|
1321
|
+
// The timestamp fallback to 0 is just to satisfy the type checker.
|
|
1322
|
+
// In practice, the timestamp is always present in well-formatted BOLT11 invoices.
|
|
1323
|
+
timestamp: decoded.sections.find((s) => s.name === "timestamp")?.value ?? 0,
|
|
1319
1324
|
amountSats: Number(millisats / 1000n),
|
|
1320
1325
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1321
1326
|
// description_hash (BOLT11 `h`) is missing from light-bolt11-decoder's
|
|
@@ -2933,7 +2938,7 @@ var createVHTLCScript = (args) => {
|
|
|
2933
2938
|
)
|
|
2934
2939
|
});
|
|
2935
2940
|
if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
|
|
2936
|
-
const hrp = network
|
|
2941
|
+
const hrp = (0, import_sdk7.getNetwork)(network).hrp;
|
|
2937
2942
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
2938
2943
|
return { vhtlcScript, vhtlcAddress };
|
|
2939
2944
|
};
|
|
@@ -3368,6 +3373,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3368
3373
|
return {
|
|
3369
3374
|
amount: pendingSwap.response.onchainAmount,
|
|
3370
3375
|
expiry: decodedInvoice.expiry,
|
|
3376
|
+
timestamp: decodedInvoice.timestamp,
|
|
3371
3377
|
invoice: pendingSwap.response.invoice,
|
|
3372
3378
|
paymentHash: decodedInvoice.paymentHash,
|
|
3373
3379
|
pendingSwap,
|
|
@@ -4335,6 +4341,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4335
4341
|
}
|
|
4336
4342
|
/**
|
|
4337
4343
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
4344
|
+
*
|
|
4345
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
4346
|
+
*
|
|
4338
4347
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
4339
4348
|
* @returns The BTC transaction ID of the claim.
|
|
4340
4349
|
*/
|
|
@@ -4350,7 +4359,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4350
4359
|
throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
|
|
4351
4360
|
const lockupTx = import_btc_signer5.Transaction.fromRaw(import_base9.hex.decode(swapStatus.transaction.hex));
|
|
4352
4361
|
const arkInfo = await this.arkProvider.getInfo();
|
|
4353
|
-
const network =
|
|
4362
|
+
const network = (0, import_sdk8.getNetwork)(arkInfo.network);
|
|
4354
4363
|
const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
|
|
4355
4364
|
const musig = tweakMusig(
|
|
4356
4365
|
create(import_base9.hex.decode(pendingSwap.ephemeralKey), [
|
|
@@ -4890,8 +4899,56 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4890
4899
|
message: "Boltz is trying to scam us (invalid address)"
|
|
4891
4900
|
});
|
|
4892
4901
|
}
|
|
4902
|
+
this.verifyBtcChainHtlc({ to, swap, arkNetwork: arkInfo.network });
|
|
4893
4903
|
return true;
|
|
4894
4904
|
}
|
|
4905
|
+
/**
|
|
4906
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
4907
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
4908
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
4909
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
4910
|
+
*/
|
|
4911
|
+
verifyBtcChainHtlc(args) {
|
|
4912
|
+
const { to, swap, arkNetwork } = args;
|
|
4913
|
+
const btcDetails = to === "ARK" ? swap.response.lockupDetails : swap.response.claimDetails;
|
|
4914
|
+
if (!btcDetails.swapTree)
|
|
4915
|
+
throw new SwapError({ message: `Swap ${swap.id}: missing swap tree in BTC details` });
|
|
4916
|
+
if (!btcDetails.serverPublicKey)
|
|
4917
|
+
throw new SwapError({
|
|
4918
|
+
message: `Swap ${swap.id}: missing server public key in BTC details`
|
|
4919
|
+
});
|
|
4920
|
+
if (typeof btcDetails.timeoutBlockHeight !== "number")
|
|
4921
|
+
throw new SwapError({
|
|
4922
|
+
message: `Swap ${swap.id}: missing timeout block height in BTC details`
|
|
4923
|
+
});
|
|
4924
|
+
const network = (0, import_sdk8.getNetwork)(arkNetwork);
|
|
4925
|
+
const swapTree = deserializeSwapTree(btcDetails.swapTree);
|
|
4926
|
+
const ephemeralPub = import_secp256k13.secp256k1.getPublicKey(import_base9.hex.decode(swap.ephemeralKey));
|
|
4927
|
+
const musig = tweakMusig(
|
|
4928
|
+
create(import_base9.hex.decode(swap.ephemeralKey), [
|
|
4929
|
+
import_base9.hex.decode(btcDetails.serverPublicKey),
|
|
4930
|
+
ephemeralPub
|
|
4931
|
+
]),
|
|
4932
|
+
swapTree.tree
|
|
4933
|
+
);
|
|
4934
|
+
const expectedScript = import_btc_signer5.OutScript.encode((0, import_btc_signer5.Address)(network).decode(btcDetails.lockupAddress));
|
|
4935
|
+
if (!(0, import_utils4.equalBytes)(p2trScript(musig.aggPubkey), expectedScript))
|
|
4936
|
+
throw new SwapError({ message: "Boltz is trying to scam us (invalid BTC address)" });
|
|
4937
|
+
const boltzXOnly = toXOnly(import_base9.hex.decode(btcDetails.serverPublicKey));
|
|
4938
|
+
const userXOnly = toXOnly(ephemeralPub);
|
|
4939
|
+
try {
|
|
4940
|
+
assertChainHtlcLeaves(swapTree, {
|
|
4941
|
+
preimageHash160: (0, import_legacy2.ripemd160)(import_base9.hex.decode(swap.request.preimageHash)),
|
|
4942
|
+
claimXOnly: to === "ARK" ? boltzXOnly : userXOnly,
|
|
4943
|
+
refundXOnly: to === "ARK" ? userXOnly : boltzXOnly,
|
|
4944
|
+
timeoutBlockHeight: btcDetails.timeoutBlockHeight
|
|
4945
|
+
});
|
|
4946
|
+
} catch (err) {
|
|
4947
|
+
throw new SwapError({
|
|
4948
|
+
message: `Boltz is trying to scam us (invalid BTC HTLC: ${err.message})`
|
|
4949
|
+
});
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4895
4952
|
/**
|
|
4896
4953
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
4897
4954
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
|
@@ -5549,14 +5606,19 @@ function createBackgroundWalletShim(args) {
|
|
|
5549
5606
|
getVtxos: async () => notImplemented("getVtxos"),
|
|
5550
5607
|
getBoardingUtxos: async () => notImplemented("getBoardingUtxos"),
|
|
5551
5608
|
getTransactionHistory: async () => notImplemented("getTransactionHistory"),
|
|
5609
|
+
getActivityHistory: async () => notImplemented("getActivityHistory"),
|
|
5552
5610
|
getContractManager: async () => notImplemented("getContractManager"),
|
|
5553
5611
|
getDelegateManager: async () => notImplemented("getDelegateManager"),
|
|
5554
5612
|
getDelegatorManager: async () => notImplemented("getDelegatorManager"),
|
|
5555
5613
|
sendBitcoin: async () => notImplemented("sendBitcoin"),
|
|
5556
5614
|
send: async () => notImplemented("send"),
|
|
5557
5615
|
settle: async () => notImplemented("settle"),
|
|
5616
|
+
clear: async () => notImplemented("clear"),
|
|
5558
5617
|
assetManager: new Proxy({}, {
|
|
5559
5618
|
get: () => notImplemented("assetManager")
|
|
5619
|
+
}),
|
|
5620
|
+
activity: new Proxy({}, {
|
|
5621
|
+
get: () => notImplemented("activity")
|
|
5560
5622
|
})
|
|
5561
5623
|
};
|
|
5562
5624
|
}
|
|
@@ -5578,13 +5640,13 @@ function defineExpoSwapBackgroundTask(taskName, options) {
|
|
|
5578
5640
|
const wallet = createBackgroundWalletShim({
|
|
5579
5641
|
identity,
|
|
5580
5642
|
getAddress: async () => {
|
|
5581
|
-
const { ArkAddress: ArkAddress3 } = await import("@arkade-os/sdk");
|
|
5643
|
+
const { ArkAddress: ArkAddress3, getNetwork: getNetwork3 } = await import("@arkade-os/sdk");
|
|
5582
5644
|
const { hex: hex9 } = await import("@scure/base");
|
|
5583
5645
|
const info = await arkProvider.getInfo();
|
|
5584
5646
|
const pubkey = await identity.xOnlyPublicKey();
|
|
5585
5647
|
const serverPubKey = hex9.decode(info.signerPubkey);
|
|
5586
5648
|
const xOnlyServerPubKey = serverPubKey.length === 33 ? serverPubKey.slice(1) : serverPubKey;
|
|
5587
|
-
const hrp = info.network
|
|
5649
|
+
const hrp = getNetwork3(info.network).hrp;
|
|
5588
5650
|
return new ArkAddress3(xOnlyServerPubKey, pubkey, hrp).encode();
|
|
5589
5651
|
}
|
|
5590
5652
|
});
|
|
@@ -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-CIqTFkV1.cjs';
|
|
2
|
+
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-CIqTFkV1.cjs';
|
|
3
3
|
import '@arkade-os/sdk/worker/expo';
|
|
4
4
|
import '@arkade-os/sdk';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-BKEkNZxK.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-C4HQHP9Z.js';
|
|
2
|
+
export { P as PersistedSwapBackgroundConfig, S as SWAP_POLL_TASK_TYPE, a as SwapTaskDependencies, s as swapsPollProcessor } from '../swapsPollProcessor-C4HQHP9Z.js';
|
|
3
3
|
import '@arkade-os/sdk/worker/expo';
|
|
4
4
|
import '@arkade-os/sdk';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-BKEkNZxK.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-HIG2OOAN.js";
|
|
5
5
|
import {
|
|
6
6
|
BoltzSwapProvider
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-VKHFXGKL.js";
|
|
8
8
|
import "../chunk-SJQJQO7P.js";
|
|
9
9
|
|
|
10
10
|
// src/expo/background.ts
|
|
@@ -27,14 +27,19 @@ function createBackgroundWalletShim(args) {
|
|
|
27
27
|
getVtxos: async () => notImplemented("getVtxos"),
|
|
28
28
|
getBoardingUtxos: async () => notImplemented("getBoardingUtxos"),
|
|
29
29
|
getTransactionHistory: async () => notImplemented("getTransactionHistory"),
|
|
30
|
+
getActivityHistory: async () => notImplemented("getActivityHistory"),
|
|
30
31
|
getContractManager: async () => notImplemented("getContractManager"),
|
|
31
32
|
getDelegateManager: async () => notImplemented("getDelegateManager"),
|
|
32
33
|
getDelegatorManager: async () => notImplemented("getDelegatorManager"),
|
|
33
34
|
sendBitcoin: async () => notImplemented("sendBitcoin"),
|
|
34
35
|
send: async () => notImplemented("send"),
|
|
35
36
|
settle: async () => notImplemented("settle"),
|
|
37
|
+
clear: async () => notImplemented("clear"),
|
|
36
38
|
assetManager: new Proxy({}, {
|
|
37
39
|
get: () => notImplemented("assetManager")
|
|
40
|
+
}),
|
|
41
|
+
activity: new Proxy({}, {
|
|
42
|
+
get: () => notImplemented("activity")
|
|
38
43
|
})
|
|
39
44
|
};
|
|
40
45
|
}
|
|
@@ -56,13 +61,13 @@ function defineExpoSwapBackgroundTask(taskName, options) {
|
|
|
56
61
|
const wallet = createBackgroundWalletShim({
|
|
57
62
|
identity,
|
|
58
63
|
getAddress: async () => {
|
|
59
|
-
const { ArkAddress } = await import("@arkade-os/sdk");
|
|
64
|
+
const { ArkAddress, getNetwork } = await import("@arkade-os/sdk");
|
|
60
65
|
const { hex } = await import("@scure/base");
|
|
61
66
|
const info = await arkProvider.getInfo();
|
|
62
67
|
const pubkey = await identity.xOnlyPublicKey();
|
|
63
68
|
const serverPubKey = hex.decode(info.signerPubkey);
|
|
64
69
|
const xOnlyServerPubKey = serverPubKey.length === 33 ? serverPubKey.slice(1) : serverPubKey;
|
|
65
|
-
const hrp = info.network
|
|
70
|
+
const hrp = getNetwork(info.network).hrp;
|
|
66
71
|
return new ArkAddress(xOnlyServerPubKey, pubkey, hrp).encode();
|
|
67
72
|
}
|
|
68
73
|
});
|
package/dist/expo/index.cjs
CHANGED
|
@@ -959,6 +959,7 @@ var BoltzSwapProvider = class {
|
|
|
959
959
|
|
|
960
960
|
// src/arkade-swaps.ts
|
|
961
961
|
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
962
|
+
var import_legacy2 = require("@noble/hashes/legacy.js");
|
|
962
963
|
var import_base9 = require("@scure/base");
|
|
963
964
|
var import_secp256k13 = require("@noble/curves/secp256k1.js");
|
|
964
965
|
var import_utils3 = require("@noble/hashes/utils.js");
|
|
@@ -1182,18 +1183,6 @@ var import_base3 = require("@scure/base");
|
|
|
1182
1183
|
var import_btc_signer = require("@scure/btc-signer");
|
|
1183
1184
|
var import_payment = require("@scure/btc-signer/payment.js");
|
|
1184
1185
|
var import_utils2 = require("@scure/btc-signer/utils.js");
|
|
1185
|
-
var REGTEST_NETWORK = {
|
|
1186
|
-
bech32: "bcrt",
|
|
1187
|
-
pubKeyHash: 111,
|
|
1188
|
-
scriptHash: 196,
|
|
1189
|
-
wif: 239
|
|
1190
|
-
};
|
|
1191
|
-
var MUTINYNET_NETWORK = {
|
|
1192
|
-
bech32: "tb",
|
|
1193
|
-
pubKeyHash: 111,
|
|
1194
|
-
scriptHash: 196,
|
|
1195
|
-
wif: 239
|
|
1196
|
-
};
|
|
1197
1186
|
var deserializeLeaf = (leaf) => ({
|
|
1198
1187
|
version: leaf.version,
|
|
1199
1188
|
output: import_base3.hex.decode(leaf.output)
|
|
@@ -1227,6 +1216,19 @@ var deserializeSwapTree = (tree) => {
|
|
|
1227
1216
|
])
|
|
1228
1217
|
};
|
|
1229
1218
|
};
|
|
1219
|
+
var TAPLEAF_V1 = 192;
|
|
1220
|
+
var PUSH_32 = Uint8Array.of(32);
|
|
1221
|
+
var decodeScriptNum = (data) => data instanceof Uint8Array && data.length > 0 ? Number((0, import_btc_signer.ScriptNum)(5, true).decode(data)) : void 0;
|
|
1222
|
+
var assertChainHtlcLeaves = (tree, expected) => {
|
|
1223
|
+
if (tree.claimLeaf.version !== TAPLEAF_V1 || tree.refundLeaf.version !== TAPLEAF_V1)
|
|
1224
|
+
throw new Error("unexpected leaf version");
|
|
1225
|
+
const claim = import_btc_signer.Script.decode(tree.claimLeaf.output);
|
|
1226
|
+
if (claim.length !== 8 || claim[0] !== "SIZE" || !(claim[1] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[1], PUSH_32) || claim[2] !== "EQUALVERIFY" || claim[3] !== "HASH160" || !(claim[4] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[4], expected.preimageHash160) || claim[5] !== "EQUALVERIFY" || !(claim[6] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[6], expected.claimXOnly) || claim[7] !== "CHECKSIG")
|
|
1227
|
+
throw new Error("unexpected claim leaf");
|
|
1228
|
+
const refund = import_btc_signer.Script.decode(tree.refundLeaf.output);
|
|
1229
|
+
if (refund.length !== 4 || !(refund[0] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(refund[0], expected.refundXOnly) || refund[1] !== "CHECKSIGVERIFY" || decodeScriptNum(refund[2]) !== expected.timeoutBlockHeight || refund[3] !== "CHECKLOCKTIMEVERIFY")
|
|
1230
|
+
throw new Error("unexpected refund leaf");
|
|
1231
|
+
};
|
|
1230
1232
|
var taprootHashTree = (tree) => {
|
|
1231
1233
|
if (!Array.isArray(tree)) {
|
|
1232
1234
|
return {
|
|
@@ -1294,8 +1296,8 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
|
|
|
1294
1296
|
return tx;
|
|
1295
1297
|
};
|
|
1296
1298
|
var targetFee = (satPerVbyte, constructTx) => {
|
|
1297
|
-
const
|
|
1298
|
-
return constructTx(BigInt(Math.ceil(
|
|
1299
|
+
const probe = constructTx(BigInt(1));
|
|
1300
|
+
return constructTx(BigInt(Math.ceil(probe.vsize * satPerVbyte)));
|
|
1299
1301
|
};
|
|
1300
1302
|
|
|
1301
1303
|
// src/utils/decoding.ts
|
|
@@ -1306,6 +1308,9 @@ var decodeInvoice = (invoice) => {
|
|
|
1306
1308
|
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1307
1309
|
return {
|
|
1308
1310
|
expiry: decoded.expiry ?? 3600,
|
|
1311
|
+
// The timestamp fallback to 0 is just to satisfy the type checker.
|
|
1312
|
+
// In practice, the timestamp is always present in well-formatted BOLT11 invoices.
|
|
1313
|
+
timestamp: decoded.sections.find((s) => s.name === "timestamp")?.value ?? 0,
|
|
1309
1314
|
amountSats: Number(millisats / 1000n),
|
|
1310
1315
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1311
1316
|
// description_hash (BOLT11 `h`) is missing from light-bolt11-decoder's
|
|
@@ -2923,7 +2928,7 @@ var createVHTLCScript = (args) => {
|
|
|
2923
2928
|
)
|
|
2924
2929
|
});
|
|
2925
2930
|
if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
|
|
2926
|
-
const hrp = network
|
|
2931
|
+
const hrp = (0, import_sdk7.getNetwork)(network).hrp;
|
|
2927
2932
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
2928
2933
|
return { vhtlcScript, vhtlcAddress };
|
|
2929
2934
|
};
|
|
@@ -3358,6 +3363,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3358
3363
|
return {
|
|
3359
3364
|
amount: pendingSwap.response.onchainAmount,
|
|
3360
3365
|
expiry: decodedInvoice.expiry,
|
|
3366
|
+
timestamp: decodedInvoice.timestamp,
|
|
3361
3367
|
invoice: pendingSwap.response.invoice,
|
|
3362
3368
|
paymentHash: decodedInvoice.paymentHash,
|
|
3363
3369
|
pendingSwap,
|
|
@@ -4325,6 +4331,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4325
4331
|
}
|
|
4326
4332
|
/**
|
|
4327
4333
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
4334
|
+
*
|
|
4335
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
4336
|
+
*
|
|
4328
4337
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
4329
4338
|
* @returns The BTC transaction ID of the claim.
|
|
4330
4339
|
*/
|
|
@@ -4340,7 +4349,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4340
4349
|
throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
|
|
4341
4350
|
const lockupTx = import_btc_signer5.Transaction.fromRaw(import_base9.hex.decode(swapStatus.transaction.hex));
|
|
4342
4351
|
const arkInfo = await this.arkProvider.getInfo();
|
|
4343
|
-
const network =
|
|
4352
|
+
const network = (0, import_sdk8.getNetwork)(arkInfo.network);
|
|
4344
4353
|
const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
|
|
4345
4354
|
const musig = tweakMusig(
|
|
4346
4355
|
create(import_base9.hex.decode(pendingSwap.ephemeralKey), [
|
|
@@ -4880,8 +4889,56 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4880
4889
|
message: "Boltz is trying to scam us (invalid address)"
|
|
4881
4890
|
});
|
|
4882
4891
|
}
|
|
4892
|
+
this.verifyBtcChainHtlc({ to, swap, arkNetwork: arkInfo.network });
|
|
4883
4893
|
return true;
|
|
4884
4894
|
}
|
|
4895
|
+
/**
|
|
4896
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
4897
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
4898
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
4899
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
4900
|
+
*/
|
|
4901
|
+
verifyBtcChainHtlc(args) {
|
|
4902
|
+
const { to, swap, arkNetwork } = args;
|
|
4903
|
+
const btcDetails = to === "ARK" ? swap.response.lockupDetails : swap.response.claimDetails;
|
|
4904
|
+
if (!btcDetails.swapTree)
|
|
4905
|
+
throw new SwapError({ message: `Swap ${swap.id}: missing swap tree in BTC details` });
|
|
4906
|
+
if (!btcDetails.serverPublicKey)
|
|
4907
|
+
throw new SwapError({
|
|
4908
|
+
message: `Swap ${swap.id}: missing server public key in BTC details`
|
|
4909
|
+
});
|
|
4910
|
+
if (typeof btcDetails.timeoutBlockHeight !== "number")
|
|
4911
|
+
throw new SwapError({
|
|
4912
|
+
message: `Swap ${swap.id}: missing timeout block height in BTC details`
|
|
4913
|
+
});
|
|
4914
|
+
const network = (0, import_sdk8.getNetwork)(arkNetwork);
|
|
4915
|
+
const swapTree = deserializeSwapTree(btcDetails.swapTree);
|
|
4916
|
+
const ephemeralPub = import_secp256k13.secp256k1.getPublicKey(import_base9.hex.decode(swap.ephemeralKey));
|
|
4917
|
+
const musig = tweakMusig(
|
|
4918
|
+
create(import_base9.hex.decode(swap.ephemeralKey), [
|
|
4919
|
+
import_base9.hex.decode(btcDetails.serverPublicKey),
|
|
4920
|
+
ephemeralPub
|
|
4921
|
+
]),
|
|
4922
|
+
swapTree.tree
|
|
4923
|
+
);
|
|
4924
|
+
const expectedScript = import_btc_signer5.OutScript.encode((0, import_btc_signer5.Address)(network).decode(btcDetails.lockupAddress));
|
|
4925
|
+
if (!(0, import_utils4.equalBytes)(p2trScript(musig.aggPubkey), expectedScript))
|
|
4926
|
+
throw new SwapError({ message: "Boltz is trying to scam us (invalid BTC address)" });
|
|
4927
|
+
const boltzXOnly = toXOnly(import_base9.hex.decode(btcDetails.serverPublicKey));
|
|
4928
|
+
const userXOnly = toXOnly(ephemeralPub);
|
|
4929
|
+
try {
|
|
4930
|
+
assertChainHtlcLeaves(swapTree, {
|
|
4931
|
+
preimageHash160: (0, import_legacy2.ripemd160)(import_base9.hex.decode(swap.request.preimageHash)),
|
|
4932
|
+
claimXOnly: to === "ARK" ? boltzXOnly : userXOnly,
|
|
4933
|
+
refundXOnly: to === "ARK" ? userXOnly : boltzXOnly,
|
|
4934
|
+
timeoutBlockHeight: btcDetails.timeoutBlockHeight
|
|
4935
|
+
});
|
|
4936
|
+
} catch (err) {
|
|
4937
|
+
throw new SwapError({
|
|
4938
|
+
message: `Boltz is trying to scam us (invalid BTC HTLC: ${err.message})`
|
|
4939
|
+
});
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4885
4942
|
/**
|
|
4886
4943
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
4887
4944
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
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 { 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-
|
|
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-BG3xEK31.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-BKEkNZxK.cjs';
|
|
3
|
+
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-CIqTFkV1.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-CIqTFkV1.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';
|
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 { 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-
|
|
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-A180YN8g.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-BKEkNZxK.js';
|
|
3
|
+
import { E as ExpoArkadeSwapsConfig } from '../swapsPollProcessor-C4HQHP9Z.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-C4HQHP9Z.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';
|
package/dist/expo/index.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -95,7 +95,7 @@ __export(index_exports, {
|
|
|
95
95
|
module.exports = __toCommonJS(index_exports);
|
|
96
96
|
|
|
97
97
|
// package.json
|
|
98
|
-
var version = "0.3.
|
|
98
|
+
var version = "0.3.47";
|
|
99
99
|
|
|
100
100
|
// src/errors.ts
|
|
101
101
|
var SwapError = class extends Error {
|
|
@@ -1091,6 +1091,7 @@ var BoltzSwapProvider = class {
|
|
|
1091
1091
|
|
|
1092
1092
|
// src/arkade-swaps.ts
|
|
1093
1093
|
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
1094
|
+
var import_legacy2 = require("@noble/hashes/legacy.js");
|
|
1094
1095
|
var import_base9 = require("@scure/base");
|
|
1095
1096
|
var import_secp256k13 = require("@noble/curves/secp256k1.js");
|
|
1096
1097
|
var import_utils3 = require("@noble/hashes/utils.js");
|
|
@@ -1314,18 +1315,6 @@ var import_base3 = require("@scure/base");
|
|
|
1314
1315
|
var import_btc_signer = require("@scure/btc-signer");
|
|
1315
1316
|
var import_payment = require("@scure/btc-signer/payment.js");
|
|
1316
1317
|
var import_utils2 = require("@scure/btc-signer/utils.js");
|
|
1317
|
-
var REGTEST_NETWORK = {
|
|
1318
|
-
bech32: "bcrt",
|
|
1319
|
-
pubKeyHash: 111,
|
|
1320
|
-
scriptHash: 196,
|
|
1321
|
-
wif: 239
|
|
1322
|
-
};
|
|
1323
|
-
var MUTINYNET_NETWORK = {
|
|
1324
|
-
bech32: "tb",
|
|
1325
|
-
pubKeyHash: 111,
|
|
1326
|
-
scriptHash: 196,
|
|
1327
|
-
wif: 239
|
|
1328
|
-
};
|
|
1329
1318
|
var deserializeLeaf = (leaf) => ({
|
|
1330
1319
|
version: leaf.version,
|
|
1331
1320
|
output: import_base3.hex.decode(leaf.output)
|
|
@@ -1359,6 +1348,19 @@ var deserializeSwapTree = (tree) => {
|
|
|
1359
1348
|
])
|
|
1360
1349
|
};
|
|
1361
1350
|
};
|
|
1351
|
+
var TAPLEAF_V1 = 192;
|
|
1352
|
+
var PUSH_32 = Uint8Array.of(32);
|
|
1353
|
+
var decodeScriptNum = (data) => data instanceof Uint8Array && data.length > 0 ? Number((0, import_btc_signer.ScriptNum)(5, true).decode(data)) : void 0;
|
|
1354
|
+
var assertChainHtlcLeaves = (tree, expected) => {
|
|
1355
|
+
if (tree.claimLeaf.version !== TAPLEAF_V1 || tree.refundLeaf.version !== TAPLEAF_V1)
|
|
1356
|
+
throw new Error("unexpected leaf version");
|
|
1357
|
+
const claim = import_btc_signer.Script.decode(tree.claimLeaf.output);
|
|
1358
|
+
if (claim.length !== 8 || claim[0] !== "SIZE" || !(claim[1] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[1], PUSH_32) || claim[2] !== "EQUALVERIFY" || claim[3] !== "HASH160" || !(claim[4] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[4], expected.preimageHash160) || claim[5] !== "EQUALVERIFY" || !(claim[6] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(claim[6], expected.claimXOnly) || claim[7] !== "CHECKSIG")
|
|
1359
|
+
throw new Error("unexpected claim leaf");
|
|
1360
|
+
const refund = import_btc_signer.Script.decode(tree.refundLeaf.output);
|
|
1361
|
+
if (refund.length !== 4 || !(refund[0] instanceof Uint8Array) || !(0, import_utils2.equalBytes)(refund[0], expected.refundXOnly) || refund[1] !== "CHECKSIGVERIFY" || decodeScriptNum(refund[2]) !== expected.timeoutBlockHeight || refund[3] !== "CHECKLOCKTIMEVERIFY")
|
|
1362
|
+
throw new Error("unexpected refund leaf");
|
|
1363
|
+
};
|
|
1362
1364
|
var taprootHashTree = (tree) => {
|
|
1363
1365
|
if (!Array.isArray(tree)) {
|
|
1364
1366
|
return {
|
|
@@ -1426,8 +1428,8 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
|
|
|
1426
1428
|
return tx;
|
|
1427
1429
|
};
|
|
1428
1430
|
var targetFee = (satPerVbyte, constructTx) => {
|
|
1429
|
-
const
|
|
1430
|
-
return constructTx(BigInt(Math.ceil(
|
|
1431
|
+
const probe = constructTx(BigInt(1));
|
|
1432
|
+
return constructTx(BigInt(Math.ceil(probe.vsize * satPerVbyte)));
|
|
1431
1433
|
};
|
|
1432
1434
|
|
|
1433
1435
|
// src/utils/decoding.ts
|
|
@@ -1438,6 +1440,9 @@ var decodeInvoice = (invoice) => {
|
|
|
1438
1440
|
const millisats = BigInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
|
|
1439
1441
|
return {
|
|
1440
1442
|
expiry: decoded.expiry ?? 3600,
|
|
1443
|
+
// The timestamp fallback to 0 is just to satisfy the type checker.
|
|
1444
|
+
// In practice, the timestamp is always present in well-formatted BOLT11 invoices.
|
|
1445
|
+
timestamp: decoded.sections.find((s) => s.name === "timestamp")?.value ?? 0,
|
|
1441
1446
|
amountSats: Number(millisats / 1000n),
|
|
1442
1447
|
description: decoded.sections.find((s) => s.name === "description")?.value ?? "",
|
|
1443
1448
|
// description_hash (BOLT11 `h`) is missing from light-bolt11-decoder's
|
|
@@ -3076,7 +3081,7 @@ var createVHTLCScript = (args) => {
|
|
|
3076
3081
|
)
|
|
3077
3082
|
});
|
|
3078
3083
|
if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
|
|
3079
|
-
const hrp = network
|
|
3084
|
+
const hrp = (0, import_sdk7.getNetwork)(network).hrp;
|
|
3080
3085
|
const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
|
|
3081
3086
|
return { vhtlcScript, vhtlcAddress };
|
|
3082
3087
|
};
|
|
@@ -3511,6 +3516,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3511
3516
|
return {
|
|
3512
3517
|
amount: pendingSwap.response.onchainAmount,
|
|
3513
3518
|
expiry: decodedInvoice.expiry,
|
|
3519
|
+
timestamp: decodedInvoice.timestamp,
|
|
3514
3520
|
invoice: pendingSwap.response.invoice,
|
|
3515
3521
|
paymentHash: decodedInvoice.paymentHash,
|
|
3516
3522
|
pendingSwap,
|
|
@@ -4478,6 +4484,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4478
4484
|
}
|
|
4479
4485
|
/**
|
|
4480
4486
|
* Claim sats on BTC chain by claiming the HTLC.
|
|
4487
|
+
*
|
|
4488
|
+
* The claim output is `swapOutput.amount − max(feeToDeliverExactAmount, targetFee)`.
|
|
4489
|
+
*
|
|
4481
4490
|
* @param pendingSwap - The pending chain swap with BTC transaction hex.
|
|
4482
4491
|
* @returns The BTC transaction ID of the claim.
|
|
4483
4492
|
*/
|
|
@@ -4493,7 +4502,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4493
4502
|
throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
|
|
4494
4503
|
const lockupTx = import_btc_signer5.Transaction.fromRaw(import_base9.hex.decode(swapStatus.transaction.hex));
|
|
4495
4504
|
const arkInfo = await this.arkProvider.getInfo();
|
|
4496
|
-
const network =
|
|
4505
|
+
const network = (0, import_sdk8.getNetwork)(arkInfo.network);
|
|
4497
4506
|
const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
|
|
4498
4507
|
const musig = tweakMusig(
|
|
4499
4508
|
create(import_base9.hex.decode(pendingSwap.ephemeralKey), [
|
|
@@ -5033,8 +5042,56 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
5033
5042
|
message: "Boltz is trying to scam us (invalid address)"
|
|
5034
5043
|
});
|
|
5035
5044
|
}
|
|
5045
|
+
this.verifyBtcChainHtlc({ to, swap, arkNetwork: arkInfo.network });
|
|
5036
5046
|
return true;
|
|
5037
5047
|
}
|
|
5048
|
+
/**
|
|
5049
|
+
* Verifies the BTC-side Taproot HTLC of a chain swap before funds are
|
|
5050
|
+
* committed: the lockup address must bind to MuSig2(boltz, user) over
|
|
5051
|
+
* Boltz's leaves, and those leaves must enforce the agreed preimage hash,
|
|
5052
|
+
* direction-specific keys, leaf version, and absolute refund CLTV.
|
|
5053
|
+
*/
|
|
5054
|
+
verifyBtcChainHtlc(args) {
|
|
5055
|
+
const { to, swap, arkNetwork } = args;
|
|
5056
|
+
const btcDetails = to === "ARK" ? swap.response.lockupDetails : swap.response.claimDetails;
|
|
5057
|
+
if (!btcDetails.swapTree)
|
|
5058
|
+
throw new SwapError({ message: `Swap ${swap.id}: missing swap tree in BTC details` });
|
|
5059
|
+
if (!btcDetails.serverPublicKey)
|
|
5060
|
+
throw new SwapError({
|
|
5061
|
+
message: `Swap ${swap.id}: missing server public key in BTC details`
|
|
5062
|
+
});
|
|
5063
|
+
if (typeof btcDetails.timeoutBlockHeight !== "number")
|
|
5064
|
+
throw new SwapError({
|
|
5065
|
+
message: `Swap ${swap.id}: missing timeout block height in BTC details`
|
|
5066
|
+
});
|
|
5067
|
+
const network = (0, import_sdk8.getNetwork)(arkNetwork);
|
|
5068
|
+
const swapTree = deserializeSwapTree(btcDetails.swapTree);
|
|
5069
|
+
const ephemeralPub = import_secp256k13.secp256k1.getPublicKey(import_base9.hex.decode(swap.ephemeralKey));
|
|
5070
|
+
const musig = tweakMusig(
|
|
5071
|
+
create(import_base9.hex.decode(swap.ephemeralKey), [
|
|
5072
|
+
import_base9.hex.decode(btcDetails.serverPublicKey),
|
|
5073
|
+
ephemeralPub
|
|
5074
|
+
]),
|
|
5075
|
+
swapTree.tree
|
|
5076
|
+
);
|
|
5077
|
+
const expectedScript = import_btc_signer5.OutScript.encode((0, import_btc_signer5.Address)(network).decode(btcDetails.lockupAddress));
|
|
5078
|
+
if (!(0, import_utils4.equalBytes)(p2trScript(musig.aggPubkey), expectedScript))
|
|
5079
|
+
throw new SwapError({ message: "Boltz is trying to scam us (invalid BTC address)" });
|
|
5080
|
+
const boltzXOnly = toXOnly(import_base9.hex.decode(btcDetails.serverPublicKey));
|
|
5081
|
+
const userXOnly = toXOnly(ephemeralPub);
|
|
5082
|
+
try {
|
|
5083
|
+
assertChainHtlcLeaves(swapTree, {
|
|
5084
|
+
preimageHash160: (0, import_legacy2.ripemd160)(import_base9.hex.decode(swap.request.preimageHash)),
|
|
5085
|
+
claimXOnly: to === "ARK" ? boltzXOnly : userXOnly,
|
|
5086
|
+
refundXOnly: to === "ARK" ? userXOnly : boltzXOnly,
|
|
5087
|
+
timeoutBlockHeight: btcDetails.timeoutBlockHeight
|
|
5088
|
+
});
|
|
5089
|
+
} catch (err) {
|
|
5090
|
+
throw new SwapError({
|
|
5091
|
+
message: `Boltz is trying to scam us (invalid BTC HTLC: ${err.message})`
|
|
5092
|
+
});
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5038
5095
|
/**
|
|
5039
5096
|
* Renegotiates the quote for an existing chain swap. Convenience wrapper
|
|
5040
5097
|
* over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Q as QuoteSwapOptions, I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-
|
|
2
|
-
export { A as ArkadeSwaps } from './arkade-swaps-
|
|
3
|
-
import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, O as OptimisticSendLightningPaymentResponse, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, j as ArkToBtcResponse, k as BtcToArkResponse, l as ChainArkRefundOutcome, m as SwapRepository, n as SwapManagerClient, o as SendLightningPaymentResponse, p as GetSwapsFilter } from './types-
|
|
4
|
-
export { q as ArkadeSwapsCreateConfig, r as BoltzSwapProvider, s as BoltzSwapStatus, I as IncomingPaymentSubscription, P as PendingChainSwap, t as PendingReverseSwap, u as PendingSubmarineSwap, v as PendingSwap, w as SubmarineProgressionStatus, x as SubmarineRecoveryStatus, y as SwapManager, z as SwapManagerCallbacks, E as SwapManagerConfig, H as SwapManagerEvents, V as Vtxo, J as hasSubmarineStatusReached, K as isChainClaimableStatus, M as isChainFailedStatus, Q as isChainFinalStatus, R as isChainPendingStatus, T as isChainRefundableStatus, U as isChainSignableStatus, W as isChainSuccessStatus, X as isChainSwapClaimable, Y as isChainSwapRefundable, Z as isPendingChainSwap, _ as isPendingReverseSwap, $ as isPendingSubmarineSwap, a0 as isReverseClaimableStatus, a1 as isReverseFailedStatus, a2 as isReverseFinalStatus, a3 as isReversePendingStatus, a4 as isReverseSuccessStatus, a5 as isReverseSwapClaimable, a6 as isSubmarineFailedStatus, a7 as isSubmarineFinalStatus, a8 as isSubmarinePendingStatus, a9 as isSubmarineRefundableStatus, aa as isSubmarineSuccessStatus, ab as isSubmarineSwapRefundable } from './types-
|
|
1
|
+
import { Q as QuoteSwapOptions, I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-BG3xEK31.cjs';
|
|
2
|
+
export { A as ArkadeSwaps } from './arkade-swaps-BG3xEK31.cjs';
|
|
3
|
+
import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, O as OptimisticSendLightningPaymentResponse, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, j as ArkToBtcResponse, k as BtcToArkResponse, l as ChainArkRefundOutcome, m as SwapRepository, n as SwapManagerClient, o as SendLightningPaymentResponse, p as GetSwapsFilter } from './types-BKEkNZxK.cjs';
|
|
4
|
+
export { q as ArkadeSwapsCreateConfig, r as BoltzSwapProvider, s as BoltzSwapStatus, I as IncomingPaymentSubscription, P as PendingChainSwap, t as PendingReverseSwap, u as PendingSubmarineSwap, v as PendingSwap, w as SubmarineProgressionStatus, x as SubmarineRecoveryStatus, y as SwapManager, z as SwapManagerCallbacks, E as SwapManagerConfig, H as SwapManagerEvents, V as Vtxo, J as hasSubmarineStatusReached, K as isChainClaimableStatus, M as isChainFailedStatus, Q as isChainFinalStatus, R as isChainPendingStatus, T as isChainRefundableStatus, U as isChainSignableStatus, W as isChainSuccessStatus, X as isChainSwapClaimable, Y as isChainSwapRefundable, Z as isPendingChainSwap, _ as isPendingReverseSwap, $ as isPendingSubmarineSwap, a0 as isReverseClaimableStatus, a1 as isReverseFailedStatus, a2 as isReverseFinalStatus, a3 as isReversePendingStatus, a4 as isReverseSuccessStatus, a5 as isReverseSwapClaimable, a6 as isSubmarineFailedStatus, a7 as isSubmarineFinalStatus, a8 as isSubmarinePendingStatus, a9 as isSubmarineRefundableStatus, aa as isSubmarineSuccessStatus, ab as isSubmarineSwapRefundable } from './types-BKEkNZxK.cjs';
|
|
5
5
|
import { Transaction } from '@scure/btc-signer';
|
|
6
6
|
import { MessageHandler, RequestEnvelope, ArkInfo, ResponseEnvelope, IWallet, IReadonlyWallet, VHTLC, Identity, ArkTxInput } from '@arkade-os/sdk';
|
|
7
7
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Q as QuoteSwapOptions, I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-
|
|
2
|
-
export { A as ArkadeSwaps } from './arkade-swaps-
|
|
3
|
-
import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, O as OptimisticSendLightningPaymentResponse, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, j as ArkToBtcResponse, k as BtcToArkResponse, l as ChainArkRefundOutcome, m as SwapRepository, n as SwapManagerClient, o as SendLightningPaymentResponse, p as GetSwapsFilter } from './types-
|
|
4
|
-
export { q as ArkadeSwapsCreateConfig, r as BoltzSwapProvider, s as BoltzSwapStatus, I as IncomingPaymentSubscription, P as PendingChainSwap, t as PendingReverseSwap, u as PendingSubmarineSwap, v as PendingSwap, w as SubmarineProgressionStatus, x as SubmarineRecoveryStatus, y as SwapManager, z as SwapManagerCallbacks, E as SwapManagerConfig, H as SwapManagerEvents, V as Vtxo, J as hasSubmarineStatusReached, K as isChainClaimableStatus, M as isChainFailedStatus, Q as isChainFinalStatus, R as isChainPendingStatus, T as isChainRefundableStatus, U as isChainSignableStatus, W as isChainSuccessStatus, X as isChainSwapClaimable, Y as isChainSwapRefundable, Z as isPendingChainSwap, _ as isPendingReverseSwap, $ as isPendingSubmarineSwap, a0 as isReverseClaimableStatus, a1 as isReverseFailedStatus, a2 as isReverseFinalStatus, a3 as isReversePendingStatus, a4 as isReverseSuccessStatus, a5 as isReverseSwapClaimable, a6 as isSubmarineFailedStatus, a7 as isSubmarineFinalStatus, a8 as isSubmarinePendingStatus, a9 as isSubmarineRefundableStatus, aa as isSubmarineSuccessStatus, ab as isSubmarineSwapRefundable } from './types-
|
|
1
|
+
import { Q as QuoteSwapOptions, I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-A180YN8g.js';
|
|
2
|
+
export { A as ArkadeSwaps } from './arkade-swaps-A180YN8g.js';
|
|
3
|
+
import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, O as OptimisticSendLightningPaymentResponse, f as SubmarineRefundOutcome, g as SubmarineRecoveryInfo, h as SubmarineRecoveryResult, i as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, j as ArkToBtcResponse, k as BtcToArkResponse, l as ChainArkRefundOutcome, m as SwapRepository, n as SwapManagerClient, o as SendLightningPaymentResponse, p as GetSwapsFilter } from './types-BKEkNZxK.js';
|
|
4
|
+
export { q as ArkadeSwapsCreateConfig, r as BoltzSwapProvider, s as BoltzSwapStatus, I as IncomingPaymentSubscription, P as PendingChainSwap, t as PendingReverseSwap, u as PendingSubmarineSwap, v as PendingSwap, w as SubmarineProgressionStatus, x as SubmarineRecoveryStatus, y as SwapManager, z as SwapManagerCallbacks, E as SwapManagerConfig, H as SwapManagerEvents, V as Vtxo, J as hasSubmarineStatusReached, K as isChainClaimableStatus, M as isChainFailedStatus, Q as isChainFinalStatus, R as isChainPendingStatus, T as isChainRefundableStatus, U as isChainSignableStatus, W as isChainSuccessStatus, X as isChainSwapClaimable, Y as isChainSwapRefundable, Z as isPendingChainSwap, _ as isPendingReverseSwap, $ as isPendingSubmarineSwap, a0 as isReverseClaimableStatus, a1 as isReverseFailedStatus, a2 as isReverseFinalStatus, a3 as isReversePendingStatus, a4 as isReverseSuccessStatus, a5 as isReverseSwapClaimable, a6 as isSubmarineFailedStatus, a7 as isSubmarineFinalStatus, a8 as isSubmarinePendingStatus, a9 as isSubmarineRefundableStatus, aa as isSubmarineSuccessStatus, ab as isSubmarineSwapRefundable } from './types-BKEkNZxK.js';
|
|
5
5
|
import { Transaction } from '@scure/btc-signer';
|
|
6
6
|
import { MessageHandler, RequestEnvelope, ArkInfo, ResponseEnvelope, IWallet, IReadonlyWallet, VHTLC, Identity, ArkTxInput } from '@arkade-os/sdk';
|
|
7
7
|
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
package/dist/index.js
CHANGED
|
@@ -53,14 +53,14 @@ import {
|
|
|
53
53
|
updateReverseSwapStatus,
|
|
54
54
|
updateSubmarineSwapStatus,
|
|
55
55
|
verifySignatures
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-VKHFXGKL.js";
|
|
57
57
|
import {
|
|
58
58
|
applyCreatedAtOrder,
|
|
59
59
|
applySwapsFilter
|
|
60
60
|
} from "./chunk-SJQJQO7P.js";
|
|
61
61
|
|
|
62
62
|
// package.json
|
|
63
|
-
var version = "0.3.
|
|
63
|
+
var version = "0.3.47";
|
|
64
64
|
|
|
65
65
|
// src/serviceWorker/arkade-swaps-message-handler.ts
|
|
66
66
|
import { RestArkProvider, RestIndexerProvider } from "@arkade-os/sdk";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RealmLike } from '@arkade-os/sdk/repositories/realm';
|
|
2
|
-
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-
|
|
2
|
+
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-BKEkNZxK.cjs';
|
|
3
3
|
import '@arkade-os/sdk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RealmLike } from '@arkade-os/sdk/repositories/realm';
|
|
2
|
-
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-
|
|
2
|
+
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-BKEkNZxK.js';
|
|
3
3
|
import '@arkade-os/sdk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
|
|
2
|
-
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-
|
|
2
|
+
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-BKEkNZxK.cjs';
|
|
3
3
|
import '@arkade-os/sdk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
|
|
2
|
-
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-
|
|
2
|
+
import { m as SwapRepository, B as BoltzSwap, p as GetSwapsFilter } from '../../types-BKEkNZxK.js';
|
|
3
3
|
import '@arkade-os/sdk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncStorageTaskQueue, TaskProcessor } from '@arkade-os/sdk/worker/expo';
|
|
2
2
|
import { Identity, ArkProvider, IndexerProvider, IWallet } from '@arkade-os/sdk';
|
|
3
|
-
import { m as SwapRepository, N as Network, r as BoltzSwapProvider, A as ArkadeSwapsConfig } from './types-
|
|
3
|
+
import { m as SwapRepository, N as Network, r as BoltzSwapProvider, A as ArkadeSwapsConfig } from './types-BKEkNZxK.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Dependencies injected into every swap processor at runtime.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncStorageTaskQueue, TaskProcessor } from '@arkade-os/sdk/worker/expo';
|
|
2
2
|
import { Identity, ArkProvider, IndexerProvider, IWallet } from '@arkade-os/sdk';
|
|
3
|
-
import { m as SwapRepository, N as Network, r as BoltzSwapProvider, A as ArkadeSwapsConfig } from './types-
|
|
3
|
+
import { m as SwapRepository, N as Network, r as BoltzSwapProvider, A as ArkadeSwapsConfig } from './types-BKEkNZxK.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Dependencies injected into every swap processor at runtime.
|
|
@@ -935,8 +935,10 @@ interface CreateLightningInvoiceRequest {
|
|
|
935
935
|
interface CreateLightningInvoiceResponse {
|
|
936
936
|
/** The on-chain amount in satoshis (after Boltz fees). */
|
|
937
937
|
amount: number;
|
|
938
|
-
/** Invoice expiry
|
|
938
|
+
/** Invoice expiry: seconds from invoice creation (timestamp) until it expires. */
|
|
939
939
|
expiry: number;
|
|
940
|
+
/** Invoice creation timestamp (Unix seconds). Always present in a valid BOLT11 invoice; `0` should not occur in practice. */
|
|
941
|
+
timestamp: number;
|
|
940
942
|
/** The BOLT11-encoded Lightning invoice string. */
|
|
941
943
|
invoice: string;
|
|
942
944
|
/** The payment hash (hex-encoded). */
|
|
@@ -1174,6 +1176,8 @@ type ArkadeSwapsCreateConfig = Omit<ArkadeSwapsConfig, "swapProvider"> & {
|
|
|
1174
1176
|
interface DecodedInvoice {
|
|
1175
1177
|
/** Invoice expiry timestamp (Unix seconds). */
|
|
1176
1178
|
expiry: number;
|
|
1179
|
+
/** Invoice creation timestamp (Unix seconds). Always present in a valid BOLT11 invoice; `0` should not occur in practice. */
|
|
1180
|
+
timestamp: number;
|
|
1177
1181
|
/** Invoice amount in satoshis. */
|
|
1178
1182
|
amountSats: number;
|
|
1179
1183
|
/** Invoice description string (BOLT11 `d` field; "" if none). */
|
|
@@ -935,8 +935,10 @@ interface CreateLightningInvoiceRequest {
|
|
|
935
935
|
interface CreateLightningInvoiceResponse {
|
|
936
936
|
/** The on-chain amount in satoshis (after Boltz fees). */
|
|
937
937
|
amount: number;
|
|
938
|
-
/** Invoice expiry
|
|
938
|
+
/** Invoice expiry: seconds from invoice creation (timestamp) until it expires. */
|
|
939
939
|
expiry: number;
|
|
940
|
+
/** Invoice creation timestamp (Unix seconds). Always present in a valid BOLT11 invoice; `0` should not occur in practice. */
|
|
941
|
+
timestamp: number;
|
|
940
942
|
/** The BOLT11-encoded Lightning invoice string. */
|
|
941
943
|
invoice: string;
|
|
942
944
|
/** The payment hash (hex-encoded). */
|
|
@@ -1174,6 +1176,8 @@ type ArkadeSwapsCreateConfig = Omit<ArkadeSwapsConfig, "swapProvider"> & {
|
|
|
1174
1176
|
interface DecodedInvoice {
|
|
1175
1177
|
/** Invoice expiry timestamp (Unix seconds). */
|
|
1176
1178
|
expiry: number;
|
|
1179
|
+
/** Invoice creation timestamp (Unix seconds). Always present in a valid BOLT11 invoice; `0` should not occur in practice. */
|
|
1180
|
+
timestamp: number;
|
|
1177
1181
|
/** Invoice amount in satoshis. */
|
|
1178
1182
|
amountSats: number;
|
|
1179
1183
|
/** Invoice description string (BOLT11 `d` field; "" if none). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkade-os/boltz-swap",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A production-ready TypeScript package that brings Boltz submarine-swaps to Arkade.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@scure/btc-signer": "2.0.1",
|
|
77
77
|
"bip68": "1.0.4",
|
|
78
78
|
"light-bolt11-decoder": "3.2.0",
|
|
79
|
-
"@arkade-os/sdk": "0.4.
|
|
79
|
+
"@arkade-os/sdk": "0.4.42"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"expo-task-manager": ">=3.0.0",
|