@arkade-os/swap 0.0.10 → 0.0.12
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 +17 -0
- package/dist/{chunk-5NPYNQ5V.js → chunk-XXWOODUE.js} +114 -29
- package/dist/index.cjs +587 -83
- package/dist/index.d.cts +171 -16
- package/dist/index.d.ts +171 -16
- package/dist/index.js +450 -36
- 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 +2 -2
- package/dist/repositories/realm/index.d.ts +2 -2
- package/dist/repositories/sqlite/index.d.cts +2 -2
- package/dist/repositories/sqlite/index.d.ts +2 -2
- package/dist/{repository-C8FXlmHY.d.cts → repository-DaK1RzRq.d.cts} +45 -5
- package/dist/{repository-Cw2EvvZG.d.ts → repository-DlLvj_y6.d.ts} +45 -5
- package/dist/{rfq-DglvHMNC.d.ts → rfq-DzsmhXX3.d.cts} +75 -20
- package/dist/{rfq-DglvHMNC.d.cts → rfq-DzsmhXX3.d.ts} +75 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
ARKADE_ASSET,
|
|
3
3
|
ARKADE_BTC,
|
|
4
4
|
AddressMismatch,
|
|
5
|
+
L1_NETWORKS,
|
|
5
6
|
LIGHTNING_BTC,
|
|
6
7
|
LIGHTNING_RECEIVE_PAIR,
|
|
7
8
|
LIGHTNING_SEND_PAIR,
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
deriveOnchainSend,
|
|
39
40
|
extractPreimage,
|
|
40
41
|
httpTransport,
|
|
42
|
+
l1ScriptForAddress,
|
|
41
43
|
lightningReceiveRequest,
|
|
42
44
|
lightningSendRequest,
|
|
43
45
|
lightningSendVtxoScript,
|
|
@@ -63,7 +65,7 @@ import {
|
|
|
63
65
|
unilateralRefundWithoutReceiverDelay,
|
|
64
66
|
verifyLockupAddress,
|
|
65
67
|
verifyReceiveInvoice
|
|
66
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-XXWOODUE.js";
|
|
67
69
|
import {
|
|
68
70
|
InMemoryAssetSwapRepository,
|
|
69
71
|
marketsCacheKey
|
|
@@ -329,12 +331,30 @@ var swapPrograms = {
|
|
|
329
331
|
wantAsset: arkade.parseArtifact(swap_want_asset_program_default),
|
|
330
332
|
wantBtc: arkade.parseArtifact(swap_want_btc_program_default)
|
|
331
333
|
};
|
|
334
|
+
function withExitClosure(program, exit) {
|
|
335
|
+
if (!exit) return program;
|
|
336
|
+
return {
|
|
337
|
+
...program,
|
|
338
|
+
// typed params are authoritative: an undeclared `$exitDelay` fails
|
|
339
|
+
// validateProgram instead of compiling against an unbound value
|
|
340
|
+
params: [...program.params ?? [], { name: "exitDelay", type: "int" }],
|
|
341
|
+
functions: {
|
|
342
|
+
...program.functions,
|
|
343
|
+
exit: {
|
|
344
|
+
tapscript: { signers: ["$user"], csv: { type: exit.type, value: "$exitDelay" } }
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
332
349
|
function swapProgramBinding(offer, serverPubkey) {
|
|
333
350
|
if (offer.makerPkScript.length !== FIELDS.makerPkScript.width) {
|
|
334
351
|
throw new Error("makerPkScript is not a 34-byte taproot scriptPubKey");
|
|
335
352
|
}
|
|
336
353
|
return {
|
|
337
|
-
program:
|
|
354
|
+
program: withExitClosure(
|
|
355
|
+
offer.wantAsset ? swapPrograms.wantAsset : swapPrograms.wantBtc,
|
|
356
|
+
offer.exitDelay
|
|
357
|
+
),
|
|
338
358
|
args: {
|
|
339
359
|
makerWP: offer.makerPkScript.subarray(2),
|
|
340
360
|
wantAmount: offer.wantAmount,
|
|
@@ -344,7 +364,8 @@ function swapProgramBinding(offer, serverPubkey) {
|
|
|
344
364
|
...offer.wantAsset && {
|
|
345
365
|
wantAssetTxid: offer.wantAsset.txid.slice().reverse(),
|
|
346
366
|
wantAssetGroupIndex: offer.wantAsset.groupIndex
|
|
347
|
-
}
|
|
367
|
+
},
|
|
368
|
+
...offer.exitDelay && { exitDelay: offer.exitDelay.value }
|
|
348
369
|
},
|
|
349
370
|
keys: {
|
|
350
371
|
serverKey: serverPubkey,
|
|
@@ -365,9 +386,27 @@ var FIELDS = {
|
|
|
365
386
|
makerPkScript: { tag: 5, width: 34 },
|
|
366
387
|
makerPublicKey: { tag: 7, width: 32 },
|
|
367
388
|
emulatorPubkey: { tag: 8, width: 32 },
|
|
368
|
-
|
|
389
|
+
ratioNum: { tag: 9, width: 8 },
|
|
390
|
+
ratioDen: { tag: 10, width: 8 },
|
|
391
|
+
offerAsset: { tag: 11, width: void 0 },
|
|
392
|
+
exitTimelock: { tag: 12, width: 9 }
|
|
369
393
|
};
|
|
394
|
+
var EXIT_TYPES = ["blocks", "seconds"];
|
|
370
395
|
var NAMES = Object.fromEntries(Object.entries(FIELDS).map(([k, f]) => [f.tag, k]));
|
|
396
|
+
function u64(name, value) {
|
|
397
|
+
if (value < BigInt(0) || value >> BigInt(64) > BigInt(0)) {
|
|
398
|
+
throw new Error(`${name} does not fit the offer wire format (u64)`);
|
|
399
|
+
}
|
|
400
|
+
const out = new Uint8Array(FIELDS.wantAmount.width);
|
|
401
|
+
new DataView(out.buffer).setBigUint64(0, value, false);
|
|
402
|
+
return out;
|
|
403
|
+
}
|
|
404
|
+
var readU64 = (value) => new DataView(value.buffer, value.byteOffset).getBigUint64(0, false);
|
|
405
|
+
var setRatio = (name, value) => {
|
|
406
|
+
if (value === void 0 || value === BigInt(0)) return void 0;
|
|
407
|
+
if (value < BigInt(0)) throw new Error(`${name} does not fit the offer wire format (u64)`);
|
|
408
|
+
return value;
|
|
409
|
+
};
|
|
371
410
|
function tlv(type, value) {
|
|
372
411
|
if (value.length > 65535) throw new Error("TLV value exceeds the u16 length field");
|
|
373
412
|
return concatBytes(Uint8Array.of(type, value.length >> 8 & 255, value.length & 255), value);
|
|
@@ -386,24 +425,45 @@ function encodeOffer(offer) {
|
|
|
386
425
|
throw new Error(`${name} must be ${FIELDS[name].width} bytes`);
|
|
387
426
|
}
|
|
388
427
|
}
|
|
389
|
-
|
|
390
|
-
|
|
428
|
+
const ratioNum = setRatio("ratioNum", offer.ratioNum);
|
|
429
|
+
const ratioDen = setRatio("ratioDen", offer.ratioDen);
|
|
430
|
+
if (ratioNum === void 0 !== (ratioDen === void 0)) {
|
|
431
|
+
throw new Error("offer must carry both ratioNum and ratioDen, or neither");
|
|
391
432
|
}
|
|
392
|
-
const amount = new Uint8Array(FIELDS.wantAmount.width);
|
|
393
|
-
new DataView(amount.buffer).setBigUint64(0, offer.wantAmount, false);
|
|
394
433
|
const recs = [
|
|
395
434
|
tlv(FIELDS.swapPkScript.tag, offer.swapPkScript),
|
|
396
|
-
tlv(FIELDS.wantAmount.tag,
|
|
435
|
+
tlv(FIELDS.wantAmount.tag, u64("wantAmount", offer.wantAmount))
|
|
397
436
|
];
|
|
398
437
|
if (offer.wantAsset) recs.push(tlv(FIELDS.wantAsset.tag, offer.wantAsset.serialize()));
|
|
438
|
+
if (ratioNum !== void 0) recs.push(tlv(FIELDS.ratioNum.tag, u64("ratioNum", ratioNum)));
|
|
439
|
+
if (ratioDen !== void 0) recs.push(tlv(FIELDS.ratioDen.tag, u64("ratioDen", ratioDen)));
|
|
399
440
|
if (offer.offerAsset) recs.push(tlv(FIELDS.offerAsset.tag, offer.offerAsset.serialize()));
|
|
400
441
|
recs.push(
|
|
401
442
|
tlv(FIELDS.makerPkScript.tag, offer.makerPkScript),
|
|
402
443
|
tlv(FIELDS.makerPublicKey.tag, offer.makerPublicKey),
|
|
403
444
|
tlv(FIELDS.emulatorPubkey.tag, offer.emulatorPubkey)
|
|
404
445
|
);
|
|
446
|
+
if (offer.exitDelay) recs.push(tlv(FIELDS.exitTimelock.tag, encodeExitDelay(offer.exitDelay)));
|
|
405
447
|
return concatBytes(...recs);
|
|
406
448
|
}
|
|
449
|
+
function encodeExitDelay(exit) {
|
|
450
|
+
return concatBytes(
|
|
451
|
+
Uint8Array.of(EXIT_TYPES.indexOf(assertExitDelay(exit).type)),
|
|
452
|
+
u64("exitDelay", exit.value)
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
function assertExitDelay(exit) {
|
|
456
|
+
if (EXIT_TYPES.indexOf(exit.type) < 0) {
|
|
457
|
+
throw new Error(`unknown exitDelay locktime type: ${exit.type}`);
|
|
458
|
+
}
|
|
459
|
+
if (exit.value <= BigInt(0)) {
|
|
460
|
+
throw new Error("exitDelay must be a positive relative locktime");
|
|
461
|
+
}
|
|
462
|
+
if (exit.value >> BigInt(32) > BigInt(0)) {
|
|
463
|
+
throw new Error("exitDelay does not fit the locktime field (u32)");
|
|
464
|
+
}
|
|
465
|
+
return exit;
|
|
466
|
+
}
|
|
407
467
|
function decodeOffer(data) {
|
|
408
468
|
const fields = {};
|
|
409
469
|
let off = 0;
|
|
@@ -423,6 +483,12 @@ function decodeOffer(data) {
|
|
|
423
483
|
for (const name of ["wantAsset", "offerAsset"]) {
|
|
424
484
|
if (fields[name]?.length === 0) throw new Error(`missing/invalid ${name}`);
|
|
425
485
|
}
|
|
486
|
+
for (const [name, value] of Object.entries(fields)) {
|
|
487
|
+
const width = FIELDS[name].width;
|
|
488
|
+
if (width !== void 0 && value.length !== width) {
|
|
489
|
+
throw new Error(`missing/invalid ${name}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
426
492
|
const need = (name) => {
|
|
427
493
|
const v = fields[name];
|
|
428
494
|
const len = FIELDS[name].width;
|
|
@@ -434,16 +500,36 @@ function decodeOffer(data) {
|
|
|
434
500
|
if (Boolean(fields.wantAsset) === Boolean(fields.offerAsset)) {
|
|
435
501
|
throw new Error("offer must carry exactly one of wantAsset or offerAsset");
|
|
436
502
|
}
|
|
503
|
+
const readRatio = (name) => {
|
|
504
|
+
const raw = fields[name];
|
|
505
|
+
if (!raw) return void 0;
|
|
506
|
+
const value = readU64(raw);
|
|
507
|
+
if (value === BigInt(0)) throw new Error(`missing/invalid ${name}`);
|
|
508
|
+
return value;
|
|
509
|
+
};
|
|
510
|
+
const ratioNum = readRatio("ratioNum");
|
|
511
|
+
const ratioDen = readRatio("ratioDen");
|
|
512
|
+
if (ratioNum === void 0 !== (ratioDen === void 0)) {
|
|
513
|
+
throw new Error("offer must carry both ratioNum and ratioDen, or neither");
|
|
514
|
+
}
|
|
437
515
|
return {
|
|
438
516
|
swapPkScript: need("swapPkScript"),
|
|
439
|
-
wantAmount:
|
|
517
|
+
wantAmount: readU64(amount),
|
|
440
518
|
...fields.wantAsset && { wantAsset: asset.AssetId.fromBytes(fields.wantAsset) },
|
|
441
519
|
...fields.offerAsset && { offerAsset: asset.AssetId.fromBytes(fields.offerAsset) },
|
|
442
520
|
makerPkScript: need("makerPkScript"),
|
|
443
521
|
makerPublicKey: need("makerPublicKey"),
|
|
444
|
-
emulatorPubkey: need("emulatorPubkey")
|
|
522
|
+
emulatorPubkey: need("emulatorPubkey"),
|
|
523
|
+
...ratioNum !== void 0 && { ratioNum },
|
|
524
|
+
...ratioDen !== void 0 && { ratioDen },
|
|
525
|
+
...fields.exitTimelock && { exitDelay: decodeExitDelay(fields.exitTimelock) }
|
|
445
526
|
};
|
|
446
527
|
}
|
|
528
|
+
function decodeExitDelay(value) {
|
|
529
|
+
const type = EXIT_TYPES[value[0]];
|
|
530
|
+
if (!type) throw new Error(`unknown exitDelay locktime type: 0x${value[0].toString(16)}`);
|
|
531
|
+
return { type, value: readU64(value.subarray(1)) };
|
|
532
|
+
}
|
|
447
533
|
var OFFER_CONTRACT_LABEL = "Arkade swap offer";
|
|
448
534
|
var OFFER_CONTRACT_KIND = "asset-swap-offer";
|
|
449
535
|
async function registerOfferContract(wallet, arkServerUrl, network, binding, serverPubkey, expectedPkScript) {
|
|
@@ -469,6 +555,14 @@ async function registerOfferContract(wallet, arkServerUrl, network, binding, ser
|
|
|
469
555
|
});
|
|
470
556
|
await promoteOfferContract(contractManager, hex2.encode(expectedPkScript));
|
|
471
557
|
}
|
|
558
|
+
function serverExitDelay(delay) {
|
|
559
|
+
if (typeof delay !== "bigint" || delay <= BigInt(0)) {
|
|
560
|
+
throw new Error(
|
|
561
|
+
"the server reports no usable unilateralExitDelay; pass `exitDelay` to set the offer's exit closure explicitly, or `noExit: true` to publish without one"
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
return assertExitDelay({ value: delay, type: delay < BigInt(512) ? "blocks" : "seconds" });
|
|
565
|
+
}
|
|
472
566
|
async function createOffer(wallet, arkServerUrl, params) {
|
|
473
567
|
if (Boolean(params.wantAsset) === Boolean(params.offerAsset)) {
|
|
474
568
|
throw new Error("set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC)");
|
|
@@ -489,7 +583,11 @@ async function createOffer(wallet, arkServerUrl, params) {
|
|
|
489
583
|
offerAsset: params.offerAsset,
|
|
490
584
|
makerPkScript: ArkAddress.decode(makerAddress).pkScript,
|
|
491
585
|
makerPublicKey,
|
|
492
|
-
emulatorPubkey: emuKey
|
|
586
|
+
emulatorPubkey: emuKey,
|
|
587
|
+
// checked HERE, before the covenant is derived and registered below:
|
|
588
|
+
// deferring it to `encodeOffer` leaves a registered contract behind for
|
|
589
|
+
// an offer that then fails to encode. @see assertExitDelay
|
|
590
|
+
exitDelay: params.noExit ? void 0 : params.exitDelay ? assertExitDelay(params.exitDelay) : serverExitDelay(info.unilateralExitDelay)
|
|
493
591
|
};
|
|
494
592
|
const script = offerVtxoScript(binding, serverPubKey);
|
|
495
593
|
const offer = { ...binding, swapPkScript: script.pkScript };
|
|
@@ -965,7 +1063,8 @@ function onchainSendProfile(result) {
|
|
|
965
1063
|
htlcLocktime: result.htlcParams.refundLocktime,
|
|
966
1064
|
network: result.l1Network,
|
|
967
1065
|
htlcAddress: result.htlc.address,
|
|
968
|
-
minConfirmations: result.minConfirmations
|
|
1066
|
+
minConfirmations: result.minConfirmations,
|
|
1067
|
+
payoutPkScript: hex3.encode(result.payoutPkScript)
|
|
969
1068
|
};
|
|
970
1069
|
}
|
|
971
1070
|
var OnchainSendCorridor = {
|
|
@@ -1014,6 +1113,9 @@ var OnchainSendCorridor = {
|
|
|
1014
1113
|
paymentHash,
|
|
1015
1114
|
htlc,
|
|
1016
1115
|
minConfirmations: profile.minConfirmations,
|
|
1116
|
+
// Optional here, required at the write: throwing on an older
|
|
1117
|
+
// record would strand the refund it is still owed.
|
|
1118
|
+
...profile.payoutPkScript ? { payoutPkScript: hex3.decode(profile.payoutPkScript) } : {},
|
|
1017
1119
|
...profile.funding ? { funding: profile.funding } : {},
|
|
1018
1120
|
...profile.claimTxid ? { claimTxid: profile.claimTxid } : {}
|
|
1019
1121
|
};
|
|
@@ -1178,7 +1280,9 @@ function classifySpend(offer, serverPubkey, spendTx, deposit) {
|
|
|
1178
1280
|
const script = offerVtxoScript(offer, serverPubkey);
|
|
1179
1281
|
if (hex5.encode(script.pkScript) !== hex5.encode(offer.swapPkScript)) return "indeterminate";
|
|
1180
1282
|
leaves = {
|
|
1181
|
-
|
|
1283
|
+
// both routes that hand the deposit back; `exit` is absent on an
|
|
1284
|
+
// offer that carries no exit closure, and drops out here
|
|
1285
|
+
returned: ["cancel", "exit"].map((name) => script.functionByName(name)?.leafScript).filter((leaf) => leaf !== void 0),
|
|
1182
1286
|
fulfill: script.functionByName("fulfill")?.leafScript
|
|
1183
1287
|
};
|
|
1184
1288
|
} catch {
|
|
@@ -1190,7 +1294,7 @@ function classifySpend(offer, serverPubkey, spendTx, deposit) {
|
|
|
1190
1294
|
if (hex5.encode(input.txid) !== deposit.txid) continue;
|
|
1191
1295
|
for (const leaf of input.tapLeafScript ?? []) {
|
|
1192
1296
|
const spent = hex5.encode(scriptFromTapLeafScript(leaf));
|
|
1193
|
-
if (leaves.
|
|
1297
|
+
if (leaves.returned.some((back) => spent === hex5.encode(back))) return "cancelled";
|
|
1194
1298
|
if (leaves.fulfill && spent === hex5.encode(leaves.fulfill)) return "fulfilled";
|
|
1195
1299
|
}
|
|
1196
1300
|
}
|
|
@@ -1392,8 +1496,294 @@ async function watchOfferSwaps({
|
|
|
1392
1496
|
};
|
|
1393
1497
|
}
|
|
1394
1498
|
|
|
1395
|
-
// src/
|
|
1499
|
+
// src/chainSource.ts
|
|
1500
|
+
import * as btc from "@scure/btc-signer";
|
|
1501
|
+
import { hex as hex7 } from "@scure/base";
|
|
1502
|
+
var addressOf = (pkScript, network) => btc.Address(L1_NETWORKS[network]).encode(btc.OutScript.decode(pkScript));
|
|
1503
|
+
var chainSourceFrom = (provider, network) => {
|
|
1504
|
+
const spenderFromHistory = async (txid, vout, pkScript) => {
|
|
1505
|
+
const txs = await provider.getTransactions(addressOf(pkScript, network));
|
|
1506
|
+
return txs.find((tx) => tx.vin?.some((i) => i.txid === txid && i.vout === vout))?.txid;
|
|
1507
|
+
};
|
|
1508
|
+
return {
|
|
1509
|
+
async getScriptUtxos(pkScript) {
|
|
1510
|
+
const address = addressOf(pkScript, network);
|
|
1511
|
+
const [coins, tip] = await Promise.all([
|
|
1512
|
+
provider.getCoins(address),
|
|
1513
|
+
provider.getChainTip()
|
|
1514
|
+
]);
|
|
1515
|
+
return coins.map((coin) => ({
|
|
1516
|
+
txid: coin.txid,
|
|
1517
|
+
vout: coin.vout,
|
|
1518
|
+
amount: BigInt(coin.value),
|
|
1519
|
+
// Zero, not one: calling a mempool output "1 deep" would let a
|
|
1520
|
+
// 1-confirmation policy claim against a replaceable transaction.
|
|
1521
|
+
confirmations: coin.status.confirmed && typeof coin.status.block_height === "number" ? Math.max(0, tip.height - coin.status.block_height + 1) : 0
|
|
1522
|
+
}));
|
|
1523
|
+
},
|
|
1524
|
+
async getSpendingTx(txid, vout, pkScript) {
|
|
1525
|
+
const outspends = await provider.getTxOutspends(txid);
|
|
1526
|
+
const outspend = outspends[vout];
|
|
1527
|
+
if (!outspend?.spent) return null;
|
|
1528
|
+
const spender = outspend.txid || await spenderFromHistory(txid, vout, pkScript);
|
|
1529
|
+
if (!spender) return null;
|
|
1530
|
+
const raw = await provider.getRawTransaction(spender);
|
|
1531
|
+
return { txHex: hex7.encode(raw) };
|
|
1532
|
+
},
|
|
1533
|
+
broadcast(txHex) {
|
|
1534
|
+
return provider.broadcastTransaction(txHex);
|
|
1535
|
+
},
|
|
1536
|
+
async getMtp() {
|
|
1537
|
+
return (await provider.getChainTip()).time;
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
// src/payment/rendezvous.ts
|
|
1543
|
+
import { selectMarkets, sideLimits as sideLimits2 } from "@arkade-os/solver-discovery";
|
|
1396
1544
|
import { hex as hex8 } from "@scure/base";
|
|
1545
|
+
var XONLY_HEX = /^[0-9a-f]{64}$/;
|
|
1546
|
+
var rendezvousOf = (market, pinned) => {
|
|
1547
|
+
const transports = { nostr: { relays: market.transports?.nostr?.relays ?? [] } };
|
|
1548
|
+
if (!market.discovery_pubkey || !transports.nostr.relays.length) return void 0;
|
|
1549
|
+
const advertised = market.emulator_pubkey;
|
|
1550
|
+
const emulatorPubkey = advertised === void 0 || advertised === null || advertised === "" ? pinned : typeof advertised === "string" && XONLY_HEX.test(advertised) ? advertised : void 0;
|
|
1551
|
+
if (!emulatorPubkey) return void 0;
|
|
1552
|
+
if (pinned && emulatorPubkey !== pinned) return void 0;
|
|
1553
|
+
const bounds = sideLimits2(market, "quote");
|
|
1554
|
+
if (!bounds) return void 0;
|
|
1555
|
+
return {
|
|
1556
|
+
solverPubkey: market.discovery_pubkey,
|
|
1557
|
+
transports,
|
|
1558
|
+
minSats: Number(bounds.min),
|
|
1559
|
+
maxSats: Number(bounds.max)
|
|
1560
|
+
};
|
|
1561
|
+
};
|
|
1562
|
+
var solverRendezvous = (markets, payoutCorridor, amountSats, fallbackEmulatorPubkey) => {
|
|
1563
|
+
const encoded = fallbackEmulatorPubkey ? hex8.encode(fallbackEmulatorPubkey) : void 0;
|
|
1564
|
+
if (encoded !== void 0 && !XONLY_HEX.test(encoded)) return void 0;
|
|
1565
|
+
const pinned = encoded;
|
|
1566
|
+
const candidates = selectMarkets(markets, {
|
|
1567
|
+
baseId: BTC_ASSET_ID,
|
|
1568
|
+
quoteId: BTC_ASSET_ID,
|
|
1569
|
+
baseCorridor: "arkade",
|
|
1570
|
+
quoteCorridor: payoutCorridor
|
|
1571
|
+
});
|
|
1572
|
+
for (const market of candidates) {
|
|
1573
|
+
const rendezvous = rendezvousOf(market, pinned);
|
|
1574
|
+
if (!rendezvous) continue;
|
|
1575
|
+
if (amountSats >= rendezvous.minSats && amountSats <= rendezvous.maxSats) {
|
|
1576
|
+
return rendezvous;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return void 0;
|
|
1580
|
+
};
|
|
1581
|
+
|
|
1582
|
+
// src/payment/solverOnchain.ts
|
|
1583
|
+
import { btcTarget, makeHandle, resolveSendAmount, tryResolveSendAmount } from "@arkade-os/sdk";
|
|
1584
|
+
var SOLVER_ONCHAIN_RAIL = "solver-onchain";
|
|
1585
|
+
var solverOnchainRendezvous = (markets, amountSats, fallbackEmulatorPubkey) => solverRendezvous(markets, "onchain", amountSats, fallbackEmulatorPubkey);
|
|
1586
|
+
function solverOnchainRail(deps) {
|
|
1587
|
+
const rendezvousFor = async (amount) => {
|
|
1588
|
+
if (amount === void 0) return void 0;
|
|
1589
|
+
const markets = await deps.discover();
|
|
1590
|
+
return solverOnchainRendezvous(markets, amount, deps.fallbackEmulatorPubkey);
|
|
1591
|
+
};
|
|
1592
|
+
return {
|
|
1593
|
+
id: SOLVER_ONCHAIN_RAIL,
|
|
1594
|
+
match: (req) => btcTarget(req.raw) !== void 0,
|
|
1595
|
+
available: async (req) => {
|
|
1596
|
+
const address = btcTarget(req.raw);
|
|
1597
|
+
if (!address) return false;
|
|
1598
|
+
try {
|
|
1599
|
+
l1ScriptForAddress(address, deps.l1Network);
|
|
1600
|
+
} catch {
|
|
1601
|
+
return false;
|
|
1602
|
+
}
|
|
1603
|
+
const amount = tryResolveSendAmount(req.raw, req.amount);
|
|
1604
|
+
if (amount === void 0) return false;
|
|
1605
|
+
return await rendezvousFor(amount) !== void 0;
|
|
1606
|
+
},
|
|
1607
|
+
quote: async (req, ctx) => {
|
|
1608
|
+
const address = btcTarget(req.raw);
|
|
1609
|
+
const amount = resolveSendAmount(SOLVER_ONCHAIN_RAIL, req.raw, req.amount);
|
|
1610
|
+
const payoutPkScript = l1ScriptForAddress(address, deps.l1Network);
|
|
1611
|
+
const rendezvous = await rendezvousFor(amount);
|
|
1612
|
+
if (!rendezvous) {
|
|
1613
|
+
throw new Error(
|
|
1614
|
+
`${SOLVER_ONCHAIN_RAIL}: no solver serves arkade:BTC -> onchain:BTC at ${amount} sats`
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1617
|
+
const negotiated = await deps.connect(
|
|
1618
|
+
rendezvous,
|
|
1619
|
+
(transport) => requestOnchainSend(ctx.wallet, deps.arkServerUrl, transport, {
|
|
1620
|
+
amount,
|
|
1621
|
+
amountSide: "to",
|
|
1622
|
+
payoutPubkey: deps.payoutPubkey,
|
|
1623
|
+
...deps.emulatorPubkey ? { emulatorPubkey: deps.emulatorPubkey } : {}
|
|
1624
|
+
})
|
|
1625
|
+
);
|
|
1626
|
+
if (negotiated.l1Network !== deps.l1Network) {
|
|
1627
|
+
throw new Error(
|
|
1628
|
+
`${SOLVER_ONCHAIN_RAIL}: rail built for ${deps.l1Network} but the swap was negotiated on ${negotiated.l1Network}`
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
const swap = { ...negotiated, rendezvous, payoutPkScript };
|
|
1632
|
+
return {
|
|
1633
|
+
railId: SOLVER_ONCHAIN_RAIL,
|
|
1634
|
+
amount,
|
|
1635
|
+
fee: swap.fundAmount - amount,
|
|
1636
|
+
total: swap.fundAmount,
|
|
1637
|
+
meta: {
|
|
1638
|
+
rfqId: swap.rfqId,
|
|
1639
|
+
validUntil: swap.quote.valid_until,
|
|
1640
|
+
htlcAddress: swap.htlc.address,
|
|
1641
|
+
minConfirmations: swap.minConfirmations,
|
|
1642
|
+
solverPubkey: rendezvous.solverPubkey,
|
|
1643
|
+
// The claim tx's fee comes out of the HTLC output at a rate
|
|
1644
|
+
// not knowable now, so `amount` is the payout, not the net.
|
|
1645
|
+
claimFeeDeductedFromPayout: true
|
|
1646
|
+
},
|
|
1647
|
+
send: async () => makeHandle(SOLVER_ONCHAIN_RAIL, async (emit) => {
|
|
1648
|
+
assertFundable({
|
|
1649
|
+
quote: swap.quote,
|
|
1650
|
+
now: Math.floor(Date.now() / 1e3),
|
|
1651
|
+
onchain: {
|
|
1652
|
+
htlcLocktime: swap.htlcParams.refundLocktime,
|
|
1653
|
+
minConfirmations: swap.minConfirmations,
|
|
1654
|
+
direction: "send"
|
|
1655
|
+
}
|
|
1656
|
+
});
|
|
1657
|
+
await deps.persist(swap);
|
|
1658
|
+
await ctx.wallet.send({
|
|
1659
|
+
address: swap.address,
|
|
1660
|
+
amount: swap.fundAmount
|
|
1661
|
+
});
|
|
1662
|
+
emit({ status: "sent" });
|
|
1663
|
+
const result = { railId: SOLVER_ONCHAIN_RAIL, swapId: swap.rfqId };
|
|
1664
|
+
if (!deps.awaitSettlement) return result;
|
|
1665
|
+
let txid;
|
|
1666
|
+
try {
|
|
1667
|
+
({ txid } = await deps.awaitSettlement(swap));
|
|
1668
|
+
} catch (e) {
|
|
1669
|
+
console.warn(
|
|
1670
|
+
`${SOLVER_ONCHAIN_RAIL}: settlement watch failed; the payment is sent`,
|
|
1671
|
+
e
|
|
1672
|
+
);
|
|
1673
|
+
return result;
|
|
1674
|
+
}
|
|
1675
|
+
const settled = { ...result, txid };
|
|
1676
|
+
emit({ status: "settled", result: settled });
|
|
1677
|
+
return settled;
|
|
1678
|
+
})
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
// src/payment/solverLightning.ts
|
|
1685
|
+
import { invoiceTarget, makeHandle as makeHandle2 } from "@arkade-os/sdk";
|
|
1686
|
+
var SOLVER_LIGHTNING_RAIL = "solver-lightning";
|
|
1687
|
+
var factsOf = (raw, decode, now) => {
|
|
1688
|
+
const invoice = invoiceTarget(raw);
|
|
1689
|
+
if (!invoice) return void 0;
|
|
1690
|
+
let facts;
|
|
1691
|
+
try {
|
|
1692
|
+
facts = decode(invoice);
|
|
1693
|
+
} catch {
|
|
1694
|
+
return void 0;
|
|
1695
|
+
}
|
|
1696
|
+
if (!Number.isInteger(facts.amountSats) || facts.amountSats <= 0) return void 0;
|
|
1697
|
+
if (facts.expiresAt <= now) return void 0;
|
|
1698
|
+
return facts;
|
|
1699
|
+
};
|
|
1700
|
+
var solverLightningRendezvous = (markets, amountSats, fallbackEmulatorPubkey) => solverRendezvous(markets, "lightning", amountSats, fallbackEmulatorPubkey);
|
|
1701
|
+
function solverLightningRail(deps) {
|
|
1702
|
+
const rendezvousFor = async (amountSats) => solverLightningRendezvous(await deps.discover(), amountSats, deps.fallbackEmulatorPubkey);
|
|
1703
|
+
return {
|
|
1704
|
+
id: SOLVER_LIGHTNING_RAIL,
|
|
1705
|
+
match: (req) => invoiceTarget(req.raw) !== void 0,
|
|
1706
|
+
available: async (req) => {
|
|
1707
|
+
const facts = factsOf(req.raw, deps.decodeInvoice, Math.floor(Date.now() / 1e3));
|
|
1708
|
+
if (!facts) return false;
|
|
1709
|
+
if (req.amount !== void 0 && req.amount !== facts.amountSats) return false;
|
|
1710
|
+
return await rendezvousFor(facts.amountSats) !== void 0;
|
|
1711
|
+
},
|
|
1712
|
+
quote: async (req, ctx) => {
|
|
1713
|
+
const facts = factsOf(req.raw, deps.decodeInvoice, Math.floor(Date.now() / 1e3));
|
|
1714
|
+
if (!facts) {
|
|
1715
|
+
throw new Error(
|
|
1716
|
+
`${SOLVER_LIGHTNING_RAIL}: the request carries no payable BOLT11 invoice (amountless, expired, or undecodable)`
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
if (req.amount !== void 0 && req.amount !== facts.amountSats) {
|
|
1720
|
+
throw new Error(
|
|
1721
|
+
`${SOLVER_LIGHTNING_RAIL}: the request names ${req.amount} sats but the invoice is for ${facts.amountSats} \u2014 the payee is paid the invoice`
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
const rendezvous = await rendezvousFor(facts.amountSats);
|
|
1725
|
+
if (!rendezvous) {
|
|
1726
|
+
throw new Error(
|
|
1727
|
+
`${SOLVER_LIGHTNING_RAIL}: no solver serves arkade:BTC -> lightning:BTC at ${facts.amountSats} sats`
|
|
1728
|
+
);
|
|
1729
|
+
}
|
|
1730
|
+
const negotiated = await deps.connect(
|
|
1731
|
+
rendezvous,
|
|
1732
|
+
(transport) => requestLightningSend(ctx.wallet, deps.arkServerUrl, transport, {
|
|
1733
|
+
invoice: facts,
|
|
1734
|
+
...deps.emulatorPubkey ? { emulatorPubkey: deps.emulatorPubkey } : {}
|
|
1735
|
+
})
|
|
1736
|
+
);
|
|
1737
|
+
const swap = { ...negotiated, invoice: facts, rendezvous };
|
|
1738
|
+
return {
|
|
1739
|
+
railId: SOLVER_LIGHTNING_RAIL,
|
|
1740
|
+
// `requestLightningSend` refuses a quote that reprices the
|
|
1741
|
+
// invoice, so the spread is a fee on top.
|
|
1742
|
+
amount: facts.amountSats,
|
|
1743
|
+
fee: swap.fundAmount - facts.amountSats,
|
|
1744
|
+
total: swap.fundAmount,
|
|
1745
|
+
meta: {
|
|
1746
|
+
rfqId: swap.rfqId,
|
|
1747
|
+
validUntil: swap.quote.valid_until,
|
|
1748
|
+
paymentHash: facts.paymentHash,
|
|
1749
|
+
invoiceExpiresAt: facts.expiresAt,
|
|
1750
|
+
solverPubkey: rendezvous.solverPubkey
|
|
1751
|
+
},
|
|
1752
|
+
send: async () => makeHandle2(SOLVER_LIGHTNING_RAIL, async (emit) => {
|
|
1753
|
+
assertFundable({
|
|
1754
|
+
quote: swap.quote,
|
|
1755
|
+
invoiceExpiresAt: facts.expiresAt,
|
|
1756
|
+
now: Math.floor(Date.now() / 1e3)
|
|
1757
|
+
});
|
|
1758
|
+
await deps.persist(swap);
|
|
1759
|
+
await ctx.wallet.send({
|
|
1760
|
+
address: swap.address,
|
|
1761
|
+
amount: swap.fundAmount
|
|
1762
|
+
});
|
|
1763
|
+
emit({ status: "sent" });
|
|
1764
|
+
const result = { railId: SOLVER_LIGHTNING_RAIL, swapId: swap.rfqId };
|
|
1765
|
+
if (!deps.awaitSettlement) return result;
|
|
1766
|
+
let preimage;
|
|
1767
|
+
try {
|
|
1768
|
+
({ preimage } = await deps.awaitSettlement(swap));
|
|
1769
|
+
} catch (e) {
|
|
1770
|
+
console.warn(
|
|
1771
|
+
`${SOLVER_LIGHTNING_RAIL}: settlement watch failed; the payment is sent`,
|
|
1772
|
+
e
|
|
1773
|
+
);
|
|
1774
|
+
return result;
|
|
1775
|
+
}
|
|
1776
|
+
const settled = { ...result, ...preimage !== void 0 && { preimage } };
|
|
1777
|
+
emit({ status: "settled", result: settled });
|
|
1778
|
+
return settled;
|
|
1779
|
+
})
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// src/claim.ts
|
|
1786
|
+
import { hex as hex10 } from "@scure/base";
|
|
1397
1787
|
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
1398
1788
|
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
1399
1789
|
import {
|
|
@@ -1403,7 +1793,7 @@ import {
|
|
|
1403
1793
|
} from "@arkade-os/sdk";
|
|
1404
1794
|
|
|
1405
1795
|
// src/refund.ts
|
|
1406
|
-
import { base64 as base643, hex as
|
|
1796
|
+
import { base64 as base643, hex as hex9 } from "@scure/base";
|
|
1407
1797
|
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
1408
1798
|
import {
|
|
1409
1799
|
CSVMultisigTapscript,
|
|
@@ -1461,7 +1851,7 @@ var LockupNeedsRecoveryError = class extends Error {
|
|
|
1461
1851
|
}
|
|
1462
1852
|
};
|
|
1463
1853
|
async function findLockupVtxos(indexer, swapPkScript) {
|
|
1464
|
-
const scripts = [
|
|
1854
|
+
const scripts = [hex9.encode(swapPkScript)];
|
|
1465
1855
|
const [spendable, recoverable] = await Promise.all([
|
|
1466
1856
|
indexer.getVtxos({ scripts, spendableOnly: true }),
|
|
1467
1857
|
indexer.getVtxos({ scripts, recoverableOnly: true })
|
|
@@ -1487,13 +1877,13 @@ async function findLockupVtxos(indexer, swapPkScript) {
|
|
|
1487
1877
|
}
|
|
1488
1878
|
return out;
|
|
1489
1879
|
}
|
|
1490
|
-
var hashesTo = (candidate, paymentHash) =>
|
|
1880
|
+
var hashesTo = (candidate, paymentHash) => hex9.encode(sha2562(candidate)) === paymentHash;
|
|
1491
1881
|
var candidateWitnessItems = (tx, inputIndex) => [
|
|
1492
1882
|
...getArkPsbtFields(tx, inputIndex, ConditionWitness).flat(),
|
|
1493
1883
|
...tx.getInput(inputIndex).finalScriptWitness ?? []
|
|
1494
1884
|
];
|
|
1495
1885
|
async function readLockupFate(indexer, input) {
|
|
1496
|
-
const { vtxos } = await indexer.getVtxos({ scripts: [
|
|
1886
|
+
const { vtxos } = await indexer.getVtxos({ scripts: [hex9.encode(input.swapPkScript)] });
|
|
1497
1887
|
const all = vtxos ?? [];
|
|
1498
1888
|
if (all.length === 0) return { fate: "unknown" };
|
|
1499
1889
|
const exited = all.filter((vtxo) => vtxo.isUnrolled && !hasTerminalSpend(vtxo));
|
|
@@ -1528,7 +1918,7 @@ async function readLockupFate(indexer, input) {
|
|
|
1528
1918
|
for (let i = 0; i < tx.inputsLength; i++) {
|
|
1529
1919
|
const spent = tx.getInput(i);
|
|
1530
1920
|
if (!spent.txid) continue;
|
|
1531
|
-
const txid =
|
|
1921
|
+
const txid = hex9.encode(spent.txid);
|
|
1532
1922
|
if (!all.some((vtxo) => vtxo.txid === txid && vtxo.vout === spent.index)) continue;
|
|
1533
1923
|
for (const candidate of candidateWitnessItems(tx, i)) {
|
|
1534
1924
|
if (hashesTo(candidate, input.paymentHash)) {
|
|
@@ -1548,16 +1938,16 @@ async function pushRefundWithoutReceiver(ark, input) {
|
|
|
1548
1938
|
input.script.options.refundLocktime
|
|
1549
1939
|
);
|
|
1550
1940
|
}
|
|
1551
|
-
const refundPkScript = input.refundPkScript ?? input.script.options.
|
|
1941
|
+
const refundPkScript = input.refundPkScript ?? input.script.options.nonInteractiveParameters?.senderPkScript;
|
|
1552
1942
|
if (!refundPkScript) {
|
|
1553
1943
|
throw new Error(
|
|
1554
|
-
"no refund destination: the contract carries no
|
|
1944
|
+
"no refund destination: the contract carries no emulator covenant suite, so pass refundPkScript explicitly"
|
|
1555
1945
|
);
|
|
1556
1946
|
}
|
|
1557
1947
|
const info = await ark.getInfo();
|
|
1558
1948
|
let serverUnrollScript;
|
|
1559
1949
|
try {
|
|
1560
|
-
serverUnrollScript = CSVMultisigTapscript.decode(
|
|
1950
|
+
serverUnrollScript = CSVMultisigTapscript.decode(hex9.decode(info.checkpointTapscript));
|
|
1561
1951
|
} catch {
|
|
1562
1952
|
throw new Error("invalid checkpointTapscript from the Arkade server");
|
|
1563
1953
|
}
|
|
@@ -1603,6 +1993,21 @@ async function refundIfUnresolved(transport, ark, indexer, input) {
|
|
|
1603
1993
|
const status = await transport.status(input.rfqId);
|
|
1604
1994
|
if (status && isResolved(status.state)) return { outcome: "resolved", status };
|
|
1605
1995
|
if (now() >= input.refundLocktime) {
|
|
1996
|
+
let fate = { fate: "unknown" };
|
|
1997
|
+
try {
|
|
1998
|
+
fate = await readLockupFate(indexer, {
|
|
1999
|
+
swapPkScript: input.script.pkScript,
|
|
2000
|
+
paymentHash: input.paymentHash
|
|
2001
|
+
});
|
|
2002
|
+
} catch {
|
|
2003
|
+
}
|
|
2004
|
+
if (fate.fate === "exited") {
|
|
2005
|
+
return {
|
|
2006
|
+
outcome: "exited",
|
|
2007
|
+
outpoints: fate.outpoints.map((o) => `${o.txid}:${o.vout}`),
|
|
2008
|
+
status
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
1606
2011
|
const vtxos = await findLockupVtxos(indexer, input.script.pkScript);
|
|
1607
2012
|
if (vtxos.length === 0) return { outcome: "nothing_to_refund", status };
|
|
1608
2013
|
try {
|
|
@@ -1668,13 +2073,13 @@ async function pushClaim(ark, input) {
|
|
|
1668
2073
|
}
|
|
1669
2074
|
}
|
|
1670
2075
|
const committed = input.script.options.preimageHash;
|
|
1671
|
-
if (
|
|
2076
|
+
if (hex10.encode(ripemd160(sha2563(input.preimage))) !== hex10.encode(committed)) {
|
|
1672
2077
|
throw new Error("preimage does not match the covenant's payment hash");
|
|
1673
2078
|
}
|
|
1674
2079
|
const info = await ark.getInfo();
|
|
1675
2080
|
let serverUnrollScript;
|
|
1676
2081
|
try {
|
|
1677
|
-
serverUnrollScript = CSVMultisigTapscript2.decode(
|
|
2082
|
+
serverUnrollScript = CSVMultisigTapscript2.decode(hex10.decode(info.checkpointTapscript));
|
|
1678
2083
|
} catch {
|
|
1679
2084
|
throw new Error("invalid checkpointTapscript from the Arkade server");
|
|
1680
2085
|
}
|
|
@@ -1793,7 +2198,7 @@ function arkadeRefunder(deps) {
|
|
|
1793
2198
|
}
|
|
1794
2199
|
|
|
1795
2200
|
// src/swapManager.ts
|
|
1796
|
-
import { hex as
|
|
2201
|
+
import { hex as hex11 } from "@scure/base";
|
|
1797
2202
|
function nextOnchainAction(input) {
|
|
1798
2203
|
switch (input.phase.phase) {
|
|
1799
2204
|
case "unfunded":
|
|
@@ -2241,7 +2646,7 @@ var RfqSwapManager = class {
|
|
|
2241
2646
|
// ── internals ────────────────────────────────────────────────────────────
|
|
2242
2647
|
track(swap) {
|
|
2243
2648
|
this.monitored.set(swap.rfqId, swap);
|
|
2244
|
-
this.byLockupScript.set(
|
|
2649
|
+
this.byLockupScript.set(hex11.encode(swap.lockupPkScript), swap);
|
|
2245
2650
|
}
|
|
2246
2651
|
/** Drops the swap from BOTH indexes. The event index is the one that stops
|
|
2247
2652
|
* a late event finding a swap that is gone; `pollSwap`'s own
|
|
@@ -2250,7 +2655,7 @@ var RfqSwapManager = class {
|
|
|
2250
2655
|
* them from silently re-driving a cancelled swap. */
|
|
2251
2656
|
untrack(rfqId) {
|
|
2252
2657
|
const swap = this.monitored.get(rfqId);
|
|
2253
|
-
if (swap) this.byLockupScript.delete(
|
|
2658
|
+
if (swap) this.byLockupScript.delete(hex11.encode(swap.lockupPkScript));
|
|
2254
2659
|
this.monitored.delete(rfqId);
|
|
2255
2660
|
this.refundRefused.delete(rfqId);
|
|
2256
2661
|
this.lastClaimError.delete(rfqId);
|
|
@@ -2312,7 +2717,7 @@ var RfqSwapManager = class {
|
|
|
2312
2717
|
if (!lockup) {
|
|
2313
2718
|
try {
|
|
2314
2719
|
const [existing] = await contracts.getContracts({
|
|
2315
|
-
script:
|
|
2720
|
+
script: hex11.encode(swap.lockupPkScript)
|
|
2316
2721
|
});
|
|
2317
2722
|
if (existing) {
|
|
2318
2723
|
this.registered.set(swap.rfqId, true);
|
|
@@ -2331,13 +2736,13 @@ var RfqSwapManager = class {
|
|
|
2331
2736
|
);
|
|
2332
2737
|
return;
|
|
2333
2738
|
}
|
|
2334
|
-
const script =
|
|
2335
|
-
if (script !==
|
|
2739
|
+
const script = hex11.encode(lockup.script.pkScript);
|
|
2740
|
+
if (script !== hex11.encode(swap.lockupPkScript)) {
|
|
2336
2741
|
this.registered.set(swap.rfqId, false);
|
|
2337
2742
|
this.emitFailed(
|
|
2338
2743
|
swap,
|
|
2339
2744
|
new Error(
|
|
2340
|
-
`swap ${swap.rfqId} lockup script ${script} does not match its lockupPkScript ${
|
|
2745
|
+
`swap ${swap.rfqId} lockup script ${script} does not match its lockupPkScript ${hex11.encode(swap.lockupPkScript)}`
|
|
2341
2746
|
)
|
|
2342
2747
|
);
|
|
2343
2748
|
return;
|
|
@@ -2356,7 +2761,7 @@ var RfqSwapManager = class {
|
|
|
2356
2761
|
* script for its whole life. Best-effort — the swap is over either way. */
|
|
2357
2762
|
retireContract(swap) {
|
|
2358
2763
|
if (!this.deps.contracts || !this.registered.get(swap.rfqId)) return;
|
|
2359
|
-
void this.deps.contracts.setContractWatchState(
|
|
2764
|
+
void this.deps.contracts.setContractWatchState(hex11.encode(swap.lockupPkScript), "retained").catch((error) => this.emitFailed(swap, error));
|
|
2360
2765
|
}
|
|
2361
2766
|
arm() {
|
|
2362
2767
|
if (!this.running) return;
|
|
@@ -2832,7 +3237,7 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
2832
3237
|
import {
|
|
2833
3238
|
ArkAddress as ArkAddress4
|
|
2834
3239
|
} from "@arkade-os/sdk";
|
|
2835
|
-
import { hex as
|
|
3240
|
+
import { hex as hex12 } from "@scure/base";
|
|
2836
3241
|
var LABELS = {
|
|
2837
3242
|
lightning_send: "Lightning send",
|
|
2838
3243
|
lightning_receive: "Lightning receive",
|
|
@@ -2907,7 +3312,7 @@ async function activityInputOf(record, indexer) {
|
|
|
2907
3312
|
async function lockupTxids(indexer, record, wantFunding) {
|
|
2908
3313
|
let script;
|
|
2909
3314
|
try {
|
|
2910
|
-
script =
|
|
3315
|
+
script = hex12.encode(ArkAddress4.decode(record.lockupAddress).pkScript);
|
|
2911
3316
|
} catch {
|
|
2912
3317
|
return [];
|
|
2913
3318
|
}
|
|
@@ -2960,6 +3365,8 @@ export {
|
|
|
2960
3365
|
RfqSwapManager,
|
|
2961
3366
|
RfqSwapOriginRequired,
|
|
2962
3367
|
SOLO_REFUND_HEADROOM_SECONDS,
|
|
3368
|
+
SOLVER_LIGHTNING_RAIL,
|
|
3369
|
+
SOLVER_ONCHAIN_RAIL,
|
|
2963
3370
|
SWAP_LOCKUP_CONTRACT_KIND,
|
|
2964
3371
|
SWAP_LOCKUP_CONTRACT_LABEL,
|
|
2965
3372
|
SWAP_LOCKUP_CONTRACT_TYPE,
|
|
@@ -2976,6 +3383,7 @@ export {
|
|
|
2976
3383
|
buildHtlcClaim,
|
|
2977
3384
|
buildHtlcRefund,
|
|
2978
3385
|
cancelOffer,
|
|
3386
|
+
chainSourceFrom,
|
|
2979
3387
|
claimOnchainFill,
|
|
2980
3388
|
claimReceiveLockup,
|
|
2981
3389
|
classifyDepositSpend,
|
|
@@ -2997,6 +3405,7 @@ export {
|
|
|
2997
3405
|
httpTransport,
|
|
2998
3406
|
isRfqSwapTerminal,
|
|
2999
3407
|
isRfqTerminal,
|
|
3408
|
+
l1ScriptForAddress,
|
|
3000
3409
|
lightningReceiveRequest,
|
|
3001
3410
|
lightningSendRequest,
|
|
3002
3411
|
lightningSendVtxoScript,
|
|
@@ -3036,6 +3445,11 @@ export {
|
|
|
3036
3445
|
sealClaimPacket,
|
|
3037
3446
|
senderIdentityForSwapRecord,
|
|
3038
3447
|
shouldRetainRfqSwap,
|
|
3448
|
+
solverLightningRail,
|
|
3449
|
+
solverLightningRendezvous,
|
|
3450
|
+
solverOnchainRail,
|
|
3451
|
+
solverOnchainRendezvous,
|
|
3452
|
+
solverRendezvous,
|
|
3039
3453
|
spendTxidsOf,
|
|
3040
3454
|
spendUpdate,
|
|
3041
3455
|
swapActivityResolver,
|