@anywalletkit/protocol-swap2-omniston 0.4.0 → 0.5.1

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.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { omniston } from './config.cjs';
2
- export { A as AssetId, C as ChainAddress, E as EscrowMessage, H as HtlcSecretStore, O as ObservableLike, a as OmnistonClientLike, b as OmnistonProviderOptions, c as OmnistonQuote, d as OmnistonQuoteStore, e as OrderEvent, f as OrderExecution, g as OrderSettlement, h as OrderSnapshot, Q as QuoteRequest, R as RfqEvent, S as SwapSettlement, i as SwapTrackEvent, T as TON_SWAP_PROTOCOL_LAYOUTS, j as TonSwapCheckInput, k as TonSwapCheckResult, l as TonSwapLeg, m as TonSwapPayloadError, n as checkTonSwapPayload, o as encodeTypedMessage, p as inMemoryQuoteStore, q as inMemorySecretStore, r as omnistonPins, s as omnistonProvider, t as omnistonVerifyBuild, v as validateEvmToTonOrderExtension, u as validateEvmTypedOrder } from './provider-D6RXRgf-.cjs';
2
+ export { A as AssetId, C as ChainAddress, E as EscrowMessage, H as HtlcSecretStore, O as ObservableLike, a as OmnistonClientLike, b as OmnistonProviderOptions, c as OmnistonQuote, d as OmnistonQuoteStore, e as OrderEvent, f as OrderExecution, g as OrderSettlement, h as OrderSnapshot, Q as QuoteRequest, R as RfqEvent, S as SwapSettlement, i as SwapTrackEvent, T as TON_SWAP_PROTOCOL_LAYOUTS, j as TonSwapCheckInput, k as TonSwapCheckResult, l as TonSwapLeg, m as TonSwapPayloadError, n as checkTonSwapPayload, o as encodeTypedMessage, p as inMemoryQuoteStore, q as inMemorySecretStore, r as omnistonPins, s as omnistonProvider, t as omnistonVerifyBuild, v as validateEvmToTonOrderExtension, u as validateEvmTypedOrder } from './provider-CcCZB-Cj.cjs';
3
3
  export { OmnistonSwap2Config, OmnistonSwap2Protocol, OmnistonSwap2Protocol as default } from './protocol.cjs';
4
4
  export { OMNISTON_ESCROWS, OMNISTON_MODULE, STONFI_ROUTERS, describeOmnistonActivity } from './activity.cjs';
5
5
  import '@anywalletkit/protocol-swap2-core/types';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { omniston } from './config.js';
2
- export { A as AssetId, C as ChainAddress, E as EscrowMessage, H as HtlcSecretStore, O as ObservableLike, a as OmnistonClientLike, b as OmnistonProviderOptions, c as OmnistonQuote, d as OmnistonQuoteStore, e as OrderEvent, f as OrderExecution, g as OrderSettlement, h as OrderSnapshot, Q as QuoteRequest, R as RfqEvent, S as SwapSettlement, i as SwapTrackEvent, T as TON_SWAP_PROTOCOL_LAYOUTS, j as TonSwapCheckInput, k as TonSwapCheckResult, l as TonSwapLeg, m as TonSwapPayloadError, n as checkTonSwapPayload, o as encodeTypedMessage, p as inMemoryQuoteStore, q as inMemorySecretStore, r as omnistonPins, s as omnistonProvider, t as omnistonVerifyBuild, v as validateEvmToTonOrderExtension, u as validateEvmTypedOrder } from './provider-D6RXRgf-.js';
2
+ export { A as AssetId, C as ChainAddress, E as EscrowMessage, H as HtlcSecretStore, O as ObservableLike, a as OmnistonClientLike, b as OmnistonProviderOptions, c as OmnistonQuote, d as OmnistonQuoteStore, e as OrderEvent, f as OrderExecution, g as OrderSettlement, h as OrderSnapshot, Q as QuoteRequest, R as RfqEvent, S as SwapSettlement, i as SwapTrackEvent, T as TON_SWAP_PROTOCOL_LAYOUTS, j as TonSwapCheckInput, k as TonSwapCheckResult, l as TonSwapLeg, m as TonSwapPayloadError, n as checkTonSwapPayload, o as encodeTypedMessage, p as inMemoryQuoteStore, q as inMemorySecretStore, r as omnistonPins, s as omnistonProvider, t as omnistonVerifyBuild, v as validateEvmToTonOrderExtension, u as validateEvmTypedOrder } from './provider-CcCZB-Cj.js';
3
3
  export { OmnistonSwap2Config, OmnistonSwap2Protocol, OmnistonSwap2Protocol as default } from './protocol.js';
4
4
  export { OMNISTON_ESCROWS, OMNISTON_MODULE, STONFI_ROUTERS, describeOmnistonActivity } from './activity.js';
5
5
  import '@anywalletkit/protocol-swap2-core/types';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OmnistonSwap2Protocol
3
- } from "./chunk-WL7BSEBR.js";
3
+ } from "./chunk-2E6CVWD6.js";
4
4
  import {
5
5
  TON_SWAP_PROTOCOL_LAYOUTS,
6
6
  TonSwapPayloadError,
@@ -13,7 +13,7 @@ import {
13
13
  omnistonVerifyBuild,
14
14
  validateEvmToTonOrderExtension,
15
15
  validateEvmTypedOrder
16
- } from "./chunk-R6B2CV5Z.js";
16
+ } from "./chunk-4JOTKQOT.js";
17
17
  import {
18
18
  omniston
19
19
  } from "./chunk-QDXFC6BC.js";
package/dist/protocol.cjs CHANGED
@@ -500,18 +500,36 @@ function toChainAddress(caip2, address) {
500
500
  if (!$case) return null;
501
501
  return { chain: { $case, value: (0, import_viem.getAddress)(address) } };
502
502
  }
503
- function encodeIntent(quoteId, trader, dest, srcChain, kind = "order") {
504
- return [INTENT_PREFIX, quoteId, trader, dest, srcChain, ...kind === "swap" ? ["swap"] : []].map(encodeURIComponent).join("|");
503
+ var QUOTE_DIGEST_SKIP = /* @__PURE__ */ new Set(["rfqId", "resolverName", "estimatedSettlementDuration", "estimatedGasConsumption"]);
504
+ function canonicalJson(value) {
505
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
506
+ if (value && typeof value === "object") {
507
+ return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`).join(",")}}`;
508
+ }
509
+ return JSON.stringify(value) ?? "null";
510
+ }
511
+ function quoteDigest(q) {
512
+ const terms = JSON.parse(JSON.stringify(q));
513
+ for (const key of QUOTE_DIGEST_SKIP) delete terms[key];
514
+ return (0, import_viem.sha256)(new TextEncoder().encode(canonicalJson(terms))).slice(2, 34);
515
+ }
516
+ var QUOTE_DIGEST = /^[0-9a-f]{32}$/;
517
+ function encodeIntent(quoteId, trader, dest, srcChain, kind, digest) {
518
+ return [INTENT_PREFIX, quoteId, trader, `${dest}#${digest}`, srcChain, ...kind === "swap" ? ["swap"] : []].map(encodeURIComponent).join("|");
505
519
  }
506
520
  var QUOTE_ID = /^[0-9a-fA-F]{48,64}$/;
507
521
  function decodeIntent(intentId) {
508
522
  try {
509
523
  const parts = intentId.split("|");
510
524
  if (parts.length !== 5 && parts.length !== 6 || parts[0] !== INTENT_PREFIX) return null;
511
- const [, quoteId = "", trader = "", dest = "", srcChain = "", kindPart = ""] = parts.map(decodeURIComponent);
525
+ const [, quoteId = "", trader = "", destPart = "", srcChain = "", kindPart = ""] = parts.map(decodeURIComponent);
526
+ const mark = destPart.lastIndexOf("#");
527
+ const dest = mark < 0 ? destPart : destPart.slice(0, mark);
528
+ const digest = mark < 0 ? void 0 : destPart.slice(mark + 1);
529
+ if (digest !== void 0 && !QUOTE_DIGEST.test(digest)) return null;
512
530
  if (!QUOTE_ID.test(quoteId) || !trader || !dest || !srcChain) return null;
513
531
  if (parts.length === 6 && kindPart !== "swap") return null;
514
- return { quoteId, trader, dest, srcChain, kind: parts.length === 6 ? "swap" : "order" };
532
+ return { quoteId, trader, dest, srcChain, kind: parts.length === 6 ? "swap" : "order", ...digest ? { digest } : {} };
515
533
  } catch {
516
534
  return null;
517
535
  }
@@ -1360,7 +1378,7 @@ function omnistonProvider(opts = {}) {
1360
1378
  return true;
1361
1379
  }
1362
1380
  const a = existing.bound, b = entry.bound;
1363
- const same = !!a && !!b && a.kind === b.kind && a.srcChain === b.srcChain && sameIntentAddress(a.trader, b.trader) && sameIntentAddress(a.dest, b.dest);
1381
+ const same = !!a && !!b && a.kind === b.kind && a.srcChain === b.srcChain && sameIntentAddress(a.trader, b.trader) && sameIntentAddress(a.dest, b.dest) && quoteDigest(existing.quote) === quoteDigest(entry.quote);
1364
1382
  if (!same) return false;
1365
1383
  await quotes.save(quoteId, json);
1366
1384
  return true;
@@ -1413,10 +1431,19 @@ function omnistonProvider(opts = {}) {
1413
1431
  throw new Error(`omniston: intent id does not match the quote it was issued for (${bound.field})`);
1414
1432
  }
1415
1433
  if (bound.legacy) trace("legacy-intent", { where });
1434
+ if (!decoded.digest) {
1435
+ trace("intent-mismatch", { where, field: "digest-missing" });
1436
+ throw new Error("omniston: this quote was issued before an update \u2014 request a fresh quote");
1437
+ }
1438
+ if (decoded.digest !== quoteDigest(entry.quote)) {
1439
+ trace("intent-mismatch", { where, field: "digest" });
1440
+ throw new Error("omniston: quote was replaced \u2014 request a fresh quote");
1441
+ }
1416
1442
  return bound.ref;
1417
1443
  }
1418
1444
  const bindKey = (quoteId) => `${quoteId}#bind`;
1419
1445
  const disclosedKey = (quoteId) => `${quoteId}#disclosed`;
1446
+ const disclosedIndicesKey = (quoteId) => `${quoteId}#disclosed-indices`;
1420
1447
  function orderBinding(ref, q) {
1421
1448
  return (0, import_viem.sha256)(new TextEncoder().encode(JSON.stringify([
1422
1449
  ref.quoteId,
@@ -1433,6 +1460,7 @@ function omnistonProvider(opts = {}) {
1433
1460
  await store.clear(quoteId);
1434
1461
  await store.clear(bindKey(quoteId));
1435
1462
  await store.clear(disclosedKey(quoteId));
1463
+ await store.clear(disclosedIndicesKey(quoteId));
1436
1464
  }
1437
1465
  async function secretsFor(ref, q, count) {
1438
1466
  const quoteId = ref.quoteId;
@@ -1461,7 +1489,7 @@ function omnistonProvider(opts = {}) {
1461
1489
  return !!existing && existing.length > 0;
1462
1490
  }
1463
1491
  const SWAP_SLIPPAGE_PIPS_DEFAULT = 5e3;
1464
- const sameChainTonReady = () => typeof opts.validateTonJettonWallet === "function" && typeof opts.validateTonSwapTarget === "function";
1492
+ const sameChainTonReady = () => typeof opts.validateTonJettonWallet === "function" && typeof opts.validateTonSwapTarget === "function" && (typeof opts.validateTonSwapLeg === "function" || opts.tonSwapPayloadCheck === "report");
1465
1493
  const tonSourceReady = (from, to) => omniston.supports(from, to) && trustedContracts.has(from) && trustedContracts.has(to) && typeof opts.validateTonJettonWallet === "function" && typeof opts.validateTonEscrowPayload === "function" && typeof opts.validateEvmOutputPosition === "function";
1466
1494
  const evmSourceReady = (from, to) => omniston.supports(from, to) && trustedOrderProtocols.has(from) && trustedContracts.has(from) && trustedContracts.has(to) && typeof opts.validateEvmInputPosition === "function" && typeof opts.validateTonOutputPosition === "function";
1467
1495
  const evmToEvmReady = (from, to) => omniston.supports(from, to) && trustedOrderProtocols.has(from) && trustedContracts.has(from) && trustedContracts.has(to) && typeof opts.validateEvmInputPosition === "function" && typeof opts.validateEvmOutputPosition === "function";
@@ -1540,7 +1568,7 @@ function omnistonProvider(opts = {}) {
1540
1568
  const feeUsd = stableOut ? feeUnits / 10 ** dest.decimals : 0;
1541
1569
  return {
1542
1570
  provider: "omniston",
1543
- intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "swap"),
1571
+ intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "swap", quoteDigest(q)),
1544
1572
  depositAddress: "",
1545
1573
  // swap settlement — the built message pays the DEX directly
1546
1574
  depositMemo: null,
@@ -1573,7 +1601,7 @@ function omnistonProvider(opts = {}) {
1573
1601
  if (!isTon(ref.srcChain) || q.inputAsset.chain.$case !== "ton" || q.outputAsset.chain.$case !== "ton") {
1574
1602
  throw new Error("omniston: swap quote is not a TON same-chain swap");
1575
1603
  }
1576
- if (!sameChainTonReady()) throw new Error("omniston: TON same-chain swaps need independent jetton-wallet and swap-target validators");
1604
+ if (!sameChainTonReady()) throw new Error("omniston: TON same-chain swaps need independent jetton-wallet, swap-target and swap-leg validators");
1577
1605
  const owner = { chain: { $case: "ton", value: ref.trader } };
1578
1606
  const receiver = { chain: { $case: "ton", value: ref.dest } };
1579
1607
  const omni = await getClient();
@@ -1672,7 +1700,7 @@ function omnistonProvider(opts = {}) {
1672
1700
  }
1673
1701
  if (checked) {
1674
1702
  if (typeof opts.validateTonSwapLeg !== "function") {
1675
- trace("ton-swap-payload", { reason: "legs-unverified", detail: "no validateTonSwapLeg hook", mode, legs: checked.legs.length });
1703
+ payloadRefusal("legs-unverified", `no validateTonSwapLeg hook for ${checked.legs.length} leg(s)`);
1676
1704
  } else {
1677
1705
  for (const leg of checked.legs) {
1678
1706
  let ok = false;
@@ -1952,13 +1980,13 @@ function omnistonProvider(opts = {}) {
1952
1980
  if (outputScaled * 2n < inputScaled || outputScaled > inputScaled * 2n) return refuse2("quoted output is outside 0.5x\u20132x of the input");
1953
1981
  if (await quoteIdInUse(q.quoteId)) return refuse2("the platform reused a quote id that already belongs to an order");
1954
1982
  if (!await claimBuilt(q.quoteId, { quote: q, at: Date.now(), bound: { trader, dest: params.destAddress, srcChain: params.sourceChain, kind: "order" } })) {
1955
- return refuse2("the platform reused a quote id that already holds another user's quote");
1983
+ return refuse2("the platform reused a quote id that already holds another quote");
1956
1984
  }
1957
1985
  const feeUnits = Number(q.protocolFeeUnits || "0") + Number(q.integratorFeeUnits || "0");
1958
1986
  const feeUsd = feeUnits / 10 ** dest.decimals;
1959
1987
  return {
1960
1988
  provider: "omniston",
1961
- intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain),
1989
+ intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "order", quoteDigest(q)),
1962
1990
  depositAddress: "",
1963
1991
  // order settlement — no static deposit address
1964
1992
  depositMemo: null,
@@ -2130,6 +2158,7 @@ function omnistonProvider(opts = {}) {
2130
2158
  );
2131
2159
  if (!order) return { state: "pending" };
2132
2160
  let secretsHex = await store.load(decoded.quoteId);
2161
+ const storedSecrets = secretsHex?.length ?? 0;
2133
2162
  if (!secretsHex || cached?.quote.settlementData.$case !== "order") trace("disclosure-skipped", { gate: "context", secrets: !!secretsHex, cached: !!cached, feedStatus: order.status });
2134
2163
  if (secretsHex && cached?.quote.settlementData.$case === "order") {
2135
2164
  const [lockedTo] = await store.load(bindKey(decoded.quoteId)) ?? [];
@@ -2138,6 +2167,7 @@ function omnistonProvider(opts = {}) {
2138
2167
  secretsHex = void 0;
2139
2168
  }
2140
2169
  }
2170
+ const disclosedNow = /* @__PURE__ */ new Set();
2141
2171
  if (secretsHex && cached?.quote.settlementData.$case === "order") {
2142
2172
  const q = cached.quote;
2143
2173
  const settlement = q.settlementData.value;
@@ -2236,11 +2266,15 @@ function omnistonProvider(opts = {}) {
2236
2266
  }
2237
2267
  await omni.orderDiscloseHtlcSecret({ quoteId: decoded.quoteId, executionIndex: i, secret: secretBytes }).then(async () => {
2238
2268
  trace("secret-disclosed", { index: i });
2269
+ disclosedNow.add(i);
2239
2270
  await store.save(disclosedKey(decoded.quoteId), ["1"]);
2240
2271
  }, (error) => trace("disclose-failed", { index: i, error: error instanceof Error ? error.message : String(error) }));
2241
2272
  })
2242
2273
  );
2243
2274
  }
2275
+ const disclosedBefore = (await store.load(disclosedIndicesKey(decoded.quoteId)) ?? []).map(Number).filter(Number.isSafeInteger);
2276
+ const disclosedAll = /* @__PURE__ */ new Set([...disclosedBefore, ...disclosedNow]);
2277
+ if (disclosedNow.size > 0) await store.save(disclosedIndicesKey(decoded.quoteId), [...disclosedAll].sort((a, b) => a - b).map(String));
2244
2278
  const status = mapOrderStatus(order);
2245
2279
  const delivered = order.executions[0]?.outputPositionAddress;
2246
2280
  const outCase = cached?.quote.outputAsset.chain.$case;
@@ -2265,6 +2299,14 @@ function omnistonProvider(opts = {}) {
2265
2299
  }).catch(() => null);
2266
2300
  if (hash) status.destTxHash = hash;
2267
2301
  }
2302
+ if (status.state === "completed" && storedSecrets > 0 && !status.destTxHash) {
2303
+ const legacyDisclosed = disclosedBefore.length === 0 && storedSecrets === 1 && (await store.load(disclosedKey(decoded.quoteId)) ?? []).length > 0;
2304
+ const allDisclosed = legacyDisclosed || (order.executions.length > 0 ? order.executions.every((execution) => disclosedAll.has(execution.index)) : disclosedAll.size > 0);
2305
+ if (!allDisclosed) {
2306
+ trace("completion-unproven", { feedStatus: order.status, executions: order.executions.length, disclosed: disclosedAll.size });
2307
+ return { state: "pending", depositReceived: order.executions.length > 0 || disclosedAll.size > 0 };
2308
+ }
2309
+ }
2268
2310
  if (status.state === "completed") {
2269
2311
  await clearSecrets(decoded.quoteId);
2270
2312
  await quotes.clear(decoded.quoteId);