@arkade-os/swap 0.0.2 → 0.0.4
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 +115 -83
- package/dist/{chunk-C5P7R7JT.js → chunk-DLM6BVTB.js} +80 -252
- package/dist/index.cjs +163 -303
- package/dist/index.d.cts +207 -22
- package/dist/index.d.ts +207 -22
- package/dist/index.js +95 -76
- package/dist/nostr.cjs +10 -14
- package/dist/nostr.d.cts +1 -2
- package/dist/nostr.d.ts +1 -2
- package/dist/nostr.js +2 -2
- package/dist/{rfq-CRgIOQ_y.d.cts → rfq-DjZlesr4.d.cts} +32 -352
- package/dist/{rfq-CRgIOQ_y.d.ts → rfq-DjZlesr4.d.ts} +32 -352
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -55,7 +55,6 @@ __export(index_exports, {
|
|
|
55
55
|
ONCHAIN_SEND_PAIR: () => ONCHAIN_SEND_PAIR,
|
|
56
56
|
QUOTE_OPTIONS: () => QUOTE_OPTIONS,
|
|
57
57
|
REFUND_MTP_LAG_SECONDS: () => REFUND_MTP_LAG_SECONDS,
|
|
58
|
-
RFQ_PREIMAGE_TAG: () => RFQ_PREIMAGE_TAG,
|
|
59
58
|
RFQ_RESOLVED_STATES: () => RFQ_RESOLVED_STATES,
|
|
60
59
|
RFQ_SWAP_TERMINAL_STATES: () => RFQ_SWAP_TERMINAL_STATES,
|
|
61
60
|
RFQ_TERMINAL_STATES: () => RFQ_TERMINAL_STATES,
|
|
@@ -66,7 +65,6 @@ __export(index_exports, {
|
|
|
66
65
|
SWAP_LOCKUP_CONTRACT_TYPE: () => SWAP_LOCKUP_CONTRACT_TYPE,
|
|
67
66
|
SwapRefusal: () => SwapRefusal,
|
|
68
67
|
addAssetSwap: () => addAssetSwap,
|
|
69
|
-
adoptSwapDescriptor: () => adoptSwapDescriptor,
|
|
70
68
|
arkadeSwapRequest: () => arkadeSwapRequest,
|
|
71
69
|
assertFundable: () => assertFundable,
|
|
72
70
|
assertReceivable: () => assertReceivable,
|
|
@@ -75,7 +73,6 @@ __export(index_exports, {
|
|
|
75
73
|
awaitRfqResolution: () => awaitRfqResolution,
|
|
76
74
|
buildHtlcClaim: () => buildHtlcClaim,
|
|
77
75
|
buildHtlcRefund: () => buildHtlcRefund,
|
|
78
|
-
buildPreimageMessage: () => buildPreimageMessage,
|
|
79
76
|
cancelOffer: () => cancelOffer,
|
|
80
77
|
claimOnchainFill: () => claimOnchainFill,
|
|
81
78
|
claimReceiveLockup: () => claimReceiveLockup,
|
|
@@ -87,8 +84,6 @@ __export(index_exports, {
|
|
|
87
84
|
deriveLightningReceive: () => deriveLightningReceive,
|
|
88
85
|
deriveOnchainReceive: () => deriveOnchainReceive,
|
|
89
86
|
deriveOnchainSend: () => deriveOnchainSend,
|
|
90
|
-
derivePreimage: () => derivePreimage,
|
|
91
|
-
deriveSwapSecrets: () => deriveSwapSecrets,
|
|
92
87
|
discoverMarkets: () => discoverMarkets,
|
|
93
88
|
encodeOffer: () => encodeOffer,
|
|
94
89
|
extractPreimage: () => extractPreimage,
|
|
@@ -97,7 +92,6 @@ __export(index_exports, {
|
|
|
97
92
|
getAssetSwaps: () => getAssetSwaps,
|
|
98
93
|
getAssetSwapsOrThrow: () => getAssetSwapsOrThrow,
|
|
99
94
|
httpTransport: () => httpTransport,
|
|
100
|
-
isDeterministicSigner: () => isDeterministicSigner,
|
|
101
95
|
isRfqSwapTerminal: () => isRfqSwapTerminal,
|
|
102
96
|
isRfqTerminal: () => isRfqTerminal,
|
|
103
97
|
lightningReceiveRequest: () => lightningReceiveRequest,
|
|
@@ -113,10 +107,8 @@ __export(index_exports, {
|
|
|
113
107
|
onchainReceiveRequest: () => onchainReceiveRequest,
|
|
114
108
|
onchainSendRequest: () => onchainSendRequest,
|
|
115
109
|
paymentHashOf: () => paymentHashOf,
|
|
116
|
-
preimageForRfqSecrets: () => preimageForRfqSecrets,
|
|
117
110
|
pushClaim: () => pushClaim,
|
|
118
111
|
pushRefundWithoutReceiver: () => pushRefundWithoutReceiver,
|
|
119
|
-
randomSwapSecrets: () => randomSwapSecrets,
|
|
120
112
|
readLockupFate: () => readLockupFate,
|
|
121
113
|
receiveVtxoScript: () => receiveVtxoScript,
|
|
122
114
|
refundIfUnresolved: () => refundIfUnresolved,
|
|
@@ -129,15 +121,12 @@ __export(index_exports, {
|
|
|
129
121
|
restoreAssetSwaps: () => restoreAssetSwaps,
|
|
130
122
|
retireSettledOfferContracts: () => retireSettledOfferContracts,
|
|
131
123
|
rfqPair: () => rfqPair,
|
|
132
|
-
rfqSecretsOfRecord: () => rfqSecretsOfRecord,
|
|
133
|
-
rfqSecretsToRecord: () => rfqSecretsToRecord,
|
|
134
124
|
sealClaimPacket: () => sealClaimPacket,
|
|
135
|
-
senderIdentityForRfqSecrets: () => senderIdentityForRfqSecrets,
|
|
136
125
|
senderIdentityForSwapRecord: () => senderIdentityForSwapRecord,
|
|
137
|
-
senderPubkeyForRfqSecrets: () => senderPubkeyForRfqSecrets,
|
|
138
126
|
spendTxidsOf: () => spendTxidsOf,
|
|
139
127
|
spendUpdate: () => spendUpdate,
|
|
140
128
|
swapPrograms: () => swapPrograms,
|
|
129
|
+
swapSecretsToRecord: () => swapSecretsToRecord,
|
|
141
130
|
unilateralClaimDelay: () => unilateralClaimDelay,
|
|
142
131
|
unilateralRefundDelay: () => unilateralRefundDelay,
|
|
143
132
|
unilateralRefundWithoutReceiverDelay: () => unilateralRefundWithoutReceiverDelay,
|
|
@@ -151,7 +140,7 @@ __export(index_exports, {
|
|
|
151
140
|
module.exports = __toCommonJS(index_exports);
|
|
152
141
|
|
|
153
142
|
// src/offer.ts
|
|
154
|
-
var
|
|
143
|
+
var import_base2 = require("@scure/base");
|
|
155
144
|
var import_utils = require("@scure/btc-signer/utils.js");
|
|
156
145
|
var import_sdk = require("@arkade-os/sdk");
|
|
157
146
|
|
|
@@ -283,6 +272,7 @@ async function retireSettledOfferContracts(manager, swaps) {
|
|
|
283
272
|
}
|
|
284
273
|
|
|
285
274
|
// src/store.ts
|
|
275
|
+
var import_base = require("@scure/base");
|
|
286
276
|
var BTC_ASSET_ID = "btc";
|
|
287
277
|
var byNewest = (a, b) => b.createdAt - a.createdAt;
|
|
288
278
|
var getAssetSwapsOrThrow = async (repository) => {
|
|
@@ -335,6 +325,10 @@ var updateAssetSwapBestEffort = async (repository, id, changes) => {
|
|
|
335
325
|
return { swaps, persisted: false };
|
|
336
326
|
}
|
|
337
327
|
};
|
|
328
|
+
var swapSecretsToRecord = (secrets) => ({
|
|
329
|
+
signingDescriptor: secrets.descriptor,
|
|
330
|
+
..."mustPersistPreimage" in secrets && secrets.mustPersistPreimage ? { preimageHex: import_base.hex.encode(secrets.preimage) } : {}
|
|
331
|
+
});
|
|
338
332
|
|
|
339
333
|
// src/offer.ts
|
|
340
334
|
var swapPrograms = {
|
|
@@ -380,14 +374,6 @@ var FIELDS = {
|
|
|
380
374
|
offerAsset: { tag: 11, width: void 0 }
|
|
381
375
|
};
|
|
382
376
|
var NAMES = Object.fromEntries(Object.entries(FIELDS).map(([k, f]) => [f.tag, k]));
|
|
383
|
-
var XONLY_LEN = 32;
|
|
384
|
-
var xOnly = (key, label) => {
|
|
385
|
-
if (key.length === XONLY_LEN) return key;
|
|
386
|
-
if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
|
|
387
|
-
throw new Error(`${label} is not a compressed or x-only public key`);
|
|
388
|
-
}
|
|
389
|
-
return key.slice(1);
|
|
390
|
-
};
|
|
391
377
|
function tlv(type, value) {
|
|
392
378
|
if (value.length > 65535) throw new Error("TLV value exceeds the u16 length field");
|
|
393
379
|
return (0, import_utils.concatBytes)(Uint8Array.of(type, value.length >> 8 & 255, value.length & 255), value);
|
|
@@ -480,16 +466,16 @@ async function registerOfferContract(wallet, arkServerUrl, network, binding, ser
|
|
|
480
466
|
contractManager
|
|
481
467
|
});
|
|
482
468
|
const contract = new import_sdk.arkade.ArkadeContract(client, program, args, keys);
|
|
483
|
-
if (
|
|
469
|
+
if (import_base2.hex.encode(contract.pkScript) !== import_base2.hex.encode(expectedPkScript)) {
|
|
484
470
|
throw new Error("derived covenant does not match the offer's swapPkScript");
|
|
485
471
|
}
|
|
486
472
|
await contract.register({
|
|
487
473
|
label: OFFER_CONTRACT_LABEL,
|
|
488
474
|
metadata: { genericallySpendable: false, kind: OFFER_CONTRACT_KIND }
|
|
489
475
|
});
|
|
490
|
-
await promoteOfferContract(contractManager,
|
|
476
|
+
await promoteOfferContract(contractManager, import_base2.hex.encode(expectedPkScript));
|
|
491
477
|
}
|
|
492
|
-
async function createOffer(wallet, arkServerUrl,
|
|
478
|
+
async function createOffer(wallet, arkServerUrl, params) {
|
|
493
479
|
if (Boolean(params.wantAsset) === Boolean(params.offerAsset)) {
|
|
494
480
|
throw new Error("set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC)");
|
|
495
481
|
}
|
|
@@ -498,8 +484,11 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
|
|
|
498
484
|
wallet.getAddress(),
|
|
499
485
|
wallet.identity.xOnlyPublicKey()
|
|
500
486
|
]);
|
|
501
|
-
const serverPubKey =
|
|
502
|
-
const
|
|
487
|
+
const serverPubKey = import_base2.hex.decode((0, import_sdk.toXOnlySignerHex)(info.signerPubkey));
|
|
488
|
+
const network = (0, import_sdk.getNetwork)(info.network);
|
|
489
|
+
const emuKey = import_base2.hex.decode(
|
|
490
|
+
(0, import_sdk.toXOnlySignerHex)((0, import_sdk.resolveEmulatorPubkey)(network, params.emulatorPubkey))
|
|
491
|
+
);
|
|
503
492
|
const binding = {
|
|
504
493
|
wantAmount: params.wantAmount,
|
|
505
494
|
wantAsset: params.wantAsset,
|
|
@@ -520,17 +509,17 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
|
|
|
520
509
|
);
|
|
521
510
|
const payload = encodeOffer(offer);
|
|
522
511
|
return {
|
|
523
|
-
offerHex:
|
|
512
|
+
offerHex: import_base2.hex.encode(payload),
|
|
524
513
|
extension: { type: OFFER_PACKET_TYPE, payload },
|
|
525
514
|
// VtxoScript.address owns address construction; assembling an ArkAddress
|
|
526
515
|
// from tweakedPublicKey here would silently miss any future step it gains
|
|
527
|
-
address: script.address(
|
|
516
|
+
address: script.address(network.hrp, serverPubKey).encode(),
|
|
528
517
|
swapPkScript: script.pkScript
|
|
529
518
|
};
|
|
530
519
|
}
|
|
531
520
|
async function cancelOffer(wallet, arkServerUrl, offerHex, opts) {
|
|
532
521
|
const { repository, fundingTxid, swapAddress } = opts;
|
|
533
|
-
const offer = decodeOffer(
|
|
522
|
+
const offer = decodeOffer(import_base2.hex.decode(offerHex));
|
|
534
523
|
const contractManager = await wallet.getContractManager();
|
|
535
524
|
const client = await import_sdk.arkade.Arkade.connect({
|
|
536
525
|
arkade: new import_sdk.RestArkProvider(arkServerUrl),
|
|
@@ -547,7 +536,7 @@ async function cancelOffer(wallet, arkServerUrl, offerHex, opts) {
|
|
|
547
536
|
const serverKey = swapAddress ? import_sdk.ArkAddress.decode(swapAddress).serverPubKey : client.serverKey;
|
|
548
537
|
const { program, args, keys } = swapProgramBinding(offer, serverKey);
|
|
549
538
|
const rebuilt = new import_sdk.arkade.ArkadeProgramScript(program, args, keys);
|
|
550
|
-
if (
|
|
539
|
+
if (import_base2.hex.encode(rebuilt.pkScript) !== import_base2.hex.encode(offer.swapPkScript)) {
|
|
551
540
|
throw new Error(
|
|
552
541
|
"rebuilt covenant does not match the offer's swapPkScript \u2014 the server signing key has likely rotated since funding; pass swapAddress (the funded address) to pin the original key"
|
|
553
542
|
);
|
|
@@ -580,7 +569,7 @@ async function cancelOffer(wallet, arkServerUrl, offerHex, opts) {
|
|
|
580
569
|
spentTxid: txid
|
|
581
570
|
});
|
|
582
571
|
if (persisted) {
|
|
583
|
-
await retireOfferContract(contractManager, swaps,
|
|
572
|
+
await retireOfferContract(contractManager, swaps, import_base2.hex.encode(offer.swapPkScript));
|
|
584
573
|
}
|
|
585
574
|
}
|
|
586
575
|
return txid;
|
|
@@ -846,7 +835,7 @@ var IndexedDbAssetSwapRepository = class {
|
|
|
846
835
|
};
|
|
847
836
|
|
|
848
837
|
// src/restore.ts
|
|
849
|
-
var
|
|
838
|
+
var import_base3 = require("@scure/base");
|
|
850
839
|
var import_sdk4 = require("@arkade-os/sdk");
|
|
851
840
|
var TXS_PER_REQUEST = 50;
|
|
852
841
|
async function fetchParsedTxs(indexer, txids) {
|
|
@@ -863,7 +852,7 @@ async function fetchParsedTxs(indexer, txids) {
|
|
|
863
852
|
if (result.status !== "fulfilled") continue;
|
|
864
853
|
for (const psbt of result.value) {
|
|
865
854
|
try {
|
|
866
|
-
const parsed = import_sdk4.Transaction.fromPSBT(
|
|
855
|
+
const parsed = import_sdk4.Transaction.fromPSBT(import_base3.base64.decode(psbt));
|
|
867
856
|
parsedByTxid.set(parsed.id, parsed);
|
|
868
857
|
} catch {
|
|
869
858
|
}
|
|
@@ -878,7 +867,7 @@ function classifySpend(offer, serverPubkey, spendTx, deposit) {
|
|
|
878
867
|
let leaves;
|
|
879
868
|
try {
|
|
880
869
|
const script = offerVtxoScript(offer, serverPubkey);
|
|
881
|
-
if (
|
|
870
|
+
if (import_base3.hex.encode(script.pkScript) !== import_base3.hex.encode(offer.swapPkScript)) return "indeterminate";
|
|
882
871
|
leaves = {
|
|
883
872
|
cancel: script.functionByName("cancel")?.leafScript,
|
|
884
873
|
fulfill: script.functionByName("fulfill")?.leafScript
|
|
@@ -889,11 +878,11 @@ function classifySpend(offer, serverPubkey, spendTx, deposit) {
|
|
|
889
878
|
for (let i = 0; i < spendTx.inputsLength; i++) {
|
|
890
879
|
const input = spendTx.getInput(i);
|
|
891
880
|
if (!input.txid || input.index !== deposit.vout) continue;
|
|
892
|
-
if (
|
|
881
|
+
if (import_base3.hex.encode(input.txid) !== deposit.txid) continue;
|
|
893
882
|
for (const leaf of input.tapLeafScript ?? []) {
|
|
894
|
-
const spent =
|
|
895
|
-
if (leaves.cancel && spent ===
|
|
896
|
-
if (leaves.fulfill && spent ===
|
|
883
|
+
const spent = import_base3.hex.encode((0, import_sdk4.scriptFromTapLeafScript)(leaf));
|
|
884
|
+
if (leaves.cancel && spent === import_base3.hex.encode(leaves.cancel)) return "cancelled";
|
|
885
|
+
if (leaves.fulfill && spent === import_base3.hex.encode(leaves.fulfill)) return "fulfilled";
|
|
897
886
|
}
|
|
898
887
|
}
|
|
899
888
|
return "indeterminate";
|
|
@@ -928,13 +917,13 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
928
917
|
found.push({
|
|
929
918
|
fundingTx,
|
|
930
919
|
offer: decodeOffer(payload),
|
|
931
|
-
offerHex:
|
|
920
|
+
offerHex: import_base3.hex.encode(payload)
|
|
932
921
|
});
|
|
933
922
|
} catch {
|
|
934
923
|
}
|
|
935
924
|
}
|
|
936
925
|
if (found.length === 0) return { restored: [], scannedTxids: fetchedTxids };
|
|
937
|
-
const scripts = [...new Set(found.map((f) =>
|
|
926
|
+
const scripts = [...new Set(found.map((f) => import_base3.hex.encode(f.offer.swapPkScript)))];
|
|
938
927
|
const { vtxos } = await indexer.getVtxos({ scripts });
|
|
939
928
|
const vtxoByScriptAndTxid = new Map(vtxos.map((v) => [`${v.script}:${v.txid}`, v]));
|
|
940
929
|
const txByAnyId = /* @__PURE__ */ new Map();
|
|
@@ -946,7 +935,7 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
946
935
|
const spendTxids = /* @__PURE__ */ new Set();
|
|
947
936
|
for (const { fundingTx, offer } of found) {
|
|
948
937
|
const vtxo = vtxoByScriptAndTxid.get(
|
|
949
|
-
`${
|
|
938
|
+
`${import_base3.hex.encode(offer.swapPkScript)}:${fundingTx.redeemTxid}`
|
|
950
939
|
);
|
|
951
940
|
if (vtxo?.virtualStatus.state !== "spent") continue;
|
|
952
941
|
for (const txid of spendTxidsOf(vtxo)) spendTxids.add(txid);
|
|
@@ -955,7 +944,7 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
955
944
|
const restored = [];
|
|
956
945
|
const unresolved = /* @__PURE__ */ new Set();
|
|
957
946
|
for (const { fundingTx, offer, offerHex } of found) {
|
|
958
|
-
const swapPkScript =
|
|
947
|
+
const swapPkScript = import_base3.hex.encode(offer.swapPkScript);
|
|
959
948
|
const vtxo = vtxoByScriptAndTxid.get(`${swapPkScript}:${fundingTx.redeemTxid}`);
|
|
960
949
|
if (!vtxo) {
|
|
961
950
|
unresolved.add(fundingTx.redeemTxid);
|
|
@@ -1012,7 +1001,7 @@ async function restoreAssetSwaps(indexer, txs, existingIds, opts) {
|
|
|
1012
1001
|
}
|
|
1013
1002
|
|
|
1014
1003
|
// src/watch.ts
|
|
1015
|
-
var
|
|
1004
|
+
var import_base4 = require("@scure/base");
|
|
1016
1005
|
var import_sdk5 = require("@arkade-os/sdk");
|
|
1017
1006
|
var TERMINAL = ["fulfilled", "cancelled", "recoverable"];
|
|
1018
1007
|
function spendUpdate(swap, spend) {
|
|
@@ -1047,9 +1036,9 @@ async function watchOfferSwaps({
|
|
|
1047
1036
|
if (candidates.length === 0) return "indeterminate";
|
|
1048
1037
|
const { txs } = await indexer.getVirtualTxs(candidates);
|
|
1049
1038
|
return classifyDepositSpend(
|
|
1050
|
-
decodeOffer(
|
|
1039
|
+
decodeOffer(import_base4.hex.decode(swap.offerHex)),
|
|
1051
1040
|
serverPubkey,
|
|
1052
|
-
txs.map((psbt) => import_sdk5.Transaction.fromPSBT(
|
|
1041
|
+
txs.map((psbt) => import_sdk5.Transaction.fromPSBT(import_base4.base64.decode(psbt))),
|
|
1053
1042
|
{ txid: vtxo.txid, vout: vtxo.vout }
|
|
1054
1043
|
);
|
|
1055
1044
|
} catch {
|
|
@@ -1093,10 +1082,10 @@ async function watchOfferSwaps({
|
|
|
1093
1082
|
// src/rfq.ts
|
|
1094
1083
|
var import_base8 = require("@scure/base");
|
|
1095
1084
|
var import_legacy2 = require("@noble/hashes/legacy.js");
|
|
1096
|
-
var
|
|
1085
|
+
var import_sdk7 = require("@arkade-os/sdk");
|
|
1097
1086
|
|
|
1098
1087
|
// src/onchainHtlc.ts
|
|
1099
|
-
var
|
|
1088
|
+
var import_base5 = require("@scure/base");
|
|
1100
1089
|
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
1101
1090
|
var import_legacy = require("@noble/hashes/legacy.js");
|
|
1102
1091
|
var btc = __toESM(require("@scure/btc-signer"), 1);
|
|
@@ -1106,8 +1095,8 @@ var MAX_MIN_CONFIRMATIONS = 6;
|
|
|
1106
1095
|
var ONCHAIN_SECONDS_PER_BLOCK = 600;
|
|
1107
1096
|
var ONCHAIN_DUST_SATS = BigInt(330);
|
|
1108
1097
|
var newPreimage = () => crypto.getRandomValues(new Uint8Array(32));
|
|
1109
|
-
var paymentHashOf = (preimage) =>
|
|
1110
|
-
var h160FromPaymentHash = (paymentHash) => (0, import_legacy.ripemd160)(
|
|
1098
|
+
var paymentHashOf = (preimage) => import_base5.hex.encode((0, import_sha2.sha256)(preimage));
|
|
1099
|
+
var h160FromPaymentHash = (paymentHash) => (0, import_legacy.ripemd160)(import_base5.hex.decode(paymentHash));
|
|
1111
1100
|
var L1_NETWORKS = {
|
|
1112
1101
|
bitcoin: btc.NETWORK,
|
|
1113
1102
|
testnet: btc.TEST_NETWORK,
|
|
@@ -1148,7 +1137,7 @@ function onchainHtlcScript(params, network) {
|
|
|
1148
1137
|
);
|
|
1149
1138
|
const controlBlockFor = (leaf) => {
|
|
1150
1139
|
for (const [block, script] of payment.tapLeafScript ?? []) {
|
|
1151
|
-
if (script.length - 1 === leaf.length &&
|
|
1140
|
+
if (script.length - 1 === leaf.length && import_base5.hex.encode(script.subarray(0, leaf.length)) === import_base5.hex.encode(leaf)) {
|
|
1152
1141
|
return btc.TaprootControlBlock.encode(block);
|
|
1153
1142
|
}
|
|
1154
1143
|
}
|
|
@@ -1241,13 +1230,13 @@ var buildHtlcRefund = (input) => buildLeafSpend({
|
|
|
1241
1230
|
function extractPreimage(txHex, paymentHash) {
|
|
1242
1231
|
let raw;
|
|
1243
1232
|
try {
|
|
1244
|
-
raw = btc.RawTx.decode(
|
|
1233
|
+
raw = btc.RawTx.decode(import_base5.hex.decode(txHex));
|
|
1245
1234
|
} catch {
|
|
1246
1235
|
return null;
|
|
1247
1236
|
}
|
|
1248
1237
|
for (const stack of raw.witnesses ?? []) {
|
|
1249
1238
|
for (const item of stack) {
|
|
1250
|
-
if (item.length === 32 &&
|
|
1239
|
+
if (item.length === 32 && import_base5.hex.encode((0, import_sha2.sha256)(item)) === paymentHash) return item;
|
|
1251
1240
|
}
|
|
1252
1241
|
}
|
|
1253
1242
|
return null;
|
|
@@ -1288,7 +1277,7 @@ async function classifyOnchainHtlc(chain, input) {
|
|
|
1288
1277
|
const spend = await chain.getSpendingTx(input.funding.txid, input.funding.vout);
|
|
1289
1278
|
if (!spend) return { phase: "unfunded" };
|
|
1290
1279
|
const preimage = extractPreimage(spend.txHex, input.htlc.paymentHash);
|
|
1291
|
-
const txid = btc.Transaction.fromRaw(
|
|
1280
|
+
const txid = btc.Transaction.fromRaw(import_base5.hex.decode(spend.txHex), {
|
|
1292
1281
|
allowUnknownInputs: true,
|
|
1293
1282
|
allowUnknownOutputs: true
|
|
1294
1283
|
}).id;
|
|
@@ -1301,177 +1290,19 @@ async function classifyOnchainHtlc(chain, input) {
|
|
|
1301
1290
|
return { phase: "claimable", utxo: best };
|
|
1302
1291
|
}
|
|
1303
1292
|
|
|
1304
|
-
// src/
|
|
1305
|
-
var
|
|
1306
|
-
var import_sha22 = require("@noble/hashes/sha2.js");
|
|
1307
|
-
var import_utils2 = require("@noble/hashes/utils.js");
|
|
1308
|
-
var import_secp256k1 = require("@noble/curves/secp256k1.js");
|
|
1309
|
-
var import_sdk6 = require("@arkade-os/sdk");
|
|
1310
|
-
var RFQ_PREIMAGE_TAG = "Arkade-RFQ-Preimage-v1";
|
|
1311
|
-
function buildPreimageMessage(xonly, index) {
|
|
1312
|
-
if (xonly.length !== 32) {
|
|
1313
|
-
throw new Error(`x-only pubkey must be 32 bytes, got ${xonly.length}`);
|
|
1314
|
-
}
|
|
1315
|
-
if (!Number.isInteger(index) || index < 0 || index > 4294967295) {
|
|
1316
|
-
throw new Error(`index must be a u32, got ${index}`);
|
|
1317
|
-
}
|
|
1318
|
-
const tag = new TextEncoder().encode(RFQ_PREIMAGE_TAG);
|
|
1319
|
-
const message = new Uint8Array(tag.length + 32 + 4);
|
|
1320
|
-
message.set(tag, 0);
|
|
1321
|
-
message.set(xonly, tag.length);
|
|
1322
|
-
new DataView(message.buffer).setUint32(tag.length + 32, index, true);
|
|
1323
|
-
return message;
|
|
1324
|
-
}
|
|
1325
|
-
var PREIMAGE_INDEX = 0;
|
|
1326
|
-
async function deriveSwapSecrets(wallet) {
|
|
1327
|
-
if (!(0, import_sdk6.isHDAllocationCapable)(wallet)) return void 0;
|
|
1328
|
-
const signingDescriptor = await wallet.getNextSigningDescriptor();
|
|
1329
|
-
if (!signingDescriptor) return void 0;
|
|
1330
|
-
return { derivable: true, signingDescriptor };
|
|
1331
|
-
}
|
|
1332
|
-
function randomSwapSecrets(opts = {}) {
|
|
1333
|
-
if (opts.preimage instanceof Uint8Array && opts.preimage.length !== 32) {
|
|
1334
|
-
throw new Error(`preimage must be 32 bytes, got ${opts.preimage.length}`);
|
|
1335
|
-
}
|
|
1336
|
-
const preimage = opts.preimage instanceof Uint8Array ? opts.preimage : opts.preimage ? (0, import_utils2.randomBytes)(32) : void 0;
|
|
1337
|
-
return {
|
|
1338
|
-
derivable: false,
|
|
1339
|
-
senderPrivateKey: import_secp256k1.schnorr.utils.randomSecretKey(),
|
|
1340
|
-
...preimage ? { preimage } : {}
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
function rfqSecretsToRecord(secrets) {
|
|
1344
|
-
if (secrets.derivable) {
|
|
1345
|
-
return {
|
|
1346
|
-
signingDescriptor: secrets.signingDescriptor,
|
|
1347
|
-
...secrets.preimage ? { preimageHex: import_base5.hex.encode(secrets.preimage) } : {}
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
return {
|
|
1351
|
-
fallbackSecrets: {
|
|
1352
|
-
version: 1,
|
|
1353
|
-
type: "stored",
|
|
1354
|
-
senderPrivateKeyHex: import_base5.hex.encode(secrets.senderPrivateKey),
|
|
1355
|
-
...secrets.preimage ? { preimageHex: import_base5.hex.encode(secrets.preimage) } : {}
|
|
1356
|
-
}
|
|
1357
|
-
};
|
|
1358
|
-
}
|
|
1359
|
-
function rfqSecretsOfRecord(record) {
|
|
1360
|
-
if (record.signingDescriptor) {
|
|
1361
|
-
return {
|
|
1362
|
-
derivable: true,
|
|
1363
|
-
signingDescriptor: record.signingDescriptor,
|
|
1364
|
-
...record.preimageHex ? { preimage: decodeHex32(record.preimageHex, "preimageHex") } : {}
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
const fallback = record.fallbackSecrets;
|
|
1368
|
-
if (!fallback) return void 0;
|
|
1369
|
-
if (fallback.version !== 1 || fallback.type !== "stored") {
|
|
1370
|
-
throw new Error("unsupported RFQ fallback secrets record");
|
|
1371
|
-
}
|
|
1372
|
-
return {
|
|
1373
|
-
derivable: false,
|
|
1374
|
-
senderPrivateKey: decodeHex32(fallback.senderPrivateKeyHex, "senderPrivateKeyHex"),
|
|
1375
|
-
...fallback.preimageHex ? { preimage: decodeHex32(fallback.preimageHex, "preimageHex") } : {}
|
|
1376
|
-
};
|
|
1377
|
-
}
|
|
1378
|
-
function decodeHex32(value, label) {
|
|
1379
|
-
const bytes = import_base5.hex.decode(value);
|
|
1380
|
-
if (bytes.length !== 32) {
|
|
1381
|
-
throw new Error(label + " must be 32 bytes, got " + bytes.length);
|
|
1382
|
-
}
|
|
1383
|
-
return bytes;
|
|
1384
|
-
}
|
|
1385
|
-
async function adoptSwapDescriptor(wallet, signingDescriptor) {
|
|
1386
|
-
if (!(0, import_sdk6.isHDAllocationCapable)(wallet)) return;
|
|
1387
|
-
await wallet.advanceSigningDescriptorWatermark(signingDescriptor);
|
|
1388
|
-
}
|
|
1389
|
-
var RefundNotLocallyPossibleError = class extends Error {
|
|
1390
|
-
constructor(reason, message, options) {
|
|
1391
|
-
super(message, options);
|
|
1392
|
-
this.reason = reason;
|
|
1393
|
-
}
|
|
1394
|
-
reason;
|
|
1395
|
-
name = "RefundNotLocallyPossibleError";
|
|
1396
|
-
};
|
|
1397
|
-
async function senderIdentityForRfqSecrets(wallet, secrets) {
|
|
1398
|
-
if (!secrets.derivable) return import_sdk6.SingleKey.fromPrivateKey(secrets.senderPrivateKey);
|
|
1399
|
-
const signer = (0, import_sdk6.isHDWalletCapable)(wallet) ? await wallet.signerForDescriptor(secrets.signingDescriptor) : void 0;
|
|
1400
|
-
if (!signer || !isDeterministicSigner(signer)) {
|
|
1401
|
-
throw new RefundNotLocallyPossibleError(
|
|
1402
|
-
"foreign-descriptor",
|
|
1403
|
-
`this wallet cannot derive ${secrets.signingDescriptor}; the swap was created on another wallet`
|
|
1404
|
-
);
|
|
1405
|
-
}
|
|
1406
|
-
return signer;
|
|
1407
|
-
}
|
|
1408
|
-
async function senderIdentityForSwapRecord(wallet, record) {
|
|
1409
|
-
let secrets;
|
|
1410
|
-
try {
|
|
1411
|
-
secrets = rfqSecretsOfRecord(record);
|
|
1412
|
-
} catch (error) {
|
|
1413
|
-
throw new RefundNotLocallyPossibleError(
|
|
1414
|
-
"unreadable-secrets",
|
|
1415
|
-
error instanceof Error ? error.message : String(error),
|
|
1416
|
-
// the record's own diagnosis, kept for a caller that wants more
|
|
1417
|
-
// than the message
|
|
1418
|
-
{ cause: error }
|
|
1419
|
-
);
|
|
1420
|
-
}
|
|
1421
|
-
if (!secrets) {
|
|
1422
|
-
throw new RefundNotLocallyPossibleError(
|
|
1423
|
-
"no-secrets",
|
|
1424
|
-
"this swap record carries no signing descriptor and no fallback secrets"
|
|
1425
|
-
);
|
|
1426
|
-
}
|
|
1427
|
-
return senderIdentityForRfqSecrets(wallet, secrets);
|
|
1428
|
-
}
|
|
1429
|
-
async function senderPubkeyForRfqSecrets(wallet, secrets) {
|
|
1430
|
-
if (!secrets.derivable) return import_secp256k1.schnorr.getPublicKey(secrets.senderPrivateKey);
|
|
1431
|
-
return (await senderIdentityForRfqSecrets(wallet, secrets)).xOnlyPublicKey();
|
|
1432
|
-
}
|
|
1433
|
-
function isDeterministicSigner(value) {
|
|
1434
|
-
if (typeof value !== "object" || value === null) return false;
|
|
1435
|
-
const v = value;
|
|
1436
|
-
return typeof v.signSchnorrDeterministic === "function" && typeof v.xOnlyPublicKey === "function";
|
|
1437
|
-
}
|
|
1438
|
-
async function derivePreimage(signer) {
|
|
1439
|
-
const xonly = await signer.xOnlyPublicKey();
|
|
1440
|
-
const message = buildPreimageMessage(xonly, PREIMAGE_INDEX);
|
|
1441
|
-
return (0, import_sha22.sha256)(await signer.signSchnorrDeterministic((0, import_sha22.sha256)(message)));
|
|
1442
|
-
}
|
|
1443
|
-
async function preimageForRfqSecrets(wallet, secrets) {
|
|
1444
|
-
if (!secrets.derivable) {
|
|
1445
|
-
if (!secrets.preimage) throw new Error("this swap carries no stored preimage");
|
|
1446
|
-
return secrets.preimage;
|
|
1447
|
-
}
|
|
1448
|
-
if (secrets.preimage) return secrets.preimage;
|
|
1449
|
-
const signer = await senderIdentityForRfqSecrets(wallet, secrets);
|
|
1450
|
-
if (!isDeterministicSigner(signer)) {
|
|
1451
|
-
throw new Error(
|
|
1452
|
-
`wallet cannot sign deterministically for ${secrets.signingDescriptor}; its preimage is not derivable`
|
|
1453
|
-
);
|
|
1454
|
-
}
|
|
1455
|
-
try {
|
|
1456
|
-
return await derivePreimage(signer);
|
|
1457
|
-
} catch (cause) {
|
|
1458
|
-
throw new Error(
|
|
1459
|
-
`wallet cannot sign deterministically for ${secrets.signingDescriptor}; its preimage is not derivable`,
|
|
1460
|
-
{ cause }
|
|
1461
|
-
);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1293
|
+
// src/rfq.ts
|
|
1294
|
+
var import_sdk8 = require("@arkade-os/sdk");
|
|
1464
1295
|
|
|
1465
1296
|
// src/claimPacket.ts
|
|
1466
1297
|
var import_base6 = require("@scure/base");
|
|
1467
|
-
var
|
|
1298
|
+
var import_secp256k1 = require("@noble/curves/secp256k1.js");
|
|
1468
1299
|
var import_hkdf = require("@noble/hashes/hkdf.js");
|
|
1469
|
-
var
|
|
1300
|
+
var import_sha22 = require("@noble/hashes/sha2.js");
|
|
1470
1301
|
var HKDF_INFO = new TextEncoder().encode("covclaimd/preimage/v1");
|
|
1471
1302
|
async function sealClaimPacket(input) {
|
|
1472
1303
|
return sealWithEntropy(
|
|
1473
1304
|
input,
|
|
1474
|
-
|
|
1305
|
+
import_secp256k1.secp256k1.utils.randomSecretKey(),
|
|
1475
1306
|
crypto.getRandomValues(new Uint8Array(12))
|
|
1476
1307
|
);
|
|
1477
1308
|
}
|
|
@@ -1480,9 +1311,9 @@ async function sealWithEntropy(input, ephemeralKey, nonce) {
|
|
|
1480
1311
|
if (input.covclaimdPubkey.length !== 33) {
|
|
1481
1312
|
throw new Error("covclaimd pubkey must be 33-byte compressed");
|
|
1482
1313
|
}
|
|
1483
|
-
const ephemeralPub =
|
|
1484
|
-
const sharedX =
|
|
1485
|
-
const key = (0, import_hkdf.hkdf)(
|
|
1314
|
+
const ephemeralPub = import_secp256k1.secp256k1.getPublicKey(ephemeralKey, true);
|
|
1315
|
+
const sharedX = import_secp256k1.secp256k1.getSharedSecret(ephemeralKey, input.covclaimdPubkey, true).subarray(1);
|
|
1316
|
+
const key = (0, import_hkdf.hkdf)(import_sha22.sha256, sharedX, ephemeralPub, HKDF_INFO, 32);
|
|
1486
1317
|
if (nonce.length !== 12) throw new Error("nonce must be 12 bytes");
|
|
1487
1318
|
const aesKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, [
|
|
1488
1319
|
"encrypt"
|
|
@@ -1507,7 +1338,7 @@ async function sealWithEntropy(input, ephemeralKey, nonce) {
|
|
|
1507
1338
|
|
|
1508
1339
|
// src/lockupContract.ts
|
|
1509
1340
|
var import_base7 = require("@scure/base");
|
|
1510
|
-
var
|
|
1341
|
+
var import_sdk6 = require("@arkade-os/sdk");
|
|
1511
1342
|
var SWAP_LOCKUP_CONTRACT_TYPE = "vhtlc-v2";
|
|
1512
1343
|
var SWAP_LOCKUP_CONTRACT_LABEL = "Arkade RFQ swap lockup";
|
|
1513
1344
|
var SWAP_LOCKUP_CONTRACT_KIND = "rfq-swap-lockup";
|
|
@@ -1529,7 +1360,7 @@ async function registerLockupContract(contracts, script, address) {
|
|
|
1529
1360
|
try {
|
|
1530
1361
|
await contracts.createContract({
|
|
1531
1362
|
type: SWAP_LOCKUP_CONTRACT_TYPE,
|
|
1532
|
-
params:
|
|
1363
|
+
params: import_sdk6.VHTLCV2ContractHandler.serializeParams(script.options),
|
|
1533
1364
|
script: import_base7.hex.encode(script.pkScript),
|
|
1534
1365
|
address,
|
|
1535
1366
|
label: SWAP_LOCKUP_CONTRACT_LABEL,
|
|
@@ -1541,7 +1372,7 @@ async function registerLockupContract(contracts, script, address) {
|
|
|
1541
1372
|
}
|
|
1542
1373
|
|
|
1543
1374
|
// src/rfq.ts
|
|
1544
|
-
var
|
|
1375
|
+
var xOnly = (key, label) => {
|
|
1545
1376
|
if (key.length === 32) return key;
|
|
1546
1377
|
if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
|
|
1547
1378
|
throw new Error(`${label} is not a compressed or x-only public key`);
|
|
@@ -1811,7 +1642,7 @@ function lightningSendVtxoScript(params) {
|
|
|
1811
1642
|
type: "seconds",
|
|
1812
1643
|
value: BigInt(value)
|
|
1813
1644
|
});
|
|
1814
|
-
return new
|
|
1645
|
+
return new import_sdk7.VHTLC.ScriptV2({
|
|
1815
1646
|
sender: params.senderPubkey,
|
|
1816
1647
|
receiver: params.solverPubkey,
|
|
1817
1648
|
server: params.serverPubkey,
|
|
@@ -1832,17 +1663,12 @@ function lightningSendVtxoScript(params) {
|
|
|
1832
1663
|
}
|
|
1833
1664
|
});
|
|
1834
1665
|
}
|
|
1835
|
-
async function requestLightningSend(wallet, arkServerUrl,
|
|
1666
|
+
async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
1836
1667
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1837
|
-
const secrets = await
|
|
1838
|
-
|
|
1839
|
-
console.warn(
|
|
1840
|
-
"[swap] wallet cannot allocate an HD descriptor: the sender key is random and MUST be persisted before funding"
|
|
1841
|
-
);
|
|
1842
|
-
}
|
|
1843
|
-
const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
|
|
1668
|
+
const secrets = await (0, import_sdk8.provisionRefundKey)(wallet);
|
|
1669
|
+
const senderPubkey = secrets.pubkey;
|
|
1844
1670
|
const [info, refundAddress] = await Promise.all([
|
|
1845
|
-
new
|
|
1671
|
+
new import_sdk7.RestArkProvider(arkServerUrl).getInfo(),
|
|
1846
1672
|
wallet.getAddress()
|
|
1847
1673
|
]);
|
|
1848
1674
|
const quote = await transport.requestQuote(
|
|
@@ -1865,19 +1691,23 @@ async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transp
|
|
|
1865
1691
|
`quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
|
|
1866
1692
|
);
|
|
1867
1693
|
}
|
|
1868
|
-
const serverPubkey =
|
|
1694
|
+
const serverPubkey = xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key");
|
|
1695
|
+
const network = (0, import_sdk7.getNetwork)(info.network);
|
|
1869
1696
|
const script = lightningSendVtxoScript({
|
|
1870
|
-
solverPubkey:
|
|
1697
|
+
solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
|
|
1871
1698
|
refundLocktime: quote.refund_locktime,
|
|
1872
1699
|
serverPubkey,
|
|
1873
1700
|
paymentHash: params.invoice.paymentHash,
|
|
1874
1701
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
1875
|
-
emulatorPubkey:
|
|
1702
|
+
emulatorPubkey: xOnly(
|
|
1703
|
+
import_base8.hex.decode((0, import_sdk7.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
1704
|
+
"emulator signer key"
|
|
1705
|
+
),
|
|
1876
1706
|
senderPubkey,
|
|
1877
1707
|
receiverPkScript: solverHex(receiverPkScriptHex, "profile.receiver_pk_script"),
|
|
1878
|
-
refundPkScript:
|
|
1708
|
+
refundPkScript: import_sdk7.ArkAddress.decode(refundAddress).pkScript
|
|
1879
1709
|
});
|
|
1880
|
-
const address = script.address(
|
|
1710
|
+
const address = script.address(network.hrp, serverPubkey).encode();
|
|
1881
1711
|
verifyLockupAddress(quote, address);
|
|
1882
1712
|
assertFundable({
|
|
1883
1713
|
quote,
|
|
@@ -1962,7 +1792,7 @@ function deriveOnchainSend(input) {
|
|
|
1962
1792
|
throw new Error("onchain-send quote is missing a binding field");
|
|
1963
1793
|
}
|
|
1964
1794
|
const script = lightningSendVtxoScript({
|
|
1965
|
-
solverPubkey:
|
|
1795
|
+
solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
|
|
1966
1796
|
refundLocktime,
|
|
1967
1797
|
serverPubkey: input.serverPubkey,
|
|
1968
1798
|
paymentHash: input.paymentHash,
|
|
@@ -1970,7 +1800,7 @@ function deriveOnchainSend(input) {
|
|
|
1970
1800
|
emulatorPubkey: input.emulatorPubkey,
|
|
1971
1801
|
senderPubkey: input.senderPubkey,
|
|
1972
1802
|
receiverPkScript: solverHex(receiverPkScriptHex, "profile.receiver_pk_script"),
|
|
1973
|
-
refundPkScript:
|
|
1803
|
+
refundPkScript: import_sdk7.ArkAddress.decode(input.refundAddress).pkScript
|
|
1974
1804
|
});
|
|
1975
1805
|
const address = script.address(input.hrp, input.serverPubkey).encode();
|
|
1976
1806
|
verifyLockupAddress(quote, address);
|
|
@@ -1978,7 +1808,7 @@ function deriveOnchainSend(input) {
|
|
|
1978
1808
|
{
|
|
1979
1809
|
paymentHash: input.paymentHash,
|
|
1980
1810
|
claimKey: input.payoutPubkey,
|
|
1981
|
-
refundKey:
|
|
1811
|
+
refundKey: xOnly(import_base8.hex.decode(htlcPubkey), "solver L1 htlc key"),
|
|
1982
1812
|
refundLocktime: htlcLocktime
|
|
1983
1813
|
},
|
|
1984
1814
|
input.l1Network
|
|
@@ -1994,27 +1824,18 @@ function deriveOnchainSend(input) {
|
|
|
1994
1824
|
minConfirmations
|
|
1995
1825
|
};
|
|
1996
1826
|
}
|
|
1997
|
-
async function requestOnchainSend(wallet, arkServerUrl,
|
|
1827
|
+
async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
1998
1828
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
}
|
|
2002
|
-
const derivedSecrets = await deriveSwapSecrets(wallet);
|
|
2003
|
-
const secrets = derivedSecrets ? params.preimage ? { ...derivedSecrets, preimage: params.preimage } : derivedSecrets : randomSwapSecrets({ preimage: params.preimage ?? true });
|
|
2004
|
-
if (!secrets.derivable) {
|
|
2005
|
-
console.warn(
|
|
2006
|
-
params.preimage ? "[swap] this swap's sender key is random; the supplied preimage and sender key MUST be persisted before funding" : "[swap] this swap's preimage and sender key are random and MUST be persisted before funding"
|
|
2007
|
-
);
|
|
2008
|
-
} else if (params.preimage) {
|
|
1829
|
+
const secrets = await (0, import_sdk8.provisionClaimSecret)(wallet, { preimage: params.preimage });
|
|
1830
|
+
if (secrets.mustPersistPreimage) {
|
|
2009
1831
|
console.warn(
|
|
2010
|
-
"[swap] this swap's preimage
|
|
1832
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
|
|
2011
1833
|
);
|
|
2012
1834
|
}
|
|
2013
|
-
const
|
|
2014
|
-
const
|
|
2015
|
-
const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
|
|
1835
|
+
const paymentHash = import_base8.hex.encode(secrets.paymentHash);
|
|
1836
|
+
const senderPubkey = secrets.pubkey;
|
|
2016
1837
|
const [info, refundAddress] = await Promise.all([
|
|
2017
|
-
new
|
|
1838
|
+
new import_sdk7.RestArkProvider(arkServerUrl).getInfo(),
|
|
2018
1839
|
wallet.getAddress()
|
|
2019
1840
|
]);
|
|
2020
1841
|
const quote = await transport.requestQuote(
|
|
@@ -2028,14 +1849,18 @@ async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transpor
|
|
|
2028
1849
|
amountSide: params.amountSide
|
|
2029
1850
|
})
|
|
2030
1851
|
);
|
|
1852
|
+
const network = (0, import_sdk7.getNetwork)(info.network);
|
|
2031
1853
|
const derived = deriveOnchainSend({
|
|
2032
1854
|
quote,
|
|
2033
1855
|
paymentHash,
|
|
2034
1856
|
payoutPubkey: params.payoutPubkey,
|
|
2035
|
-
serverPubkey:
|
|
2036
|
-
emulatorPubkey:
|
|
1857
|
+
serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
|
|
1858
|
+
emulatorPubkey: xOnly(
|
|
1859
|
+
import_base8.hex.decode((0, import_sdk7.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
1860
|
+
"emulator signer key"
|
|
1861
|
+
),
|
|
2037
1862
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
2038
|
-
hrp:
|
|
1863
|
+
hrp: network.hrp,
|
|
2039
1864
|
l1Network: l1NetworkFromArk(info.network),
|
|
2040
1865
|
refundAddress,
|
|
2041
1866
|
senderPubkey
|
|
@@ -2139,7 +1964,7 @@ function receiveVtxoScript(params) {
|
|
|
2139
1964
|
type: "seconds",
|
|
2140
1965
|
value: BigInt(value)
|
|
2141
1966
|
});
|
|
2142
|
-
return new
|
|
1967
|
+
return new import_sdk7.VHTLC.ScriptV2({
|
|
2143
1968
|
sender: params.solverPubkey,
|
|
2144
1969
|
receiver: params.payoutPubkey,
|
|
2145
1970
|
server: params.serverPubkey,
|
|
@@ -2170,7 +1995,7 @@ function deriveLightningReceive(input) {
|
|
|
2170
1995
|
throw new Error("lightning-receive quote is missing a binding field");
|
|
2171
1996
|
}
|
|
2172
1997
|
const script = receiveVtxoScript({
|
|
2173
|
-
solverPubkey:
|
|
1998
|
+
solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2174
1999
|
refundLocktime,
|
|
2175
2000
|
serverPubkey: input.serverPubkey,
|
|
2176
2001
|
paymentHash: input.paymentHash,
|
|
@@ -2178,25 +2003,25 @@ function deriveLightningReceive(input) {
|
|
|
2178
2003
|
emulatorPubkey: input.emulatorPubkey,
|
|
2179
2004
|
solverRefundPkScript: solverHex(solverRefundPkScriptHex, "profile.solver_refund_pk_script"),
|
|
2180
2005
|
payoutPubkey: input.payoutPubkey,
|
|
2181
|
-
payoutPkScript:
|
|
2006
|
+
payoutPkScript: import_sdk7.ArkAddress.decode(input.payoutAddress).pkScript
|
|
2182
2007
|
});
|
|
2183
2008
|
const address = script.address(input.hrp, input.serverPubkey).encode();
|
|
2184
2009
|
verifyLockupAddress(quote, address);
|
|
2185
2010
|
return { address, swapPkScript: script.pkScript, script, invoice, refundLocktime };
|
|
2186
2011
|
}
|
|
2187
|
-
async function requestLightningReceive(wallet, arkServerUrl,
|
|
2012
|
+
async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
|
|
2188
2013
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2189
|
-
const secrets = await
|
|
2190
|
-
if (
|
|
2014
|
+
const secrets = await (0, import_sdk8.provisionClaimSecret)(wallet);
|
|
2015
|
+
if (secrets.mustPersistPreimage) {
|
|
2191
2016
|
console.warn(
|
|
2192
|
-
"[swap] this swap's preimage
|
|
2017
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before paying"
|
|
2193
2018
|
);
|
|
2194
2019
|
}
|
|
2195
|
-
const preimage =
|
|
2196
|
-
const paymentHash =
|
|
2197
|
-
const payoutPubkey =
|
|
2020
|
+
const preimage = secrets.preimage;
|
|
2021
|
+
const paymentHash = import_base8.hex.encode(secrets.paymentHash);
|
|
2022
|
+
const payoutPubkey = secrets.pubkey;
|
|
2198
2023
|
const [info, payoutAddress] = await Promise.all([
|
|
2199
|
-
new
|
|
2024
|
+
new import_sdk7.RestArkProvider(arkServerUrl).getInfo(),
|
|
2200
2025
|
wallet.getAddress()
|
|
2201
2026
|
]);
|
|
2202
2027
|
const claimPacket = await sealClaimPacket({
|
|
@@ -2215,15 +2040,19 @@ async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, tra
|
|
|
2215
2040
|
})
|
|
2216
2041
|
);
|
|
2217
2042
|
assertQuotedAmount(quote, params.amountSide, params.amount);
|
|
2043
|
+
const network = (0, import_sdk7.getNetwork)(info.network);
|
|
2218
2044
|
const derived = deriveLightningReceive({
|
|
2219
2045
|
quote,
|
|
2220
2046
|
paymentHash,
|
|
2221
2047
|
payoutPubkey,
|
|
2222
2048
|
payoutAddress,
|
|
2223
|
-
serverPubkey:
|
|
2224
|
-
emulatorPubkey:
|
|
2049
|
+
serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
|
|
2050
|
+
emulatorPubkey: xOnly(
|
|
2051
|
+
import_base8.hex.decode((0, import_sdk7.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
2052
|
+
"emulator signer key"
|
|
2053
|
+
),
|
|
2225
2054
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
2226
|
-
hrp:
|
|
2055
|
+
hrp: network.hrp
|
|
2227
2056
|
});
|
|
2228
2057
|
const now = Math.floor(Date.now() / 1e3);
|
|
2229
2058
|
const { payDeadline } = verifyReceiveInvoice({
|
|
@@ -2266,7 +2095,7 @@ function deriveOnchainReceive(input) {
|
|
|
2266
2095
|
throw new Error("onchain-receive quote is missing a binding field");
|
|
2267
2096
|
}
|
|
2268
2097
|
const script = receiveVtxoScript({
|
|
2269
|
-
solverPubkey:
|
|
2098
|
+
solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
|
|
2270
2099
|
refundLocktime,
|
|
2271
2100
|
serverPubkey: input.serverPubkey,
|
|
2272
2101
|
paymentHash: input.paymentHash,
|
|
@@ -2274,14 +2103,14 @@ function deriveOnchainReceive(input) {
|
|
|
2274
2103
|
emulatorPubkey: input.emulatorPubkey,
|
|
2275
2104
|
solverRefundPkScript: solverHex(solverRefundPkScriptHex, "profile.solver_refund_pk_script"),
|
|
2276
2105
|
payoutPubkey: input.payoutPubkey,
|
|
2277
|
-
payoutPkScript:
|
|
2106
|
+
payoutPkScript: import_sdk7.ArkAddress.decode(input.payoutAddress).pkScript
|
|
2278
2107
|
});
|
|
2279
2108
|
const address = script.address(input.hrp, input.serverPubkey).encode();
|
|
2280
2109
|
verifyLockupAddress(quote, address);
|
|
2281
2110
|
const htlc = onchainHtlcScript(
|
|
2282
2111
|
{
|
|
2283
2112
|
paymentHash: input.paymentHash,
|
|
2284
|
-
claimKey:
|
|
2113
|
+
claimKey: xOnly(import_base8.hex.decode(claimPubkey), "solver L1 claim key"),
|
|
2285
2114
|
refundKey: input.refundPubkey,
|
|
2286
2115
|
refundLocktime: htlcLocktime
|
|
2287
2116
|
},
|
|
@@ -2298,19 +2127,19 @@ function deriveOnchainReceive(input) {
|
|
|
2298
2127
|
minConfirmations
|
|
2299
2128
|
};
|
|
2300
2129
|
}
|
|
2301
|
-
async function requestOnchainReceive(wallet, arkServerUrl,
|
|
2130
|
+
async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
2302
2131
|
const rfqId = params.rfqId ?? newRfqId();
|
|
2303
|
-
const secrets = await
|
|
2304
|
-
if (
|
|
2132
|
+
const secrets = await (0, import_sdk8.provisionClaimSecret)(wallet);
|
|
2133
|
+
if (secrets.mustPersistPreimage) {
|
|
2305
2134
|
console.warn(
|
|
2306
|
-
"[swap] this swap's preimage
|
|
2135
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
|
|
2307
2136
|
);
|
|
2308
2137
|
}
|
|
2309
|
-
const preimage =
|
|
2310
|
-
const paymentHash =
|
|
2311
|
-
const payoutPubkey =
|
|
2138
|
+
const preimage = secrets.preimage;
|
|
2139
|
+
const paymentHash = import_base8.hex.encode(secrets.paymentHash);
|
|
2140
|
+
const payoutPubkey = secrets.pubkey;
|
|
2312
2141
|
const [info, payoutAddress] = await Promise.all([
|
|
2313
|
-
new
|
|
2142
|
+
new import_sdk7.RestArkProvider(arkServerUrl).getInfo(),
|
|
2314
2143
|
wallet.getAddress()
|
|
2315
2144
|
]);
|
|
2316
2145
|
const claimPacket = await sealClaimPacket({
|
|
@@ -2330,16 +2159,20 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
|
|
|
2330
2159
|
})
|
|
2331
2160
|
);
|
|
2332
2161
|
assertQuotedAmount(quote, params.amountSide, params.amount);
|
|
2162
|
+
const network = (0, import_sdk7.getNetwork)(info.network);
|
|
2333
2163
|
const derived = deriveOnchainReceive({
|
|
2334
2164
|
quote,
|
|
2335
2165
|
paymentHash,
|
|
2336
2166
|
payoutPubkey,
|
|
2337
2167
|
payoutAddress,
|
|
2338
2168
|
refundPubkey: params.refundPubkey,
|
|
2339
|
-
serverPubkey:
|
|
2340
|
-
emulatorPubkey:
|
|
2169
|
+
serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
|
|
2170
|
+
emulatorPubkey: xOnly(
|
|
2171
|
+
import_base8.hex.decode((0, import_sdk7.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
|
|
2172
|
+
"emulator signer key"
|
|
2173
|
+
),
|
|
2341
2174
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
2342
|
-
hrp:
|
|
2175
|
+
hrp: network.hrp,
|
|
2343
2176
|
l1Network: l1NetworkFromArk(info.network)
|
|
2344
2177
|
});
|
|
2345
2178
|
assertFundable({
|
|
@@ -2374,12 +2207,12 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
|
|
|
2374
2207
|
// src/claim.ts
|
|
2375
2208
|
var import_base10 = require("@scure/base");
|
|
2376
2209
|
var import_legacy3 = require("@noble/hashes/legacy.js");
|
|
2377
|
-
var
|
|
2210
|
+
var import_sha24 = require("@noble/hashes/sha2.js");
|
|
2378
2211
|
var import_sdk10 = require("@arkade-os/sdk");
|
|
2379
2212
|
|
|
2380
2213
|
// src/refund.ts
|
|
2381
2214
|
var import_base9 = require("@scure/base");
|
|
2382
|
-
var
|
|
2215
|
+
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
2383
2216
|
var import_sdk9 = require("@arkade-os/sdk");
|
|
2384
2217
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2385
2218
|
var isRfqTerminal = (state) => RFQ_TERMINAL_STATES.includes(state);
|
|
@@ -2452,7 +2285,7 @@ async function findLockupVtxos(indexer, swapPkScript) {
|
|
|
2452
2285
|
}
|
|
2453
2286
|
return out;
|
|
2454
2287
|
}
|
|
2455
|
-
var hashesTo = (candidate, paymentHash) => import_base9.hex.encode((0,
|
|
2288
|
+
var hashesTo = (candidate, paymentHash) => import_base9.hex.encode((0, import_sha23.sha256)(candidate)) === paymentHash;
|
|
2456
2289
|
var candidateWitnessItems = (tx, inputIndex) => [
|
|
2457
2290
|
...(0, import_sdk9.getArkPsbtFields)(tx, inputIndex, import_sdk9.ConditionWitness).flat(),
|
|
2458
2291
|
...tx.getInput(inputIndex).finalScriptWitness ?? []
|
|
@@ -2621,7 +2454,7 @@ async function pushClaim(ark, input) {
|
|
|
2621
2454
|
}
|
|
2622
2455
|
}
|
|
2623
2456
|
const committed = input.script.options.preimageHash;
|
|
2624
|
-
if (import_base10.hex.encode((0, import_legacy3.ripemd160)((0,
|
|
2457
|
+
if (import_base10.hex.encode((0, import_legacy3.ripemd160)((0, import_sha24.sha256)(input.preimage))) !== import_base10.hex.encode(committed)) {
|
|
2625
2458
|
throw new Error("preimage does not match the covenant's payment hash");
|
|
2626
2459
|
}
|
|
2627
2460
|
const info = await ark.getInfo();
|
|
@@ -2680,6 +2513,44 @@ async function claimReceiveLockup(indexer, ark, input) {
|
|
|
2680
2513
|
});
|
|
2681
2514
|
}
|
|
2682
2515
|
|
|
2516
|
+
// src/refundBlocked.ts
|
|
2517
|
+
var import_sdk11 = require("@arkade-os/sdk");
|
|
2518
|
+
var RefundNotLocallyPossibleError = class extends Error {
|
|
2519
|
+
constructor(reason, message, options) {
|
|
2520
|
+
super(message, options);
|
|
2521
|
+
this.reason = reason;
|
|
2522
|
+
}
|
|
2523
|
+
reason;
|
|
2524
|
+
name = "RefundNotLocallyPossibleError";
|
|
2525
|
+
};
|
|
2526
|
+
async function senderIdentityForSwapRecord(wallet, record) {
|
|
2527
|
+
if (!record.signingDescriptor) {
|
|
2528
|
+
throw new RefundNotLocallyPossibleError(
|
|
2529
|
+
"no-secrets",
|
|
2530
|
+
"this swap record carries no signing descriptor"
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
try {
|
|
2534
|
+
return await (0, import_sdk11.contractSigner)(wallet, record.signingDescriptor);
|
|
2535
|
+
} catch (cause) {
|
|
2536
|
+
if (cause instanceof import_sdk11.WalletCannotSignError) {
|
|
2537
|
+
throw new RefundNotLocallyPossibleError(
|
|
2538
|
+
"unsignable-wallet",
|
|
2539
|
+
`this wallet holds ${record.signingDescriptor} but cannot sign with it; attach its signer`,
|
|
2540
|
+
{ cause }
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
if (cause instanceof import_sdk11.ForeignDescriptorError) {
|
|
2544
|
+
throw new RefundNotLocallyPossibleError(
|
|
2545
|
+
"foreign-descriptor",
|
|
2546
|
+
`this wallet cannot derive ${record.signingDescriptor}; the swap was created on another wallet`,
|
|
2547
|
+
{ cause }
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
2550
|
+
throw cause;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2683
2554
|
// src/swapManager.ts
|
|
2684
2555
|
var import_base11 = require("@scure/base");
|
|
2685
2556
|
var RFQ_SWAP_TERMINAL_STATES = ["settled", "refunded", "failed"];
|
|
@@ -3473,7 +3344,6 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3473
3344
|
ONCHAIN_SEND_PAIR,
|
|
3474
3345
|
QUOTE_OPTIONS,
|
|
3475
3346
|
REFUND_MTP_LAG_SECONDS,
|
|
3476
|
-
RFQ_PREIMAGE_TAG,
|
|
3477
3347
|
RFQ_RESOLVED_STATES,
|
|
3478
3348
|
RFQ_SWAP_TERMINAL_STATES,
|
|
3479
3349
|
RFQ_TERMINAL_STATES,
|
|
@@ -3484,7 +3354,6 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3484
3354
|
SWAP_LOCKUP_CONTRACT_TYPE,
|
|
3485
3355
|
SwapRefusal,
|
|
3486
3356
|
addAssetSwap,
|
|
3487
|
-
adoptSwapDescriptor,
|
|
3488
3357
|
arkadeSwapRequest,
|
|
3489
3358
|
assertFundable,
|
|
3490
3359
|
assertReceivable,
|
|
@@ -3493,7 +3362,6 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3493
3362
|
awaitRfqResolution,
|
|
3494
3363
|
buildHtlcClaim,
|
|
3495
3364
|
buildHtlcRefund,
|
|
3496
|
-
buildPreimageMessage,
|
|
3497
3365
|
cancelOffer,
|
|
3498
3366
|
claimOnchainFill,
|
|
3499
3367
|
claimReceiveLockup,
|
|
@@ -3505,8 +3373,6 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3505
3373
|
deriveLightningReceive,
|
|
3506
3374
|
deriveOnchainReceive,
|
|
3507
3375
|
deriveOnchainSend,
|
|
3508
|
-
derivePreimage,
|
|
3509
|
-
deriveSwapSecrets,
|
|
3510
3376
|
discoverMarkets,
|
|
3511
3377
|
encodeOffer,
|
|
3512
3378
|
extractPreimage,
|
|
@@ -3515,7 +3381,6 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3515
3381
|
getAssetSwaps,
|
|
3516
3382
|
getAssetSwapsOrThrow,
|
|
3517
3383
|
httpTransport,
|
|
3518
|
-
isDeterministicSigner,
|
|
3519
3384
|
isRfqSwapTerminal,
|
|
3520
3385
|
isRfqTerminal,
|
|
3521
3386
|
lightningReceiveRequest,
|
|
@@ -3531,10 +3396,8 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3531
3396
|
onchainReceiveRequest,
|
|
3532
3397
|
onchainSendRequest,
|
|
3533
3398
|
paymentHashOf,
|
|
3534
|
-
preimageForRfqSecrets,
|
|
3535
3399
|
pushClaim,
|
|
3536
3400
|
pushRefundWithoutReceiver,
|
|
3537
|
-
randomSwapSecrets,
|
|
3538
3401
|
readLockupFate,
|
|
3539
3402
|
receiveVtxoScript,
|
|
3540
3403
|
refundIfUnresolved,
|
|
@@ -3547,15 +3410,12 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
|
|
|
3547
3410
|
restoreAssetSwaps,
|
|
3548
3411
|
retireSettledOfferContracts,
|
|
3549
3412
|
rfqPair,
|
|
3550
|
-
rfqSecretsOfRecord,
|
|
3551
|
-
rfqSecretsToRecord,
|
|
3552
3413
|
sealClaimPacket,
|
|
3553
|
-
senderIdentityForRfqSecrets,
|
|
3554
3414
|
senderIdentityForSwapRecord,
|
|
3555
|
-
senderPubkeyForRfqSecrets,
|
|
3556
3415
|
spendTxidsOf,
|
|
3557
3416
|
spendUpdate,
|
|
3558
3417
|
swapPrograms,
|
|
3418
|
+
swapSecretsToRecord,
|
|
3559
3419
|
unilateralClaimDelay,
|
|
3560
3420
|
unilateralRefundDelay,
|
|
3561
3421
|
unilateralRefundWithoutReceiverDelay,
|