@arkade-os/swap 0.0.18 → 0.0.19

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.cjs CHANGED
@@ -84,6 +84,7 @@ __export(index_exports, {
84
84
  arkadeAssetLeg: () => arkadeAssetLeg,
85
85
  arkadeRefunder: () => arkadeRefunder,
86
86
  arkadeSwapRequest: () => arkadeSwapRequest,
87
+ assertArkadeFundable: () => assertArkadeFundable,
87
88
  assertFundable: () => assertFundable,
88
89
  assertReceivable: () => assertReceivable,
89
90
  awaitLockupFunding: () => awaitLockupFunding,
@@ -92,6 +93,7 @@ __export(index_exports, {
92
93
  buildHtlcClaim: () => buildHtlcClaim,
93
94
  buildHtlcRefund: () => buildHtlcRefund,
94
95
  cancelOffer: () => cancelOffer,
96
+ canonicalAssetAmount: () => canonicalAssetAmount,
95
97
  chainSourceFrom: () => chainSourceFrom,
96
98
  claimOnchainFill: () => claimOnchainFill,
97
99
  claimPacketShape: () => claimPacketShape,
@@ -132,6 +134,8 @@ __export(index_exports, {
132
134
  newPreimage: () => newPreimage,
133
135
  newRfqId: () => newRfqId,
134
136
  nextOnchainAction: () => nextOnchainAction,
137
+ normalizeMakerPkScript: () => normalizeMakerPkScript,
138
+ normalizeMakerPublicKey: () => normalizeMakerPublicKey,
135
139
  offerTermsFromQuote: () => offerTermsFromQuote,
136
140
  offerVtxoScript: () => offerVtxoScript,
137
141
  onchainHtlcScript: () => onchainHtlcScript,
@@ -149,6 +153,7 @@ __export(index_exports, {
149
153
  registerAssetSwapRestore: () => registerAssetSwapRestore,
150
154
  registerLockupContract: () => registerLockupContract,
151
155
  relayTransport: () => relayTransport,
156
+ requestArkadeSwap: () => requestArkadeSwap,
152
157
  requestLightningReceive: () => requestLightningReceive,
153
158
  requestLightningSend: () => requestLightningSend,
154
159
  requestOnchainReceive: () => requestOnchainReceive,
@@ -186,6 +191,7 @@ __export(index_exports, {
186
191
  updateRfqSwapRecord: () => updateRfqSwapRecord,
187
192
  validatePlan: () => validatePlan,
188
193
  verifyLockupAddress: () => verifyLockupAddress,
194
+ verifyOfferAddress: () => verifyOfferAddress,
189
195
  verifyReceiveInvoice: () => verifyReceiveInvoice,
190
196
  watchOfferSwaps: () => watchOfferSwaps
191
197
  });
@@ -1064,12 +1070,14 @@ var discoverMarkets = async (options) => {
1064
1070
  fetchImpl,
1065
1071
  useCache = true
1066
1072
  } = options;
1067
- if (!registry || !(0, import_solver_discovery.isNetwork)(network)) return [];
1068
- const cached = repository && await readMarketsCache(repository, network, registry);
1073
+ if (!(0, import_solver_discovery.isNetwork)(network)) return [];
1074
+ const registries = registry ? [registry] : void 0;
1075
+ const registryKey = registries?.[0] ?? (0, import_solver_discovery.registryIndexUrl)(network);
1076
+ const cached = repository && await readMarketsCache(repository, network, registryKey);
1069
1077
  if (useCache && cached && Date.now() - cached.fetchedAt < MARKETS_CACHE_TTL_MS)
1070
1078
  return cached.markets;
1071
1079
  const { markets, sources, warnings } = await (0, import_solver_discovery.discover)({
1072
- registries: [registry],
1080
+ registries,
1073
1081
  localCards,
1074
1082
  network,
1075
1083
  fetchImpl
@@ -1079,7 +1087,7 @@ var discoverMarkets = async (options) => {
1079
1087
  if (!reachable && cached) return cached.markets;
1080
1088
  if (reachable && repository) {
1081
1089
  try {
1082
- await repository.saveCachedMarkets(network, registry, {
1090
+ await repository.saveCachedMarkets(network, registryKey, {
1083
1091
  markets,
1084
1092
  fetchedAt: Date.now()
1085
1093
  });
@@ -1980,6 +1988,7 @@ function onchainSendProfile(result) {
1980
1988
  network: result.l1Network,
1981
1989
  htlcAddress: result.htlc.address,
1982
1990
  minConfirmations: result.minConfirmations,
1991
+ expectedAmount: result.expectedAmount,
1983
1992
  payoutPkScript: import_base5.hex.encode(result.payoutPkScript)
1984
1993
  };
1985
1994
  }
@@ -1991,6 +2000,7 @@ var OnchainSendCorridor = {
1991
2000
  project: (swap) => {
1992
2001
  const send = swap;
1993
2002
  return {
2003
+ expectedAmount: send.expectedAmount,
1994
2004
  ...send.funding ? { funding: send.funding } : {},
1995
2005
  ...send.claimTxid ? { claimTxid: send.claimTxid } : {}
1996
2006
  };
@@ -2007,6 +2017,11 @@ var OnchainSendCorridor = {
2007
2017
  `onchain_send record carries no usable minConfirmations (${String(profile.minConfirmations)}); the confirmation gate cannot be checked \u2014 refusing to restore a swap that would claim an unconfirmed fill`
2008
2018
  );
2009
2019
  }
2020
+ if (!Number.isSafeInteger(profile.expectedAmount) || profile.expectedAmount <= 0) {
2021
+ throw new Error(
2022
+ `onchain_send record carries no usable expectedAmount (${String(profile.expectedAmount)}); the funded value cannot be checked \u2014 refusing to restore a swap that would claim an underfunded fill`
2023
+ );
2024
+ }
2010
2025
  const htlc = onchainHtlcScript(
2011
2026
  {
2012
2027
  // From the profile, not the covenant: the lockup commits to
@@ -2029,6 +2044,7 @@ var OnchainSendCorridor = {
2029
2044
  paymentHash,
2030
2045
  htlc,
2031
2046
  minConfirmations: profile.minConfirmations,
2047
+ expectedAmount: profile.expectedAmount,
2032
2048
  // Optional here, required at the write: throwing on an older
2033
2049
  // record would strand the refund it is still owed.
2034
2050
  ...profile.payoutPkScript ? { payoutPkScript: import_base5.hex.decode(profile.payoutPkScript) } : {},
@@ -2419,6 +2435,12 @@ var solverHex = (value, field) => {
2419
2435
  throw new Error(`solver sent malformed hex for ${field}`);
2420
2436
  }
2421
2437
  };
2438
+ var quoteSats = (value, field) => {
2439
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
2440
+ throw new Error(`HTLC quote carries a non-sats ${field}: ${String(value)}`);
2441
+ }
2442
+ return value;
2443
+ };
2422
2444
  var ARKADE_BTC = "arkade:BTC";
2423
2445
  var LIGHTNING_BTC = "lightning:BTC";
2424
2446
  var ONCHAIN_BTC = "onchain:BTC";
@@ -2530,12 +2552,12 @@ var lightningSendRequest = (input) => ({
2530
2552
  var arkadeSwapRequest = (input) => {
2531
2553
  if (!input.wantAsset && !input.offerAsset) {
2532
2554
  throw new Error(
2533
- "set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC) \u2014 with neither set both legs are BTC, which is not a swap"
2555
+ "set at least one of wantAsset or offerAsset \u2014 with neither set both legs are BTC, which is not a swap"
2534
2556
  );
2535
2557
  }
2536
- if (input.wantAsset && input.offerAsset) {
2558
+ if (input.amountSide !== void 0 && input.amountSide !== "from") {
2537
2559
  throw new Error(
2538
- "set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC) \u2014 asset->asset is nameable on the wire but no solver quotes it yet"
2560
+ 'arkade\u2194arkade quotes are exact-in only: use amountSide "from" with the deposit amount'
2539
2561
  );
2540
2562
  }
2541
2563
  const pair = rfqPair(
@@ -2548,16 +2570,59 @@ var arkadeSwapRequest = (input) => {
2548
2570
  type: "rfq_request",
2549
2571
  rfq_id: input.rfqId,
2550
2572
  pair,
2551
- amount_side: input.amountSide,
2552
- amount: input.amount,
2553
- // The pair is the only place the asset ids appear. Repeating them here
2554
- // would be a key the solver's `.strict()` profile schema does not
2555
- // declare, and an undeclared key is `unsupported_payload` — a refusal,
2556
- // not an ignored extra. Empty, not absent: `profile` is required on
2557
- // every other request shape this wire carries.
2558
- profile: {}
2573
+ amount_side: "from",
2574
+ amount: canonicalAssetAmount(input.amount),
2575
+ // The pair names the assets; the profile names the trader. Both are
2576
+ // covenant parameters, and the solver's `.strict()` schema refuses
2577
+ // anything else — an undeclared key is `unsupported_payload`.
2578
+ profile: {
2579
+ maker_pk_script: normalizeMakerPkScript(input.makerPkScript),
2580
+ maker_public_key: normalizeMakerPublicKey(input.makerPublicKey)
2581
+ }
2559
2582
  };
2560
2583
  };
2584
+ var canonicalAssetAmount = (amount) => {
2585
+ if (typeof amount === "bigint") {
2586
+ if (amount <= 0n) throw new Error(`amount must be positive, got ${amount}`);
2587
+ return amount.toString();
2588
+ }
2589
+ if (typeof amount === "number") {
2590
+ if (!Number.isSafeInteger(amount) || amount <= 0) {
2591
+ throw new Error(`amount must be a positive safe integer, got ${amount}`);
2592
+ }
2593
+ return String(amount);
2594
+ }
2595
+ if (!/^(0|[1-9][0-9]*)$/.test(amount) || BigInt(amount) <= 0n) {
2596
+ throw new Error(`amount must be a canonical decimal string of atomic units, got ${amount}`);
2597
+ }
2598
+ return amount;
2599
+ };
2600
+ var normalizeHexBytes = (value, expectedBytes, label) => {
2601
+ if (value === void 0 || value === null) {
2602
+ throw new Error(`${label} is required`);
2603
+ }
2604
+ const bytes = typeof value === "string" ? solverHex(value, label) : value;
2605
+ if (!(bytes instanceof Uint8Array) || bytes.length !== expectedBytes) {
2606
+ const got = bytes instanceof Uint8Array ? bytes.length : typeof bytes;
2607
+ throw new Error(`${label} must be ${expectedBytes} bytes, got ${got}`);
2608
+ }
2609
+ return import_base10.hex.encode(bytes);
2610
+ };
2611
+ var normalizeMakerPkScript = (value) => {
2612
+ const encoded = normalizeHexBytes(value, 34, "maker_pk_script");
2613
+ if (!encoded.startsWith("5100") && !encoded.startsWith("5120")) {
2614
+ throw new Error("maker_pk_script must be a taproot scriptPubKey (OP_1 <32-byte program>)");
2615
+ }
2616
+ return encoded;
2617
+ };
2618
+ var normalizeMakerPublicKey = (value) => {
2619
+ const raw = typeof value === "string" ? value : import_base10.hex.encode(value);
2620
+ const bytes = solverHex(raw, "maker_public_key");
2621
+ if (bytes.length === 33) {
2622
+ throw new Error("maker_public_key must be x-only (32 bytes), not compressed (33 bytes)");
2623
+ }
2624
+ return normalizeHexBytes(bytes, 32, "maker_public_key");
2625
+ };
2561
2626
  var MIN_HEADROOM_SECONDS = 90 * 60;
2562
2627
  var gateError = (reason, message) => {
2563
2628
  const error = new Error(message);
@@ -2605,6 +2670,9 @@ var assertFundable = (input) => {
2605
2670
  }
2606
2671
  if (input.now >= input.quote.valid_until)
2607
2672
  fail("quote_expired", "quote expired \u2014 request a fresh one");
2673
+ if (quoteSats(input.quote.from_amount, "from_amount") <= 0 || quoteSats(input.quote.to_amount, "to_amount") <= 0) {
2674
+ fail("non_positive_amount", "quote carries a non-positive amount");
2675
+ }
2608
2676
  if (input.quote.refund_locktime !== void 0 && input.quote.refund_locktime - input.now < MIN_HEADROOM_SECONDS) {
2609
2677
  fail("insufficient_headroom", "refund deadline headroom below 90 minutes");
2610
2678
  }
@@ -2634,13 +2702,12 @@ var assertFundable = (input) => {
2634
2702
  `maxFee.referenceRate must be a positive finite number, got ${referenceRate}`
2635
2703
  );
2636
2704
  }
2637
- const fee = sameAsset ? input.quote.from_amount - input.quote.to_amount : Math.ceil(
2638
- (input.quote.from_amount * referenceRate - input.quote.to_amount) / referenceRate
2639
- );
2640
- const allowed = Math.max(
2641
- sats ?? 0,
2642
- Math.floor(input.quote.from_amount * (bps ?? 0) / 1e4)
2705
+ const fromSats = quoteSats(input.quote.from_amount, "from_amount");
2706
+ const toSats = quoteSats(input.quote.to_amount, "to_amount");
2707
+ const fee = sameAsset ? fromSats - toSats : Math.ceil(
2708
+ (fromSats * referenceRate - toSats) / referenceRate
2643
2709
  );
2710
+ const allowed = Math.max(sats ?? 0, Math.floor(fromSats * (bps ?? 0) / 1e4));
2644
2711
  if (fee > allowed) {
2645
2712
  fail("fee_too_high", `fee ${fee} exceeds the ${allowed} this client allows`);
2646
2713
  }
@@ -2882,12 +2949,12 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
2882
2949
  if (receiverPkScriptHex === void 0) {
2883
2950
  throw new Error("lightning-send quote is missing profile.receiver_pk_script");
2884
2951
  }
2885
- if (quote.to_amount !== params.invoice.amountSats) {
2952
+ if (quoteSats(quote.to_amount, "to_amount") !== params.invoice.amountSats) {
2886
2953
  throw new Error(
2887
2954
  `quote to_amount ${quote.to_amount} does not match the invoice's ${params.invoice.amountSats}`
2888
2955
  );
2889
2956
  }
2890
- if (quote.from_amount < quote.to_amount) {
2957
+ if (quoteSats(quote.from_amount, "from_amount") < quoteSats(quote.to_amount, "to_amount")) {
2891
2958
  throw new Error(
2892
2959
  `quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
2893
2960
  );
@@ -2933,7 +3000,7 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
2933
3000
  address,
2934
3001
  // What the lockup must carry: the quote's `from_amount` — the invoice
2935
3002
  // PLUS the corridor's fee, never the bare invoice amount.
2936
- fundAmount: quote.from_amount,
3003
+ fundAmount: quoteSats(quote.from_amount, "from_amount"),
2937
3004
  swapPkScript: script.pkScript,
2938
3005
  script,
2939
3006
  refundAddress,
@@ -2943,11 +3010,91 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
2943
3010
  };
2944
3011
  }
2945
3012
  var offerTermsFromQuote = (quote, assets) => {
2946
- if (Boolean(assets.wantAsset) === Boolean(assets.offerAsset)) {
2947
- throw new Error("set exactly one of wantAsset or offerAsset");
3013
+ if (!assets.wantAsset && !assets.offerAsset) {
3014
+ throw new Error("set at least one of wantAsset or offerAsset");
3015
+ }
3016
+ const wantAmount = BigInt(quote.to_amount);
3017
+ if (assets.wantAsset) return { wantAmount, wantAsset: assets.wantAsset };
3018
+ return { wantAmount, offerAsset: assets.offerAsset };
3019
+ };
3020
+ var verifyOfferAddress = (quote, derived) => {
3021
+ const quotedAddress = quote.profile?.offer_address;
3022
+ const quotedScript = quote.profile?.offer_pk_script;
3023
+ const derivedScript = import_base10.hex.encode(derived.swapPkScript);
3024
+ if (quotedAddress !== derived.address || quotedScript !== derivedScript) {
3025
+ throw new AddressMismatch([derived.address], quotedAddress);
3026
+ }
3027
+ return derived;
3028
+ };
3029
+ var assertArkadeFundable = (input) => {
3030
+ const now = input.now ?? Math.floor(Date.now() / 1e3);
3031
+ if (!Number.isSafeInteger(input.quote.valid_until)) {
3032
+ throw gateError("quote_expired", "quote carries no valid_until");
3033
+ }
3034
+ if (now >= input.quote.valid_until) {
3035
+ throw gateError("quote_expired", `quote lapsed at ${input.quote.valid_until} (now ${now})`);
3036
+ }
3037
+ if (BigInt(input.quote.from_amount) <= 0n || BigInt(input.quote.to_amount) <= 0n) {
3038
+ throw gateError("quote_expired", "quote carries a non-positive amount");
2948
3039
  }
2949
- return { wantAmount: BigInt(quote.to_amount), ...assets };
2950
3040
  };
3041
+ async function requestArkadeSwap(wallet, arkServerUrl, transport, params) {
3042
+ if (!params.wantAsset && !params.offerAsset) {
3043
+ throw new Error("set at least one of wantAsset or offerAsset; BTC-to-BTC is not a swap");
3044
+ }
3045
+ const rfqId = params.rfqId ?? newRfqId();
3046
+ const [makerAddress, makerPublicKey] = await Promise.all([
3047
+ wallet.getAddress(),
3048
+ wallet.identity.xOnlyPublicKey()
3049
+ ]);
3050
+ const makerPkScript = import_sdk10.ArkAddress.decode(makerAddress).pkScript;
3051
+ const pair = rfqPair(
3052
+ params.offerAsset ? arkadeAssetLeg(params.offerAsset) : ARKADE_BTC,
3053
+ params.wantAsset ? arkadeAssetLeg(params.wantAsset) : ARKADE_BTC
3054
+ );
3055
+ const quote = await transport.requestQuote(
3056
+ arkadeSwapRequest({
3057
+ rfqId,
3058
+ ...params.offerAsset !== void 0 ? { offerAsset: params.offerAsset } : {},
3059
+ ...params.wantAsset !== void 0 ? { wantAsset: params.wantAsset } : {},
3060
+ amount: params.amount,
3061
+ makerPkScript,
3062
+ makerPublicKey
3063
+ })
3064
+ );
3065
+ if (quote.pair !== pair) {
3066
+ throw new Error(`solver quoted ${JSON.stringify(quote.pair)}, not the requested ${pair}`);
3067
+ }
3068
+ assertArkadeFundable({ quote, ...params.now !== void 0 ? { now: params.now } : {} });
3069
+ const terms = offerTermsFromQuote(quote, {
3070
+ ...params.offerAsset !== void 0 ? { offerAsset: params.offerAsset } : {},
3071
+ ...params.wantAsset !== void 0 ? { wantAsset: params.wantAsset } : {}
3072
+ });
3073
+ if (BigInt(quote.from_amount).toString() !== canonicalAssetAmount(params.amount)) {
3074
+ throw new Error(
3075
+ `quote from_amount ${quote.from_amount} does not match the requested ${canonicalAssetAmount(params.amount)}`
3076
+ );
3077
+ }
3078
+ const offer = await createOffer(wallet, arkServerUrl, {
3079
+ wantAmount: terms.wantAmount,
3080
+ ...terms.wantAsset !== void 0 ? { wantAsset: terms.wantAsset } : {},
3081
+ ...terms.offerAsset !== void 0 ? { offerAsset: terms.offerAsset } : {},
3082
+ ...params.emulatorPubkey !== void 0 ? { emulatorPubkey: params.emulatorPubkey } : {}
3083
+ });
3084
+ verifyOfferAddress(quote, offer);
3085
+ const fundAmount = BigInt(quote.from_amount);
3086
+ return {
3087
+ rfqId,
3088
+ quote,
3089
+ pair,
3090
+ address: offer.address,
3091
+ fundAmount,
3092
+ carrierSats: params.offerAsset !== void 0 ? ASSET_CARRIER_SATS : 0n,
3093
+ swapPkScript: offer.swapPkScript,
3094
+ offerHex: offer.offerHex,
3095
+ extension: offer.extension
3096
+ };
3097
+ }
2951
3098
  var l1NetworkFromArk = (network) => network === "bitcoin" ? "bitcoin" : network === "regtest" ? "regtest" : "testnet";
2952
3099
  var onchainSendRequest = (input) => ({
2953
3100
  v: 1,
@@ -3038,7 +3185,8 @@ function deriveOnchainSend(input) {
3038
3185
  l1Network: input.l1Network,
3039
3186
  refundLocktime,
3040
3187
  htlcLocktime,
3041
- minConfirmations
3188
+ minConfirmations,
3189
+ expectedAmount: quoteSats(quote.to_amount, "to_amount")
3042
3190
  };
3043
3191
  }
3044
3192
  async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
@@ -3101,7 +3249,8 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
3101
3249
  rfqId,
3102
3250
  quote,
3103
3251
  address: derived.address,
3104
- fundAmount: quote.from_amount,
3252
+ fundAmount: quoteSats(quote.from_amount, "from_amount"),
3253
+ expectedAmount: quoteSats(quote.to_amount, "to_amount"),
3105
3254
  swapPkScript: derived.swapPkScript,
3106
3255
  script: derived.script,
3107
3256
  refundAddress,
@@ -3114,7 +3263,7 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
3114
3263
  };
3115
3264
  }
3116
3265
  var assertQuotedAmount = (quote, amountSide, amount) => {
3117
- const quoted = amountSide === "from" ? quote.from_amount : quote.to_amount;
3266
+ const quoted = amountSide === "from" ? quoteSats(quote.from_amount, "from_amount") : quoteSats(quote.to_amount, "to_amount");
3118
3267
  if (quoted !== amount) {
3119
3268
  throw new Error(
3120
3269
  `quote ${amountSide === "from" ? "from_amount" : "to_amount"} ${quoted} does not match the requested ${amount} \u2014 not this trade's quote`
@@ -3173,7 +3322,7 @@ var assertReceivable = (input) => {
3173
3322
  `a payment at the deadline would leave under ${minClaimWindow}s to claim before the solver's refund opens`
3174
3323
  );
3175
3324
  }
3176
- if (input.maxPayAmount !== void 0 && input.quote.from_amount > input.maxPayAmount) {
3325
+ if (input.maxPayAmount !== void 0 && quoteSats(input.quote.from_amount, "from_amount") > input.maxPayAmount) {
3177
3326
  throw gateError(
3178
3327
  "price_too_high",
3179
3328
  `quote asks ${input.quote.from_amount} sats, above the ${input.maxPayAmount} ceiling`
@@ -3304,8 +3453,8 @@ async function requestLightningReceive(wallet, arkServerUrl, transport, params)
3304
3453
  rfqId,
3305
3454
  quote,
3306
3455
  invoice: derived.invoice,
3307
- payAmount: quote.from_amount,
3308
- expectedAmount: quote.to_amount,
3456
+ payAmount: quoteSats(quote.from_amount, "from_amount"),
3457
+ expectedAmount: quoteSats(quote.to_amount, "to_amount"),
3309
3458
  invoiceExpiresAt: payDeadline,
3310
3459
  address: derived.address,
3311
3460
  swapPkScript: derived.swapPkScript,
@@ -3431,8 +3580,8 @@ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
3431
3580
  rfqId,
3432
3581
  quote,
3433
3582
  address: derived.address,
3434
- fundAmount: quote.from_amount,
3435
- expectedAmount: quote.to_amount,
3583
+ fundAmount: quoteSats(quote.from_amount, "from_amount"),
3584
+ expectedAmount: quoteSats(quote.to_amount, "to_amount"),
3436
3585
  swapPkScript: derived.swapPkScript,
3437
3586
  script: derived.script,
3438
3587
  htlc: derived.htlc,
@@ -5144,6 +5293,21 @@ var RfqSwapManager = class {
5144
5293
  });
5145
5294
  if (action === "claim" && phase.phase === "claimable") {
5146
5295
  if (swap.claimTxid) return "continue";
5296
+ if (!Number.isSafeInteger(swap.expectedAmount) || swap.expectedAmount <= 0) {
5297
+ this.block(
5298
+ swap,
5299
+ `expectedAmount is not a positive number of sats (${String(swap.expectedAmount)}), so the funded value cannot be checked \u2014 refusing to publish the preimage`
5300
+ );
5301
+ return "handled";
5302
+ }
5303
+ const filled = Number(phase.utxo.amount);
5304
+ if (!Number.isFinite(filled) || filled < swap.expectedAmount) {
5305
+ this.block(
5306
+ swap,
5307
+ `fill holds ${filled} sats, below the agreed ${swap.expectedAmount} \u2014 refusing to publish the preimage`
5308
+ );
5309
+ return "handled";
5310
+ }
5147
5311
  if (this.callbacks && !this.callbacks.claimOnchain) {
5148
5312
  this.block(
5149
5313
  swap,
@@ -5197,6 +5361,8 @@ var RfqSwapManager = class {
5197
5361
  if (pushed) {
5198
5362
  swap.refundArkTxid = pushed.arkTxid;
5199
5363
  this.touch(swap);
5364
+ } else if (now < swap.refundLocktime + REFUND_MTP_LAG_SECONDS) {
5365
+ return;
5200
5366
  }
5201
5367
  this.setState(swap, "refunded");
5202
5368
  this.emitAction(swap, "refundArkade");
@@ -5565,6 +5731,7 @@ async function lockupTxids(indexer, record, wantFunding) {
5565
5731
  arkadeAssetLeg,
5566
5732
  arkadeRefunder,
5567
5733
  arkadeSwapRequest,
5734
+ assertArkadeFundable,
5568
5735
  assertFundable,
5569
5736
  assertReceivable,
5570
5737
  awaitLockupFunding,
@@ -5573,6 +5740,7 @@ async function lockupTxids(indexer, record, wantFunding) {
5573
5740
  buildHtlcClaim,
5574
5741
  buildHtlcRefund,
5575
5742
  cancelOffer,
5743
+ canonicalAssetAmount,
5576
5744
  chainSourceFrom,
5577
5745
  claimOnchainFill,
5578
5746
  claimPacketShape,
@@ -5613,6 +5781,8 @@ async function lockupTxids(indexer, record, wantFunding) {
5613
5781
  newPreimage,
5614
5782
  newRfqId,
5615
5783
  nextOnchainAction,
5784
+ normalizeMakerPkScript,
5785
+ normalizeMakerPublicKey,
5616
5786
  offerTermsFromQuote,
5617
5787
  offerVtxoScript,
5618
5788
  onchainHtlcScript,
@@ -5630,6 +5800,7 @@ async function lockupTxids(indexer, record, wantFunding) {
5630
5800
  registerAssetSwapRestore,
5631
5801
  registerLockupContract,
5632
5802
  relayTransport,
5803
+ requestArkadeSwap,
5633
5804
  requestLightningReceive,
5634
5805
  requestLightningSend,
5635
5806
  requestOnchainReceive,
@@ -5667,6 +5838,7 @@ async function lockupTxids(indexer, record, wantFunding) {
5667
5838
  updateRfqSwapRecord,
5668
5839
  validatePlan,
5669
5840
  verifyLockupAddress,
5841
+ verifyOfferAddress,
5670
5842
  verifyReceiveInvoice,
5671
5843
  watchOfferSwaps
5672
5844
  });
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { ProvisionedKey, ProvisionedClaimSecret, ArkTxInput, asset, RelativeTimelock, IWallet, EmulatorProvider, arkade, RestIndexerProvider, Transaction, IContractManager, OnchainProvider, PaymentRail, Asset, VHTLC, Identity, ActivityResolver } from '@arkade-os/sdk';
2
- import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, b as RefundArkProvider, c as RefundIndexer, L as LockupVtxo, d as RfqSwap, e as ArkadeRefundResult, f as LockupSpendIndexer, g as RfqSwapState } from './repository-BwasQwkR.cjs';
3
- export { h as AssetSwapStatus, i as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, j as LightningReceiveSwap, k as LightningSendSwap, l as LockupFate, m as LockupNeedsRecoveryError, n as LockupParams, o as LockupSpend, O as OnchainSendAction, p as OnchainSendSwap, P as PersistableRfqSwap, q as PreimageBlockedReason, r as PreimageNotRecoverableError, s as REFUND_MTP_LAG_SECONDS, t as RFQ_RESOLVED_STATES, u as RFQ_SWAP_RETENTION_SECONDS, v as RFQ_SWAP_TERMINAL_STATES, w as RefundOutcome, x as RfqRestoreFailure, y as RfqRestoreOptions, z as RfqRestoreResult, C as RfqSwapActionName, D as RfqSwapLockup, E as RfqSwapManager, F as RfqSwapManagerCallbacks, G as RfqSwapManagerConfig, H as RfqSwapManagerDeps, J as RfqSwapManagerEvents, K as RfqSwapOrigin, N as RfqSwapOriginRequired, Q as RfqSwapOutcome, T as RfqSwapRecordStore, U as SwapContractRegistry, V as addAssetSwap, W as awaitRfqResolution, X as createRfqSwapRecord, Y as findLockupVtxos, Z as getAssetSwaps, _ as getAssetSwapsOrThrow, $ as isRfqSwapTerminal, a0 as isRfqTerminal, a1 as nextOnchainAction, a2 as preimageForSwapRecord, a3 as pushRefundWithoutReceiver, a4 as readLockupFate, a5 as rebuildRfqSwap, a6 as refundIfUnresolved, a7 as rfqSwapOriginOf, a8 as shouldRetainRfqSwap, a9 as swapSecretsToRecord, aa as updateAssetSwap, ab as updateAssetSwapBestEffort, ac as updateRfqSwapRecord } from './repository-BwasQwkR.cjs';
2
+ import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, b as RefundArkProvider, c as RefundIndexer, L as LockupVtxo, d as RfqSwap, e as ArkadeRefundResult, f as LockupSpendIndexer, g as RfqSwapState } from './repository-BXIcmIIC.cjs';
3
+ export { h as AssetSwapStatus, i as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, j as LightningReceiveSwap, k as LightningSendSwap, l as LockupFate, m as LockupNeedsRecoveryError, n as LockupParams, o as LockupSpend, O as OnchainSendAction, p as OnchainSendSwap, P as PersistableRfqSwap, q as PreimageBlockedReason, r as PreimageNotRecoverableError, s as REFUND_MTP_LAG_SECONDS, t as RFQ_RESOLVED_STATES, u as RFQ_SWAP_RETENTION_SECONDS, v as RFQ_SWAP_TERMINAL_STATES, w as RefundOutcome, x as RfqRestoreFailure, y as RfqRestoreOptions, z as RfqRestoreResult, C as RfqSwapActionName, D as RfqSwapLockup, E as RfqSwapManager, F as RfqSwapManagerCallbacks, G as RfqSwapManagerConfig, H as RfqSwapManagerDeps, J as RfqSwapManagerEvents, K as RfqSwapOrigin, N as RfqSwapOriginRequired, Q as RfqSwapOutcome, T as RfqSwapRecordStore, U as SwapContractRegistry, V as addAssetSwap, W as awaitRfqResolution, X as createRfqSwapRecord, Y as findLockupVtxos, Z as getAssetSwaps, _ as getAssetSwapsOrThrow, $ as isRfqSwapTerminal, a0 as isRfqTerminal, a1 as nextOnchainAction, a2 as preimageForSwapRecord, a3 as pushRefundWithoutReceiver, a4 as readLockupFate, a5 as rebuildRfqSwap, a6 as refundIfUnresolved, a7 as rfqSwapOriginOf, a8 as shouldRetainRfqSwap, a9 as swapSecretsToRecord, aa as updateAssetSwap, ab as updateAssetSwapBestEffort, ac as updateRfqSwapRecord } from './repository-BXIcmIIC.cjs';
4
4
  import { Network, LocalCardInput, DiscoveredMarket, Side, OfferPlan } from '@arkade-os/solver-discovery';
5
- import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend } from './rfq-B_2hM0xk.cjs';
6
- export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, f as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, g as LIGHTNING_RECEIVE_PAIR, h as LIGHTNING_SEND_PAIR, i as LOCKTIME_THRESHOLD, j as LightningReceiveTreeParams, k as LightningSendTreeParams, M as MAX_MIN_CONFIRMATIONS, l as MIN_CLAIM_WINDOW_SECONDS, m as MIN_HEADROOM_SECONDS, n as ONCHAIN_BTC, o as ONCHAIN_CLAIM_MARGIN_SECONDS, p as ONCHAIN_DUST_SATS, q as ONCHAIN_ORDER_MARGIN_SECONDS, s as ONCHAIN_RECEIVE_PAIR, t as ONCHAIN_SECONDS_PER_BLOCK, u as ONCHAIN_SEND_PAIR, v as OnchainHtlcPhase, w as RFQ_REFUSAL_ERROR_CODES, x as RFQ_TERMINAL_STATES, y as RelaySocket, z as RfqQuote, B as RfqRefusalDetail, D as RfqRefusalErrorCode, E as RfqRefusalReason, F as RfqRefusalUnit, G as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, J as SwapRefusal, K as arkadeAssetLeg, N as arkadeSwapRequest, P as assertFundable, Q as assertReceivable, T as awaitOnchainFill, U as buildHtlcClaim, V as buildHtlcRefund, W as claimOnchainFill, X as classifyOnchainHtlc, Y as deriveLightningReceive, Z as deriveOnchainReceive, _ as deriveOnchainSend, $ as extractPreimage, a0 as httpTransport, a1 as isRfqRefusalErrorCode, a2 as l1ScriptForAddress, a3 as lightningReceiveRequest, a4 as lightningSendRequest, a5 as lightningSendVtxoScript, a6 as newPreimage, a7 as newRfqId, a8 as offerTermsFromQuote, a9 as onchainHtlcScript, aa as onchainReceiveRequest, ab as onchainSendRequest, ac as paymentHashOf, ad as receiveVtxoScript, ae as relayTransport, af as requestLightningReceive, ag as requestOnchainReceive, ah as rfqPair, ai as unilateralClaimDelay, aj as unilateralRefundDelay, ak as unilateralRefundWithoutReceiverDelay, al as verifyLockupAddress, am as verifyReceiveInvoice } from './rfq-B_2hM0xk.cjs';
5
+ import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend } from './rfq-D96aLvCA.cjs';
6
+ export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, f as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, g as LIGHTNING_RECEIVE_PAIR, h as LIGHTNING_SEND_PAIR, i as LOCKTIME_THRESHOLD, j as LightningReceiveTreeParams, k as LightningSendTreeParams, M as MAX_MIN_CONFIRMATIONS, l as MIN_CLAIM_WINDOW_SECONDS, m as MIN_HEADROOM_SECONDS, n as ONCHAIN_BTC, o as ONCHAIN_CLAIM_MARGIN_SECONDS, p as ONCHAIN_DUST_SATS, q as ONCHAIN_ORDER_MARGIN_SECONDS, s as ONCHAIN_RECEIVE_PAIR, t as ONCHAIN_SECONDS_PER_BLOCK, u as ONCHAIN_SEND_PAIR, v as OnchainHtlcPhase, w as RFQ_REFUSAL_ERROR_CODES, x as RFQ_TERMINAL_STATES, y as RelaySocket, z as RfqQuote, B as RfqRefusalDetail, D as RfqRefusalErrorCode, E as RfqRefusalReason, F as RfqRefusalUnit, G as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, J as SwapRefusal, K as arkadeAssetLeg, N as arkadeSwapRequest, P as assertArkadeFundable, Q as assertFundable, T as assertReceivable, U as awaitOnchainFill, V as buildHtlcClaim, W as buildHtlcRefund, X as canonicalAssetAmount, Y as claimOnchainFill, Z as classifyOnchainHtlc, _ as deriveLightningReceive, $ as deriveOnchainReceive, a0 as deriveOnchainSend, a1 as extractPreimage, a2 as httpTransport, a3 as isRfqRefusalErrorCode, a4 as l1ScriptForAddress, a5 as lightningReceiveRequest, a6 as lightningSendRequest, a7 as lightningSendVtxoScript, a8 as newPreimage, a9 as newRfqId, aa as normalizeMakerPkScript, ab as normalizeMakerPublicKey, ac as offerTermsFromQuote, ad as onchainHtlcScript, ae as onchainReceiveRequest, af as onchainSendRequest, ag as paymentHashOf, ah as receiveVtxoScript, ai as relayTransport, aj as requestArkadeSwap, ak as requestLightningReceive, al as requestOnchainReceive, am as rfqPair, an as unilateralClaimDelay, ao as unilateralRefundDelay, ap as unilateralRefundWithoutReceiverDelay, aq as verifyLockupAddress, ar as verifyOfferAddress, as as verifyReceiveInvoice } from './rfq-D96aLvCA.cjs';
7
7
 
8
8
  /**
9
9
  * Which wallet key signs this leg. Stored at `profile.signer`.
@@ -141,6 +141,7 @@ interface OnchainSendProfile extends Record<string, unknown> {
141
141
  htlcAddress: string;
142
142
  /** `profile.min_confirmations`; gates when the fill is claimable. */
143
143
  minConfirmations: number;
144
+ expectedAmount: number;
144
145
  /** Where the claim PAYS, hex. The spender's own choice, so nothing else
145
146
  * gives it back — and `buildHtlcClaim` needs it. */
146
147
  payoutPkScript: string;
@@ -183,6 +184,7 @@ declare function onchainSendProfile(result: {
183
184
  htlcParams: OnchainHtlcParams;
184
185
  l1Network: OnchainNetwork;
185
186
  minConfirmations: number;
187
+ expectedAmount: number;
186
188
  payoutPkScript: Uint8Array;
187
189
  }): Omit<OnchainSendProfile, "signer" | "hashlock">;
188
190
 
@@ -503,7 +505,11 @@ declare const QUOTE_OPTIONS: {
503
505
  declare const makeCachedFeedFetch: (ttlMs?: number, fetchImpl?: typeof fetch) => typeof fetch;
504
506
  interface DiscoverMarketsOptions {
505
507
  network: Network;
506
- /** The network's solver registry index URL; no registry means no markets. */
508
+ /** Overrides the registry this network publishes by default. Omit (or pass
509
+ * `undefined`) to follow `@arkade-os/solver-discovery`'s per-network
510
+ * default index, which the library can move in a release without a client
511
+ * change; this package never hardcodes the URL. The markets cache is keyed
512
+ * by the URL actually followed, default included. */
507
513
  registryUrl: string | undefined;
508
514
  /** Backs the 1-hour markets cache and its stale fallback. Omit for a
509
515
  * one-shot discovery that always hits the registry. */
@@ -523,9 +529,11 @@ interface DiscoverMarketsOptions {
523
529
  useCache?: boolean;
524
530
  }
525
531
  /**
526
- * Markets from the network's solver registry; [] when none is configured.
527
- * Registry content changes rarely, so results are cached for an hour and a
528
- * stale cache backstops an unreachable registry (quotes stay live either way).
532
+ * Markets from this network's solver registry — the caller's `registryUrl` when
533
+ * given, else the network's published default. Only an unrecognised network
534
+ * yields []. Registry content changes rarely, so results are cached for an hour
535
+ * and a stale cache backstops an unreachable registry (quotes stay live either
536
+ * way).
529
537
  */
530
538
  declare const discoverMarkets: (options: DiscoverMarketsOptions) => Promise<DiscoveredMarket[]>;
531
539
  /** Best market for a from/to pair, in either orientation. `give` is the side
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { ProvisionedKey, ProvisionedClaimSecret, ArkTxInput, asset, RelativeTimelock, IWallet, EmulatorProvider, arkade, RestIndexerProvider, Transaction, IContractManager, OnchainProvider, PaymentRail, Asset, VHTLC, Identity, ActivityResolver } from '@arkade-os/sdk';
2
- import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, b as RefundArkProvider, c as RefundIndexer, L as LockupVtxo, d as RfqSwap, e as ArkadeRefundResult, f as LockupSpendIndexer, g as RfqSwapState } from './repository-CucjFZN1.js';
3
- export { h as AssetSwapStatus, i as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, j as LightningReceiveSwap, k as LightningSendSwap, l as LockupFate, m as LockupNeedsRecoveryError, n as LockupParams, o as LockupSpend, O as OnchainSendAction, p as OnchainSendSwap, P as PersistableRfqSwap, q as PreimageBlockedReason, r as PreimageNotRecoverableError, s as REFUND_MTP_LAG_SECONDS, t as RFQ_RESOLVED_STATES, u as RFQ_SWAP_RETENTION_SECONDS, v as RFQ_SWAP_TERMINAL_STATES, w as RefundOutcome, x as RfqRestoreFailure, y as RfqRestoreOptions, z as RfqRestoreResult, C as RfqSwapActionName, D as RfqSwapLockup, E as RfqSwapManager, F as RfqSwapManagerCallbacks, G as RfqSwapManagerConfig, H as RfqSwapManagerDeps, J as RfqSwapManagerEvents, K as RfqSwapOrigin, N as RfqSwapOriginRequired, Q as RfqSwapOutcome, T as RfqSwapRecordStore, U as SwapContractRegistry, V as addAssetSwap, W as awaitRfqResolution, X as createRfqSwapRecord, Y as findLockupVtxos, Z as getAssetSwaps, _ as getAssetSwapsOrThrow, $ as isRfqSwapTerminal, a0 as isRfqTerminal, a1 as nextOnchainAction, a2 as preimageForSwapRecord, a3 as pushRefundWithoutReceiver, a4 as readLockupFate, a5 as rebuildRfqSwap, a6 as refundIfUnresolved, a7 as rfqSwapOriginOf, a8 as shouldRetainRfqSwap, a9 as swapSecretsToRecord, aa as updateAssetSwap, ab as updateAssetSwapBestEffort, ac as updateRfqSwapRecord } from './repository-CucjFZN1.js';
2
+ import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, b as RefundArkProvider, c as RefundIndexer, L as LockupVtxo, d as RfqSwap, e as ArkadeRefundResult, f as LockupSpendIndexer, g as RfqSwapState } from './repository-B6VPDGHC.js';
3
+ export { h as AssetSwapStatus, i as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, j as LightningReceiveSwap, k as LightningSendSwap, l as LockupFate, m as LockupNeedsRecoveryError, n as LockupParams, o as LockupSpend, O as OnchainSendAction, p as OnchainSendSwap, P as PersistableRfqSwap, q as PreimageBlockedReason, r as PreimageNotRecoverableError, s as REFUND_MTP_LAG_SECONDS, t as RFQ_RESOLVED_STATES, u as RFQ_SWAP_RETENTION_SECONDS, v as RFQ_SWAP_TERMINAL_STATES, w as RefundOutcome, x as RfqRestoreFailure, y as RfqRestoreOptions, z as RfqRestoreResult, C as RfqSwapActionName, D as RfqSwapLockup, E as RfqSwapManager, F as RfqSwapManagerCallbacks, G as RfqSwapManagerConfig, H as RfqSwapManagerDeps, J as RfqSwapManagerEvents, K as RfqSwapOrigin, N as RfqSwapOriginRequired, Q as RfqSwapOutcome, T as RfqSwapRecordStore, U as SwapContractRegistry, V as addAssetSwap, W as awaitRfqResolution, X as createRfqSwapRecord, Y as findLockupVtxos, Z as getAssetSwaps, _ as getAssetSwapsOrThrow, $ as isRfqSwapTerminal, a0 as isRfqTerminal, a1 as nextOnchainAction, a2 as preimageForSwapRecord, a3 as pushRefundWithoutReceiver, a4 as readLockupFate, a5 as rebuildRfqSwap, a6 as refundIfUnresolved, a7 as rfqSwapOriginOf, a8 as shouldRetainRfqSwap, a9 as swapSecretsToRecord, aa as updateAssetSwap, ab as updateAssetSwapBestEffort, ac as updateRfqSwapRecord } from './repository-B6VPDGHC.js';
4
4
  import { Network, LocalCardInput, DiscoveredMarket, Side, OfferPlan } from '@arkade-os/solver-discovery';
5
- import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend } from './rfq-B_2hM0xk.js';
6
- export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, f as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, g as LIGHTNING_RECEIVE_PAIR, h as LIGHTNING_SEND_PAIR, i as LOCKTIME_THRESHOLD, j as LightningReceiveTreeParams, k as LightningSendTreeParams, M as MAX_MIN_CONFIRMATIONS, l as MIN_CLAIM_WINDOW_SECONDS, m as MIN_HEADROOM_SECONDS, n as ONCHAIN_BTC, o as ONCHAIN_CLAIM_MARGIN_SECONDS, p as ONCHAIN_DUST_SATS, q as ONCHAIN_ORDER_MARGIN_SECONDS, s as ONCHAIN_RECEIVE_PAIR, t as ONCHAIN_SECONDS_PER_BLOCK, u as ONCHAIN_SEND_PAIR, v as OnchainHtlcPhase, w as RFQ_REFUSAL_ERROR_CODES, x as RFQ_TERMINAL_STATES, y as RelaySocket, z as RfqQuote, B as RfqRefusalDetail, D as RfqRefusalErrorCode, E as RfqRefusalReason, F as RfqRefusalUnit, G as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, J as SwapRefusal, K as arkadeAssetLeg, N as arkadeSwapRequest, P as assertFundable, Q as assertReceivable, T as awaitOnchainFill, U as buildHtlcClaim, V as buildHtlcRefund, W as claimOnchainFill, X as classifyOnchainHtlc, Y as deriveLightningReceive, Z as deriveOnchainReceive, _ as deriveOnchainSend, $ as extractPreimage, a0 as httpTransport, a1 as isRfqRefusalErrorCode, a2 as l1ScriptForAddress, a3 as lightningReceiveRequest, a4 as lightningSendRequest, a5 as lightningSendVtxoScript, a6 as newPreimage, a7 as newRfqId, a8 as offerTermsFromQuote, a9 as onchainHtlcScript, aa as onchainReceiveRequest, ab as onchainSendRequest, ac as paymentHashOf, ad as receiveVtxoScript, ae as relayTransport, af as requestLightningReceive, ag as requestOnchainReceive, ah as rfqPair, ai as unilateralClaimDelay, aj as unilateralRefundDelay, ak as unilateralRefundWithoutReceiverDelay, al as verifyLockupAddress, am as verifyReceiveInvoice } from './rfq-B_2hM0xk.js';
5
+ import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend } from './rfq-D96aLvCA.js';
6
+ export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, f as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, g as LIGHTNING_RECEIVE_PAIR, h as LIGHTNING_SEND_PAIR, i as LOCKTIME_THRESHOLD, j as LightningReceiveTreeParams, k as LightningSendTreeParams, M as MAX_MIN_CONFIRMATIONS, l as MIN_CLAIM_WINDOW_SECONDS, m as MIN_HEADROOM_SECONDS, n as ONCHAIN_BTC, o as ONCHAIN_CLAIM_MARGIN_SECONDS, p as ONCHAIN_DUST_SATS, q as ONCHAIN_ORDER_MARGIN_SECONDS, s as ONCHAIN_RECEIVE_PAIR, t as ONCHAIN_SECONDS_PER_BLOCK, u as ONCHAIN_SEND_PAIR, v as OnchainHtlcPhase, w as RFQ_REFUSAL_ERROR_CODES, x as RFQ_TERMINAL_STATES, y as RelaySocket, z as RfqQuote, B as RfqRefusalDetail, D as RfqRefusalErrorCode, E as RfqRefusalReason, F as RfqRefusalUnit, G as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, J as SwapRefusal, K as arkadeAssetLeg, N as arkadeSwapRequest, P as assertArkadeFundable, Q as assertFundable, T as assertReceivable, U as awaitOnchainFill, V as buildHtlcClaim, W as buildHtlcRefund, X as canonicalAssetAmount, Y as claimOnchainFill, Z as classifyOnchainHtlc, _ as deriveLightningReceive, $ as deriveOnchainReceive, a0 as deriveOnchainSend, a1 as extractPreimage, a2 as httpTransport, a3 as isRfqRefusalErrorCode, a4 as l1ScriptForAddress, a5 as lightningReceiveRequest, a6 as lightningSendRequest, a7 as lightningSendVtxoScript, a8 as newPreimage, a9 as newRfqId, aa as normalizeMakerPkScript, ab as normalizeMakerPublicKey, ac as offerTermsFromQuote, ad as onchainHtlcScript, ae as onchainReceiveRequest, af as onchainSendRequest, ag as paymentHashOf, ah as receiveVtxoScript, ai as relayTransport, aj as requestArkadeSwap, ak as requestLightningReceive, al as requestOnchainReceive, am as rfqPair, an as unilateralClaimDelay, ao as unilateralRefundDelay, ap as unilateralRefundWithoutReceiverDelay, aq as verifyLockupAddress, ar as verifyOfferAddress, as as verifyReceiveInvoice } from './rfq-D96aLvCA.js';
7
7
 
8
8
  /**
9
9
  * Which wallet key signs this leg. Stored at `profile.signer`.
@@ -141,6 +141,7 @@ interface OnchainSendProfile extends Record<string, unknown> {
141
141
  htlcAddress: string;
142
142
  /** `profile.min_confirmations`; gates when the fill is claimable. */
143
143
  minConfirmations: number;
144
+ expectedAmount: number;
144
145
  /** Where the claim PAYS, hex. The spender's own choice, so nothing else
145
146
  * gives it back — and `buildHtlcClaim` needs it. */
146
147
  payoutPkScript: string;
@@ -183,6 +184,7 @@ declare function onchainSendProfile(result: {
183
184
  htlcParams: OnchainHtlcParams;
184
185
  l1Network: OnchainNetwork;
185
186
  minConfirmations: number;
187
+ expectedAmount: number;
186
188
  payoutPkScript: Uint8Array;
187
189
  }): Omit<OnchainSendProfile, "signer" | "hashlock">;
188
190
 
@@ -503,7 +505,11 @@ declare const QUOTE_OPTIONS: {
503
505
  declare const makeCachedFeedFetch: (ttlMs?: number, fetchImpl?: typeof fetch) => typeof fetch;
504
506
  interface DiscoverMarketsOptions {
505
507
  network: Network;
506
- /** The network's solver registry index URL; no registry means no markets. */
508
+ /** Overrides the registry this network publishes by default. Omit (or pass
509
+ * `undefined`) to follow `@arkade-os/solver-discovery`'s per-network
510
+ * default index, which the library can move in a release without a client
511
+ * change; this package never hardcodes the URL. The markets cache is keyed
512
+ * by the URL actually followed, default included. */
507
513
  registryUrl: string | undefined;
508
514
  /** Backs the 1-hour markets cache and its stale fallback. Omit for a
509
515
  * one-shot discovery that always hits the registry. */
@@ -523,9 +529,11 @@ interface DiscoverMarketsOptions {
523
529
  useCache?: boolean;
524
530
  }
525
531
  /**
526
- * Markets from the network's solver registry; [] when none is configured.
527
- * Registry content changes rarely, so results are cached for an hour and a
528
- * stale cache backstops an unreachable registry (quotes stay live either way).
532
+ * Markets from this network's solver registry — the caller's `registryUrl` when
533
+ * given, else the network's published default. Only an unrecognised network
534
+ * yields []. Registry content changes rarely, so results are cached for an hour
535
+ * and a stale cache backstops an unreachable registry (quotes stay live either
536
+ * way).
529
537
  */
530
538
  declare const discoverMarkets: (options: DiscoverMarketsOptions) => Promise<DiscoveredMarket[]>;
531
539
  /** Best market for a from/to pair, in either orientation. `give` is the side