@arkade-os/swap 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ import {
65
65
  unilateralRefundWithoutReceiverDelay,
66
66
  verifyLockupAddress,
67
67
  verifyReceiveInvoice
68
- } from "./chunk-XXWOODUE.js";
68
+ } from "./chunk-IFZOBTTG.js";
69
69
  import {
70
70
  InMemoryAssetSwapRepository,
71
71
  marketsCacheKey
@@ -1580,7 +1580,14 @@ var solverRendezvous = (markets, payoutCorridor, amountSats, fallbackEmulatorPub
1580
1580
  };
1581
1581
 
1582
1582
  // src/payment/solverOnchain.ts
1583
- import { btcTarget, makeHandle, resolveSendAmount, tryResolveSendAmount } from "@arkade-os/sdk";
1583
+ import {
1584
+ assertNoAssets,
1585
+ assetsOf,
1586
+ btcTarget,
1587
+ makeHandle,
1588
+ resolveSendAmount,
1589
+ tryResolveSendAmount
1590
+ } from "@arkade-os/sdk";
1584
1591
  var SOLVER_ONCHAIN_RAIL = "solver-onchain";
1585
1592
  var solverOnchainRendezvous = (markets, amountSats, fallbackEmulatorPubkey) => solverRendezvous(markets, "onchain", amountSats, fallbackEmulatorPubkey);
1586
1593
  function solverOnchainRail(deps) {
@@ -1593,6 +1600,7 @@ function solverOnchainRail(deps) {
1593
1600
  id: SOLVER_ONCHAIN_RAIL,
1594
1601
  match: (req) => btcTarget(req.raw) !== void 0,
1595
1602
  available: async (req) => {
1603
+ if (assetsOf(req).length > 0) return false;
1596
1604
  const address = btcTarget(req.raw);
1597
1605
  if (!address) return false;
1598
1606
  try {
@@ -1606,6 +1614,7 @@ function solverOnchainRail(deps) {
1606
1614
  },
1607
1615
  quote: async (req, ctx) => {
1608
1616
  const address = btcTarget(req.raw);
1617
+ assertNoAssets(SOLVER_ONCHAIN_RAIL, req);
1609
1618
  const amount = resolveSendAmount(SOLVER_ONCHAIN_RAIL, req.raw, req.amount);
1610
1619
  const payoutPkScript = l1ScriptForAddress(address, deps.l1Network);
1611
1620
  const rendezvous = await rendezvousFor(amount);
@@ -1682,7 +1691,7 @@ function solverOnchainRail(deps) {
1682
1691
  }
1683
1692
 
1684
1693
  // src/payment/solverLightning.ts
1685
- import { invoiceTarget, makeHandle as makeHandle2 } from "@arkade-os/sdk";
1694
+ import { assertNoAssets as assertNoAssets2, assetsOf as assetsOf2, invoiceTarget, makeHandle as makeHandle2 } from "@arkade-os/sdk";
1686
1695
  var SOLVER_LIGHTNING_RAIL = "solver-lightning";
1687
1696
  var factsOf = (raw, decode, now) => {
1688
1697
  const invoice = invoiceTarget(raw);
@@ -1704,12 +1713,14 @@ function solverLightningRail(deps) {
1704
1713
  id: SOLVER_LIGHTNING_RAIL,
1705
1714
  match: (req) => invoiceTarget(req.raw) !== void 0,
1706
1715
  available: async (req) => {
1716
+ if (assetsOf2(req).length > 0) return false;
1707
1717
  const facts = factsOf(req.raw, deps.decodeInvoice, Math.floor(Date.now() / 1e3));
1708
1718
  if (!facts) return false;
1709
1719
  if (req.amount !== void 0 && req.amount !== facts.amountSats) return false;
1710
1720
  return await rendezvousFor(facts.amountSats) !== void 0;
1711
1721
  },
1712
1722
  quote: async (req, ctx) => {
1723
+ assertNoAssets2(SOLVER_LIGHTNING_RAIL, req);
1713
1724
  const facts = factsOf(req.raw, deps.decodeInvoice, Math.floor(Date.now() / 1e3));
1714
1725
  if (!facts) {
1715
1726
  throw new Error(
@@ -1782,10 +1793,260 @@ function solverLightningRail(deps) {
1782
1793
  };
1783
1794
  }
1784
1795
 
1785
- // src/claim.ts
1786
- import { hex as hex10 } from "@scure/base";
1796
+ // src/payment/crossAsset.ts
1797
+ import {
1798
+ arkTarget,
1799
+ asset as assetExt,
1800
+ assetsOf as assetsOf3,
1801
+ makeHandle as makeHandle3,
1802
+ resolveAssetAmount
1803
+ } from "@arkade-os/sdk";
1804
+ var CROSS_ASSET_RAIL = "cross-asset";
1805
+ var DEFAULT_CARRIER_SATS = 330;
1806
+ var parseAssetId = (assetId) => {
1807
+ try {
1808
+ return assetExt.AssetId.fromString(assetId);
1809
+ } catch {
1810
+ return void 0;
1811
+ }
1812
+ };
1813
+ function crossAssetRail(deps) {
1814
+ const planFor = async (asset2) => {
1815
+ const markets = await deps.discover();
1816
+ const found = findMarket(markets, BTC_ASSET_ID, asset2.assetId);
1817
+ const market = found?.market;
1818
+ if (!market) return void 0;
1819
+ const plan = await deps.quote(market, found.give, asset2.amount);
1820
+ const [balance, dust] = await Promise.all([deps.btcBalance(), deps.dust()]);
1821
+ return { plan, error: validatePlan(plan, balance, dust) };
1822
+ };
1823
+ return {
1824
+ id: CROSS_ASSET_RAIL,
1825
+ match: (req) => arkTarget(req.raw) !== void 0,
1826
+ available: async (req) => {
1827
+ const assets = assetsOf3(req);
1828
+ if (assets.length !== 1) return false;
1829
+ const [asset2] = assets;
1830
+ if (asset2.assetId === BTC_ASSET_ID) return false;
1831
+ if (typeof asset2.amount !== "bigint" || asset2.amount <= 0n) return false;
1832
+ if (!parseAssetId(asset2.assetId)) return false;
1833
+ const planned = await planFor(asset2);
1834
+ return planned !== void 0 && planned.error === void 0;
1835
+ },
1836
+ quote: async (req, ctx) => {
1837
+ const payTo = arkTarget(req.raw);
1838
+ const asset2 = resolveAssetAmount(CROSS_ASSET_RAIL, req);
1839
+ const wantAsset = parseAssetId(asset2.assetId);
1840
+ if (!wantAsset) {
1841
+ throw new Error(
1842
+ `${CROSS_ASSET_RAIL}: ${asset2.assetId} is not an asset id (expected 34 bytes of hex)`
1843
+ );
1844
+ }
1845
+ const planned = await planFor(asset2);
1846
+ if (!planned) {
1847
+ throw new Error(`${CROSS_ASSET_RAIL}: no market swaps BTC into ${asset2.assetId}`);
1848
+ }
1849
+ if (planned.error) {
1850
+ throw new Error(
1851
+ `${CROSS_ASSET_RAIL}: cannot swap into ${asset2.assetId} \u2014 ${planned.error}`
1852
+ );
1853
+ }
1854
+ const { plan } = planned;
1855
+ if (!Number.isSafeInteger(Number(plan.deposit.atomic))) {
1856
+ throw new Error(
1857
+ `${CROSS_ASSET_RAIL}: deposit of ${plan.deposit.atomic} does not fit a JS number`
1858
+ );
1859
+ }
1860
+ const depositSats = Number(plan.deposit.atomic);
1861
+ const carrier = deps.carrierSats ?? DEFAULT_CARRIER_SATS;
1862
+ return {
1863
+ railId: CROSS_ASSET_RAIL,
1864
+ // OPEN QUESTION for review: `total = amount + fee` forces the
1865
+ // purchase price into `fee`, which reads as a service charge.
1866
+ // A third field instead? `assets.spent` labels it correctly.
1867
+ amount: carrier,
1868
+ fee: depositSats,
1869
+ total: depositSats + carrier,
1870
+ assets: {
1871
+ delivered: asset2,
1872
+ spent: { assetId: BTC_ASSET_ID, amount: plan.deposit.atomic }
1873
+ },
1874
+ meta: {
1875
+ market: plan.market.pair,
1876
+ priceDisplay: plan.priceDisplay,
1877
+ give: plan.give
1878
+ },
1879
+ send: async () => makeHandle3(CROSS_ASSET_RAIL, async (emit) => {
1880
+ const offer = await createOffer(ctx.wallet, deps.arkServerUrl, {
1881
+ wantAmount: asset2.amount,
1882
+ wantAsset,
1883
+ ...deps.emulatorPubkey ? { emulatorPubkey: deps.emulatorPubkey } : {}
1884
+ });
1885
+ const swap = {
1886
+ phase: "quoted",
1887
+ offerHex: offer.offerHex,
1888
+ address: offer.address,
1889
+ swapPkScript: offer.swapPkScript,
1890
+ depositSats,
1891
+ asset: asset2,
1892
+ payTo,
1893
+ plan
1894
+ };
1895
+ await deps.persist(swap);
1896
+ await ctx.wallet.send({
1897
+ address: offer.address,
1898
+ amount: depositSats,
1899
+ extensions: [offer.extension]
1900
+ });
1901
+ emit({ status: "sent" });
1902
+ await deps.awaitFill(swap);
1903
+ await deps.persist({ ...swap, phase: "filled" });
1904
+ await deps.persist({ ...swap, phase: "paying" });
1905
+ const txid = await ctx.wallet.send({
1906
+ address: payTo,
1907
+ amount: carrier,
1908
+ assets: [asset2]
1909
+ });
1910
+ await deps.persist({ ...swap, phase: "settled", txid });
1911
+ const result = {
1912
+ railId: CROSS_ASSET_RAIL,
1913
+ txid,
1914
+ swapId: offer.offerHex
1915
+ };
1916
+ emit({ status: "settled", result });
1917
+ return result;
1918
+ })
1919
+ };
1920
+ }
1921
+ };
1922
+ }
1923
+
1924
+ // src/reveal.ts
1925
+ import { base64 as base643, hex as hex9 } from "@scure/base";
1787
1926
  import { ripemd160 } from "@noble/hashes/legacy.js";
1788
- import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1927
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1928
+ import { ArkAddress as ArkAddress4 } from "@arkade-os/sdk";
1929
+ var CovclaimdRevealError = class extends Error {
1930
+ name = "CovclaimdRevealError";
1931
+ status;
1932
+ detail;
1933
+ retryable;
1934
+ constructor(what, status, detail) {
1935
+ super(`covclaimd ${what} failed: ${status || "no response"} ${detail}`.trimEnd());
1936
+ this.status = status;
1937
+ this.detail = detail;
1938
+ this.retryable = status === 0 || status === 429 || status >= 500;
1939
+ }
1940
+ };
1941
+ var decodeKey = (value, field) => {
1942
+ if (typeof value !== "string") throw new Error(`covclaimd info: ${field} is not a string`);
1943
+ let bytes;
1944
+ try {
1945
+ bytes = hex9.decode(value);
1946
+ } catch {
1947
+ throw new Error(`covclaimd info: ${field} is not hex`);
1948
+ }
1949
+ if (bytes.length !== 33) {
1950
+ throw new Error(`covclaimd info: ${field} must be 33-byte compressed, got ${bytes.length}`);
1951
+ }
1952
+ return bytes;
1953
+ };
1954
+ var LOOPBACK = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
1955
+ var assertTransportSecure = (baseUrl, allowInsecureHttp) => {
1956
+ const { protocol, hostname } = new URL(baseUrl);
1957
+ if (protocol === "https:" || allowInsecureHttp) return;
1958
+ if (protocol === "http:" && LOOPBACK.has(hostname)) return;
1959
+ throw new Error(
1960
+ `covclaimd URL must be https (got ${protocol}//${hostname}): the key it serves is the one the preimage gets sealed to. Pass allowInsecureHttp to override.`
1961
+ );
1962
+ };
1963
+ var covclaimdClient = (baseUrl, options = {}) => {
1964
+ assertTransportSecure(baseUrl, options.allowInsecureHttp === true);
1965
+ const url = baseUrl.replace(/\/+$/, "");
1966
+ const fetchImpl = options.fetchImpl ?? fetch;
1967
+ const timeoutMs = options.timeoutMs ?? 3e4;
1968
+ const send = async (what, path, init) => {
1969
+ let response;
1970
+ try {
1971
+ response = await fetchImpl(`${url}${path}`, {
1972
+ ...init,
1973
+ // a redirect would move the key fetch off the vetted origin
1974
+ redirect: "error",
1975
+ signal: AbortSignal.timeout(timeoutMs)
1976
+ });
1977
+ } catch (error) {
1978
+ throw new CovclaimdRevealError(what, 0, String(error));
1979
+ }
1980
+ if (!response.ok) {
1981
+ throw new CovclaimdRevealError(what, response.status, await response.text());
1982
+ }
1983
+ return response;
1984
+ };
1985
+ const readJson = async (what, response) => {
1986
+ const body = await response.text();
1987
+ try {
1988
+ return JSON.parse(body);
1989
+ } catch {
1990
+ throw new CovclaimdRevealError(
1991
+ what,
1992
+ response.status,
1993
+ `non-JSON body: ${body.slice(0, 200)}`
1994
+ );
1995
+ }
1996
+ };
1997
+ return {
1998
+ async info() {
1999
+ const response = await send("info", "/v1/preimage/covclaimd-pubkey", {
2000
+ method: "GET"
2001
+ });
2002
+ const body = await readJson("info", response);
2003
+ return {
2004
+ covclaimdPubkey: decodeKey(body?.covclaimd_pub_key, "covclaimd_pub_key"),
2005
+ emulatorPubkey: hex9.encode(decodeKey(body?.emulator_pub_key, "emulator_pub_key"))
2006
+ };
2007
+ },
2008
+ async reveal(params) {
2009
+ await send("reveal", "/v1/reveal", {
2010
+ method: "POST",
2011
+ headers: { "content-type": "application/json" },
2012
+ body: JSON.stringify({
2013
+ swap_address: params.swapAddress,
2014
+ packet: { ciphertext: params.ciphertext, arkade_script: params.arkadeScript },
2015
+ taptree: params.taptree
2016
+ })
2017
+ });
2018
+ }
2019
+ };
2020
+ };
2021
+ function revealFieldsFromScript(script) {
2022
+ if (!script.nonInteractiveClaimArkadeScript) {
2023
+ throw new Error("this covenant has no non-interactive claim leaf to reveal against");
2024
+ }
2025
+ return {
2026
+ arkadeScript: base643.encode(script.nonInteractiveClaimArkadeScript),
2027
+ taptree: hex9.encode(script.encode())
2028
+ };
2029
+ }
2030
+ async function revealClaimPacket(client, input) {
2031
+ const fields = revealFieldsFromScript(input.script);
2032
+ if (hex9.encode(ArkAddress4.decode(input.address).pkScript) !== hex9.encode(input.script.pkScript)) {
2033
+ throw new Error("address does not belong to this covenant");
2034
+ }
2035
+ if (hex9.encode(ripemd160(sha2562(input.preimage))) !== hex9.encode(input.script.options.preimageHash)) {
2036
+ throw new Error("preimage does not match the covenant's payment hash");
2037
+ }
2038
+ const { ciphertext } = await sealClaimPacket({
2039
+ preimage: input.preimage,
2040
+ covclaimdPubkey: (await client.info()).covclaimdPubkey
2041
+ });
2042
+ await client.reveal({ swapAddress: input.address, ciphertext, ...fields });
2043
+ return { ciphertext };
2044
+ }
2045
+
2046
+ // src/claim.ts
2047
+ import { hex as hex11 } from "@scure/base";
2048
+ import { ripemd160 as ripemd1602 } from "@noble/hashes/legacy.js";
2049
+ import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
1789
2050
  import {
1790
2051
  CSVMultisigTapscript as CSVMultisigTapscript2,
1791
2052
  claimWithPreimageIdentity,
@@ -1793,8 +2054,8 @@ import {
1793
2054
  } from "@arkade-os/sdk";
1794
2055
 
1795
2056
  // src/refund.ts
1796
- import { base64 as base643, hex as hex9 } from "@scure/base";
1797
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
2057
+ import { base64 as base644, hex as hex10 } from "@scure/base";
2058
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1798
2059
  import {
1799
2060
  CSVMultisigTapscript,
1800
2061
  ConditionWitness,
@@ -1851,7 +2112,7 @@ var LockupNeedsRecoveryError = class extends Error {
1851
2112
  }
1852
2113
  };
1853
2114
  async function findLockupVtxos(indexer, swapPkScript) {
1854
- const scripts = [hex9.encode(swapPkScript)];
2115
+ const scripts = [hex10.encode(swapPkScript)];
1855
2116
  const [spendable, recoverable] = await Promise.all([
1856
2117
  indexer.getVtxos({ scripts, spendableOnly: true }),
1857
2118
  indexer.getVtxos({ scripts, recoverableOnly: true })
@@ -1877,13 +2138,13 @@ async function findLockupVtxos(indexer, swapPkScript) {
1877
2138
  }
1878
2139
  return out;
1879
2140
  }
1880
- var hashesTo = (candidate, paymentHash) => hex9.encode(sha2562(candidate)) === paymentHash;
2141
+ var hashesTo = (candidate, paymentHash) => hex10.encode(sha2563(candidate)) === paymentHash;
1881
2142
  var candidateWitnessItems = (tx, inputIndex) => [
1882
2143
  ...getArkPsbtFields(tx, inputIndex, ConditionWitness).flat(),
1883
2144
  ...tx.getInput(inputIndex).finalScriptWitness ?? []
1884
2145
  ];
1885
2146
  async function readLockupFate(indexer, input) {
1886
- const { vtxos } = await indexer.getVtxos({ scripts: [hex9.encode(input.swapPkScript)] });
2147
+ const { vtxos } = await indexer.getVtxos({ scripts: [hex10.encode(input.swapPkScript)] });
1887
2148
  const all = vtxos ?? [];
1888
2149
  if (all.length === 0) return { fate: "unknown" };
1889
2150
  const exited = all.filter((vtxo) => vtxo.isUnrolled && !hasTerminalSpend(vtxo));
@@ -1910,7 +2171,7 @@ async function readLockupFate(indexer, input) {
1910
2171
  for (const raw of txs) {
1911
2172
  let tx;
1912
2173
  try {
1913
- tx = Transaction3.fromPSBT(base643.decode(raw));
2174
+ tx = Transaction3.fromPSBT(base644.decode(raw));
1914
2175
  } catch {
1915
2176
  continue;
1916
2177
  }
@@ -1918,7 +2179,7 @@ async function readLockupFate(indexer, input) {
1918
2179
  for (let i = 0; i < tx.inputsLength; i++) {
1919
2180
  const spent = tx.getInput(i);
1920
2181
  if (!spent.txid) continue;
1921
- const txid = hex9.encode(spent.txid);
2182
+ const txid = hex10.encode(spent.txid);
1922
2183
  if (!all.some((vtxo) => vtxo.txid === txid && vtxo.vout === spent.index)) continue;
1923
2184
  for (const candidate of candidateWitnessItems(tx, i)) {
1924
2185
  if (hashesTo(candidate, input.paymentHash)) {
@@ -1947,7 +2208,7 @@ async function pushRefundWithoutReceiver(ark, input) {
1947
2208
  const info = await ark.getInfo();
1948
2209
  let serverUnrollScript;
1949
2210
  try {
1950
- serverUnrollScript = CSVMultisigTapscript.decode(hex9.decode(info.checkpointTapscript));
2211
+ serverUnrollScript = CSVMultisigTapscript.decode(hex10.decode(info.checkpointTapscript));
1951
2212
  } catch {
1952
2213
  throw new Error("invalid checkpointTapscript from the Arkade server");
1953
2214
  }
@@ -1967,8 +2228,8 @@ async function pushRefundWithoutReceiver(ark, input) {
1967
2228
  );
1968
2229
  const signedArkTx = await input.sender.sign(arkTx);
1969
2230
  const submitted = await ark.submitTx(
1970
- base643.encode(signedArkTx.toPSBT()),
1971
- checkpoints.map((c) => base643.encode(c.toPSBT()))
2231
+ base644.encode(signedArkTx.toPSBT()),
2232
+ checkpoints.map((c) => base644.encode(c.toPSBT()))
1972
2233
  );
1973
2234
  assertSubmittedArkTxid(submitted, signedArkTx, "refundWithoutReceiver");
1974
2235
  const matched = matchServerCheckpoints(
@@ -1978,7 +2239,7 @@ async function pushRefundWithoutReceiver(ark, input) {
1978
2239
  );
1979
2240
  const finalCheckpoints = await Promise.all(
1980
2241
  matched.map(
1981
- async ({ server }) => base643.encode((await input.sender.sign(server, [0])).toPSBT())
2242
+ async ({ server }) => base644.encode((await input.sender.sign(server, [0])).toPSBT())
1982
2243
  )
1983
2244
  );
1984
2245
  await ark.finalizeTx(submitted.arkTxid, finalCheckpoints);
@@ -2073,13 +2334,13 @@ async function pushClaim(ark, input) {
2073
2334
  }
2074
2335
  }
2075
2336
  const committed = input.script.options.preimageHash;
2076
- if (hex10.encode(ripemd160(sha2563(input.preimage))) !== hex10.encode(committed)) {
2337
+ if (hex11.encode(ripemd1602(sha2564(input.preimage))) !== hex11.encode(committed)) {
2077
2338
  throw new Error("preimage does not match the covenant's payment hash");
2078
2339
  }
2079
2340
  const info = await ark.getInfo();
2080
2341
  let serverUnrollScript;
2081
2342
  try {
2082
- serverUnrollScript = CSVMultisigTapscript2.decode(hex10.decode(info.checkpointTapscript));
2343
+ serverUnrollScript = CSVMultisigTapscript2.decode(hex11.decode(info.checkpointTapscript));
2083
2344
  } catch {
2084
2345
  throw new Error("invalid checkpointTapscript from the Arkade server");
2085
2346
  }
@@ -2198,7 +2459,7 @@ function arkadeRefunder(deps) {
2198
2459
  }
2199
2460
 
2200
2461
  // src/swapManager.ts
2201
- import { hex as hex11 } from "@scure/base";
2462
+ import { hex as hex12 } from "@scure/base";
2202
2463
  function nextOnchainAction(input) {
2203
2464
  switch (input.phase.phase) {
2204
2465
  case "unfunded":
@@ -2646,7 +2907,7 @@ var RfqSwapManager = class {
2646
2907
  // ── internals ────────────────────────────────────────────────────────────
2647
2908
  track(swap) {
2648
2909
  this.monitored.set(swap.rfqId, swap);
2649
- this.byLockupScript.set(hex11.encode(swap.lockupPkScript), swap);
2910
+ this.byLockupScript.set(hex12.encode(swap.lockupPkScript), swap);
2650
2911
  }
2651
2912
  /** Drops the swap from BOTH indexes. The event index is the one that stops
2652
2913
  * a late event finding a swap that is gone; `pollSwap`'s own
@@ -2655,7 +2916,7 @@ var RfqSwapManager = class {
2655
2916
  * them from silently re-driving a cancelled swap. */
2656
2917
  untrack(rfqId) {
2657
2918
  const swap = this.monitored.get(rfqId);
2658
- if (swap) this.byLockupScript.delete(hex11.encode(swap.lockupPkScript));
2919
+ if (swap) this.byLockupScript.delete(hex12.encode(swap.lockupPkScript));
2659
2920
  this.monitored.delete(rfqId);
2660
2921
  this.refundRefused.delete(rfqId);
2661
2922
  this.lastClaimError.delete(rfqId);
@@ -2717,7 +2978,7 @@ var RfqSwapManager = class {
2717
2978
  if (!lockup) {
2718
2979
  try {
2719
2980
  const [existing] = await contracts.getContracts({
2720
- script: hex11.encode(swap.lockupPkScript)
2981
+ script: hex12.encode(swap.lockupPkScript)
2721
2982
  });
2722
2983
  if (existing) {
2723
2984
  this.registered.set(swap.rfqId, true);
@@ -2736,13 +2997,13 @@ var RfqSwapManager = class {
2736
2997
  );
2737
2998
  return;
2738
2999
  }
2739
- const script = hex11.encode(lockup.script.pkScript);
2740
- if (script !== hex11.encode(swap.lockupPkScript)) {
3000
+ const script = hex12.encode(lockup.script.pkScript);
3001
+ if (script !== hex12.encode(swap.lockupPkScript)) {
2741
3002
  this.registered.set(swap.rfqId, false);
2742
3003
  this.emitFailed(
2743
3004
  swap,
2744
3005
  new Error(
2745
- `swap ${swap.rfqId} lockup script ${script} does not match its lockupPkScript ${hex11.encode(swap.lockupPkScript)}`
3006
+ `swap ${swap.rfqId} lockup script ${script} does not match its lockupPkScript ${hex12.encode(swap.lockupPkScript)}`
2746
3007
  )
2747
3008
  );
2748
3009
  return;
@@ -2761,7 +3022,7 @@ var RfqSwapManager = class {
2761
3022
  * script for its whole life. Best-effort — the swap is over either way. */
2762
3023
  retireContract(swap) {
2763
3024
  if (!this.deps.contracts || !this.registered.get(swap.rfqId)) return;
2764
- void this.deps.contracts.setContractWatchState(hex11.encode(swap.lockupPkScript), "retained").catch((error) => this.emitFailed(swap, error));
3025
+ void this.deps.contracts.setContractWatchState(hex12.encode(swap.lockupPkScript), "retained").catch((error) => this.emitFailed(swap, error));
2765
3026
  }
2766
3027
  arm() {
2767
3028
  if (!this.running) return;
@@ -3235,9 +3496,9 @@ var outpointKey = (vtxo) => `${vtxo.txid}:${vtxo.vout}`;
3235
3496
 
3236
3497
  // src/activity.ts
3237
3498
  import {
3238
- ArkAddress as ArkAddress4
3499
+ ArkAddress as ArkAddress5
3239
3500
  } from "@arkade-os/sdk";
3240
- import { hex as hex12 } from "@scure/base";
3501
+ import { hex as hex13 } from "@scure/base";
3241
3502
  var LABELS = {
3242
3503
  lightning_send: "Lightning send",
3243
3504
  lightning_receive: "Lightning receive",
@@ -3312,7 +3573,7 @@ async function activityInputOf(record, indexer) {
3312
3573
  async function lockupTxids(indexer, record, wantFunding) {
3313
3574
  let script;
3314
3575
  try {
3315
- script = hex12.encode(ArkAddress4.decode(record.lockupAddress).pkScript);
3576
+ script = hex13.encode(ArkAddress5.decode(record.lockupAddress).pkScript);
3316
3577
  } catch {
3317
3578
  return [];
3318
3579
  }
@@ -3333,6 +3594,8 @@ export {
3333
3594
  ARKADE_BTC,
3334
3595
  AddressMismatch,
3335
3596
  BTC_ASSET_ID,
3597
+ CROSS_ASSET_RAIL,
3598
+ CovclaimdRevealError,
3336
3599
  InMemoryAssetSwapRepository,
3337
3600
  IndexedDbAssetSwapRepository,
3338
3601
  LIGHTNING_BTC,
@@ -3389,8 +3652,10 @@ export {
3389
3652
  classifyDepositSpend,
3390
3653
  classifyOnchainHtlc,
3391
3654
  classifySpend,
3655
+ covclaimdClient,
3392
3656
  createOffer,
3393
3657
  createRfqSwapRecord,
3658
+ crossAssetRail,
3394
3659
  decodeOffer,
3395
3660
  deriveLightningReceive,
3396
3661
  deriveOnchainReceive,
@@ -3436,6 +3701,8 @@ export {
3436
3701
  requestOnchainSend,
3437
3702
  restoreAssetSwaps,
3438
3703
  retireSettledOfferContracts,
3704
+ revealClaimPacket,
3705
+ revealFieldsFromScript,
3439
3706
  rfqClaimSecretOf,
3440
3707
  rfqPair,
3441
3708
  rfqSecretsProfile,
package/dist/nostr.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { R as RfqTransport } from './rfq-DzsmhXX3.cjs';
1
+ import { R as RfqTransport } from './rfq-CYfKvAPp.cjs';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
 
package/dist/nostr.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { R as RfqTransport } from './rfq-DzsmhXX3.js';
1
+ import { R as RfqTransport } from './rfq-CYfKvAPp.js';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
 
package/dist/nostr.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  expectQuote,
3
3
  pairOf
4
- } from "./chunk-XXWOODUE.js";
4
+ } from "./chunk-IFZOBTTG.js";
5
5
 
6
6
  // src/nostr.ts
7
7
  import {
@@ -1,8 +1,8 @@
1
1
  import { RealmLike } from '@arkade-os/sdk/repositories/realm';
2
- import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-DaK1RzRq.cjs';
2
+ import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-Vfx65uF1.cjs';
3
3
  import '@arkade-os/solver-discovery';
4
4
  import '@arkade-os/sdk';
5
- import '../../rfq-DzsmhXX3.cjs';
5
+ import '../../rfq-CYfKvAPp.cjs';
6
6
 
7
7
  /**
8
8
  * Realm backend for React Native.
@@ -1,8 +1,8 @@
1
1
  import { RealmLike } from '@arkade-os/sdk/repositories/realm';
2
- import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-DlLvj_y6.js';
2
+ import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-D5JoeqwB.js';
3
3
  import '@arkade-os/solver-discovery';
4
4
  import '@arkade-os/sdk';
5
- import '../../rfq-DzsmhXX3.js';
5
+ import '../../rfq-CYfKvAPp.js';
6
6
 
7
7
  /**
8
8
  * Realm backend for React Native.
@@ -1,8 +1,8 @@
1
1
  import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
2
- import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-DaK1RzRq.cjs';
2
+ import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-Vfx65uF1.cjs';
3
3
  import '@arkade-os/solver-discovery';
4
4
  import '@arkade-os/sdk';
5
- import '../../rfq-DzsmhXX3.cjs';
5
+ import '../../rfq-CYfKvAPp.cjs';
6
6
 
7
7
  /**
8
8
  * SQLite backend over the SDK's `SQLExecutor`, so any driver plugs in
@@ -1,8 +1,8 @@
1
1
  import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
2
- import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-DlLvj_y6.js';
2
+ import { A as AssetSwapRepository, a as AssetSwap, R as RfqSwapRecord, M as MarketsCacheEntry } from '../../repository-D5JoeqwB.js';
3
3
  import '@arkade-os/solver-discovery';
4
4
  import '@arkade-os/sdk';
5
- import '../../rfq-DzsmhXX3.js';
5
+ import '../../rfq-CYfKvAPp.js';
6
6
 
7
7
  /**
8
8
  * SQLite backend over the SDK's `SQLExecutor`, so any driver plugs in
@@ -1,6 +1,6 @@
1
1
  import { DiscoveredMarket } from '@arkade-os/solver-discovery';
2
2
  import { IWallet, ProvisionedKey, ProvisionedClaimSecret, RestArkProvider, RestIndexerProvider, VHTLC, Identity, IContractManager } from '@arkade-os/sdk';
3
- import { B as RfqStatus, R as RfqTransport, a as OnchainHtlc, f as ChainUtxo, C as ChainSource, v as OnchainHtlcPhase } from './rfq-DzsmhXX3.js';
3
+ import { B as RfqStatus, R as RfqTransport, a as OnchainHtlc, f as ChainUtxo, C as ChainSource, v as OnchainHtlcPhase } from './rfq-CYfKvAPp.js';
4
4
 
5
5
  type AssetSwapStatus = "pending" | "cancelling" | "fulfilled" | "cancelled" | "recoverable" | "awaiting_fill" | "claimable" | "claimed" | "refunded_l1";
6
6
  /** The sentinel asset id for BTC itself, as opposed to a 68-hex asset id.
@@ -1,6 +1,6 @@
1
1
  import { DiscoveredMarket } from '@arkade-os/solver-discovery';
2
2
  import { IWallet, ProvisionedKey, ProvisionedClaimSecret, RestArkProvider, RestIndexerProvider, VHTLC, Identity, IContractManager } from '@arkade-os/sdk';
3
- import { B as RfqStatus, R as RfqTransport, a as OnchainHtlc, f as ChainUtxo, C as ChainSource, v as OnchainHtlcPhase } from './rfq-DzsmhXX3.cjs';
3
+ import { B as RfqStatus, R as RfqTransport, a as OnchainHtlc, f as ChainUtxo, C as ChainSource, v as OnchainHtlcPhase } from './rfq-CYfKvAPp.cjs';
4
4
 
5
5
  type AssetSwapStatus = "pending" | "cancelling" | "fulfilled" | "cancelled" | "recoverable" | "awaiting_fill" | "claimable" | "claimed" | "refunded_l1";
6
6
  /** The sentinel asset id for BTC itself, as opposed to a 68-hex asset id.
@@ -640,8 +640,10 @@ declare const lightningReceiveRequest: (input: {
640
640
  payoutAddress: string;
641
641
  /** Trader's x-only arkade key — the covenant's `receiver` role. */
642
642
  payoutPubkey: Uint8Array;
643
- /** `P` sealed to covclaimd, base64 — `sealClaimPacket(...).ciphertext`. */
644
- claimPacket: string;
643
+ /** `P` sealed to covclaimd, base64 — `sealClaimPacket(...).ciphertext`.
644
+ * Omitted when there is no covclaimd to seal to; the field is then left off
645
+ * the wire entirely, since the solver refuses an empty packet. */
646
+ claimPacket?: string;
645
647
  amount: number;
646
648
  amountSide: "from" | "to";
647
649
  }) => Record<string, unknown>;
@@ -659,8 +661,9 @@ declare const onchainReceiveRequest: (input: {
659
661
  payoutPubkey: Uint8Array;
660
662
  /** Trader's x-only L1 key for the HTLC's refund leaf. */
661
663
  refundPubkey: Uint8Array;
662
- /** `P` sealed to covclaimd, base64 — `sealClaimPacket(...).ciphertext`. */
663
- claimPacket: string;
664
+ /** `P` sealed to covclaimd, base64. Omitted when there is none to seal to —
665
+ * see {@link lightningReceiveRequest}. */
666
+ claimPacket?: string;
664
667
  amount: number;
665
668
  amountSide: "from" | "to";
666
669
  }) => Record<string, unknown>;
@@ -942,8 +945,10 @@ declare function requestLightningReceive(wallet: IWallet, arkServerUrl: string,
942
945
  * {@link resolveEmulatorPubkey}. */
943
946
  emulatorPubkey?: string;
944
947
  /** covclaimd's 33-byte compressed pubkey (from its own info endpoint)
945
- * — the claim packet seals to it and only it can ever read `P` early. */
946
- covclaimdPubkey: Uint8Array;
948
+ * — the claim packet seals to it and only it can ever read `P` early.
949
+ * Unset where no covclaimd is deployed: nothing is sealed and no packet
950
+ * is sent. Never substitute a throwaway key — nobody could open it. */
951
+ covclaimdPubkey?: Uint8Array;
947
952
  /** The caller's own BOLT11 decoder, applied to the SOLVER's invoice.
948
953
  * Required: an optional verifier is one integrators skip, and this is
949
954
  * the check whose absence loses the whole payment. */
@@ -1032,8 +1037,9 @@ declare function requestOnchainReceive(wallet: IWallet, arkServerUrl: string, tr
1032
1037
  emulatorPubkey?: string;
1033
1038
  /** Trader's x-only L1 key for the HTLC's refund leaf. */
1034
1039
  refundPubkey: Uint8Array;
1035
- /** covclaimd's 33-byte compressed pubkey — see {@link requestLightningReceive}. */
1036
- covclaimdPubkey: Uint8Array;
1040
+ /** covclaimd's 33-byte compressed pubkey, unset where none is deployed
1041
+ * — see {@link requestLightningReceive}. */
1042
+ covclaimdPubkey?: Uint8Array;
1037
1043
  rfqId?: string;
1038
1044
  }): Promise<{
1039
1045
  rfqId: string;