@anywalletkit/protocol-swap2-omniston 0.3.0 → 0.4.0

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/provider.cjs CHANGED
@@ -429,6 +429,38 @@ function sameJetton(a, b) {
429
429
  }
430
430
  }
431
431
 
432
+ // src/validators/settlement.ts
433
+ var AUDITED_OMNISTON_SETTLEMENT_CONTRACTS = {
434
+ "ton:-239": ["EQAbWJ3Y1HgIIvcMq1prG1anlDC0T3cZlAU7luPT6LmTpmrZ"],
435
+ "eip155:1": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
436
+ "eip155:56": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
437
+ "eip155:137": ["0x41A392062A4307a6961d48e30FF20bF6823715B8"],
438
+ "eip155:4663": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
439
+ "eip155:8453": ["0xACa3E2F9b61a44892926bC6c3e104192E7D1c3cd"],
440
+ "eip155:42161": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
441
+ "eip155:43114": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
442
+ // 2026-10-20: one factory address on X Layer, HyperEVM and Plasma. Runtime
443
+ // bytecode equals Ethereum's 0xafCF… byte for byte except the immutable slots
444
+ // (escrow implementations, its order protocol, domain hash); it references
445
+ // the order protocol trusted below on the same chain.
446
+ "eip155:196": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
447
+ "eip155:999": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
448
+ "eip155:9745": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"]
449
+ };
450
+ var AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS = {
451
+ "eip155:1": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
452
+ "eip155:56": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
453
+ "eip155:137": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
454
+ "eip155:8453": ["0xe7405fAcDEDB2512e91F2886BDff13231343aF5E"],
455
+ "eip155:42161": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
456
+ "eip155:43114": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
457
+ // 2026-10-20: bytecode equals Ethereum's 0xb581… except immutables (wrapped
458
+ // native, own address, chain id 196 / 9745 / 999 at the chain-id slot).
459
+ "eip155:196": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
460
+ "eip155:9745": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
461
+ "eip155:999": ["0xD84778bbeEC5D2a8d17c6424249C438EC0b1ABE3"]
462
+ };
463
+
432
464
  // src/provider.ts
433
465
  var import_core4 = require("@anywalletkit/core");
434
466
  var EVM_CASE = {
@@ -639,9 +671,9 @@ function validEvmAddress(value) {
639
671
  }
640
672
  }
641
673
  var EVM_DEST_PROTOCOL_FEE_RECIPIENTS = /* @__PURE__ */ new Set(["0x076268146b4ec6d21fc49c27586cfa91b9079a00"]);
642
- async function validateEvmToTonOrderExtension(extension, expected) {
643
- const evmDest = expected.dstChainId !== void 0;
644
- if (evmDest && (!Number.isSafeInteger(expected.dstChainId) || expected.dstChainId <= 0)) throw new Error("omniston: invalid EVM destination chain id");
674
+ var EVM_AUCTION_POINTS = [[800000n, 100n], [700000n, 100n], [600000n, 100n], [500000n, 100n], [400000n, 100n]];
675
+ var EVM_TIMELOCKS = [1n, 120n, 240n, 300n, 1n, 120n, 180n, 0n].reduce((packed, value, index) => packed | value << BigInt(index * 32), 0n);
676
+ function readEvmOrderExtension(extension) {
645
677
  if (extension.length < 32) throw new Error("omniston: malformed EVM order extension");
646
678
  const view = new DataView(extension.buffer, extension.byteOffset, extension.byteLength);
647
679
  const fields = [];
@@ -661,54 +693,48 @@ async function validateEvmToTonOrderExtension(extension, expected) {
661
693
  }
662
694
  let target;
663
695
  for (const index of [2, 3, 7]) {
664
- const field = fields[index];
665
- if (field.length <= 20) throw new Error("omniston: incomplete EVM order extension program");
666
- const address = (0, import_viem.getAddress)(`0x${bytesToHex(field.slice(0, 20))}`);
667
- if (!expected.trustedTarget(address) || target !== void 0 && (0, import_viem.getAddress)(target) !== address) {
696
+ const field2 = fields[index];
697
+ if (field2.length <= 20) throw new Error("omniston: incomplete EVM order extension program");
698
+ const address = (0, import_viem.getAddress)(`0x${bytesToHex(field2.slice(0, 20))}`);
699
+ if (target !== void 0 && (0, import_viem.getAddress)(target) !== address) {
668
700
  throw new Error("omniston: EVM order extension target is not independently trusted");
669
701
  }
670
702
  target = address;
671
703
  }
672
- const getter = fields[2];
704
+ const field = fields[2];
673
705
  let cursor = 20;
674
- const gasBump = readBigEndian(getter, cursor, 3);
706
+ const gasBump = readBigEndian(field, cursor, 3);
675
707
  cursor += 3;
676
- const gasPrice = readBigEndian(getter, cursor, 4);
708
+ const gasPrice = readBigEndian(field, cursor, 4);
677
709
  cursor += 4;
678
- const auctionStart = readBigEndian(getter, cursor, 4);
710
+ const auctionStart = readBigEndian(field, cursor, 4);
679
711
  cursor += 4;
680
- const duration = readBigEndian(getter, cursor, 3);
712
+ const duration = readBigEndian(field, cursor, 3);
681
713
  cursor += 3;
682
- const initialRateBump = readBigEndian(getter, cursor, 3);
714
+ const initialRateBump = readBigEndian(field, cursor, 3);
683
715
  cursor += 3;
684
- const pointCount = (0, import_core4.bigintToNumber)(readBigEndian(getter, cursor, 1));
716
+ const pointCount = (0, import_core4.bigintToNumber)(readBigEndian(field, cursor, 1));
685
717
  cursor += 1;
686
718
  if (pointCount !== 5) throw new Error("omniston: unsupported EVM auction profile");
687
719
  const points = [];
688
720
  for (let index = 0; index < pointCount; index++) {
689
- points.push([readBigEndian(getter, cursor, 3), readBigEndian(getter, cursor + 3, 2)]);
721
+ points.push([readBigEndian(field, cursor, 3), readBigEndian(field, cursor + 3, 2)]);
690
722
  cursor += 5;
691
723
  }
692
- const integratorFee = readBigEndian(getter, cursor, 2);
724
+ const integratorFee = readBigEndian(field, cursor, 2);
693
725
  cursor += 2;
694
- const integratorShare = readBigEndian(getter, cursor, 1);
726
+ const integratorShare = readBigEndian(field, cursor, 1);
695
727
  cursor += 1;
696
- const resolverFee = readBigEndian(getter, cursor, 2);
728
+ const resolverFee = readBigEndian(field, cursor, 2);
697
729
  cursor += 2;
698
- const whitelistDiscount = readBigEndian(getter, cursor, 1);
730
+ const whitelistDiscount = readBigEndian(field, cursor, 1);
699
731
  cursor += 1;
700
- const getterWhitelistCount = (0, import_core4.bigintToNumber)(readBigEndian(getter, cursor, 1));
732
+ const getterWhitelistCount = (0, import_core4.bigintToNumber)(readBigEndian(field, cursor, 1));
701
733
  cursor += 1;
702
- if (getterWhitelistCount !== 1 || cursor + getterWhitelistCount * 10 !== getter.length) {
734
+ if (getterWhitelistCount !== 1 || cursor + getterWhitelistCount * 10 !== field.length) {
703
735
  throw new Error("omniston: malformed EVM amount-getter whitelist");
704
736
  }
705
- const getterResolver = readBigEndian(getter, cursor, 10);
706
- const expectedPoints = [[800000n, 100n], [700000n, 100n], [600000n, 100n], [500000n, 100n], [400000n, 100n]];
707
- const quoteResolverFee = expected.protocolFeePips % 10 === 0 ? BigInt(expected.protocolFeePips / 10) : -1n;
708
- const resolverLow80 = BigInt((0, import_viem.getAddress)(expected.initialResolverAddress)) & (1n << 80n) - 1n;
709
- if (gasBump !== 0n || gasPrice !== 0n || !within(auctionStart, expected.quoteTimestamp, 5, 5) || duration !== 1800n || initialRateBump !== 900000n || points.some((point, index) => point[0] !== expectedPoints[index][0] || point[1] !== expectedPoints[index][1]) || expected.integratorFeePips !== 0 || integratorFee !== 0n || integratorShare !== 100n || quoteResolverFee < 0n || resolverFee !== quoteResolverFee || whitelistDiscount !== 50n || getterResolver !== resolverLow80) {
710
- throw new Error("omniston: EVM amount-getter terms do not match the pinned v1beta8 profile");
711
- }
737
+ const getter = { gasBump, gasPrice, auctionStart, duration, initialRateBump, points, integratorFee, integratorShare, resolverFee, whitelistDiscount, resolver: readBigEndian(field, cursor, 10) };
712
738
  const post = fields[7];
713
739
  cursor = 20;
714
740
  const integratorRecipient = post.slice(cursor, cursor + 20);
@@ -734,28 +760,51 @@ async function validateEvmToTonOrderExtension(extension, expected) {
734
760
  cursor += 10;
735
761
  const resolverTimeDelta = readBigEndian(post, cursor, 2);
736
762
  cursor += 2;
737
- if (!zeroBytes(integratorRecipient) || !(zeroBytes(protocolRecipient) || evmDest && EVM_DEST_PROTOCOL_FEE_RECIPIENTS.has(`0x${bytesToHex(protocolRecipient)}`)) || postIntegratorFee !== 0n || postIntegratorShare !== 100n || postResolverFee !== quoteResolverFee || postDiscount !== 50n || !within(allowedTime, expected.quoteTimestamp, 60, 5) || postResolver !== resolverLow80 || resolverTimeDelta !== 0n) {
738
- throw new Error("omniston: EVM post-interaction terms do not match the pinned v1beta8 profile");
739
- }
740
763
  const extra = Array.from({ length: 5 }, () => {
741
764
  const value = readBigEndian(post, cursor, 32);
742
765
  cursor += 32;
743
766
  return value;
744
767
  });
768
+ const customData = extension.slice(32 + begin);
769
+ if (customData.length !== 131) throw new Error("omniston: malformed EVM order extension custom data");
770
+ return {
771
+ target,
772
+ getter,
773
+ post: { integratorRecipient, protocolRecipient, integratorFee: postIntegratorFee, integratorShare: postIntegratorShare, resolverFee: postResolverFee, discount: postDiscount, allowedTime, resolver: postResolver, resolverTimeDelta },
774
+ extra,
775
+ customData
776
+ };
777
+ }
778
+ async function validateEvmToTonOrderExtension(extension, expected) {
779
+ const evmDest = expected.dstChainId !== void 0;
780
+ if (evmDest && (!Number.isSafeInteger(expected.dstChainId) || expected.dstChainId <= 0)) throw new Error("omniston: invalid EVM destination chain id");
781
+ const { target, getter, post, extra, customData } = readEvmOrderExtension(extension);
782
+ if (!expected.trustedTarget(target)) throw new Error("omniston: EVM order extension target is not independently trusted");
783
+ const quoteResolverFee = expected.protocolFeePips % 10 === 0 ? BigInt(expected.protocolFeePips / 10) : -1n;
784
+ const resolverLow80 = BigInt((0, import_viem.getAddress)(expected.initialResolverAddress)) & (1n << 80n) - 1n;
785
+ if (getter.gasBump !== 0n || getter.gasPrice !== 0n || !within(getter.auctionStart, expected.quoteTimestamp, 5, 5) || getter.duration !== 1800n || getter.initialRateBump !== 900000n || getter.points.some((point, index) => point[0] !== EVM_AUCTION_POINTS[index][0] || point[1] !== EVM_AUCTION_POINTS[index][1]) || expected.integratorFeePips !== 0 || getter.integratorFee !== 0n || getter.integratorShare !== 100n || quoteResolverFee < 0n || getter.resolverFee !== quoteResolverFee || getter.whitelistDiscount !== 50n || getter.resolver !== resolverLow80) {
786
+ throw new Error("omniston: EVM amount-getter terms do not match the pinned v1beta8 profile");
787
+ }
788
+ if (!zeroBytes(post.integratorRecipient) || !(zeroBytes(post.protocolRecipient) || evmDest && EVM_DEST_PROTOCOL_FEE_RECIPIENTS.has(`0x${bytesToHex(post.protocolRecipient)}`)) || post.integratorFee !== 0n || post.integratorShare !== 100n || post.resolverFee !== quoteResolverFee || post.discount !== 50n || !within(post.allowedTime, expected.quoteTimestamp, 60, 5) || post.resolver !== resolverLow80 || post.resolverTimeDelta !== 0n) {
789
+ throw new Error("omniston: EVM post-interaction terms do not match the pinned v1beta8 profile");
790
+ }
745
791
  const hashlock2 = readBigEndian(expected.secretHash, 0, expected.secretHash.length);
746
792
  const dstToken = evmDest ? BigInt((0, import_viem.getAddress)(expected.outputTokenAddress)) : BigInt((0, import_viem.getAddress)(expected.takerAsset));
747
793
  const deposits = BigInt(expected.srcSecurityDepositUnits) << 128n | BigInt(expected.dstSecurityDepositUnits);
748
- const timelocks = [1n, 120n, 240n, 300n, 1n, 120n, 180n, 0n].reduce((packed, value, index) => packed | value << BigInt(index * 32), 0n);
749
- if (expected.secretHash.length !== 32 || extra[0] !== hashlock2 || extra[1] !== (evmDest ? BigInt(expected.dstChainId) : 0n) || extra[2] !== dstToken || extra[3] !== deposits || extra[4] !== timelocks) {
794
+ if (expected.secretHash.length !== 32 || extra[0] !== hashlock2 || extra[1] !== (evmDest ? BigInt(expected.dstChainId) : 0n) || extra[2] !== dstToken || extra[3] !== deposits || extra[4] !== EVM_TIMELOCKS) {
750
795
  throw new Error("omniston: signed EVM HTLC terms do not match the validated order details");
751
796
  }
752
- const customData = extension.slice(32 + begin);
753
- if (customData.length !== 131) throw new Error("omniston: malformed EVM order extension custom data");
754
- if (evmDest) {
797
+ await checkOrderCustomData(customData, { evmDest, outputToken: expected.outputTokenAddress, traderDst: expected.traderDstAddress, quoteId: expected.quoteId });
798
+ if (expected.tradeStartDeadline < expected.quoteTimestamp) {
799
+ throw new Error("omniston: invalid EVM order quote deadline");
800
+ }
801
+ }
802
+ async function checkOrderCustomData(customData, expected) {
803
+ if (expected.evmDest) {
755
804
  if (!zeroBytes(customData.slice(0, 66))) throw new Error("omniston: unexpected TON addresses in an EVM-destination order");
756
805
  } else {
757
806
  const { Address: Address3 } = await import("@ton/core");
758
- const expectedTon = [expected.outputTokenAddress, expected.traderDstAddress].map((value) => Address3.parse(value));
807
+ const expectedTon = [expected.outputToken, expected.traderDst].map((value) => Address3.parse(value));
759
808
  for (let index = 0; index < expectedTon.length; index++) {
760
809
  const offset = index * 33;
761
810
  const workchain = customData[offset] === 255 ? -1 : customData[offset];
@@ -771,9 +820,6 @@ async function validateEvmToTonOrderExtension(extension, expected) {
771
820
  if (!QUOTE_ID.test(quoteId) || !sliceEqual(customData.slice(99), hexToBytes(quoteId.padStart(64, "0")))) {
772
821
  throw new Error("omniston: EVM order extension custom data is not bound to the quote id");
773
822
  }
774
- if (expected.tradeStartDeadline < expected.quoteTimestamp) {
775
- throw new Error("omniston: invalid EVM order quote deadline");
776
- }
777
823
  }
778
824
  function validateEvmTypedOrder(td, expected) {
779
825
  const value = td;
@@ -1225,11 +1271,124 @@ function omnistonPins(trustedEvmOrderProtocols) {
1225
1271
  const byChain = new Map(Object.entries(trustedEvmOrderProtocols).map(([chain, list]) => [chain, list.map((a) => (0, import_viem.getAddress)(a))]));
1226
1272
  return Object.freeze({ callTargets: () => [], spenders: (chain) => byChain.get(chain) ?? [] });
1227
1273
  }
1274
+ var MAX_EVM_ORDER_LIFETIME_S = 900;
1275
+ async function checkRemoteEvmOrder(quote, tx, params, trusted) {
1276
+ const chainId = evmRef2(params.sourceChain);
1277
+ if (chainId === null || !params.sourceChain.startsWith("eip155:")) return "a typed order needs an EVM source";
1278
+ const intent = decodeIntent(quote.intentId.replace(/~[0-9a-f]{32}$/, ""));
1279
+ if (!intent || intent.kind !== "order" || intent.srcChain !== params.sourceChain) return "the quote's intent is not an order from this chain";
1280
+ if (!tx.orderExtension || !/^0x(?:[0-9a-fA-F]{2})+$/.test(tx.orderExtension)) return "the build carries no order extension to check";
1281
+ const source = (0, import_swap2_assets.ccAsset)(params.sourceChain, params.sourceToken);
1282
+ if (!source?.contract) return "unknown source token";
1283
+ const tonDest = isTon(params.destChain);
1284
+ const destChainId = tonDest ? null : evmRef2(params.destChain);
1285
+ if (!tonDest && (destChainId === null || !params.destChain.startsWith("eip155:"))) return "the destination is neither TON nor an EVM chain";
1286
+ const outputToken = (0, import_swap2_assets.ccAssetByToken)(params.destChain, params.destToken)?.contract ?? params.destToken;
1287
+ const listed = (table, chain, address) => typeof address === "string" && validEvmAddress(address) && (table[chain] ?? []).some((a) => validEvmAddress(a) && (0, import_viem.getAddress)(a) === (0, import_viem.getAddress)(address));
1288
+ let td;
1289
+ try {
1290
+ td = JSON.parse(tx.typedData ?? "");
1291
+ } catch {
1292
+ return "the typed data is not JSON";
1293
+ }
1294
+ const domain = td.domain ?? {};
1295
+ const contract = domain.verifyingContract;
1296
+ if (domain.name !== "1inch Limit Order Protocol" || domain.version !== "4") return "the domain is not the 1inch Limit Order Protocol v4";
1297
+ if (!listed(trusted.orderProtocols, params.sourceChain, contract) || !tx.approvalAddress || (0, import_viem.getAddress)(tx.approvalAddress) !== (0, import_viem.getAddress)(String(contract))) {
1298
+ return `${String(contract)} is not a trusted order protocol on ${params.sourceChain}`;
1299
+ }
1300
+ if (Number(domain.chainId) !== chainId || tx.chainId !== void 0 && tx.chainId !== chainId) return "the domain chainId is not the source chain";
1301
+ const order = td.types?.Order;
1302
+ const message = td.message;
1303
+ if (td.primaryType !== "Order" || !Array.isArray(order) || order.length !== ORDER_FIELDS.length || !order.every((field, i) => field.name === ORDER_FIELDS[i][0] && field.type === ORDER_FIELDS[i][1]) || !message || Object.keys(message).length !== ORDER_FIELDS.length || !ORDER_FIELDS.every(([name]) => Object.hasOwn(message, name)) || !ORDER_FIELDS.every(([name, type]) => type === "address" ? validEvmAddress(message[name]) : validUint256(message[name]))) {
1304
+ return "the typed data is not exactly a v4 Order";
1305
+ }
1306
+ if (!validEvmAddress(intent.trader) || (0, import_viem.getAddress)(String(message.maker)) !== (0, import_viem.getAddress)(intent.trader)) return "the maker is not the trader";
1307
+ if ((0, import_viem.getAddress)(String(message.makerAsset)) !== (0, import_viem.getAddress)(source.contract)) return "the makerAsset is not the source token";
1308
+ if (BigInt(message.makingAmount) !== BigInt(quote.sourceAmount)) return "the makingAmount is not the input";
1309
+ if ((0, import_viem.getAddress)(String(message.takerAsset)) === (0, import_viem.getAddress)(String(message.makerAsset))) return "the takerAsset is the makerAsset";
1310
+ const floor = [quote.minDestAmount, params.minAmountOut ?? "0"].filter((v) => /^\d{1,80}$/.test(v)).map((v) => BigInt(v)).reduce((a, b) => a > b ? a : b, 0n);
1311
+ if (floor <= 0n || BigInt(message.takingAmount) < floor) return `takingAmount ${String(message.takingAmount)} is below the quote's minimum ${floor}`;
1312
+ const traits = BigInt(message.makerTraits);
1313
+ const flags = traits & (1n << 56n) - 1n << 200n;
1314
+ const baseFlags = 1n << 251n | 1n << 249n;
1315
+ if (flags !== baseFlags && flags !== (baseFlags | 1n << 255n)) return "the makerTraits flags are not a single-fill order with its extension";
1316
+ if ((traits & (1n << 80n) - 1n) !== 0n || (traits >> 160n & (1n << 40n) - 1n) !== 0n) return "the makerTraits restrict the taker or the series";
1317
+ const now = BigInt(Math.floor(Date.now() / 1e3));
1318
+ const expiration = traits >> 80n & (1n << 40n) - 1n;
1319
+ if (expiration <= now || expiration > now + BigInt(MAX_EVM_ORDER_LIFETIME_S)) return "the order's expiry is not minutes away";
1320
+ const extension = (0, import_viem.hexToBytes)(tx.orderExtension);
1321
+ const mask = (1n << 160n) - 1n;
1322
+ if ((BigInt(message.salt) & mask) !== (BigInt((0, import_viem.keccak256)(extension)) & mask)) return "the salt does not commit the order extension";
1323
+ let parsed;
1324
+ try {
1325
+ parsed = readEvmOrderExtension(extension);
1326
+ } catch (e) {
1327
+ return e instanceof Error ? e.message.replace(/^omniston: /, "") : String(e);
1328
+ }
1329
+ const { target, getter, post, extra, customData } = parsed;
1330
+ if (!listed(trusted.factories, params.sourceChain, target)) return `the extension targets ${target}, not a trusted escrow factory on ${params.sourceChain}`;
1331
+ const receiverLow80 = BigInt((0, import_viem.getAddress)(String(message.receiver))) & (1n << 80n) - 1n;
1332
+ if (getter.resolver !== receiverLow80 || post.resolver !== receiverLow80) return "the order's receiver is not the resolver its extension whitelists";
1333
+ if (getter.gasBump !== 0n || getter.gasPrice !== 0n || getter.duration !== 1800n || getter.initialRateBump !== 900000n || getter.points.some((point, index) => point[0] !== EVM_AUCTION_POINTS[index][0] || point[1] !== EVM_AUCTION_POINTS[index][1]) || getter.integratorFee !== 0n || getter.integratorShare !== 100n || getter.whitelistDiscount !== 50n || !within(getter.auctionStart, (0, import_core4.bigintToNumber)(now), MAX_EVM_ORDER_LIFETIME_S, 60)) {
1334
+ return "the amount-getter terms do not match the pinned v1beta8 profile";
1335
+ }
1336
+ if (!zeroBytes(post.integratorRecipient) || !(zeroBytes(post.protocolRecipient) || !tonDest && EVM_DEST_PROTOCOL_FEE_RECIPIENTS.has(`0x${bytesToHex(post.protocolRecipient)}`)) || post.integratorFee !== 0n || post.integratorShare !== 100n || post.resolverFee !== getter.resolverFee || post.discount !== 50n || post.resolverTimeDelta !== 0n || !within(post.allowedTime, (0, import_core4.bigintToNumber)(getter.auctionStart), 60, 5)) {
1337
+ return "the post-interaction terms do not match the pinned v1beta8 profile";
1338
+ }
1339
+ let dstToken;
1340
+ try {
1341
+ dstToken = tonDest ? BigInt((0, import_viem.getAddress)(String(message.takerAsset))) : BigInt((0, import_viem.getAddress)(outputToken));
1342
+ } catch {
1343
+ return "the destination token is not an EVM address";
1344
+ }
1345
+ if (extra[1] !== (tonDest ? 0n : BigInt(destChainId)) || extra[2] !== dstToken || extra[4] !== EVM_TIMELOCKS) {
1346
+ return "the signed HTLC terms name another destination chain or token, or other timelocks";
1347
+ }
1348
+ try {
1349
+ await checkOrderCustomData(customData, { evmDest: !tonDest, outputToken, traderDst: params.destAddress, quoteId: intent.quoteId });
1350
+ } catch (e) {
1351
+ return e instanceof Error ? e.message.replace(/^omniston: /, "") : String(e);
1352
+ }
1353
+ return null;
1354
+ }
1228
1355
  function omnistonVerifyBuild(hooks) {
1356
+ const trusted = {
1357
+ orderProtocols: hooks.trustedEvmOrderProtocols ?? AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS,
1358
+ factories: hooks.trustedSettlementContracts ?? AUDITED_OMNISTON_SETTLEMENT_CONTRACTS
1359
+ };
1229
1360
  return async (quote, tx, params) => {
1361
+ if (tx.typedData !== void 0) {
1362
+ if (!params) return "the request this quote answered is unknown";
1363
+ try {
1364
+ return await checkRemoteEvmOrder(quote, tx, params, trusted);
1365
+ } catch {
1366
+ return "the typed order could not be checked";
1367
+ }
1368
+ }
1230
1369
  if (tx.bodyBoc === void 0) return null;
1231
1370
  if (!params) return "the request this quote answered is unknown";
1232
- if (quote.providerData?.settlement !== "swap") return "only TON swap bodies can be checked on the client";
1371
+ if (quote.providerData?.settlement !== "swap") {
1372
+ if (params.sourceChain.startsWith("ton:") && params.destChain.startsWith("eip155:")) {
1373
+ if (!hooks.verifyTonEscrowBuild) return "a TON \u2192 EVM escrow body needs verifyTonEscrowBuild (createOmnistonTonValidators)";
1374
+ if (!params.refundAddress) return "the trader's TON address (refundAddress) is unknown";
1375
+ const floor = [quote.minDestAmount, params.minAmountOut ?? "0"].filter((v) => /^\d{1,80}$/.test(v)).map((v) => BigInt(v)).reduce((a, b) => a > b ? a : b, 0n);
1376
+ try {
1377
+ return await hooks.verifyTonEscrowBuild({
1378
+ payloadBocHex: import_buffer2.Buffer.from(tx.bodyBoc, "base64").toString("hex"),
1379
+ ownerAddress: params.refundAddress,
1380
+ inputUnits: quote.sourceAmount,
1381
+ destinationChain: params.destChain,
1382
+ destinationAddress: params.destAddress,
1383
+ outputTokenAddress: params.destToken,
1384
+ minResolverSendsUnits: floor.toString()
1385
+ });
1386
+ } catch {
1387
+ return "the escrow body could not be checked";
1388
+ }
1389
+ }
1390
+ return "only TON swap and TON \u2192 EVM escrow bodies can be checked on the client";
1391
+ }
1233
1392
  let steps;
1234
1393
  try {
1235
1394
  steps = JSON.parse(quote.providerData.routeSteps ?? "");
@@ -1896,7 +2055,7 @@ function omnistonProvider(opts = {}) {
1896
2055
  }
1897
2056
  });
1898
2057
  const orderProtocol = (0, import_viem.getAddress)(protocol.chain.value);
1899
- return { chain: srcChain, to: orderProtocol, value: "0", chainId, approvalAddress: orderProtocol, typedData };
2058
+ return { chain: srcChain, to: orderProtocol, value: "0", chainId, approvalAddress: orderProtocol, typedData, orderExtension: `0x${bytesToHex(payload.orderExtension)}` };
1900
2059
  }
1901
2060
  return {
1902
2061
  name: "omniston",