@arkade-os/swap 0.0.11 → 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -15
- package/dist/{chunk-RIC5ZTZK.js → chunk-AM3NNUMR.js} +59 -53
- package/dist/index.cjs +585 -202
- package/dist/index.d.cts +127 -36
- package/dist/index.d.ts +127 -36
- package/dist/index.js +528 -157
- package/dist/nostr.cjs +4 -1
- package/dist/nostr.d.cts +1 -1
- package/dist/nostr.d.ts +1 -1
- package/dist/nostr.js +1 -1
- package/dist/repositories/realm/index.d.cts +4 -4
- package/dist/repositories/realm/index.d.ts +4 -4
- package/dist/repositories/sqlite/index.d.cts +2 -2
- package/dist/repositories/sqlite/index.d.ts +2 -2
- package/dist/{repository-CfE18Fif.d.ts → repository-BWP1UstE.d.cts} +84 -56
- package/dist/{repository-B02vsgcV.d.cts → repository-DLpH41ZO.d.ts} +84 -56
- package/dist/{rfq-DkckzRKK.d.ts → rfq-CzCGjICq.d.cts} +42 -32
- package/dist/{rfq-DkckzRKK.d.cts → rfq-CzCGjICq.d.ts} +42 -32
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -89,6 +89,7 @@ __export(index_exports, {
|
|
|
89
89
|
classifySpend: () => classifySpend,
|
|
90
90
|
createOffer: () => createOffer,
|
|
91
91
|
createRfqSwapRecord: () => createRfqSwapRecord,
|
|
92
|
+
createSwapClient: () => createSwapClient,
|
|
92
93
|
decodeOffer: () => decodeOffer,
|
|
93
94
|
deriveLightningReceive: () => deriveLightningReceive,
|
|
94
95
|
deriveOnchainReceive: () => deriveOnchainReceive,
|
|
@@ -103,16 +104,18 @@ __export(index_exports, {
|
|
|
103
104
|
httpTransport: () => httpTransport,
|
|
104
105
|
isRfqSwapTerminal: () => isRfqSwapTerminal,
|
|
105
106
|
isRfqTerminal: () => isRfqTerminal,
|
|
107
|
+
lightningReceiveContract: () => lightningReceiveContract,
|
|
106
108
|
lightningReceiveRequest: () => lightningReceiveRequest,
|
|
109
|
+
lightningSendContract: () => lightningSendContract,
|
|
107
110
|
lightningSendRequest: () => lightningSendRequest,
|
|
108
|
-
lightningSendVtxoScript: () => lightningSendVtxoScript,
|
|
109
111
|
lockupContractParams: () => lockupContractParams,
|
|
110
112
|
makeCachedFeedFetch: () => makeCachedFeedFetch,
|
|
111
113
|
newPreimage: () => newPreimage,
|
|
112
114
|
newRfqId: () => newRfqId,
|
|
113
115
|
nextOnchainAction: () => nextOnchainAction,
|
|
116
|
+
normalizeRfqSwapRecord: () => normalizeRfqSwapRecord,
|
|
117
|
+
offerContract: () => offerContract,
|
|
114
118
|
offerTermsFromQuote: () => offerTermsFromQuote,
|
|
115
|
-
offerVtxoScript: () => offerVtxoScript,
|
|
116
119
|
onchainHtlcScript: () => onchainHtlcScript,
|
|
117
120
|
onchainReceiveRequest: () => onchainReceiveRequest,
|
|
118
121
|
onchainSendProfile: () => onchainSendProfile,
|
|
@@ -123,7 +126,6 @@ __export(index_exports, {
|
|
|
123
126
|
pushRefundWithoutReceiver: () => pushRefundWithoutReceiver,
|
|
124
127
|
readLockupFate: () => readLockupFate,
|
|
125
128
|
rebuildRfqSwap: () => rebuildRfqSwap,
|
|
126
|
-
receiveVtxoScript: () => receiveVtxoScript,
|
|
127
129
|
refundIfUnresolved: () => refundIfUnresolved,
|
|
128
130
|
registerLockupContract: () => registerLockupContract,
|
|
129
131
|
relayTransport: () => relayTransport,
|
|
@@ -426,7 +428,7 @@ function withExitClosure(program, exit) {
|
|
|
426
428
|
}
|
|
427
429
|
};
|
|
428
430
|
}
|
|
429
|
-
function swapProgramBinding(offer,
|
|
431
|
+
function swapProgramBinding(offer, operatorPubkey) {
|
|
430
432
|
if (offer.makerPkScript.length !== FIELDS.makerPkScript.width) {
|
|
431
433
|
throw new Error("makerPkScript is not a 34-byte taproot scriptPubKey");
|
|
432
434
|
}
|
|
@@ -438,7 +440,7 @@ function swapProgramBinding(offer, serverPubkey) {
|
|
|
438
440
|
args: {
|
|
439
441
|
makerWP: offer.makerPkScript.subarray(2),
|
|
440
442
|
wantAmount: offer.wantAmount,
|
|
441
|
-
server:
|
|
443
|
+
server: operatorPubkey,
|
|
442
444
|
user: offer.makerPublicKey,
|
|
443
445
|
// internal byte order
|
|
444
446
|
...offer.wantAsset && {
|
|
@@ -448,14 +450,14 @@ function swapProgramBinding(offer, serverPubkey) {
|
|
|
448
450
|
...offer.exitDelay && { exitDelay: offer.exitDelay.value }
|
|
449
451
|
},
|
|
450
452
|
keys: {
|
|
451
|
-
serverKey:
|
|
453
|
+
serverKey: operatorPubkey,
|
|
452
454
|
userKey: offer.makerPublicKey,
|
|
453
455
|
emulatorKey: offer.emulatorPubkey
|
|
454
456
|
}
|
|
455
457
|
};
|
|
456
458
|
}
|
|
457
|
-
function
|
|
458
|
-
const { program, args, keys } = swapProgramBinding(offer,
|
|
459
|
+
function offerContract(offer, operatorPubkey) {
|
|
460
|
+
const { program, args, keys } = swapProgramBinding(offer, operatorPubkey);
|
|
459
461
|
return new import_sdk2.arkade.ArkadeProgramScript(program, args, keys);
|
|
460
462
|
}
|
|
461
463
|
var OFFER_PACKET_TYPE = 3;
|
|
@@ -569,14 +571,14 @@ function decodeOffer(data) {
|
|
|
569
571
|
throw new Error(`missing/invalid ${name}`);
|
|
570
572
|
}
|
|
571
573
|
}
|
|
572
|
-
const
|
|
574
|
+
const need2 = (name) => {
|
|
573
575
|
const v = fields[name];
|
|
574
576
|
const len = FIELDS[name].width;
|
|
575
577
|
if (!v || len !== void 0 && v.length !== len)
|
|
576
578
|
throw new Error(`missing/invalid ${name}`);
|
|
577
579
|
return v;
|
|
578
580
|
};
|
|
579
|
-
const amount =
|
|
581
|
+
const amount = need2("wantAmount");
|
|
580
582
|
if (Boolean(fields.wantAsset) === Boolean(fields.offerAsset)) {
|
|
581
583
|
throw new Error("offer must carry exactly one of wantAsset or offerAsset");
|
|
582
584
|
}
|
|
@@ -593,13 +595,13 @@ function decodeOffer(data) {
|
|
|
593
595
|
throw new Error("offer must carry both ratioNum and ratioDen, or neither");
|
|
594
596
|
}
|
|
595
597
|
return {
|
|
596
|
-
swapPkScript:
|
|
598
|
+
swapPkScript: need2("swapPkScript"),
|
|
597
599
|
wantAmount: readU64(amount),
|
|
598
600
|
...fields.wantAsset && { wantAsset: import_sdk2.asset.AssetId.fromBytes(fields.wantAsset) },
|
|
599
601
|
...fields.offerAsset && { offerAsset: import_sdk2.asset.AssetId.fromBytes(fields.offerAsset) },
|
|
600
|
-
makerPkScript:
|
|
601
|
-
makerPublicKey:
|
|
602
|
-
emulatorPubkey:
|
|
602
|
+
makerPkScript: need2("makerPkScript"),
|
|
603
|
+
makerPublicKey: need2("makerPublicKey"),
|
|
604
|
+
emulatorPubkey: need2("emulatorPubkey"),
|
|
603
605
|
...ratioNum !== void 0 && { ratioNum },
|
|
604
606
|
...ratioDen !== void 0 && { ratioDen },
|
|
605
607
|
...fields.exitTimelock && { exitDelay: decodeExitDelay(fields.exitTimelock) }
|
|
@@ -612,17 +614,21 @@ function decodeExitDelay(value) {
|
|
|
612
614
|
}
|
|
613
615
|
var OFFER_CONTRACT_LABEL = "Arkade swap offer";
|
|
614
616
|
var OFFER_CONTRACT_KIND = "asset-swap-offer";
|
|
615
|
-
async function registerOfferContract(wallet,
|
|
616
|
-
const { program, args, keys } = swapProgramBinding(binding,
|
|
617
|
+
async function registerOfferContract(wallet, info, binding, operatorPubkey, expectedPkScript) {
|
|
618
|
+
const { program, args, keys } = swapProgramBinding(binding, operatorPubkey);
|
|
617
619
|
const contractManager = await wallet.getContractManager();
|
|
618
620
|
const client = await import_sdk2.arkade.Arkade.connect({
|
|
619
|
-
|
|
620
|
-
|
|
621
|
+
// Registration derives and persists; it never broadcasts and never
|
|
622
|
+
// reads UTXOs, so the only thing the client needs off the server is the
|
|
623
|
+
// info the caller already resolved. Handing that back — rather than a
|
|
624
|
+
// provider built from a URL — is what lets `createOffer` take just a
|
|
625
|
+
// wallet, and spares a second `/v1/info` round-trip.
|
|
626
|
+
arkade: { getInfo: async () => info },
|
|
621
627
|
identity: wallet.identity,
|
|
622
628
|
// without this the row's `address` would be derived against the SDK's
|
|
623
629
|
// default network while its script is right — a row that disagrees with
|
|
624
630
|
// the address the user is about to fund
|
|
625
|
-
network: (0, import_sdk2.
|
|
631
|
+
network: (0, import_sdk2.networkFromArkadeInfo)(info),
|
|
626
632
|
contractManager
|
|
627
633
|
});
|
|
628
634
|
const contract = new import_sdk2.arkade.ArkadeContract(client, program, args, keys);
|
|
@@ -643,17 +649,21 @@ function serverExitDelay(delay) {
|
|
|
643
649
|
}
|
|
644
650
|
return assertExitDelay({ value: delay, type: delay < BigInt(512) ? "blocks" : "seconds" });
|
|
645
651
|
}
|
|
646
|
-
async function createOffer(wallet,
|
|
652
|
+
async function createOffer(wallet, params) {
|
|
647
653
|
if (Boolean(params.wantAsset) === Boolean(params.offerAsset)) {
|
|
648
654
|
throw new Error("set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC)");
|
|
649
655
|
}
|
|
650
656
|
const [info, makerAddress, makerPublicKey] = await Promise.all([
|
|
651
|
-
|
|
657
|
+
// requireLive: this info binds signerPubkey into the covenant — a
|
|
658
|
+
// snapshot could derive an address the operator no longer co-signs
|
|
659
|
+
// for, so an unreachable operator fails the call instead (fail closed,
|
|
660
|
+
// the same behaviour the pre-#734 caller-held provider had)
|
|
661
|
+
wallet.getArkadeInfo({ requireLive: true }),
|
|
652
662
|
wallet.getAddress(),
|
|
653
663
|
wallet.identity.xOnlyPublicKey()
|
|
654
664
|
]);
|
|
655
|
-
const
|
|
656
|
-
const network = (0, import_sdk2.
|
|
665
|
+
const operatorPubKey = import_base2.hex.decode((0, import_sdk2.toXOnlySignerHex)(info.signerPubkey));
|
|
666
|
+
const network = (0, import_sdk2.networkFromArkadeInfo)(info);
|
|
657
667
|
const emuKey = import_base2.hex.decode(
|
|
658
668
|
(0, import_sdk2.toXOnlySignerHex)((0, import_sdk2.resolveEmulatorPubkey)(network, params.emulatorPubkey))
|
|
659
669
|
);
|
|
@@ -669,33 +679,33 @@ async function createOffer(wallet, arkServerUrl, params) {
|
|
|
669
679
|
// an offer that then fails to encode. @see assertExitDelay
|
|
670
680
|
exitDelay: params.noExit ? void 0 : params.exitDelay ? assertExitDelay(params.exitDelay) : serverExitDelay(info.unilateralExitDelay)
|
|
671
681
|
};
|
|
672
|
-
const script =
|
|
682
|
+
const script = offerContract(binding, operatorPubKey);
|
|
673
683
|
const offer = { ...binding, swapPkScript: script.pkScript };
|
|
674
|
-
await registerOfferContract(
|
|
675
|
-
wallet,
|
|
676
|
-
arkServerUrl,
|
|
677
|
-
info.network,
|
|
678
|
-
binding,
|
|
679
|
-
serverPubKey,
|
|
680
|
-
script.pkScript
|
|
681
|
-
);
|
|
684
|
+
await registerOfferContract(wallet, info, binding, operatorPubKey, script.pkScript);
|
|
682
685
|
const payload = encodeOffer(offer);
|
|
683
686
|
return {
|
|
684
687
|
offerHex: import_base2.hex.encode(payload),
|
|
685
688
|
extension: { type: OFFER_PACKET_TYPE, payload },
|
|
686
|
-
//
|
|
689
|
+
// the contract's .address() builds the address; assembling an ArkAddress
|
|
687
690
|
// from tweakedPublicKey here would silently miss any future step it gains
|
|
688
|
-
address: script.address(network.hrp,
|
|
691
|
+
address: script.address(network.hrp, operatorPubKey).encode(),
|
|
689
692
|
swapPkScript: script.pkScript
|
|
690
693
|
};
|
|
691
694
|
}
|
|
692
|
-
async function cancelOffer(wallet,
|
|
695
|
+
async function cancelOffer(wallet, offerHex, opts) {
|
|
693
696
|
const { repository, fundingTxid, swapAddress } = opts;
|
|
694
697
|
const offer = decodeOffer(import_base2.hex.decode(offerHex));
|
|
695
|
-
const contractManager = await
|
|
698
|
+
const [contractManager, info, reader, broadcaster] = await Promise.all([
|
|
699
|
+
wallet.getContractManager(),
|
|
700
|
+
wallet.getArkadeInfo({ requireLive: true }),
|
|
701
|
+
wallet.getArkadeReader(),
|
|
702
|
+
wallet.getArkadeBroadcaster()
|
|
703
|
+
]);
|
|
696
704
|
const client = await import_sdk2.arkade.Arkade.connect({
|
|
697
|
-
|
|
698
|
-
|
|
705
|
+
// info the wallet already holds, plus its broadcast pair — the shape
|
|
706
|
+
// `ArkadeServerProvider` describes, without a second `/v1/info`
|
|
707
|
+
arkade: { getInfo: async () => info, ...broadcaster },
|
|
708
|
+
indexer: reader,
|
|
699
709
|
identity: wallet.identity,
|
|
700
710
|
// registered offers resolve their VTXOs from the contract repository
|
|
701
711
|
// instead of a direct indexer query; the indexer above stays as the
|
|
@@ -710,7 +720,7 @@ async function cancelOffer(wallet, arkServerUrl, offerHex, opts) {
|
|
|
710
720
|
const rebuilt = new import_sdk2.arkade.ArkadeProgramScript(program, args, keys);
|
|
711
721
|
if (import_base2.hex.encode(rebuilt.pkScript) !== import_base2.hex.encode(offer.swapPkScript)) {
|
|
712
722
|
throw new Error(
|
|
713
|
-
"rebuilt covenant does not match the offer's swapPkScript \u2014 the
|
|
723
|
+
"rebuilt covenant does not match the offer's swapPkScript \u2014 the operator signing key has likely rotated since funding; pass swapAddress (the funded address) to pin the original key"
|
|
714
724
|
);
|
|
715
725
|
}
|
|
716
726
|
const contract = new import_sdk2.arkade.ArkadeContract(client, program, args, keys);
|
|
@@ -1374,7 +1384,7 @@ var LightningReceiveCorridor = {
|
|
|
1374
1384
|
const receive = swap;
|
|
1375
1385
|
return {
|
|
1376
1386
|
expectedAmount: receive.expectedAmount,
|
|
1377
|
-
...receive.
|
|
1387
|
+
...receive.claimTxid ? { claimTxid: receive.claimTxid } : {}
|
|
1378
1388
|
};
|
|
1379
1389
|
},
|
|
1380
1390
|
hydrate(profile) {
|
|
@@ -1384,13 +1394,13 @@ var LightningReceiveCorridor = {
|
|
|
1384
1394
|
return {
|
|
1385
1395
|
...hydrateHashlock(profile),
|
|
1386
1396
|
expectedAmount: profile.expectedAmount,
|
|
1387
|
-
...profile.
|
|
1397
|
+
...profile.claimTxid ? { claimTxid: profile.claimTxid } : {}
|
|
1388
1398
|
};
|
|
1389
1399
|
},
|
|
1390
1400
|
// We are the claimant here, so the preimage material on the hashlock is
|
|
1391
1401
|
// ours to use.
|
|
1392
1402
|
claimSecret: (profile) => ({ ...profile.signer, ...profile.hashlock }),
|
|
1393
|
-
activityTxids: (profile) => profile.
|
|
1403
|
+
activityTxids: (profile) => profile.claimTxid ? [profile.claimTxid] : []
|
|
1394
1404
|
};
|
|
1395
1405
|
function onchainSendProfile(result) {
|
|
1396
1406
|
return {
|
|
@@ -1474,13 +1484,32 @@ var isRfqSwapTerminal = (state) => RFQ_SWAP_TERMINAL_STATES.includes(state);
|
|
|
1474
1484
|
|
|
1475
1485
|
// src/rfqRecord.ts
|
|
1476
1486
|
var RFQ_SWAP_RETENTION_SECONDS = 30 * 24 * 60 * 60;
|
|
1487
|
+
function renameLegacyClaimTxid(profile) {
|
|
1488
|
+
const { claimArkTxid, ...rest } = profile;
|
|
1489
|
+
return { ...rest, claimTxid: rest.claimTxid ?? claimArkTxid };
|
|
1490
|
+
}
|
|
1491
|
+
function normalizeRfqSwapRecord(record) {
|
|
1492
|
+
const { fundingArkTxid, refundArkTxid, lockupSpendArkTxids, ...rest } = record;
|
|
1493
|
+
const legacyClaim = record.kind === "lightning_receive" && record.profile.claimArkTxid !== void 0;
|
|
1494
|
+
if (!fundingArkTxid && !refundArkTxid && !lockupSpendArkTxids && !legacyClaim) return record;
|
|
1495
|
+
const fundingTxid = rest.fundingTxid ?? fundingArkTxid;
|
|
1496
|
+
const refundTxid = rest.refundTxid ?? refundArkTxid;
|
|
1497
|
+
const lockupSpendTxids = rest.lockupSpendTxids ?? lockupSpendArkTxids;
|
|
1498
|
+
return {
|
|
1499
|
+
...rest,
|
|
1500
|
+
...fundingTxid ? { fundingTxid } : {},
|
|
1501
|
+
...refundTxid ? { refundTxid } : {},
|
|
1502
|
+
...lockupSpendTxids?.length ? { lockupSpendTxids } : {},
|
|
1503
|
+
...legacyClaim ? { profile: renameLegacyClaimTxid(record.profile) } : {}
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1477
1506
|
var managerState = (swap) => ({
|
|
1478
1507
|
rfqId: swap.rfqId,
|
|
1479
1508
|
state: swap.state,
|
|
1480
1509
|
createdAt: swap.createdAt,
|
|
1481
1510
|
updatedAt: swap.updatedAt,
|
|
1482
|
-
...swap.
|
|
1483
|
-
...swap.
|
|
1511
|
+
...swap.refundTxid ? { refundTxid: swap.refundTxid } : {},
|
|
1512
|
+
...swap.lockupSpendTxids?.length ? { lockupSpendTxids: [...swap.lockupSpendTxids] } : {},
|
|
1484
1513
|
...swap.failure ? { failure: swap.failure } : {},
|
|
1485
1514
|
...swap.blockedReason ? { blockedReason: swap.blockedReason } : {}
|
|
1486
1515
|
});
|
|
@@ -1511,27 +1540,29 @@ function createRfqSwapRecord(origin, swap) {
|
|
|
1511
1540
|
}
|
|
1512
1541
|
function updateRfqSwapRecord(record, swap) {
|
|
1513
1542
|
assertSameSwap(record, swap);
|
|
1543
|
+
const stored = normalizeRfqSwapRecord(record);
|
|
1514
1544
|
const {
|
|
1515
|
-
|
|
1516
|
-
|
|
1545
|
+
refundTxid: _refundTxid,
|
|
1546
|
+
lockupSpendTxids: _lockupSpendTxids,
|
|
1517
1547
|
failure: _failure,
|
|
1518
1548
|
blockedReason: _blockedReason,
|
|
1519
1549
|
...origin
|
|
1520
|
-
} =
|
|
1521
|
-
const handler = rfqCorridorHandlers.getOrThrow(
|
|
1550
|
+
} = stored;
|
|
1551
|
+
const handler = rfqCorridorHandlers.getOrThrow(stored.kind);
|
|
1522
1552
|
return {
|
|
1523
1553
|
...origin,
|
|
1524
1554
|
...managerState(swap),
|
|
1525
|
-
profile: { ...
|
|
1555
|
+
profile: { ...stored.profile, ...handler.project(swap) }
|
|
1526
1556
|
};
|
|
1527
1557
|
}
|
|
1528
1558
|
function rfqSwapOriginOf(record) {
|
|
1559
|
+
const stored = normalizeRfqSwapRecord(record);
|
|
1529
1560
|
return {
|
|
1530
|
-
kind:
|
|
1531
|
-
lockupAddress:
|
|
1532
|
-
profile: { ...
|
|
1533
|
-
...
|
|
1534
|
-
...
|
|
1561
|
+
kind: stored.kind,
|
|
1562
|
+
lockupAddress: stored.lockupAddress,
|
|
1563
|
+
profile: { ...stored.profile },
|
|
1564
|
+
...stored.amount !== void 0 ? { amount: stored.amount } : {},
|
|
1565
|
+
...stored.fundingTxid ? { fundingTxid: stored.fundingTxid } : {}
|
|
1535
1566
|
};
|
|
1536
1567
|
}
|
|
1537
1568
|
function lockupScript(params, lockupAddress) {
|
|
@@ -1545,27 +1576,28 @@ function lockupScript(params, lockupAddress) {
|
|
|
1545
1576
|
return script;
|
|
1546
1577
|
}
|
|
1547
1578
|
function rebuildRfqSwap(record, params) {
|
|
1548
|
-
const
|
|
1579
|
+
const stored = normalizeRfqSwapRecord(record);
|
|
1580
|
+
const script = lockupScript(params, stored.lockupAddress);
|
|
1549
1581
|
const common = {
|
|
1550
|
-
rfqId:
|
|
1551
|
-
state:
|
|
1582
|
+
rfqId: stored.rfqId,
|
|
1583
|
+
state: stored.state,
|
|
1552
1584
|
lockupPkScript: script.pkScript,
|
|
1553
|
-
lockup: { script, address:
|
|
1585
|
+
lockup: { script, address: stored.lockupAddress },
|
|
1554
1586
|
// From the covenant, which binds it: the record's own copy would be a
|
|
1555
1587
|
// second source for the deadline the refund is gated on.
|
|
1556
1588
|
refundLocktime: Number(script.options.refundLocktime),
|
|
1557
|
-
createdAt:
|
|
1558
|
-
updatedAt:
|
|
1559
|
-
...
|
|
1560
|
-
...
|
|
1561
|
-
...
|
|
1562
|
-
...
|
|
1589
|
+
createdAt: stored.createdAt,
|
|
1590
|
+
updatedAt: stored.updatedAt,
|
|
1591
|
+
...stored.refundTxid ? { refundTxid: stored.refundTxid } : {},
|
|
1592
|
+
...stored.lockupSpendTxids?.length ? { lockupSpendTxids: [...stored.lockupSpendTxids] } : {},
|
|
1593
|
+
...stored.failure ? { failure: stored.failure } : {},
|
|
1594
|
+
...stored.blockedReason ? { blockedReason: stored.blockedReason } : {}
|
|
1563
1595
|
};
|
|
1564
|
-
const handler = rfqCorridorHandlers.getOrThrow(
|
|
1596
|
+
const handler = rfqCorridorHandlers.getOrThrow(stored.kind);
|
|
1565
1597
|
return {
|
|
1566
1598
|
...common,
|
|
1567
|
-
kind:
|
|
1568
|
-
...handler.hydrate(
|
|
1599
|
+
kind: stored.kind,
|
|
1600
|
+
...handler.hydrate(stored.profile, { lockup: script })
|
|
1569
1601
|
};
|
|
1570
1602
|
}
|
|
1571
1603
|
function shouldRetainRfqSwap(record, now) {
|
|
@@ -1602,10 +1634,10 @@ async function fetchParsedTxs(indexer, txids) {
|
|
|
1602
1634
|
var unscannedSwapCandidates = (txs, existingIds, scanned) => txs.filter(
|
|
1603
1635
|
(tx) => tx.type === "sent" && tx.redeemTxid && !existingIds.has(tx.redeemTxid) && !scanned.has(tx.redeemTxid)
|
|
1604
1636
|
);
|
|
1605
|
-
function classifySpend(offer,
|
|
1637
|
+
function classifySpend(offer, operatorPubkey, spendTx, deposit) {
|
|
1606
1638
|
let leaves;
|
|
1607
1639
|
try {
|
|
1608
|
-
const script =
|
|
1640
|
+
const script = offerContract(offer, operatorPubkey);
|
|
1609
1641
|
if (import_base6.hex.encode(script.pkScript) !== import_base6.hex.encode(offer.swapPkScript)) return "indeterminate";
|
|
1610
1642
|
leaves = {
|
|
1611
1643
|
// both routes that hand the deposit back; `exit` is absent on an
|
|
@@ -1629,15 +1661,15 @@ function classifySpend(offer, serverPubkey, spendTx, deposit) {
|
|
|
1629
1661
|
return "indeterminate";
|
|
1630
1662
|
}
|
|
1631
1663
|
var spendTxidsOf = (vtxo) => [vtxo.spentBy, vtxo.arkTxId].filter((id) => Boolean(id));
|
|
1632
|
-
function classifyDepositSpend(offer,
|
|
1664
|
+
function classifyDepositSpend(offer, operatorPubkey, spendTxs, deposit) {
|
|
1633
1665
|
for (const tx of spendTxs) {
|
|
1634
|
-
const kind = classifySpend(offer,
|
|
1666
|
+
const kind = classifySpend(offer, operatorPubkey, tx, deposit);
|
|
1635
1667
|
if (kind !== "indeterminate") return kind;
|
|
1636
1668
|
}
|
|
1637
1669
|
return "indeterminate";
|
|
1638
1670
|
}
|
|
1639
1671
|
async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
1640
|
-
const {
|
|
1672
|
+
const { operatorPubkey, scanned = /* @__PURE__ */ new Set() } = opts;
|
|
1641
1673
|
const candidates = unscannedSwapCandidates(txs, existingIds, scanned);
|
|
1642
1674
|
if (candidates.length === 0) return { restored: [], scannedTxids: [] };
|
|
1643
1675
|
const byTxid = new Map(candidates.map((tx) => [tx.redeemTxid, tx]));
|
|
@@ -1706,7 +1738,7 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
1706
1738
|
if (state === "swept") status = "recoverable";
|
|
1707
1739
|
else if (state === "spent") {
|
|
1708
1740
|
const spendTxs = spendTxidsOf(vtxo).map((id) => spendTxByTxid.get(id)).filter((tx) => tx !== void 0);
|
|
1709
|
-
const kind = classifyDepositSpend(offer,
|
|
1741
|
+
const kind = classifyDepositSpend(offer, operatorPubkey, spendTxs, {
|
|
1710
1742
|
txid: vtxo.txid,
|
|
1711
1743
|
vout: vtxo.vout
|
|
1712
1744
|
});
|
|
@@ -1723,7 +1755,7 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
1723
1755
|
fromAmount,
|
|
1724
1756
|
toAmount: offer.wantAmount.toString(),
|
|
1725
1757
|
// ponytail(arkade-os/ts-sdk#680): empty address makes cancel fall back
|
|
1726
|
-
// to the current
|
|
1758
|
+
// to the current operator key; store the funded address if operator-key
|
|
1727
1759
|
// rotations become real (cancelOffer now at least diagnoses the
|
|
1728
1760
|
// mismatch instead of reporting a missing VTXO)
|
|
1729
1761
|
swapAddress: "",
|
|
@@ -1758,13 +1790,15 @@ function spendUpdate(swap, spend) {
|
|
|
1758
1790
|
}
|
|
1759
1791
|
async function watchOfferSwaps({
|
|
1760
1792
|
wallet,
|
|
1761
|
-
arkServerUrl,
|
|
1762
1793
|
repository,
|
|
1763
1794
|
onUpdate
|
|
1764
1795
|
}) {
|
|
1765
|
-
const manager = await
|
|
1766
|
-
|
|
1767
|
-
|
|
1796
|
+
const [manager, address, indexer] = await Promise.all([
|
|
1797
|
+
wallet.getContractManager(),
|
|
1798
|
+
wallet.getAddress(),
|
|
1799
|
+
wallet.getArkadeReader()
|
|
1800
|
+
]);
|
|
1801
|
+
const operatorPubkey = import_sdk7.ArkAddress.decode(address).serverPubKey;
|
|
1768
1802
|
let queue = Promise.resolve();
|
|
1769
1803
|
const enqueue = (task) => {
|
|
1770
1804
|
queue = queue.then(task).catch(() => {
|
|
@@ -1778,7 +1812,7 @@ async function watchOfferSwaps({
|
|
|
1778
1812
|
const { txs } = await indexer.getVirtualTxs(candidates);
|
|
1779
1813
|
return classifyDepositSpend(
|
|
1780
1814
|
decodeOffer(import_base7.hex.decode(swap.offerHex)),
|
|
1781
|
-
|
|
1815
|
+
operatorPubkey,
|
|
1782
1816
|
txs.map((psbt) => import_sdk7.Transaction.fromPSBT(import_base7.base64.decode(psbt))),
|
|
1783
1817
|
{ txid: vtxo.txid, vout: vtxo.vout }
|
|
1784
1818
|
);
|
|
@@ -1932,11 +1966,14 @@ var ONCHAIN_SEND_PAIR = rfqPair(ARKADE_BTC, ONCHAIN_BTC);
|
|
|
1932
1966
|
var ONCHAIN_RECEIVE_PAIR = rfqPair(ONCHAIN_BTC, ARKADE_BTC);
|
|
1933
1967
|
var RFQ_TERMINAL_STATES = ["settled", "refused", "expired", "refunded", "stuck"];
|
|
1934
1968
|
var SwapRefusal = class extends Error {
|
|
1969
|
+
/** Literal-typed so the v2 error taxonomy's union discriminates on `name`
|
|
1970
|
+
* — a `string` here collapses the discriminant for every member. Same value
|
|
1971
|
+
* the constructor has always set, moved to a field initializer. */
|
|
1972
|
+
name = "SwapRefusal";
|
|
1935
1973
|
reason;
|
|
1936
1974
|
rfqId;
|
|
1937
1975
|
constructor(reason, rfqId) {
|
|
1938
1976
|
super(`solver refused: ${reason}`);
|
|
1939
|
-
this.name = "SwapRefusal";
|
|
1940
1977
|
this.reason = reason;
|
|
1941
1978
|
this.rfqId = rfqId;
|
|
1942
1979
|
}
|
|
@@ -2202,22 +2239,22 @@ var relayTransport = (relayUrl, options) => {
|
|
|
2202
2239
|
};
|
|
2203
2240
|
var SEQUENCE_GRANULARITY_SECONDS = 512;
|
|
2204
2241
|
var SOLO_REFUND_HEADROOM_SECONDS = 8 * SEQUENCE_GRANULARITY_SECONDS;
|
|
2205
|
-
var unilateralClaimDelay = (
|
|
2206
|
-
if (!Number.isFinite(
|
|
2242
|
+
var unilateralClaimDelay = (operatorExitDelaySeconds) => {
|
|
2243
|
+
if (!Number.isFinite(operatorExitDelaySeconds) || operatorExitDelaySeconds < SEQUENCE_GRANULARITY_SECONDS) {
|
|
2207
2244
|
throw new Error(
|
|
2208
|
-
`
|
|
2245
|
+
`operator exit delay must be at least ${SEQUENCE_GRANULARITY_SECONDS}s of seconds, got ${operatorExitDelaySeconds}`
|
|
2209
2246
|
);
|
|
2210
2247
|
}
|
|
2211
|
-
if (
|
|
2248
|
+
if (operatorExitDelaySeconds > 65535 * SEQUENCE_GRANULARITY_SECONDS - SOLO_REFUND_HEADROOM_SECONDS) {
|
|
2212
2249
|
throw new Error(
|
|
2213
|
-
`
|
|
2250
|
+
`operator exit delay ${operatorExitDelaySeconds}s exceeds what BIP68 can encode once the solo refund's headroom is stacked above it`
|
|
2214
2251
|
);
|
|
2215
2252
|
}
|
|
2216
|
-
return Math.ceil(
|
|
2253
|
+
return Math.ceil(operatorExitDelaySeconds / SEQUENCE_GRANULARITY_SECONDS) * SEQUENCE_GRANULARITY_SECONDS;
|
|
2217
2254
|
};
|
|
2218
2255
|
var unilateralRefundDelay = (claimDelay) => claimDelay;
|
|
2219
2256
|
var unilateralRefundWithoutReceiverDelay = (claimDelay) => claimDelay + SOLO_REFUND_HEADROOM_SECONDS;
|
|
2220
|
-
function
|
|
2257
|
+
function lightningSendContract(params) {
|
|
2221
2258
|
const seconds = (value) => ({
|
|
2222
2259
|
type: "seconds",
|
|
2223
2260
|
value: BigInt(value)
|
|
@@ -2225,7 +2262,7 @@ function lightningSendVtxoScript(params) {
|
|
|
2225
2262
|
return new import_sdk9.VHTLC.ScriptV2({
|
|
2226
2263
|
sender: params.senderPubkey,
|
|
2227
2264
|
receiver: params.solverPubkey,
|
|
2228
|
-
server: params.
|
|
2265
|
+
server: params.operatorPubkey,
|
|
2229
2266
|
preimageHash: (0, import_legacy2.ripemd160)(import_base10.hex.decode(params.paymentHash)),
|
|
2230
2267
|
refundLocktime: BigInt(params.refundLocktime),
|
|
2231
2268
|
unilateralClaimDelay: seconds(params.claimDelay),
|
|
@@ -2241,12 +2278,12 @@ function lightningSendVtxoScript(params) {
|
|
|
2241
2278
|
}
|
|
2242
2279
|
});
|
|
2243
2280
|
}
|
|
2244
|
-
async function requestLightningSend(wallet,
|
|
2281
|
+
async function requestLightningSend(wallet, transport, params) {
|
|
2245
2282
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2246
2283
|
const secrets = await (0, import_sdk10.provisionRefundKey)(wallet);
|
|
2247
2284
|
const senderPubkey = secrets.pubkey;
|
|
2248
2285
|
const refundAddress = secrets.address;
|
|
2249
|
-
const info = await
|
|
2286
|
+
const info = await wallet.getArkadeInfo({ requireLive: true });
|
|
2250
2287
|
const quote = await transport.requestQuote(
|
|
2251
2288
|
lightningSendRequest({ rfqId, invoice: params.invoice.raw, refundAddress, senderPubkey })
|
|
2252
2289
|
);
|
|
@@ -2267,12 +2304,12 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
|
2267
2304
|
`quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
|
|
2268
2305
|
);
|
|
2269
2306
|
}
|
|
2270
|
-
const
|
|
2271
|
-
const network = (0, import_sdk9.
|
|
2272
|
-
const
|
|
2307
|
+
const operatorPubkey = (0, import_sdk9.toXOnly)(import_base10.hex.decode(info.signerPubkey), "ark signer key");
|
|
2308
|
+
const network = (0, import_sdk9.networkFromArkadeInfo)(info);
|
|
2309
|
+
const contractParams = {
|
|
2273
2310
|
solverPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2274
2311
|
refundLocktime: quote.refund_locktime,
|
|
2275
|
-
|
|
2312
|
+
operatorPubkey,
|
|
2276
2313
|
paymentHash: params.invoice.paymentHash,
|
|
2277
2314
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
2278
2315
|
emulatorPubkey: (0, import_sdk9.toXOnly)(
|
|
@@ -2286,13 +2323,13 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
|
2286
2323
|
const matched = matchQuotedLockup(
|
|
2287
2324
|
quote,
|
|
2288
2325
|
network.hrp,
|
|
2289
|
-
|
|
2290
|
-
(legacy) =>
|
|
2326
|
+
operatorPubkey,
|
|
2327
|
+
(legacy) => lightningSendContract({ ...contractParams, ...legacy !== void 0 && { legacy } })
|
|
2291
2328
|
);
|
|
2292
2329
|
const script = matched.script;
|
|
2293
2330
|
const address = matched.address;
|
|
2294
|
-
const
|
|
2295
|
-
...
|
|
2331
|
+
const matchedContractParams = {
|
|
2332
|
+
...contractParams,
|
|
2296
2333
|
...matched.legacy !== void 0 && { legacy: matched.legacy }
|
|
2297
2334
|
};
|
|
2298
2335
|
assertFundable({
|
|
@@ -2313,7 +2350,7 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
|
2313
2350
|
refundAddress,
|
|
2314
2351
|
senderPubkey,
|
|
2315
2352
|
secrets,
|
|
2316
|
-
|
|
2353
|
+
contractParams: matchedContractParams
|
|
2317
2354
|
};
|
|
2318
2355
|
}
|
|
2319
2356
|
var offerTermsFromQuote = (quote, assets) => {
|
|
@@ -2378,10 +2415,10 @@ function deriveOnchainSend(input) {
|
|
|
2378
2415
|
if (refundLocktime === void 0 || htlcPubkey === void 0 || htlcLocktime === void 0 || minConfirmations === void 0 || receiverPkScriptHex === void 0) {
|
|
2379
2416
|
throw new Error("onchain-send quote is missing a binding field");
|
|
2380
2417
|
}
|
|
2381
|
-
const
|
|
2418
|
+
const contractParams = {
|
|
2382
2419
|
solverPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2383
2420
|
refundLocktime,
|
|
2384
|
-
|
|
2421
|
+
operatorPubkey: input.operatorPubkey,
|
|
2385
2422
|
paymentHash: input.paymentHash,
|
|
2386
2423
|
claimDelay: input.claimDelay,
|
|
2387
2424
|
emulatorPubkey: input.emulatorPubkey,
|
|
@@ -2392,8 +2429,8 @@ function deriveOnchainSend(input) {
|
|
|
2392
2429
|
const { script, address } = matchQuotedLockup(
|
|
2393
2430
|
quote,
|
|
2394
2431
|
input.hrp,
|
|
2395
|
-
input.
|
|
2396
|
-
(legacy) =>
|
|
2432
|
+
input.operatorPubkey,
|
|
2433
|
+
(legacy) => lightningSendContract({ ...contractParams, ...legacy !== void 0 && { legacy } })
|
|
2397
2434
|
);
|
|
2398
2435
|
const htlcParams = {
|
|
2399
2436
|
paymentHash: input.paymentHash,
|
|
@@ -2415,7 +2452,7 @@ function deriveOnchainSend(input) {
|
|
|
2415
2452
|
minConfirmations
|
|
2416
2453
|
};
|
|
2417
2454
|
}
|
|
2418
|
-
async function requestOnchainSend(wallet,
|
|
2455
|
+
async function requestOnchainSend(wallet, transport, params) {
|
|
2419
2456
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2420
2457
|
const secrets = await (0, import_sdk10.provisionClaimSecret)(wallet, { preimage: params.preimage });
|
|
2421
2458
|
if (secrets.mustPersistPreimage) {
|
|
@@ -2426,7 +2463,7 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
|
2426
2463
|
const paymentHash = import_base10.hex.encode(secrets.paymentHash);
|
|
2427
2464
|
const senderPubkey = secrets.pubkey;
|
|
2428
2465
|
const [info, refundAddress] = await Promise.all([
|
|
2429
|
-
|
|
2466
|
+
wallet.getArkadeInfo({ requireLive: true }),
|
|
2430
2467
|
wallet.getAddress()
|
|
2431
2468
|
]);
|
|
2432
2469
|
const quote = await transport.requestQuote(
|
|
@@ -2440,12 +2477,12 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
|
2440
2477
|
amountSide: params.amountSide
|
|
2441
2478
|
})
|
|
2442
2479
|
);
|
|
2443
|
-
const network = (0, import_sdk9.
|
|
2480
|
+
const network = (0, import_sdk9.networkFromArkadeInfo)(info);
|
|
2444
2481
|
const derived = deriveOnchainSend({
|
|
2445
2482
|
quote,
|
|
2446
2483
|
paymentHash,
|
|
2447
2484
|
payoutPubkey: params.payoutPubkey,
|
|
2448
|
-
|
|
2485
|
+
operatorPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(info.signerPubkey), "ark signer key"),
|
|
2449
2486
|
emulatorPubkey: (0, import_sdk9.toXOnly)(
|
|
2450
2487
|
import_base10.hex.decode((0, import_sdk9.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
2451
2488
|
"emulator signer key"
|
|
@@ -2482,6 +2519,7 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
|
2482
2519
|
htlcParams: derived.htlcParams,
|
|
2483
2520
|
l1Network: derived.l1Network,
|
|
2484
2521
|
minConfirmations: derived.minConfirmations,
|
|
2522
|
+
refundLocktime: derived.refundLocktime,
|
|
2485
2523
|
senderPubkey,
|
|
2486
2524
|
secrets
|
|
2487
2525
|
};
|
|
@@ -2553,7 +2591,7 @@ var assertReceivable = (input) => {
|
|
|
2553
2591
|
);
|
|
2554
2592
|
}
|
|
2555
2593
|
};
|
|
2556
|
-
function
|
|
2594
|
+
function lightningReceiveContract(params) {
|
|
2557
2595
|
const seconds = (value) => ({
|
|
2558
2596
|
type: "seconds",
|
|
2559
2597
|
value: BigInt(value)
|
|
@@ -2561,7 +2599,7 @@ function receiveVtxoScript(params) {
|
|
|
2561
2599
|
return new import_sdk9.VHTLC.ScriptV2({
|
|
2562
2600
|
sender: params.solverPubkey,
|
|
2563
2601
|
receiver: params.payoutPubkey,
|
|
2564
|
-
server: params.
|
|
2602
|
+
server: params.operatorPubkey,
|
|
2565
2603
|
preimageHash: (0, import_legacy2.ripemd160)(import_base10.hex.decode(params.paymentHash)),
|
|
2566
2604
|
refundLocktime: BigInt(params.refundLocktime),
|
|
2567
2605
|
unilateralClaimDelay: seconds(params.claimDelay),
|
|
@@ -2586,10 +2624,10 @@ function deriveLightningReceive(input) {
|
|
|
2586
2624
|
if (refundLocktime === void 0 || invoice === void 0 || solverRefundPkScriptHex === void 0) {
|
|
2587
2625
|
throw new Error("lightning-receive quote is missing a binding field");
|
|
2588
2626
|
}
|
|
2589
|
-
const
|
|
2627
|
+
const contractParams = {
|
|
2590
2628
|
solverPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2591
2629
|
refundLocktime,
|
|
2592
|
-
|
|
2630
|
+
operatorPubkey: input.operatorPubkey,
|
|
2593
2631
|
paymentHash: input.paymentHash,
|
|
2594
2632
|
claimDelay: input.claimDelay,
|
|
2595
2633
|
emulatorPubkey: input.emulatorPubkey,
|
|
@@ -2600,8 +2638,8 @@ function deriveLightningReceive(input) {
|
|
|
2600
2638
|
const matched = matchQuotedLockup(
|
|
2601
2639
|
quote,
|
|
2602
2640
|
input.hrp,
|
|
2603
|
-
input.
|
|
2604
|
-
(legacy) =>
|
|
2641
|
+
input.operatorPubkey,
|
|
2642
|
+
(legacy) => lightningReceiveContract({ ...contractParams, ...legacy !== void 0 && { legacy } })
|
|
2605
2643
|
);
|
|
2606
2644
|
return {
|
|
2607
2645
|
address: matched.address,
|
|
@@ -2609,13 +2647,13 @@ function deriveLightningReceive(input) {
|
|
|
2609
2647
|
script: matched.script,
|
|
2610
2648
|
invoice,
|
|
2611
2649
|
refundLocktime,
|
|
2612
|
-
|
|
2613
|
-
...
|
|
2650
|
+
contractParams: {
|
|
2651
|
+
...contractParams,
|
|
2614
2652
|
...matched.legacy !== void 0 && { legacy: matched.legacy }
|
|
2615
2653
|
}
|
|
2616
2654
|
};
|
|
2617
2655
|
}
|
|
2618
|
-
async function requestLightningReceive(wallet,
|
|
2656
|
+
async function requestLightningReceive(wallet, transport, params) {
|
|
2619
2657
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2620
2658
|
const secrets = await (0, import_sdk10.provisionClaimSecret)(wallet);
|
|
2621
2659
|
if (secrets.mustPersistPreimage) {
|
|
@@ -2627,7 +2665,7 @@ async function requestLightningReceive(wallet, arkServerUrl, transport, params)
|
|
|
2627
2665
|
const paymentHash = import_base10.hex.encode(secrets.paymentHash);
|
|
2628
2666
|
const payoutPubkey = secrets.pubkey;
|
|
2629
2667
|
const [info, payoutAddress] = await Promise.all([
|
|
2630
|
-
|
|
2668
|
+
wallet.getArkadeInfo({ requireLive: true }),
|
|
2631
2669
|
wallet.getAddress()
|
|
2632
2670
|
]);
|
|
2633
2671
|
const claimPacket = await sealClaimPacket({
|
|
@@ -2646,13 +2684,13 @@ async function requestLightningReceive(wallet, arkServerUrl, transport, params)
|
|
|
2646
2684
|
})
|
|
2647
2685
|
);
|
|
2648
2686
|
assertQuotedAmount(quote, params.amountSide, params.amount);
|
|
2649
|
-
const network = (0, import_sdk9.
|
|
2687
|
+
const network = (0, import_sdk9.networkFromArkadeInfo)(info);
|
|
2650
2688
|
const derived = deriveLightningReceive({
|
|
2651
2689
|
quote,
|
|
2652
2690
|
paymentHash,
|
|
2653
2691
|
payoutPubkey,
|
|
2654
2692
|
payoutAddress,
|
|
2655
|
-
|
|
2693
|
+
operatorPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(info.signerPubkey), "ark signer key"),
|
|
2656
2694
|
emulatorPubkey: (0, import_sdk9.toXOnly)(
|
|
2657
2695
|
import_base10.hex.decode((0, import_sdk9.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
2658
2696
|
"emulator signer key"
|
|
@@ -2686,7 +2724,7 @@ async function requestLightningReceive(wallet, arkServerUrl, transport, params)
|
|
|
2686
2724
|
payoutAddress,
|
|
2687
2725
|
payoutPubkey,
|
|
2688
2726
|
secrets,
|
|
2689
|
-
|
|
2727
|
+
contractParams: derived.contractParams
|
|
2690
2728
|
};
|
|
2691
2729
|
}
|
|
2692
2730
|
function deriveOnchainReceive(input) {
|
|
@@ -2701,10 +2739,10 @@ function deriveOnchainReceive(input) {
|
|
|
2701
2739
|
if (refundLocktime === void 0 || claimPubkey === void 0 || htlcLocktime === void 0 || minConfirmations === void 0 || solverRefundPkScriptHex === void 0) {
|
|
2702
2740
|
throw new Error("onchain-receive quote is missing a binding field");
|
|
2703
2741
|
}
|
|
2704
|
-
const
|
|
2742
|
+
const contractParams = {
|
|
2705
2743
|
solverPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2706
2744
|
refundLocktime,
|
|
2707
|
-
|
|
2745
|
+
operatorPubkey: input.operatorPubkey,
|
|
2708
2746
|
paymentHash: input.paymentHash,
|
|
2709
2747
|
claimDelay: input.claimDelay,
|
|
2710
2748
|
emulatorPubkey: input.emulatorPubkey,
|
|
@@ -2715,8 +2753,11 @@ function deriveOnchainReceive(input) {
|
|
|
2715
2753
|
const { script, address } = matchQuotedLockup(
|
|
2716
2754
|
quote,
|
|
2717
2755
|
input.hrp,
|
|
2718
|
-
input.
|
|
2719
|
-
(legacy) =>
|
|
2756
|
+
input.operatorPubkey,
|
|
2757
|
+
(legacy) => lightningReceiveContract({
|
|
2758
|
+
...contractParams,
|
|
2759
|
+
...legacy !== void 0 && { legacy }
|
|
2760
|
+
})
|
|
2720
2761
|
);
|
|
2721
2762
|
const htlc = onchainHtlcScript(
|
|
2722
2763
|
{
|
|
@@ -2738,7 +2779,7 @@ function deriveOnchainReceive(input) {
|
|
|
2738
2779
|
minConfirmations
|
|
2739
2780
|
};
|
|
2740
2781
|
}
|
|
2741
|
-
async function requestOnchainReceive(wallet,
|
|
2782
|
+
async function requestOnchainReceive(wallet, transport, params) {
|
|
2742
2783
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2743
2784
|
const secrets = await (0, import_sdk10.provisionClaimSecret)(wallet);
|
|
2744
2785
|
if (secrets.mustPersistPreimage) {
|
|
@@ -2750,7 +2791,7 @@ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
|
2750
2791
|
const paymentHash = import_base10.hex.encode(secrets.paymentHash);
|
|
2751
2792
|
const payoutPubkey = secrets.pubkey;
|
|
2752
2793
|
const [info, payoutAddress] = await Promise.all([
|
|
2753
|
-
|
|
2794
|
+
wallet.getArkadeInfo({ requireLive: true }),
|
|
2754
2795
|
wallet.getAddress()
|
|
2755
2796
|
]);
|
|
2756
2797
|
const claimPacket = await sealClaimPacket({
|
|
@@ -2770,14 +2811,14 @@ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
|
2770
2811
|
})
|
|
2771
2812
|
);
|
|
2772
2813
|
assertQuotedAmount(quote, params.amountSide, params.amount);
|
|
2773
|
-
const network = (0, import_sdk9.
|
|
2814
|
+
const network = (0, import_sdk9.networkFromArkadeInfo)(info);
|
|
2774
2815
|
const derived = deriveOnchainReceive({
|
|
2775
2816
|
quote,
|
|
2776
2817
|
paymentHash,
|
|
2777
2818
|
payoutPubkey,
|
|
2778
2819
|
payoutAddress,
|
|
2779
2820
|
refundPubkey: params.refundPubkey,
|
|
2780
|
-
|
|
2821
|
+
operatorPubkey: (0, import_sdk9.toXOnly)(import_base10.hex.decode(info.signerPubkey), "ark signer key"),
|
|
2781
2822
|
emulatorPubkey: (0, import_sdk9.toXOnly)(
|
|
2782
2823
|
import_base10.hex.decode((0, import_sdk9.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
2783
2824
|
"emulator signer key"
|
|
@@ -2855,11 +2896,10 @@ var LockupNeedsRecoveryError = class extends Error {
|
|
|
2855
2896
|
* into one settlement with no CLTV awareness, so an early attempt can fail
|
|
2856
2897
|
* the whole batch — including unrelated outputs that were otherwise fine.
|
|
2857
2898
|
*
|
|
2858
|
-
* Exposed as a value, not only inside the message, so a caller can
|
|
2859
|
-
*
|
|
2860
|
-
*
|
|
2861
|
-
*
|
|
2862
|
-
* not an exact alarm.
|
|
2899
|
+
* Exposed as a value, not only inside the message, so a caller can skip
|
|
2900
|
+
* pre-CLTV recoverable outputs without parsing prose. Seconds-based
|
|
2901
|
+
* locktimes mature against the chain tip's timestamp rather than wall
|
|
2902
|
+
* clock, so treat this as a floor to wait past, not an exact alarm.
|
|
2863
2903
|
*/
|
|
2864
2904
|
recoverableAfter;
|
|
2865
2905
|
constructor(outpoints, recoverableAfter) {
|
|
@@ -2920,7 +2960,7 @@ async function readLockupFate(indexer, input) {
|
|
|
2920
2960
|
if (vtxo.spentBy)
|
|
2921
2961
|
spentBy.set(vtxo.spentBy, {
|
|
2922
2962
|
checkpointTxid: vtxo.spentBy,
|
|
2923
|
-
|
|
2963
|
+
txid: vtxo.arkTxId
|
|
2924
2964
|
});
|
|
2925
2965
|
else everySpendNamed = false;
|
|
2926
2966
|
}
|
|
@@ -2949,32 +2989,32 @@ async function readLockupFate(indexer, input) {
|
|
|
2949
2989
|
}
|
|
2950
2990
|
return everySpendNamed && observed.size === spentBy.size ? { fate: "returned", spends } : { fate: "unknown" };
|
|
2951
2991
|
}
|
|
2952
|
-
async function pushRefundWithoutReceiver(
|
|
2992
|
+
async function pushRefundWithoutReceiver(operator, input) {
|
|
2953
2993
|
if (input.vtxos.length === 0) throw new Error("nothing to refund: no funded outputs");
|
|
2954
2994
|
const swept = input.vtxos.filter((vtxo) => vtxo.recoverable);
|
|
2955
2995
|
if (swept.length > 0) {
|
|
2956
2996
|
throw new LockupNeedsRecoveryError(
|
|
2957
2997
|
swept.map((vtxo) => `${vtxo.txid}:${vtxo.vout}`),
|
|
2958
|
-
input.
|
|
2998
|
+
input.contract.options.refundLocktime
|
|
2959
2999
|
);
|
|
2960
3000
|
}
|
|
2961
|
-
const refundPkScript = input.refundPkScript ?? input.
|
|
3001
|
+
const refundPkScript = input.refundPkScript ?? input.contract.options.nonInteractiveParameters?.senderPkScript;
|
|
2962
3002
|
if (!refundPkScript) {
|
|
2963
3003
|
throw new Error(
|
|
2964
3004
|
"no refund destination: the contract carries no emulator covenant suite, so pass refundPkScript explicitly"
|
|
2965
3005
|
);
|
|
2966
3006
|
}
|
|
2967
|
-
const info = await
|
|
2968
|
-
let
|
|
3007
|
+
const info = await operator.getInfo();
|
|
3008
|
+
let operatorUnrollScript;
|
|
2969
3009
|
try {
|
|
2970
|
-
|
|
3010
|
+
operatorUnrollScript = import_sdk11.CSVMultisigTapscript.decode(import_base11.hex.decode(info.checkpointTapscript));
|
|
2971
3011
|
} catch {
|
|
2972
|
-
throw new Error("invalid checkpointTapscript from the
|
|
3012
|
+
throw new Error("invalid checkpointTapscript from the operator");
|
|
2973
3013
|
}
|
|
2974
|
-
const leaf = input.
|
|
2975
|
-
const tapTree = input.
|
|
3014
|
+
const leaf = input.contract.refundWithoutReceiver();
|
|
3015
|
+
const tapTree = input.contract.encode();
|
|
2976
3016
|
const amount = input.vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
|
|
2977
|
-
const { arkTx, checkpoints } = (0, import_sdk11.buildOffchainTx)(
|
|
3017
|
+
const { arkTx: tx, checkpoints } = (0, import_sdk11.buildOffchainTx)(
|
|
2978
3018
|
input.vtxos.map((vtxo) => ({
|
|
2979
3019
|
txid: vtxo.txid,
|
|
2980
3020
|
vout: vtxo.vout,
|
|
@@ -2983,14 +3023,14 @@ async function pushRefundWithoutReceiver(ark, input) {
|
|
|
2983
3023
|
tapTree
|
|
2984
3024
|
})),
|
|
2985
3025
|
[{ script: refundPkScript, amount: BigInt(amount) }],
|
|
2986
|
-
|
|
3026
|
+
operatorUnrollScript
|
|
2987
3027
|
);
|
|
2988
|
-
const
|
|
2989
|
-
const submitted = await
|
|
2990
|
-
import_base11.base64.encode(
|
|
3028
|
+
const signedTx = await input.sender.sign(tx);
|
|
3029
|
+
const submitted = await operator.submitTx(
|
|
3030
|
+
import_base11.base64.encode(signedTx.toPSBT()),
|
|
2991
3031
|
checkpoints.map((c) => import_base11.base64.encode(c.toPSBT()))
|
|
2992
3032
|
);
|
|
2993
|
-
(0, import_sdk11.assertSubmittedArkTxid)(submitted,
|
|
3033
|
+
(0, import_sdk11.assertSubmittedArkTxid)(submitted, signedTx, "refundWithoutReceiver");
|
|
2994
3034
|
const matched = (0, import_sdk11.matchServerCheckpoints)(
|
|
2995
3035
|
submitted.signedCheckpointTxs,
|
|
2996
3036
|
checkpoints,
|
|
@@ -3001,11 +3041,11 @@ async function pushRefundWithoutReceiver(ark, input) {
|
|
|
3001
3041
|
async ({ server }) => import_base11.base64.encode((await input.sender.sign(server, [0])).toPSBT())
|
|
3002
3042
|
)
|
|
3003
3043
|
);
|
|
3004
|
-
await
|
|
3005
|
-
return {
|
|
3044
|
+
await operator.finalizeTx(submitted.arkTxid, finalCheckpoints);
|
|
3045
|
+
return { txid: submitted.arkTxid, amount };
|
|
3006
3046
|
}
|
|
3007
3047
|
var REFUND_MTP_LAG_SECONDS = 2 * 60 * 60;
|
|
3008
|
-
async function refundIfUnresolved(transport,
|
|
3048
|
+
async function refundIfUnresolved(transport, operator, indexer, input) {
|
|
3009
3049
|
const pollMs = input.pollMs ?? 5e3;
|
|
3010
3050
|
const now = input.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
3011
3051
|
const attemptDeadline = input.attemptDeadline ?? input.refundLocktime + REFUND_MTP_LAG_SECONDS;
|
|
@@ -3016,7 +3056,7 @@ async function refundIfUnresolved(transport, ark, indexer, input) {
|
|
|
3016
3056
|
let fate = { fate: "unknown" };
|
|
3017
3057
|
try {
|
|
3018
3058
|
fate = await readLockupFate(indexer, {
|
|
3019
|
-
swapPkScript: input.
|
|
3059
|
+
swapPkScript: input.contract.pkScript,
|
|
3020
3060
|
paymentHash: input.paymentHash
|
|
3021
3061
|
});
|
|
3022
3062
|
} catch {
|
|
@@ -3028,11 +3068,11 @@ async function refundIfUnresolved(transport, ark, indexer, input) {
|
|
|
3028
3068
|
status
|
|
3029
3069
|
};
|
|
3030
3070
|
}
|
|
3031
|
-
const vtxos = await findLockupVtxos(indexer, input.
|
|
3071
|
+
const vtxos = await findLockupVtxos(indexer, input.contract.pkScript);
|
|
3032
3072
|
if (vtxos.length === 0) return { outcome: "nothing_to_refund", status };
|
|
3033
3073
|
try {
|
|
3034
|
-
const pushed = await pushRefundWithoutReceiver(
|
|
3035
|
-
|
|
3074
|
+
const pushed = await pushRefundWithoutReceiver(operator, {
|
|
3075
|
+
contract: input.contract,
|
|
3036
3076
|
sender: input.sender,
|
|
3037
3077
|
vtxos,
|
|
3038
3078
|
refundPkScript: input.refundPkScript
|
|
@@ -3075,13 +3115,13 @@ var assertFiniteAmount = (value, reason, label) => {
|
|
|
3075
3115
|
error.reason = reason;
|
|
3076
3116
|
throw error;
|
|
3077
3117
|
};
|
|
3078
|
-
async function pushClaim(
|
|
3118
|
+
async function pushClaim(operator, input) {
|
|
3079
3119
|
if (input.vtxos.length === 0) throw new Error("nothing to claim: no funded outputs");
|
|
3080
3120
|
const swept = input.vtxos.filter((vtxo) => vtxo.recoverable);
|
|
3081
3121
|
if (swept.length > 0) {
|
|
3082
3122
|
throw new LockupNeedsRecoveryError(
|
|
3083
3123
|
swept.map((vtxo) => `${vtxo.txid}:${vtxo.vout}`),
|
|
3084
|
-
input.
|
|
3124
|
+
input.contract.options.refundLocktime
|
|
3085
3125
|
);
|
|
3086
3126
|
}
|
|
3087
3127
|
const locked = input.vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
|
|
@@ -3092,22 +3132,22 @@ async function pushClaim(ark, input) {
|
|
|
3092
3132
|
throw new LockupAmountMismatchError(input.expectedAmount, locked);
|
|
3093
3133
|
}
|
|
3094
3134
|
}
|
|
3095
|
-
const committed = input.
|
|
3135
|
+
const committed = input.contract.options.preimageHash;
|
|
3096
3136
|
if (import_base12.hex.encode((0, import_legacy3.ripemd160)((0, import_sha25.sha256)(input.preimage))) !== import_base12.hex.encode(committed)) {
|
|
3097
3137
|
throw new Error("preimage does not match the covenant's payment hash");
|
|
3098
3138
|
}
|
|
3099
|
-
const info = await
|
|
3100
|
-
let
|
|
3139
|
+
const info = await operator.getInfo();
|
|
3140
|
+
let operatorUnrollScript;
|
|
3101
3141
|
try {
|
|
3102
|
-
|
|
3142
|
+
operatorUnrollScript = import_sdk12.CSVMultisigTapscript.decode(import_base12.hex.decode(info.checkpointTapscript));
|
|
3103
3143
|
} catch {
|
|
3104
|
-
throw new Error("invalid checkpointTapscript from the
|
|
3144
|
+
throw new Error("invalid checkpointTapscript from the operator");
|
|
3105
3145
|
}
|
|
3106
|
-
const leaf = input.
|
|
3107
|
-
const tapTree = input.
|
|
3108
|
-
const
|
|
3146
|
+
const leaf = input.contract.claim();
|
|
3147
|
+
const tapTree = input.contract.encode();
|
|
3148
|
+
const txid = await (0, import_sdk12.signAndSubmitOffchainTx)({
|
|
3109
3149
|
identity: (0, import_sdk12.claimWithPreimageIdentity)(input.receiver, input.preimage),
|
|
3110
|
-
provider:
|
|
3150
|
+
provider: operator,
|
|
3111
3151
|
inputs: input.vtxos.map((vtxo) => ({
|
|
3112
3152
|
txid: vtxo.txid,
|
|
3113
3153
|
vout: vtxo.vout,
|
|
@@ -3118,10 +3158,10 @@ async function pushClaim(ark, input) {
|
|
|
3118
3158
|
// One aggregate output: unlike the covenant refund, this leaf inspects
|
|
3119
3159
|
// nothing about the output set.
|
|
3120
3160
|
outputs: [{ script: input.destinationPkScript, amount: BigInt(locked) }],
|
|
3121
|
-
serverUnrollScript,
|
|
3122
|
-
verifyServerSignatures: { serverPubkey: input.
|
|
3161
|
+
serverUnrollScript: operatorUnrollScript,
|
|
3162
|
+
verifyServerSignatures: { serverPubkey: input.contract.options.server }
|
|
3123
3163
|
});
|
|
3124
|
-
return {
|
|
3164
|
+
return { txid, amount: locked };
|
|
3125
3165
|
}
|
|
3126
3166
|
async function awaitLockupFunding(indexer, swapPkScript, options = {}) {
|
|
3127
3167
|
const pollMs = options.pollMs ?? 5e3;
|
|
@@ -3136,13 +3176,13 @@ async function awaitLockupFunding(indexer, swapPkScript, options = {}) {
|
|
|
3136
3176
|
await sleep3(pollMs);
|
|
3137
3177
|
}
|
|
3138
3178
|
}
|
|
3139
|
-
async function claimReceiveLockup(indexer,
|
|
3179
|
+
async function claimReceiveLockup(indexer, operator, input) {
|
|
3140
3180
|
const vtxos = await awaitLockupFunding(indexer, input.swapPkScript, {
|
|
3141
3181
|
pollMs: input.pollMs,
|
|
3142
3182
|
deadline: input.deadline
|
|
3143
3183
|
});
|
|
3144
|
-
return pushClaim(
|
|
3145
|
-
|
|
3184
|
+
return pushClaim(operator, {
|
|
3185
|
+
contract: input.contract,
|
|
3146
3186
|
receiver: input.receiver,
|
|
3147
3187
|
preimage: input.preimage,
|
|
3148
3188
|
vtxos,
|
|
@@ -3193,8 +3233,8 @@ async function senderIdentityForSwapRecord(wallet, record) {
|
|
|
3193
3233
|
// src/arkadeRefunder.ts
|
|
3194
3234
|
function arkadeRefunder(deps) {
|
|
3195
3235
|
return async (swap) => {
|
|
3196
|
-
const
|
|
3197
|
-
if (!
|
|
3236
|
+
const contract = swap.lockup?.script;
|
|
3237
|
+
if (!contract) {
|
|
3198
3238
|
throw new Error(
|
|
3199
3239
|
`swap ${swap.rfqId} carries no lockup covenant, so its refund cannot be built`
|
|
3200
3240
|
);
|
|
@@ -3209,7 +3249,7 @@ function arkadeRefunder(deps) {
|
|
|
3209
3249
|
);
|
|
3210
3250
|
}
|
|
3211
3251
|
const sender = await senderIdentityForSwapRecord(deps.wallet, rfqSignerOf(record) ?? {});
|
|
3212
|
-
return pushRefundWithoutReceiver(deps.
|
|
3252
|
+
return pushRefundWithoutReceiver(deps.operator, { contract, sender, vtxos });
|
|
3213
3253
|
};
|
|
3214
3254
|
}
|
|
3215
3255
|
|
|
@@ -3605,6 +3645,19 @@ var RfqSwapManager = class {
|
|
|
3605
3645
|
async getPendingSwaps() {
|
|
3606
3646
|
return [...this.monitored.values()];
|
|
3607
3647
|
}
|
|
3648
|
+
/**
|
|
3649
|
+
* Every swap this manager holds — {@link getPendingSwaps} plus the ones
|
|
3650
|
+
* that already ended. The two sets are disjoint: a swap leaves `monitored`
|
|
3651
|
+
* as it enters `finished`.
|
|
3652
|
+
*
|
|
3653
|
+
* The finished half is what this process has seen, which after
|
|
3654
|
+
* {@link restoreFromRepository} is the stored history minus what retention
|
|
3655
|
+
* pruned. A manager that has restored nothing answers with the live swaps
|
|
3656
|
+
* alone.
|
|
3657
|
+
*/
|
|
3658
|
+
async getAllSwaps() {
|
|
3659
|
+
return [...this.monitored.values(), ...this.finished.values()];
|
|
3660
|
+
}
|
|
3608
3661
|
async hasSwap(rfqId) {
|
|
3609
3662
|
return this.monitored.has(rfqId);
|
|
3610
3663
|
}
|
|
@@ -3883,14 +3936,14 @@ var RfqSwapManager = class {
|
|
|
3883
3936
|
return this.claimIfFunded(swap, vtxos);
|
|
3884
3937
|
}
|
|
3885
3938
|
if (now < swap.refundLocktime + REFUND_MTP_LAG_SECONDS) {
|
|
3886
|
-
if (swap.
|
|
3939
|
+
if (swap.claimTxid) return;
|
|
3887
3940
|
return this.block(
|
|
3888
3941
|
swap,
|
|
3889
3942
|
"the claim window closed with the lockup unclaimed \u2014 only the solver can act now"
|
|
3890
3943
|
);
|
|
3891
3944
|
}
|
|
3892
3945
|
const failure = this.lastClaimError.get(swap.rfqId);
|
|
3893
|
-
if (failure && !swap.
|
|
3946
|
+
if (failure && !swap.claimTxid) {
|
|
3894
3947
|
return this.fail(swap, new Error(failure));
|
|
3895
3948
|
}
|
|
3896
3949
|
this.setState(swap, "refunded");
|
|
@@ -3905,7 +3958,7 @@ var RfqSwapManager = class {
|
|
|
3905
3958
|
*/
|
|
3906
3959
|
async claimIfFunded(swap, vtxos) {
|
|
3907
3960
|
if (vtxos.length === 0) return this.unblock(swap);
|
|
3908
|
-
const partiallyClaimed = swap.
|
|
3961
|
+
const partiallyClaimed = swap.claimTxid !== void 0;
|
|
3909
3962
|
if (partiallyClaimed && !this.hasUnclaimedOutpoint(swap.rfqId, vtxos)) {
|
|
3910
3963
|
return;
|
|
3911
3964
|
}
|
|
@@ -3933,10 +3986,10 @@ var RfqSwapManager = class {
|
|
|
3933
3986
|
this.setState(swap, "claimable");
|
|
3934
3987
|
if (!this.config.enableAutoActions) return;
|
|
3935
3988
|
try {
|
|
3936
|
-
const {
|
|
3989
|
+
const { txid } = await this.callbacks.claimLockup(swap, vtxos, { partiallyClaimed });
|
|
3937
3990
|
this.lastClaimError.delete(swap.rfqId);
|
|
3938
3991
|
this.rememberClaimed(swap.rfqId, vtxos);
|
|
3939
|
-
swap.
|
|
3992
|
+
swap.claimTxid = txid;
|
|
3940
3993
|
this.touch(swap);
|
|
3941
3994
|
this.setState(swap, "claimed");
|
|
3942
3995
|
this.emitAction(swap, "claimLockup");
|
|
@@ -4028,7 +4081,7 @@ var RfqSwapManager = class {
|
|
|
4028
4081
|
try {
|
|
4029
4082
|
const pushed = await this.callbacks.refundArkade(swap);
|
|
4030
4083
|
if (pushed) {
|
|
4031
|
-
swap.
|
|
4084
|
+
swap.refundTxid = pushed.txid;
|
|
4032
4085
|
this.touch(swap);
|
|
4033
4086
|
}
|
|
4034
4087
|
this.setState(swap, "refunded");
|
|
@@ -4101,7 +4154,7 @@ var RfqSwapManager = class {
|
|
|
4101
4154
|
/**
|
|
4102
4155
|
* Record which ark transactions ended the lockup.
|
|
4103
4156
|
*
|
|
4104
|
-
* Only the ones the indexer actually named: `LockupSpend.
|
|
4157
|
+
* Only the ones the indexer actually named: `LockupSpend.txid` is
|
|
4105
4158
|
* optional, and a checkpoint txid is not what history correlates on — a
|
|
4106
4159
|
* record carrying one would name a transaction the wallet's own activity
|
|
4107
4160
|
* never shows. Fewer txids is the right failure here.
|
|
@@ -4111,9 +4164,9 @@ var RfqSwapManager = class {
|
|
|
4111
4164
|
* verdict once.
|
|
4112
4165
|
*/
|
|
4113
4166
|
stampLockupSpends(swap, spends) {
|
|
4114
|
-
const
|
|
4115
|
-
if (
|
|
4116
|
-
swap.
|
|
4167
|
+
const txids = spends.map((spend) => spend.txid).filter((txid) => txid !== void 0);
|
|
4168
|
+
if (txids.length === 0) return;
|
|
4169
|
+
swap.lockupSpendTxids = txids;
|
|
4117
4170
|
this.touch(swap);
|
|
4118
4171
|
}
|
|
4119
4172
|
touch(swap) {
|
|
@@ -4194,10 +4247,9 @@ var RfqSwapManager = class {
|
|
|
4194
4247
|
/**
|
|
4195
4248
|
* Drop a terminal swap from monitoring and report it exactly once.
|
|
4196
4249
|
*
|
|
4197
|
-
* `onSwapCompleted` and `onSwapFailed` are mutually exclusive here
|
|
4198
|
-
*
|
|
4199
|
-
*
|
|
4200
|
-
* also fires on failure is a trap worth not inheriting.
|
|
4250
|
+
* `onSwapCompleted` and `onSwapFailed` are mutually exclusive here: a
|
|
4251
|
+
* listener named "completed" that also fires on failure is a trap, so a
|
|
4252
|
+
* swap that leaves monitoring reports through exactly one of them.
|
|
4201
4253
|
*/
|
|
4202
4254
|
finalize(swap) {
|
|
4203
4255
|
if (!this.monitored.has(swap.rfqId)) return;
|
|
@@ -4233,7 +4285,7 @@ var traderClaimTxid = (swap) => {
|
|
|
4233
4285
|
case "onchain_send":
|
|
4234
4286
|
return swap.claimTxid;
|
|
4235
4287
|
case "lightning_receive":
|
|
4236
|
-
return swap.
|
|
4288
|
+
return swap.claimTxid;
|
|
4237
4289
|
default:
|
|
4238
4290
|
return void 0;
|
|
4239
4291
|
}
|
|
@@ -4243,7 +4295,7 @@ var outcomeOf = (swap) => {
|
|
|
4243
4295
|
const lostReceive = swap.kind === "lightning_receive" && swap.state === "refunded";
|
|
4244
4296
|
return {
|
|
4245
4297
|
state: swap.state,
|
|
4246
|
-
txid: lostReceive ? swap.
|
|
4298
|
+
txid: lostReceive ? swap.refundTxid : traderClaimTxid(swap) ?? swap.refundTxid
|
|
4247
4299
|
};
|
|
4248
4300
|
};
|
|
4249
4301
|
var errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -4308,16 +4360,17 @@ async function rfqSwapActivityInputs(deps) {
|
|
|
4308
4360
|
const records = await deps.repository.getAllRfqSwaps();
|
|
4309
4361
|
return Promise.all(records.map((record) => activityInputOf(record, deps.indexer)));
|
|
4310
4362
|
}
|
|
4311
|
-
async function activityInputOf(
|
|
4363
|
+
async function activityInputOf(stored, indexer) {
|
|
4364
|
+
const record = normalizeRfqSwapRecord(stored);
|
|
4312
4365
|
const txids = /* @__PURE__ */ new Set();
|
|
4313
|
-
if (record.
|
|
4314
|
-
if (record.
|
|
4366
|
+
if (record.fundingTxid) txids.add(record.fundingTxid);
|
|
4367
|
+
if (record.refundTxid) txids.add(record.refundTxid);
|
|
4315
4368
|
const handler = rfqCorridorHandlers.getOrThrow(record.kind);
|
|
4316
4369
|
for (const txid of handler.activityTxids?.(record.profile) ?? []) txids.add(txid);
|
|
4317
|
-
for (const txid of record.
|
|
4318
|
-
const spendUnknown = isRfqSwapTerminal(record.state) && !record.
|
|
4319
|
-
if (indexer && (!record.
|
|
4320
|
-
for (const txid of await lockupTxids(indexer, record, !record.
|
|
4370
|
+
for (const txid of record.lockupSpendTxids ?? []) txids.add(txid);
|
|
4371
|
+
const spendUnknown = isRfqSwapTerminal(record.state) && !record.refundTxid && !record.lockupSpendTxids?.length;
|
|
4372
|
+
if (indexer && (!record.fundingTxid || spendUnknown)) {
|
|
4373
|
+
for (const txid of await lockupTxids(indexer, record, !record.fundingTxid)) {
|
|
4321
4374
|
txids.add(txid);
|
|
4322
4375
|
}
|
|
4323
4376
|
}
|
|
@@ -4342,6 +4395,334 @@ async function lockupTxids(indexer, record, wantFunding) {
|
|
|
4342
4395
|
return [];
|
|
4343
4396
|
}
|
|
4344
4397
|
}
|
|
4398
|
+
|
|
4399
|
+
// src/swapClient.ts
|
|
4400
|
+
var import_base15 = require("@scure/base");
|
|
4401
|
+
var import_sdk15 = require("@arkade-os/sdk");
|
|
4402
|
+
var import_solver_discovery2 = require("@arkade-os/solver-discovery");
|
|
4403
|
+
var sideCorridorsOf = (market) => {
|
|
4404
|
+
const read = (value) => value === "lightning" || value === "onchain" ? value : "arkade";
|
|
4405
|
+
const m = market;
|
|
4406
|
+
return { base: read(m.base_corridor), quote: read(m.quote_corridor) };
|
|
4407
|
+
};
|
|
4408
|
+
var resolveKind = (market, give) => {
|
|
4409
|
+
const corridors = sideCorridorsOf(market);
|
|
4410
|
+
const giveCorridor = corridors[give];
|
|
4411
|
+
const receiveCorridor = corridors[give === "base" ? "quote" : "base"];
|
|
4412
|
+
if (giveCorridor === "arkade" && receiveCorridor === "arkade") return "spot";
|
|
4413
|
+
if (receiveCorridor === "lightning") return "ln_send";
|
|
4414
|
+
if (giveCorridor === "lightning") return "ln_receive";
|
|
4415
|
+
if (receiveCorridor === "onchain") return "onchain_send";
|
|
4416
|
+
return "onchain_receive";
|
|
4417
|
+
};
|
|
4418
|
+
var need = (value, what, leg) => {
|
|
4419
|
+
if (value === void 0) throw new Error(`a ${leg} quote needs ${what}`);
|
|
4420
|
+
return value;
|
|
4421
|
+
};
|
|
4422
|
+
var corridorAmount = (input, leg) => {
|
|
4423
|
+
const raw = need(input.amount, "an amount", leg);
|
|
4424
|
+
const amountOn = need(input.amountOn, "amountOn ('give' or 'receive')", leg);
|
|
4425
|
+
const amount = Number(raw);
|
|
4426
|
+
if (!Number.isSafeInteger(amount) || amount <= 0) {
|
|
4427
|
+
throw new Error(`a ${leg} amount must be a positive integer of sats, got ${String(raw)}`);
|
|
4428
|
+
}
|
|
4429
|
+
return { amount, amountSide: amountOn === "give" ? "from" : "to" };
|
|
4430
|
+
};
|
|
4431
|
+
function createSwapClient(deps) {
|
|
4432
|
+
const { wallet, repository, transportFor } = deps;
|
|
4433
|
+
let broadcaster;
|
|
4434
|
+
const broadcasting = () => broadcaster ??= wallet.getArkadeBroadcaster();
|
|
4435
|
+
const ark = deps.ark ?? {
|
|
4436
|
+
getInfo: () => wallet.getArkadeInfo({ requireLive: true }),
|
|
4437
|
+
submitTx: async (...args) => (await broadcasting()).submitTx(...args),
|
|
4438
|
+
finalizeTx: async (...args) => (await broadcasting()).finalizeTx(...args)
|
|
4439
|
+
};
|
|
4440
|
+
let reader;
|
|
4441
|
+
const reading = () => reader ??= wallet.getArkadeReader();
|
|
4442
|
+
const indexer = deps.indexer ?? {
|
|
4443
|
+
getVtxos: async (opts) => {
|
|
4444
|
+
if (!opts)
|
|
4445
|
+
throw new Error("getVtxos on the swap indexer requires scripts or outpoints");
|
|
4446
|
+
return (await reading()).getVtxos(opts);
|
|
4447
|
+
},
|
|
4448
|
+
getVirtualTxs: async (...args) => (await reading()).getVirtualTxs(...args)
|
|
4449
|
+
};
|
|
4450
|
+
const managerDeps = { indexer, chain: deps.chain, repository };
|
|
4451
|
+
const manager = new RfqSwapManager(managerDeps);
|
|
4452
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4453
|
+
const notify2 = (swap) => {
|
|
4454
|
+
for (const listener of listeners) {
|
|
4455
|
+
try {
|
|
4456
|
+
listener(swap);
|
|
4457
|
+
} catch {
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
};
|
|
4461
|
+
manager.onSwapUpdate((swap) => notify2({ family: "rfq", swap }));
|
|
4462
|
+
const claimLockup = async (swap, vtxos, { partiallyClaimed }) => {
|
|
4463
|
+
const record = await repository.getRfqSwap(swap.rfqId);
|
|
4464
|
+
if (!record) throw new Error(`rfq swap ${swap.rfqId} has no stored record to claim from`);
|
|
4465
|
+
const secret = rfqClaimSecretOf(record);
|
|
4466
|
+
if (!secret) throw new Error(`rfq swap ${swap.rfqId} carries no claim secret`);
|
|
4467
|
+
const script = swap.lockup?.script;
|
|
4468
|
+
if (!script) throw new Error(`rfq swap ${swap.rfqId} carries no lockup covenant`);
|
|
4469
|
+
const payoutAddress = record.profile.payoutAddress;
|
|
4470
|
+
if (!payoutAddress) throw new Error(`rfq swap ${swap.rfqId} carries no payoutAddress`);
|
|
4471
|
+
return pushClaim(ark, {
|
|
4472
|
+
contract: script,
|
|
4473
|
+
receiver: await (0, import_sdk15.contractSigner)(wallet, secret.signingDescriptor),
|
|
4474
|
+
preimage: await preimageForSwapRecord(wallet, secret),
|
|
4475
|
+
vtxos,
|
|
4476
|
+
destinationPkScript: import_sdk15.ArkAddress.decode(payoutAddress).pkScript,
|
|
4477
|
+
expectedAmount: swap.expectedAmount,
|
|
4478
|
+
partiallyClaimed
|
|
4479
|
+
});
|
|
4480
|
+
};
|
|
4481
|
+
manager.setCallbacks({
|
|
4482
|
+
refundArkade: arkadeRefunder({ operator: ark, indexer, wallet, repository }),
|
|
4483
|
+
claimLockup,
|
|
4484
|
+
...deps.claimOnchain ? { claimOnchain: deps.claimOnchain } : {}
|
|
4485
|
+
});
|
|
4486
|
+
let watcher;
|
|
4487
|
+
const quote = async (market, input) => {
|
|
4488
|
+
const kind = resolveKind(market, input.give);
|
|
4489
|
+
switch (kind) {
|
|
4490
|
+
case "spot": {
|
|
4491
|
+
const raw = need(input.amount, "an amount", kind);
|
|
4492
|
+
const amountOn = need(input.amountOn, "amountOn ('give' or 'receive')", kind);
|
|
4493
|
+
const plan = await (0, import_solver_discovery2.quoteOffer)(market, {
|
|
4494
|
+
give: input.give,
|
|
4495
|
+
...amountOn === "give" ? { giveAmount: raw } : { wantAmount: raw },
|
|
4496
|
+
fetchImpl: deps.discovery.fetchImpl
|
|
4497
|
+
});
|
|
4498
|
+
return { kind, market, plan };
|
|
4499
|
+
}
|
|
4500
|
+
case "ln_send": {
|
|
4501
|
+
const invoice = need(input.invoice, "the invoice to pay", kind);
|
|
4502
|
+
const request = await requestLightningSend(wallet, transportFor(market), {
|
|
4503
|
+
invoice,
|
|
4504
|
+
emulatorPubkey: deps.emulatorPubkey
|
|
4505
|
+
});
|
|
4506
|
+
return { kind, market, request };
|
|
4507
|
+
}
|
|
4508
|
+
case "ln_receive": {
|
|
4509
|
+
const params = {
|
|
4510
|
+
...corridorAmount(input, kind),
|
|
4511
|
+
covclaimdPubkey: need(deps.covclaimdPubkey, "deps.covclaimdPubkey", kind),
|
|
4512
|
+
decodeInvoice: need(deps.decodeInvoice, "deps.decodeInvoice", kind),
|
|
4513
|
+
maxPayAmount: input.maxPayAmount,
|
|
4514
|
+
emulatorPubkey: deps.emulatorPubkey
|
|
4515
|
+
};
|
|
4516
|
+
const request = await requestLightningReceive(wallet, transportFor(market), params);
|
|
4517
|
+
return { kind, market, request, invoice: request.invoice };
|
|
4518
|
+
}
|
|
4519
|
+
case "onchain_send": {
|
|
4520
|
+
need(deps.chain, "deps.chain (L1 access)", kind);
|
|
4521
|
+
const params = {
|
|
4522
|
+
...corridorAmount(input, kind),
|
|
4523
|
+
payoutPubkey: need(input.payoutPubkey, "a payoutPubkey", kind),
|
|
4524
|
+
preimage: input.preimage,
|
|
4525
|
+
emulatorPubkey: deps.emulatorPubkey
|
|
4526
|
+
};
|
|
4527
|
+
const request = await requestOnchainSend(wallet, transportFor(market), params);
|
|
4528
|
+
return { kind, market, request };
|
|
4529
|
+
}
|
|
4530
|
+
case "onchain_receive":
|
|
4531
|
+
throw new Error(
|
|
4532
|
+
"onchain->arkade is not driven by RfqSwapManager yet; quote it directly with requestOnchainReceive"
|
|
4533
|
+
);
|
|
4534
|
+
}
|
|
4535
|
+
};
|
|
4536
|
+
const admit = async (swap, origin) => {
|
|
4537
|
+
let announced = false;
|
|
4538
|
+
const heard = manager.onSwapUpdate((updated) => {
|
|
4539
|
+
if (updated.rfqId === swap.rfqId) announced = true;
|
|
4540
|
+
});
|
|
4541
|
+
try {
|
|
4542
|
+
await manager.addSwap(swap, origin);
|
|
4543
|
+
} finally {
|
|
4544
|
+
heard();
|
|
4545
|
+
}
|
|
4546
|
+
const unified = { family: "rfq", swap };
|
|
4547
|
+
if (!announced) notify2(unified);
|
|
4548
|
+
return unified;
|
|
4549
|
+
};
|
|
4550
|
+
const fundPersisted = async (swap, origin, funding) => {
|
|
4551
|
+
await repository.saveRfqSwap(createRfqSwapRecord(origin, swap));
|
|
4552
|
+
return wallet.send({ address: funding.address, amount: funding.amount });
|
|
4553
|
+
};
|
|
4554
|
+
const accept = async (accepted) => {
|
|
4555
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
4556
|
+
switch (accepted.kind) {
|
|
4557
|
+
case "spot": {
|
|
4558
|
+
const { plan } = accepted;
|
|
4559
|
+
const depositIsBtc = plan.deposit.asset.id === BTC_ASSET_ID;
|
|
4560
|
+
const offer = await createOffer(wallet, {
|
|
4561
|
+
wantAmount: plan.receive.atomic,
|
|
4562
|
+
...plan.receive.asset.id === BTC_ASSET_ID ? { offerAsset: import_sdk15.asset.AssetId.fromString(plan.deposit.asset.id) } : { wantAsset: import_sdk15.asset.AssetId.fromString(plan.receive.asset.id) },
|
|
4563
|
+
emulatorPubkey: deps.emulatorPubkey
|
|
4564
|
+
});
|
|
4565
|
+
const txid = await wallet.send({
|
|
4566
|
+
address: offer.address,
|
|
4567
|
+
// asset deposits ride the SDK's dust-sat carrier
|
|
4568
|
+
amount: depositIsBtc ? Number(plan.deposit.atomic) : void 0,
|
|
4569
|
+
assets: depositIsBtc ? void 0 : [{ assetId: plan.deposit.asset.id, amount: plan.deposit.atomic }],
|
|
4570
|
+
extensions: [offer.extension]
|
|
4571
|
+
});
|
|
4572
|
+
const swap = {
|
|
4573
|
+
id: txid,
|
|
4574
|
+
fromAsset: plan.deposit.asset.id,
|
|
4575
|
+
toAsset: plan.receive.asset.id,
|
|
4576
|
+
fromAmount: plan.deposit.atomic.toString(),
|
|
4577
|
+
toAmount: plan.receive.atomic.toString(),
|
|
4578
|
+
swapAddress: offer.address,
|
|
4579
|
+
swapPkScript: import_base15.hex.encode(offer.swapPkScript),
|
|
4580
|
+
offerHex: offer.offerHex,
|
|
4581
|
+
fundingTxid: txid,
|
|
4582
|
+
status: "pending",
|
|
4583
|
+
createdAt: Date.now()
|
|
4584
|
+
};
|
|
4585
|
+
await addAssetSwap(repository, swap);
|
|
4586
|
+
const unified = { family: "offer", swap };
|
|
4587
|
+
notify2(unified);
|
|
4588
|
+
return unified;
|
|
4589
|
+
}
|
|
4590
|
+
case "ln_send": {
|
|
4591
|
+
const { request } = accepted;
|
|
4592
|
+
const swap = {
|
|
4593
|
+
kind: "lightning_send",
|
|
4594
|
+
rfqId: request.rfqId,
|
|
4595
|
+
state: "pending",
|
|
4596
|
+
lockupPkScript: request.swapPkScript,
|
|
4597
|
+
lockup: { script: request.script, address: request.address },
|
|
4598
|
+
// the trader's own decode, never the solver's echo
|
|
4599
|
+
paymentHash: request.contractParams.paymentHash,
|
|
4600
|
+
refundLocktime: request.contractParams.refundLocktime,
|
|
4601
|
+
createdAt: now,
|
|
4602
|
+
updatedAt: now
|
|
4603
|
+
};
|
|
4604
|
+
const origin = {
|
|
4605
|
+
kind: "lightning_send",
|
|
4606
|
+
lockupAddress: request.address,
|
|
4607
|
+
profile: rfqSecretsProfile(request.secrets, swap.paymentHash),
|
|
4608
|
+
amount: request.fundAmount
|
|
4609
|
+
};
|
|
4610
|
+
const txid = await fundPersisted(swap, origin, {
|
|
4611
|
+
address: request.address,
|
|
4612
|
+
amount: request.fundAmount
|
|
4613
|
+
});
|
|
4614
|
+
return admit(swap, { ...origin, fundingTxid: txid });
|
|
4615
|
+
}
|
|
4616
|
+
case "ln_receive": {
|
|
4617
|
+
const { request } = accepted;
|
|
4618
|
+
const paymentHash = import_base15.hex.encode(request.secrets.paymentHash);
|
|
4619
|
+
const swap = {
|
|
4620
|
+
kind: "lightning_receive",
|
|
4621
|
+
rfqId: request.rfqId,
|
|
4622
|
+
state: "pending",
|
|
4623
|
+
lockupPkScript: request.swapPkScript,
|
|
4624
|
+
lockup: { script: request.script, address: request.address },
|
|
4625
|
+
paymentHash,
|
|
4626
|
+
refundLocktime: request.contractParams.refundLocktime,
|
|
4627
|
+
expectedAmount: request.expectedAmount,
|
|
4628
|
+
createdAt: now,
|
|
4629
|
+
updatedAt: now
|
|
4630
|
+
};
|
|
4631
|
+
return admit(swap, {
|
|
4632
|
+
kind: "lightning_receive",
|
|
4633
|
+
lockupAddress: request.address,
|
|
4634
|
+
profile: {
|
|
4635
|
+
...rfqSecretsProfile(request.secrets, paymentHash),
|
|
4636
|
+
expectedAmount: request.expectedAmount,
|
|
4637
|
+
payoutAddress: request.payoutAddress
|
|
4638
|
+
},
|
|
4639
|
+
amount: request.expectedAmount
|
|
4640
|
+
});
|
|
4641
|
+
}
|
|
4642
|
+
case "onchain_send": {
|
|
4643
|
+
const { request } = accepted;
|
|
4644
|
+
const paymentHash = import_base15.hex.encode(request.secrets.paymentHash);
|
|
4645
|
+
const swap = {
|
|
4646
|
+
kind: "onchain_send",
|
|
4647
|
+
rfqId: request.rfqId,
|
|
4648
|
+
state: "pending",
|
|
4649
|
+
lockupPkScript: request.swapPkScript,
|
|
4650
|
+
lockup: { script: request.script, address: request.address },
|
|
4651
|
+
paymentHash,
|
|
4652
|
+
refundLocktime: request.refundLocktime,
|
|
4653
|
+
htlc: request.htlc,
|
|
4654
|
+
minConfirmations: request.minConfirmations,
|
|
4655
|
+
createdAt: now,
|
|
4656
|
+
updatedAt: now
|
|
4657
|
+
};
|
|
4658
|
+
const origin = {
|
|
4659
|
+
kind: "onchain_send",
|
|
4660
|
+
lockupAddress: request.address,
|
|
4661
|
+
profile: {
|
|
4662
|
+
...rfqSecretsProfile(request.secrets, paymentHash),
|
|
4663
|
+
...onchainSendProfile(request)
|
|
4664
|
+
},
|
|
4665
|
+
amount: request.fundAmount
|
|
4666
|
+
};
|
|
4667
|
+
const txid = await fundPersisted(swap, origin, {
|
|
4668
|
+
address: request.address,
|
|
4669
|
+
amount: request.fundAmount
|
|
4670
|
+
});
|
|
4671
|
+
return admit(swap, { ...origin, fundingTxid: txid });
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
};
|
|
4675
|
+
return {
|
|
4676
|
+
manager,
|
|
4677
|
+
markets: (useCache) => discoverMarkets({ ...deps.discovery, repository, useCache }),
|
|
4678
|
+
quote,
|
|
4679
|
+
accept,
|
|
4680
|
+
cancel: async (fundingTxid) => {
|
|
4681
|
+
const swaps = await getAssetSwapsOrThrow(repository);
|
|
4682
|
+
const swap = swaps.find((s) => s.id === fundingTxid);
|
|
4683
|
+
if (!swap) throw new Error(`no offer swap with funding txid ${fundingTxid}`);
|
|
4684
|
+
if (swap.status !== "pending") {
|
|
4685
|
+
throw new Error(`offer swap ${fundingTxid} is ${swap.status}, not cancellable`);
|
|
4686
|
+
}
|
|
4687
|
+
await updateAssetSwap(repository, fundingTxid, { status: "cancelling" });
|
|
4688
|
+
await cancelOffer(wallet, swap.offerHex, {
|
|
4689
|
+
repository,
|
|
4690
|
+
fundingTxid
|
|
4691
|
+
});
|
|
4692
|
+
},
|
|
4693
|
+
// Both families, live AND terminal — the offer half reads the whole
|
|
4694
|
+
// stored history, and the RFQ half is every swap the manager holds.
|
|
4695
|
+
// Its history is what `start()` restored plus what this session
|
|
4696
|
+
// accepted; records past `RFQ_SWAP_RETENTION_SECONDS` are pruned.
|
|
4697
|
+
swaps: async () => {
|
|
4698
|
+
const offers = await getAssetSwaps(repository);
|
|
4699
|
+
const rfq = await manager.getAllSwaps();
|
|
4700
|
+
return [
|
|
4701
|
+
...offers.map((swap) => ({ family: "offer", swap })),
|
|
4702
|
+
...rfq.map((swap) => ({ family: "rfq", swap }))
|
|
4703
|
+
];
|
|
4704
|
+
},
|
|
4705
|
+
onUpdate: (listener) => {
|
|
4706
|
+
listeners.add(listener);
|
|
4707
|
+
return () => listeners.delete(listener);
|
|
4708
|
+
},
|
|
4709
|
+
start: async () => {
|
|
4710
|
+
managerDeps.contracts ??= await wallet.getContractManager();
|
|
4711
|
+
await manager.restoreFromRepository();
|
|
4712
|
+
await manager.start();
|
|
4713
|
+
watcher ??= await watchOfferSwaps({
|
|
4714
|
+
wallet,
|
|
4715
|
+
repository,
|
|
4716
|
+
onUpdate: (swap) => notify2({ family: "offer", swap })
|
|
4717
|
+
});
|
|
4718
|
+
},
|
|
4719
|
+
stop: async () => {
|
|
4720
|
+
await manager.stop();
|
|
4721
|
+
watcher?.stop();
|
|
4722
|
+
watcher = void 0;
|
|
4723
|
+
}
|
|
4724
|
+
};
|
|
4725
|
+
}
|
|
4345
4726
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4346
4727
|
0 && (module.exports = {
|
|
4347
4728
|
ARKADE_ASSET,
|
|
@@ -4403,6 +4784,7 @@ async function lockupTxids(indexer, record, wantFunding) {
|
|
|
4403
4784
|
classifySpend,
|
|
4404
4785
|
createOffer,
|
|
4405
4786
|
createRfqSwapRecord,
|
|
4787
|
+
createSwapClient,
|
|
4406
4788
|
decodeOffer,
|
|
4407
4789
|
deriveLightningReceive,
|
|
4408
4790
|
deriveOnchainReceive,
|
|
@@ -4417,16 +4799,18 @@ async function lockupTxids(indexer, record, wantFunding) {
|
|
|
4417
4799
|
httpTransport,
|
|
4418
4800
|
isRfqSwapTerminal,
|
|
4419
4801
|
isRfqTerminal,
|
|
4802
|
+
lightningReceiveContract,
|
|
4420
4803
|
lightningReceiveRequest,
|
|
4804
|
+
lightningSendContract,
|
|
4421
4805
|
lightningSendRequest,
|
|
4422
|
-
lightningSendVtxoScript,
|
|
4423
4806
|
lockupContractParams,
|
|
4424
4807
|
makeCachedFeedFetch,
|
|
4425
4808
|
newPreimage,
|
|
4426
4809
|
newRfqId,
|
|
4427
4810
|
nextOnchainAction,
|
|
4811
|
+
normalizeRfqSwapRecord,
|
|
4812
|
+
offerContract,
|
|
4428
4813
|
offerTermsFromQuote,
|
|
4429
|
-
offerVtxoScript,
|
|
4430
4814
|
onchainHtlcScript,
|
|
4431
4815
|
onchainReceiveRequest,
|
|
4432
4816
|
onchainSendProfile,
|
|
@@ -4437,7 +4821,6 @@ async function lockupTxids(indexer, record, wantFunding) {
|
|
|
4437
4821
|
pushRefundWithoutReceiver,
|
|
4438
4822
|
readLockupFate,
|
|
4439
4823
|
rebuildRfqSwap,
|
|
4440
|
-
receiveVtxoScript,
|
|
4441
4824
|
refundIfUnresolved,
|
|
4442
4825
|
registerLockupContract,
|
|
4443
4826
|
relayTransport,
|