@anywalletkit/protocol-swap2-omniston 0.3.1 → 0.5.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/README.md +20 -4
- package/dist/{chunk-HOTFZYSW.js → chunk-2DGCZD5K.js} +214 -62
- package/dist/chunk-2DGCZD5K.js.map +1 -0
- package/dist/{chunk-RW4XZWNC.js → chunk-4MKR2SUZ.js} +2 -2
- package/dist/chunk-JWYDIW4V.js +37 -0
- package/dist/chunk-JWYDIW4V.js.map +1 -0
- package/dist/index.cjs +241 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -2
- package/dist/protocol.cjs +108 -52
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.js +3 -2
- package/dist/{provider-BBG2zhpu.d.cts → provider-CcCZB-Cj.d.cts} +15 -5
- package/dist/{provider-BBG2zhpu.d.ts → provider-CcCZB-Cj.d.ts} +15 -5
- package/dist/provider.cjs +241 -61
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.d.cts +1 -1
- package/dist/provider.d.ts +1 -1
- package/dist/provider.js +2 -1
- package/dist/validators.d.cts +1 -1
- package/dist/validators.d.ts +1 -1
- package/dist/validators.js +5 -34
- package/dist/validators.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-HOTFZYSW.js.map +0 -1
- /package/dist/{chunk-RW4XZWNC.js.map → chunk-4MKR2SUZ.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
omnistonProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2DGCZD5K.js";
|
|
4
4
|
import {
|
|
5
5
|
omniston
|
|
6
6
|
} from "./chunk-QDXFC6BC.js";
|
|
@@ -24,4 +24,4 @@ var OmnistonSwap2Protocol = class extends SingleProviderSwap2 {
|
|
|
24
24
|
export {
|
|
25
25
|
OmnistonSwap2Protocol
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=chunk-
|
|
27
|
+
//# sourceMappingURL=chunk-4MKR2SUZ.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/validators/settlement.ts
|
|
2
|
+
var AUDITED_OMNISTON_SETTLEMENT_CONTRACTS = {
|
|
3
|
+
"ton:-239": ["EQAbWJ3Y1HgIIvcMq1prG1anlDC0T3cZlAU7luPT6LmTpmrZ"],
|
|
4
|
+
"eip155:1": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
5
|
+
"eip155:56": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
6
|
+
"eip155:137": ["0x41A392062A4307a6961d48e30FF20bF6823715B8"],
|
|
7
|
+
"eip155:4663": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
8
|
+
"eip155:8453": ["0xACa3E2F9b61a44892926bC6c3e104192E7D1c3cd"],
|
|
9
|
+
"eip155:42161": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
10
|
+
"eip155:43114": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
11
|
+
// 2026-10-20: one factory address on X Layer, HyperEVM and Plasma. Runtime
|
|
12
|
+
// bytecode equals Ethereum's 0xafCF… byte for byte except the immutable slots
|
|
13
|
+
// (escrow implementations, its order protocol, domain hash); it references
|
|
14
|
+
// the order protocol trusted below on the same chain.
|
|
15
|
+
"eip155:196": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
|
|
16
|
+
"eip155:999": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
|
|
17
|
+
"eip155:9745": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"]
|
|
18
|
+
};
|
|
19
|
+
var AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS = {
|
|
20
|
+
"eip155:1": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
21
|
+
"eip155:56": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
22
|
+
"eip155:137": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
23
|
+
"eip155:8453": ["0xe7405fAcDEDB2512e91F2886BDff13231343aF5E"],
|
|
24
|
+
"eip155:42161": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
25
|
+
"eip155:43114": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
26
|
+
// 2026-10-20: bytecode equals Ethereum's 0xb581… except immutables (wrapped
|
|
27
|
+
// native, own address, chain id 196 / 9745 / 999 at the chain-id slot).
|
|
28
|
+
"eip155:196": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
29
|
+
"eip155:9745": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
30
|
+
"eip155:999": ["0xD84778bbeEC5D2a8d17c6424249C438EC0b1ABE3"]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
AUDITED_OMNISTON_SETTLEMENT_CONTRACTS,
|
|
35
|
+
AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=chunk-JWYDIW4V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validators/settlement.ts"],"sourcesContent":["/**\n * Settlement contracts this deployment trusts for Omniston, per CAIP-2 chain.\n * Audited public addresses — no secret — so both the server wiring and the\n * browser-side provider import them from here.\n * See how-to-project/OMNISTON-NETWORK-ONBOARDING.md before adding a network.\n */\nexport const AUDITED_OMNISTON_SETTLEMENT_CONTRACTS: Record<string, string[]> = {\n \"ton:-239\": [\"EQAbWJ3Y1HgIIvcMq1prG1anlDC0T3cZlAU7luPT6LmTpmrZ\"],\n \"eip155:1\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n \"eip155:56\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n \"eip155:137\": [\"0x41A392062A4307a6961d48e30FF20bF6823715B8\"],\n \"eip155:4663\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n \"eip155:8453\": [\"0xACa3E2F9b61a44892926bC6c3e104192E7D1c3cd\"],\n \"eip155:42161\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n \"eip155:43114\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n // 2026-10-20: one factory address on X Layer, HyperEVM and Plasma. Runtime\n // bytecode equals Ethereum's 0xafCF… byte for byte except the immutable slots\n // (escrow implementations, its order protocol, domain hash); it references\n // the order protocol trusted below on the same chain.\n \"eip155:196\": [\"0xd602079AFa5c38F550510a2a988CbFa698Fa0189\"],\n \"eip155:999\": [\"0xd602079AFa5c38F550510a2a988CbFa698Fa0189\"],\n \"eip155:9745\": [\"0xd602079AFa5c38F550510a2a988CbFa698Fa0189\"],\n};\n\n/**\n * EVM order protocols (Omniston's fork of the 1inch Limit Order Protocol v4 —\n * NOT the canonical 1inch deployment) an EVM→TON order is signed against. The\n * wallet approves this contract for the input amount and signs an EIP-712\n * order whose domain names it; on fill it moves the input into the escrow the\n * factory above deploys. One address, different roles per chain (0xafCF… is\n * the factory elsewhere and the order protocol on Polygon), so this table is\n * separate from the factory table and CAIP-scoped. Runtime code hashes are in\n * how-to-project/OMNISTON-NETWORK-ONBOARDING.md (snapshot 2026-10-16).\n */\nexport const AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS: Record<string, string[]> = {\n \"eip155:1\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n \"eip155:56\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n \"eip155:137\": [\"0xafCF681272AF10959736f45616eeCBC22D7095E2\"],\n \"eip155:8453\": [\"0xe7405fAcDEDB2512e91F2886BDff13231343aF5E\"],\n \"eip155:42161\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n \"eip155:43114\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n // 2026-10-20: bytecode equals Ethereum's 0xb581… except immutables (wrapped\n // native, own address, chain id 196 / 9745 / 999 at the chain-id slot).\n \"eip155:196\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n \"eip155:9745\": [\"0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9\"],\n \"eip155:999\": [\"0xD84778bbeEC5D2a8d17c6424249C438EC0b1ABE3\"],\n};\n"],"mappings":";AAMO,IAAM,wCAAkE;AAAA,EAC7E,YAAY,CAAC,kDAAkD;AAAA,EAC/D,YAAY,CAAC,4CAA4C;AAAA,EACzD,aAAa,CAAC,4CAA4C;AAAA,EAC1D,cAAc,CAAC,4CAA4C;AAAA,EAC3D,eAAe,CAAC,4CAA4C;AAAA,EAC5D,eAAe,CAAC,4CAA4C;AAAA,EAC5D,gBAAgB,CAAC,4CAA4C;AAAA,EAC7D,gBAAgB,CAAC,4CAA4C;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7D,cAAc,CAAC,4CAA4C;AAAA,EAC3D,cAAc,CAAC,4CAA4C;AAAA,EAC3D,eAAe,CAAC,4CAA4C;AAC9D;AAYO,IAAM,uCAAiE;AAAA,EAC5E,YAAY,CAAC,4CAA4C;AAAA,EACzD,aAAa,CAAC,4CAA4C;AAAA,EAC1D,cAAc,CAAC,4CAA4C;AAAA,EAC3D,eAAe,CAAC,4CAA4C;AAAA,EAC5D,gBAAgB,CAAC,4CAA4C;AAAA,EAC7D,gBAAgB,CAAC,4CAA4C;AAAA;AAAA;AAAA,EAG7D,cAAc,CAAC,4CAA4C;AAAA,EAC3D,eAAe,CAAC,4CAA4C;AAAA,EAC5D,cAAc,CAAC,4CAA4C;AAC7D;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -438,6 +438,38 @@ function sameJetton(a, b) {
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
// src/validators/settlement.ts
|
|
442
|
+
var AUDITED_OMNISTON_SETTLEMENT_CONTRACTS = {
|
|
443
|
+
"ton:-239": ["EQAbWJ3Y1HgIIvcMq1prG1anlDC0T3cZlAU7luPT6LmTpmrZ"],
|
|
444
|
+
"eip155:1": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
445
|
+
"eip155:56": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
446
|
+
"eip155:137": ["0x41A392062A4307a6961d48e30FF20bF6823715B8"],
|
|
447
|
+
"eip155:4663": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
448
|
+
"eip155:8453": ["0xACa3E2F9b61a44892926bC6c3e104192E7D1c3cd"],
|
|
449
|
+
"eip155:42161": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
450
|
+
"eip155:43114": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
451
|
+
// 2026-10-20: one factory address on X Layer, HyperEVM and Plasma. Runtime
|
|
452
|
+
// bytecode equals Ethereum's 0xafCF… byte for byte except the immutable slots
|
|
453
|
+
// (escrow implementations, its order protocol, domain hash); it references
|
|
454
|
+
// the order protocol trusted below on the same chain.
|
|
455
|
+
"eip155:196": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
|
|
456
|
+
"eip155:999": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"],
|
|
457
|
+
"eip155:9745": ["0xd602079AFa5c38F550510a2a988CbFa698Fa0189"]
|
|
458
|
+
};
|
|
459
|
+
var AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS = {
|
|
460
|
+
"eip155:1": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
461
|
+
"eip155:56": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
462
|
+
"eip155:137": ["0xafCF681272AF10959736f45616eeCBC22D7095E2"],
|
|
463
|
+
"eip155:8453": ["0xe7405fAcDEDB2512e91F2886BDff13231343aF5E"],
|
|
464
|
+
"eip155:42161": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
465
|
+
"eip155:43114": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
466
|
+
// 2026-10-20: bytecode equals Ethereum's 0xb581… except immutables (wrapped
|
|
467
|
+
// native, own address, chain id 196 / 9745 / 999 at the chain-id slot).
|
|
468
|
+
"eip155:196": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
469
|
+
"eip155:9745": ["0xb5810aCfD45D85Eaa938bF90a5857295513DA7E9"],
|
|
470
|
+
"eip155:999": ["0xD84778bbeEC5D2a8d17c6424249C438EC0b1ABE3"]
|
|
471
|
+
};
|
|
472
|
+
|
|
441
473
|
// src/provider.ts
|
|
442
474
|
var import_core4 = require("@anywalletkit/core");
|
|
443
475
|
var EVM_CASE = {
|
|
@@ -516,18 +548,36 @@ function toChainAddress(caip2, address) {
|
|
|
516
548
|
if (!$case) return null;
|
|
517
549
|
return { chain: { $case, value: (0, import_viem.getAddress)(address) } };
|
|
518
550
|
}
|
|
519
|
-
|
|
520
|
-
|
|
551
|
+
var QUOTE_DIGEST_SKIP = /* @__PURE__ */ new Set(["rfqId", "resolverName", "estimatedSettlementDuration", "estimatedGasConsumption"]);
|
|
552
|
+
function canonicalJson(value) {
|
|
553
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
554
|
+
if (value && typeof value === "object") {
|
|
555
|
+
return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`).join(",")}}`;
|
|
556
|
+
}
|
|
557
|
+
return JSON.stringify(value) ?? "null";
|
|
558
|
+
}
|
|
559
|
+
function quoteDigest(q) {
|
|
560
|
+
const terms = JSON.parse(JSON.stringify(q));
|
|
561
|
+
for (const key of QUOTE_DIGEST_SKIP) delete terms[key];
|
|
562
|
+
return (0, import_viem.sha256)(new TextEncoder().encode(canonicalJson(terms))).slice(2, 34);
|
|
563
|
+
}
|
|
564
|
+
var QUOTE_DIGEST = /^[0-9a-f]{32}$/;
|
|
565
|
+
function encodeIntent(quoteId, trader, dest, srcChain, kind, digest) {
|
|
566
|
+
return [INTENT_PREFIX, quoteId, trader, `${dest}#${digest}`, srcChain, ...kind === "swap" ? ["swap"] : []].map(encodeURIComponent).join("|");
|
|
521
567
|
}
|
|
522
568
|
var QUOTE_ID = /^[0-9a-fA-F]{48,64}$/;
|
|
523
569
|
function decodeIntent(intentId) {
|
|
524
570
|
try {
|
|
525
571
|
const parts = intentId.split("|");
|
|
526
572
|
if (parts.length !== 5 && parts.length !== 6 || parts[0] !== INTENT_PREFIX) return null;
|
|
527
|
-
const [, quoteId = "", trader = "",
|
|
573
|
+
const [, quoteId = "", trader = "", destPart = "", srcChain = "", kindPart = ""] = parts.map(decodeURIComponent);
|
|
574
|
+
const mark = destPart.lastIndexOf("#");
|
|
575
|
+
const dest = mark < 0 ? destPart : destPart.slice(0, mark);
|
|
576
|
+
const digest = mark < 0 ? void 0 : destPart.slice(mark + 1);
|
|
577
|
+
if (digest !== void 0 && !QUOTE_DIGEST.test(digest)) return null;
|
|
528
578
|
if (!QUOTE_ID.test(quoteId) || !trader || !dest || !srcChain) return null;
|
|
529
579
|
if (parts.length === 6 && kindPart !== "swap") return null;
|
|
530
|
-
return { quoteId, trader, dest, srcChain, kind: parts.length === 6 ? "swap" : "order" };
|
|
580
|
+
return { quoteId, trader, dest, srcChain, kind: parts.length === 6 ? "swap" : "order", ...digest ? { digest } : {} };
|
|
531
581
|
} catch {
|
|
532
582
|
return null;
|
|
533
583
|
}
|
|
@@ -648,9 +698,9 @@ function validEvmAddress(value) {
|
|
|
648
698
|
}
|
|
649
699
|
}
|
|
650
700
|
var EVM_DEST_PROTOCOL_FEE_RECIPIENTS = /* @__PURE__ */ new Set(["0x076268146b4ec6d21fc49c27586cfa91b9079a00"]);
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
701
|
+
var EVM_AUCTION_POINTS = [[800000n, 100n], [700000n, 100n], [600000n, 100n], [500000n, 100n], [400000n, 100n]];
|
|
702
|
+
var EVM_TIMELOCKS = [1n, 120n, 240n, 300n, 1n, 120n, 180n, 0n].reduce((packed, value, index) => packed | value << BigInt(index * 32), 0n);
|
|
703
|
+
function readEvmOrderExtension(extension) {
|
|
654
704
|
if (extension.length < 32) throw new Error("omniston: malformed EVM order extension");
|
|
655
705
|
const view = new DataView(extension.buffer, extension.byteOffset, extension.byteLength);
|
|
656
706
|
const fields = [];
|
|
@@ -670,54 +720,48 @@ async function validateEvmToTonOrderExtension(extension, expected) {
|
|
|
670
720
|
}
|
|
671
721
|
let target;
|
|
672
722
|
for (const index of [2, 3, 7]) {
|
|
673
|
-
const
|
|
674
|
-
if (
|
|
675
|
-
const address = (0, import_viem.getAddress)(`0x${bytesToHex(
|
|
676
|
-
if (
|
|
723
|
+
const field2 = fields[index];
|
|
724
|
+
if (field2.length <= 20) throw new Error("omniston: incomplete EVM order extension program");
|
|
725
|
+
const address = (0, import_viem.getAddress)(`0x${bytesToHex(field2.slice(0, 20))}`);
|
|
726
|
+
if (target !== void 0 && (0, import_viem.getAddress)(target) !== address) {
|
|
677
727
|
throw new Error("omniston: EVM order extension target is not independently trusted");
|
|
678
728
|
}
|
|
679
729
|
target = address;
|
|
680
730
|
}
|
|
681
|
-
const
|
|
731
|
+
const field = fields[2];
|
|
682
732
|
let cursor = 20;
|
|
683
|
-
const gasBump = readBigEndian(
|
|
733
|
+
const gasBump = readBigEndian(field, cursor, 3);
|
|
684
734
|
cursor += 3;
|
|
685
|
-
const gasPrice = readBigEndian(
|
|
735
|
+
const gasPrice = readBigEndian(field, cursor, 4);
|
|
686
736
|
cursor += 4;
|
|
687
|
-
const auctionStart = readBigEndian(
|
|
737
|
+
const auctionStart = readBigEndian(field, cursor, 4);
|
|
688
738
|
cursor += 4;
|
|
689
|
-
const duration = readBigEndian(
|
|
739
|
+
const duration = readBigEndian(field, cursor, 3);
|
|
690
740
|
cursor += 3;
|
|
691
|
-
const initialRateBump = readBigEndian(
|
|
741
|
+
const initialRateBump = readBigEndian(field, cursor, 3);
|
|
692
742
|
cursor += 3;
|
|
693
|
-
const pointCount = (0, import_core4.bigintToNumber)(readBigEndian(
|
|
743
|
+
const pointCount = (0, import_core4.bigintToNumber)(readBigEndian(field, cursor, 1));
|
|
694
744
|
cursor += 1;
|
|
695
745
|
if (pointCount !== 5) throw new Error("omniston: unsupported EVM auction profile");
|
|
696
746
|
const points = [];
|
|
697
747
|
for (let index = 0; index < pointCount; index++) {
|
|
698
|
-
points.push([readBigEndian(
|
|
748
|
+
points.push([readBigEndian(field, cursor, 3), readBigEndian(field, cursor + 3, 2)]);
|
|
699
749
|
cursor += 5;
|
|
700
750
|
}
|
|
701
|
-
const integratorFee = readBigEndian(
|
|
751
|
+
const integratorFee = readBigEndian(field, cursor, 2);
|
|
702
752
|
cursor += 2;
|
|
703
|
-
const integratorShare = readBigEndian(
|
|
753
|
+
const integratorShare = readBigEndian(field, cursor, 1);
|
|
704
754
|
cursor += 1;
|
|
705
|
-
const resolverFee = readBigEndian(
|
|
755
|
+
const resolverFee = readBigEndian(field, cursor, 2);
|
|
706
756
|
cursor += 2;
|
|
707
|
-
const whitelistDiscount = readBigEndian(
|
|
757
|
+
const whitelistDiscount = readBigEndian(field, cursor, 1);
|
|
708
758
|
cursor += 1;
|
|
709
|
-
const getterWhitelistCount = (0, import_core4.bigintToNumber)(readBigEndian(
|
|
759
|
+
const getterWhitelistCount = (0, import_core4.bigintToNumber)(readBigEndian(field, cursor, 1));
|
|
710
760
|
cursor += 1;
|
|
711
|
-
if (getterWhitelistCount !== 1 || cursor + getterWhitelistCount * 10 !==
|
|
761
|
+
if (getterWhitelistCount !== 1 || cursor + getterWhitelistCount * 10 !== field.length) {
|
|
712
762
|
throw new Error("omniston: malformed EVM amount-getter whitelist");
|
|
713
763
|
}
|
|
714
|
-
const
|
|
715
|
-
const expectedPoints = [[800000n, 100n], [700000n, 100n], [600000n, 100n], [500000n, 100n], [400000n, 100n]];
|
|
716
|
-
const quoteResolverFee = expected.protocolFeePips % 10 === 0 ? BigInt(expected.protocolFeePips / 10) : -1n;
|
|
717
|
-
const resolverLow80 = BigInt((0, import_viem.getAddress)(expected.initialResolverAddress)) & (1n << 80n) - 1n;
|
|
718
|
-
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) {
|
|
719
|
-
throw new Error("omniston: EVM amount-getter terms do not match the pinned v1beta8 profile");
|
|
720
|
-
}
|
|
764
|
+
const getter = { gasBump, gasPrice, auctionStart, duration, initialRateBump, points, integratorFee, integratorShare, resolverFee, whitelistDiscount, resolver: readBigEndian(field, cursor, 10) };
|
|
721
765
|
const post = fields[7];
|
|
722
766
|
cursor = 20;
|
|
723
767
|
const integratorRecipient = post.slice(cursor, cursor + 20);
|
|
@@ -743,28 +787,51 @@ async function validateEvmToTonOrderExtension(extension, expected) {
|
|
|
743
787
|
cursor += 10;
|
|
744
788
|
const resolverTimeDelta = readBigEndian(post, cursor, 2);
|
|
745
789
|
cursor += 2;
|
|
746
|
-
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) {
|
|
747
|
-
throw new Error("omniston: EVM post-interaction terms do not match the pinned v1beta8 profile");
|
|
748
|
-
}
|
|
749
790
|
const extra = Array.from({ length: 5 }, () => {
|
|
750
791
|
const value = readBigEndian(post, cursor, 32);
|
|
751
792
|
cursor += 32;
|
|
752
793
|
return value;
|
|
753
794
|
});
|
|
795
|
+
const customData = extension.slice(32 + begin);
|
|
796
|
+
if (customData.length !== 131) throw new Error("omniston: malformed EVM order extension custom data");
|
|
797
|
+
return {
|
|
798
|
+
target,
|
|
799
|
+
getter,
|
|
800
|
+
post: { integratorRecipient, protocolRecipient, integratorFee: postIntegratorFee, integratorShare: postIntegratorShare, resolverFee: postResolverFee, discount: postDiscount, allowedTime, resolver: postResolver, resolverTimeDelta },
|
|
801
|
+
extra,
|
|
802
|
+
customData
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
async function validateEvmToTonOrderExtension(extension, expected) {
|
|
806
|
+
const evmDest = expected.dstChainId !== void 0;
|
|
807
|
+
if (evmDest && (!Number.isSafeInteger(expected.dstChainId) || expected.dstChainId <= 0)) throw new Error("omniston: invalid EVM destination chain id");
|
|
808
|
+
const { target, getter, post, extra, customData } = readEvmOrderExtension(extension);
|
|
809
|
+
if (!expected.trustedTarget(target)) throw new Error("omniston: EVM order extension target is not independently trusted");
|
|
810
|
+
const quoteResolverFee = expected.protocolFeePips % 10 === 0 ? BigInt(expected.protocolFeePips / 10) : -1n;
|
|
811
|
+
const resolverLow80 = BigInt((0, import_viem.getAddress)(expected.initialResolverAddress)) & (1n << 80n) - 1n;
|
|
812
|
+
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) {
|
|
813
|
+
throw new Error("omniston: EVM amount-getter terms do not match the pinned v1beta8 profile");
|
|
814
|
+
}
|
|
815
|
+
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) {
|
|
816
|
+
throw new Error("omniston: EVM post-interaction terms do not match the pinned v1beta8 profile");
|
|
817
|
+
}
|
|
754
818
|
const hashlock2 = readBigEndian(expected.secretHash, 0, expected.secretHash.length);
|
|
755
819
|
const dstToken = evmDest ? BigInt((0, import_viem.getAddress)(expected.outputTokenAddress)) : BigInt((0, import_viem.getAddress)(expected.takerAsset));
|
|
756
820
|
const deposits = BigInt(expected.srcSecurityDepositUnits) << 128n | BigInt(expected.dstSecurityDepositUnits);
|
|
757
|
-
|
|
758
|
-
if (expected.secretHash.length !== 32 || extra[0] !== hashlock2 || extra[1] !== (evmDest ? BigInt(expected.dstChainId) : 0n) || extra[2] !== dstToken || extra[3] !== deposits || extra[4] !== timelocks) {
|
|
821
|
+
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) {
|
|
759
822
|
throw new Error("omniston: signed EVM HTLC terms do not match the validated order details");
|
|
760
823
|
}
|
|
761
|
-
|
|
762
|
-
if (
|
|
763
|
-
|
|
824
|
+
await checkOrderCustomData(customData, { evmDest, outputToken: expected.outputTokenAddress, traderDst: expected.traderDstAddress, quoteId: expected.quoteId });
|
|
825
|
+
if (expected.tradeStartDeadline < expected.quoteTimestamp) {
|
|
826
|
+
throw new Error("omniston: invalid EVM order quote deadline");
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
async function checkOrderCustomData(customData, expected) {
|
|
830
|
+
if (expected.evmDest) {
|
|
764
831
|
if (!zeroBytes(customData.slice(0, 66))) throw new Error("omniston: unexpected TON addresses in an EVM-destination order");
|
|
765
832
|
} else {
|
|
766
833
|
const { Address: Address3 } = await import("@ton/core");
|
|
767
|
-
const expectedTon = [expected.
|
|
834
|
+
const expectedTon = [expected.outputToken, expected.traderDst].map((value) => Address3.parse(value));
|
|
768
835
|
for (let index = 0; index < expectedTon.length; index++) {
|
|
769
836
|
const offset = index * 33;
|
|
770
837
|
const workchain = customData[offset] === 255 ? -1 : customData[offset];
|
|
@@ -780,9 +847,6 @@ async function validateEvmToTonOrderExtension(extension, expected) {
|
|
|
780
847
|
if (!QUOTE_ID.test(quoteId) || !sliceEqual(customData.slice(99), hexToBytes(quoteId.padStart(64, "0")))) {
|
|
781
848
|
throw new Error("omniston: EVM order extension custom data is not bound to the quote id");
|
|
782
849
|
}
|
|
783
|
-
if (expected.tradeStartDeadline < expected.quoteTimestamp) {
|
|
784
|
-
throw new Error("omniston: invalid EVM order quote deadline");
|
|
785
|
-
}
|
|
786
850
|
}
|
|
787
851
|
function validateEvmTypedOrder(td, expected) {
|
|
788
852
|
const value = td;
|
|
@@ -1234,8 +1298,101 @@ function omnistonPins(trustedEvmOrderProtocols) {
|
|
|
1234
1298
|
const byChain = new Map(Object.entries(trustedEvmOrderProtocols).map(([chain, list]) => [chain, list.map((a) => (0, import_viem.getAddress)(a))]));
|
|
1235
1299
|
return Object.freeze({ callTargets: () => [], spenders: (chain) => byChain.get(chain) ?? [] });
|
|
1236
1300
|
}
|
|
1301
|
+
var MAX_EVM_ORDER_LIFETIME_S = 900;
|
|
1302
|
+
async function checkRemoteEvmOrder(quote, tx, params, trusted) {
|
|
1303
|
+
const chainId = evmRef2(params.sourceChain);
|
|
1304
|
+
if (chainId === null || !params.sourceChain.startsWith("eip155:")) return "a typed order needs an EVM source";
|
|
1305
|
+
const intent = decodeIntent(quote.intentId.replace(/~[0-9a-f]{32}$/, ""));
|
|
1306
|
+
if (!intent || intent.kind !== "order" || intent.srcChain !== params.sourceChain) return "the quote's intent is not an order from this chain";
|
|
1307
|
+
if (!tx.orderExtension || !/^0x(?:[0-9a-fA-F]{2})+$/.test(tx.orderExtension)) return "the build carries no order extension to check";
|
|
1308
|
+
const source = (0, import_swap2_assets.ccAsset)(params.sourceChain, params.sourceToken);
|
|
1309
|
+
if (!source?.contract) return "unknown source token";
|
|
1310
|
+
const tonDest = isTon(params.destChain);
|
|
1311
|
+
const destChainId = tonDest ? null : evmRef2(params.destChain);
|
|
1312
|
+
if (!tonDest && (destChainId === null || !params.destChain.startsWith("eip155:"))) return "the destination is neither TON nor an EVM chain";
|
|
1313
|
+
const outputToken = (0, import_swap2_assets.ccAssetByToken)(params.destChain, params.destToken)?.contract ?? params.destToken;
|
|
1314
|
+
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));
|
|
1315
|
+
let td;
|
|
1316
|
+
try {
|
|
1317
|
+
td = JSON.parse(tx.typedData ?? "");
|
|
1318
|
+
} catch {
|
|
1319
|
+
return "the typed data is not JSON";
|
|
1320
|
+
}
|
|
1321
|
+
const domain = td.domain ?? {};
|
|
1322
|
+
const contract = domain.verifyingContract;
|
|
1323
|
+
if (domain.name !== "1inch Limit Order Protocol" || domain.version !== "4") return "the domain is not the 1inch Limit Order Protocol v4";
|
|
1324
|
+
if (!listed(trusted.orderProtocols, params.sourceChain, contract) || !tx.approvalAddress || (0, import_viem.getAddress)(tx.approvalAddress) !== (0, import_viem.getAddress)(String(contract))) {
|
|
1325
|
+
return `${String(contract)} is not a trusted order protocol on ${params.sourceChain}`;
|
|
1326
|
+
}
|
|
1327
|
+
if (Number(domain.chainId) !== chainId || tx.chainId !== void 0 && tx.chainId !== chainId) return "the domain chainId is not the source chain";
|
|
1328
|
+
const order = td.types?.Order;
|
|
1329
|
+
const message = td.message;
|
|
1330
|
+
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]))) {
|
|
1331
|
+
return "the typed data is not exactly a v4 Order";
|
|
1332
|
+
}
|
|
1333
|
+
if (!validEvmAddress(intent.trader) || (0, import_viem.getAddress)(String(message.maker)) !== (0, import_viem.getAddress)(intent.trader)) return "the maker is not the trader";
|
|
1334
|
+
if ((0, import_viem.getAddress)(String(message.makerAsset)) !== (0, import_viem.getAddress)(source.contract)) return "the makerAsset is not the source token";
|
|
1335
|
+
if (BigInt(message.makingAmount) !== BigInt(quote.sourceAmount)) return "the makingAmount is not the input";
|
|
1336
|
+
if ((0, import_viem.getAddress)(String(message.takerAsset)) === (0, import_viem.getAddress)(String(message.makerAsset))) return "the takerAsset is the makerAsset";
|
|
1337
|
+
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);
|
|
1338
|
+
if (floor <= 0n || BigInt(message.takingAmount) < floor) return `takingAmount ${String(message.takingAmount)} is below the quote's minimum ${floor}`;
|
|
1339
|
+
const traits = BigInt(message.makerTraits);
|
|
1340
|
+
const flags = traits & (1n << 56n) - 1n << 200n;
|
|
1341
|
+
const baseFlags = 1n << 251n | 1n << 249n;
|
|
1342
|
+
if (flags !== baseFlags && flags !== (baseFlags | 1n << 255n)) return "the makerTraits flags are not a single-fill order with its extension";
|
|
1343
|
+
if ((traits & (1n << 80n) - 1n) !== 0n || (traits >> 160n & (1n << 40n) - 1n) !== 0n) return "the makerTraits restrict the taker or the series";
|
|
1344
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1345
|
+
const expiration = traits >> 80n & (1n << 40n) - 1n;
|
|
1346
|
+
if (expiration <= now || expiration > now + BigInt(MAX_EVM_ORDER_LIFETIME_S)) return "the order's expiry is not minutes away";
|
|
1347
|
+
const extension = (0, import_viem.hexToBytes)(tx.orderExtension);
|
|
1348
|
+
const mask = (1n << 160n) - 1n;
|
|
1349
|
+
if ((BigInt(message.salt) & mask) !== (BigInt((0, import_viem.keccak256)(extension)) & mask)) return "the salt does not commit the order extension";
|
|
1350
|
+
let parsed;
|
|
1351
|
+
try {
|
|
1352
|
+
parsed = readEvmOrderExtension(extension);
|
|
1353
|
+
} catch (e) {
|
|
1354
|
+
return e instanceof Error ? e.message.replace(/^omniston: /, "") : String(e);
|
|
1355
|
+
}
|
|
1356
|
+
const { target, getter, post, extra, customData } = parsed;
|
|
1357
|
+
if (!listed(trusted.factories, params.sourceChain, target)) return `the extension targets ${target}, not a trusted escrow factory on ${params.sourceChain}`;
|
|
1358
|
+
const receiverLow80 = BigInt((0, import_viem.getAddress)(String(message.receiver))) & (1n << 80n) - 1n;
|
|
1359
|
+
if (getter.resolver !== receiverLow80 || post.resolver !== receiverLow80) return "the order's receiver is not the resolver its extension whitelists";
|
|
1360
|
+
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)) {
|
|
1361
|
+
return "the amount-getter terms do not match the pinned v1beta8 profile";
|
|
1362
|
+
}
|
|
1363
|
+
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)) {
|
|
1364
|
+
return "the post-interaction terms do not match the pinned v1beta8 profile";
|
|
1365
|
+
}
|
|
1366
|
+
let dstToken;
|
|
1367
|
+
try {
|
|
1368
|
+
dstToken = tonDest ? BigInt((0, import_viem.getAddress)(String(message.takerAsset))) : BigInt((0, import_viem.getAddress)(outputToken));
|
|
1369
|
+
} catch {
|
|
1370
|
+
return "the destination token is not an EVM address";
|
|
1371
|
+
}
|
|
1372
|
+
if (extra[1] !== (tonDest ? 0n : BigInt(destChainId)) || extra[2] !== dstToken || extra[4] !== EVM_TIMELOCKS) {
|
|
1373
|
+
return "the signed HTLC terms name another destination chain or token, or other timelocks";
|
|
1374
|
+
}
|
|
1375
|
+
try {
|
|
1376
|
+
await checkOrderCustomData(customData, { evmDest: !tonDest, outputToken, traderDst: params.destAddress, quoteId: intent.quoteId });
|
|
1377
|
+
} catch (e) {
|
|
1378
|
+
return e instanceof Error ? e.message.replace(/^omniston: /, "") : String(e);
|
|
1379
|
+
}
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1237
1382
|
function omnistonVerifyBuild(hooks) {
|
|
1383
|
+
const trusted = {
|
|
1384
|
+
orderProtocols: hooks.trustedEvmOrderProtocols ?? AUDITED_OMNISTON_EVM_ORDER_PROTOCOLS,
|
|
1385
|
+
factories: hooks.trustedSettlementContracts ?? AUDITED_OMNISTON_SETTLEMENT_CONTRACTS
|
|
1386
|
+
};
|
|
1238
1387
|
return async (quote, tx, params) => {
|
|
1388
|
+
if (tx.typedData !== void 0) {
|
|
1389
|
+
if (!params) return "the request this quote answered is unknown";
|
|
1390
|
+
try {
|
|
1391
|
+
return await checkRemoteEvmOrder(quote, tx, params, trusted);
|
|
1392
|
+
} catch {
|
|
1393
|
+
return "the typed order could not be checked";
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1239
1396
|
if (tx.bodyBoc === void 0) return null;
|
|
1240
1397
|
if (!params) return "the request this quote answered is unknown";
|
|
1241
1398
|
if (quote.providerData?.settlement !== "swap") {
|
|
@@ -1296,16 +1453,15 @@ function omnistonVerifyBuild(hooks) {
|
|
|
1296
1453
|
} catch {
|
|
1297
1454
|
return "the swap target could not be checked";
|
|
1298
1455
|
}
|
|
1299
|
-
if (hooks.validateTonSwapLeg)
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
}
|
|
1307
|
-
if (!ok) return `${leg.kind} v${leg.version} leg not verified`;
|
|
1456
|
+
if (!hooks.validateTonSwapLeg) return "a TON swap body needs validateTonSwapLeg (createOmnistonTonValidators)";
|
|
1457
|
+
for (const leg of checked.legs) {
|
|
1458
|
+
let ok = false;
|
|
1459
|
+
try {
|
|
1460
|
+
ok = await hooks.validateTonSwapLeg(leg);
|
|
1461
|
+
} catch {
|
|
1462
|
+
ok = false;
|
|
1308
1463
|
}
|
|
1464
|
+
if (!ok) return `${leg.kind} v${leg.version} leg not verified`;
|
|
1309
1465
|
}
|
|
1310
1466
|
return null;
|
|
1311
1467
|
};
|
|
@@ -1442,7 +1598,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1442
1598
|
return true;
|
|
1443
1599
|
}
|
|
1444
1600
|
const a = existing.bound, b = entry.bound;
|
|
1445
|
-
const same = !!a && !!b && a.kind === b.kind && a.srcChain === b.srcChain && sameIntentAddress(a.trader, b.trader) && sameIntentAddress(a.dest, b.dest);
|
|
1601
|
+
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);
|
|
1446
1602
|
if (!same) return false;
|
|
1447
1603
|
await quotes.save(quoteId, json);
|
|
1448
1604
|
return true;
|
|
@@ -1495,10 +1651,19 @@ function omnistonProvider(opts = {}) {
|
|
|
1495
1651
|
throw new Error(`omniston: intent id does not match the quote it was issued for (${bound.field})`);
|
|
1496
1652
|
}
|
|
1497
1653
|
if (bound.legacy) trace("legacy-intent", { where });
|
|
1654
|
+
if (!decoded.digest) {
|
|
1655
|
+
trace("intent-mismatch", { where, field: "digest-missing" });
|
|
1656
|
+
throw new Error("omniston: this quote was issued before an update \u2014 request a fresh quote");
|
|
1657
|
+
}
|
|
1658
|
+
if (decoded.digest !== quoteDigest(entry.quote)) {
|
|
1659
|
+
trace("intent-mismatch", { where, field: "digest" });
|
|
1660
|
+
throw new Error("omniston: quote was replaced \u2014 request a fresh quote");
|
|
1661
|
+
}
|
|
1498
1662
|
return bound.ref;
|
|
1499
1663
|
}
|
|
1500
1664
|
const bindKey = (quoteId) => `${quoteId}#bind`;
|
|
1501
1665
|
const disclosedKey = (quoteId) => `${quoteId}#disclosed`;
|
|
1666
|
+
const disclosedIndicesKey = (quoteId) => `${quoteId}#disclosed-indices`;
|
|
1502
1667
|
function orderBinding(ref, q) {
|
|
1503
1668
|
return (0, import_viem.sha256)(new TextEncoder().encode(JSON.stringify([
|
|
1504
1669
|
ref.quoteId,
|
|
@@ -1515,6 +1680,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1515
1680
|
await store.clear(quoteId);
|
|
1516
1681
|
await store.clear(bindKey(quoteId));
|
|
1517
1682
|
await store.clear(disclosedKey(quoteId));
|
|
1683
|
+
await store.clear(disclosedIndicesKey(quoteId));
|
|
1518
1684
|
}
|
|
1519
1685
|
async function secretsFor(ref, q, count) {
|
|
1520
1686
|
const quoteId = ref.quoteId;
|
|
@@ -1543,7 +1709,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1543
1709
|
return !!existing && existing.length > 0;
|
|
1544
1710
|
}
|
|
1545
1711
|
const SWAP_SLIPPAGE_PIPS_DEFAULT = 5e3;
|
|
1546
|
-
const sameChainTonReady = () => typeof opts.validateTonJettonWallet === "function" && typeof opts.validateTonSwapTarget === "function";
|
|
1712
|
+
const sameChainTonReady = () => typeof opts.validateTonJettonWallet === "function" && typeof opts.validateTonSwapTarget === "function" && (typeof opts.validateTonSwapLeg === "function" || opts.tonSwapPayloadCheck === "report");
|
|
1547
1713
|
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";
|
|
1548
1714
|
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";
|
|
1549
1715
|
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";
|
|
@@ -1622,7 +1788,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1622
1788
|
const feeUsd = stableOut ? feeUnits / 10 ** dest.decimals : 0;
|
|
1623
1789
|
return {
|
|
1624
1790
|
provider: "omniston",
|
|
1625
|
-
intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "swap"),
|
|
1791
|
+
intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "swap", quoteDigest(q)),
|
|
1626
1792
|
depositAddress: "",
|
|
1627
1793
|
// swap settlement — the built message pays the DEX directly
|
|
1628
1794
|
depositMemo: null,
|
|
@@ -1655,7 +1821,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1655
1821
|
if (!isTon(ref.srcChain) || q.inputAsset.chain.$case !== "ton" || q.outputAsset.chain.$case !== "ton") {
|
|
1656
1822
|
throw new Error("omniston: swap quote is not a TON same-chain swap");
|
|
1657
1823
|
}
|
|
1658
|
-
if (!sameChainTonReady()) throw new Error("omniston: TON same-chain swaps need independent jetton-wallet and swap-
|
|
1824
|
+
if (!sameChainTonReady()) throw new Error("omniston: TON same-chain swaps need independent jetton-wallet, swap-target and swap-leg validators");
|
|
1659
1825
|
const owner = { chain: { $case: "ton", value: ref.trader } };
|
|
1660
1826
|
const receiver = { chain: { $case: "ton", value: ref.dest } };
|
|
1661
1827
|
const omni = await getClient();
|
|
@@ -1754,7 +1920,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1754
1920
|
}
|
|
1755
1921
|
if (checked) {
|
|
1756
1922
|
if (typeof opts.validateTonSwapLeg !== "function") {
|
|
1757
|
-
|
|
1923
|
+
payloadRefusal("legs-unverified", `no validateTonSwapLeg hook for ${checked.legs.length} leg(s)`);
|
|
1758
1924
|
} else {
|
|
1759
1925
|
for (const leg of checked.legs) {
|
|
1760
1926
|
let ok = false;
|
|
@@ -1925,7 +2091,7 @@ function omnistonProvider(opts = {}) {
|
|
|
1925
2091
|
}
|
|
1926
2092
|
});
|
|
1927
2093
|
const orderProtocol = (0, import_viem.getAddress)(protocol.chain.value);
|
|
1928
|
-
return { chain: srcChain, to: orderProtocol, value: "0", chainId, approvalAddress: orderProtocol, typedData };
|
|
2094
|
+
return { chain: srcChain, to: orderProtocol, value: "0", chainId, approvalAddress: orderProtocol, typedData, orderExtension: `0x${bytesToHex(payload.orderExtension)}` };
|
|
1929
2095
|
}
|
|
1930
2096
|
return {
|
|
1931
2097
|
name: "omniston",
|
|
@@ -2034,13 +2200,13 @@ function omnistonProvider(opts = {}) {
|
|
|
2034
2200
|
if (outputScaled * 2n < inputScaled || outputScaled > inputScaled * 2n) return refuse2("quoted output is outside 0.5x\u20132x of the input");
|
|
2035
2201
|
if (await quoteIdInUse(q.quoteId)) return refuse2("the platform reused a quote id that already belongs to an order");
|
|
2036
2202
|
if (!await claimBuilt(q.quoteId, { quote: q, at: Date.now(), bound: { trader, dest: params.destAddress, srcChain: params.sourceChain, kind: "order" } })) {
|
|
2037
|
-
return refuse2("the platform reused a quote id that already holds another
|
|
2203
|
+
return refuse2("the platform reused a quote id that already holds another quote");
|
|
2038
2204
|
}
|
|
2039
2205
|
const feeUnits = Number(q.protocolFeeUnits || "0") + Number(q.integratorFeeUnits || "0");
|
|
2040
2206
|
const feeUsd = feeUnits / 10 ** dest.decimals;
|
|
2041
2207
|
return {
|
|
2042
2208
|
provider: "omniston",
|
|
2043
|
-
intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain),
|
|
2209
|
+
intentId: encodeIntent(q.quoteId, trader, params.destAddress, params.sourceChain, "order", quoteDigest(q)),
|
|
2044
2210
|
depositAddress: "",
|
|
2045
2211
|
// order settlement — no static deposit address
|
|
2046
2212
|
depositMemo: null,
|
|
@@ -2212,6 +2378,7 @@ function omnistonProvider(opts = {}) {
|
|
|
2212
2378
|
);
|
|
2213
2379
|
if (!order) return { state: "pending" };
|
|
2214
2380
|
let secretsHex = await store.load(decoded.quoteId);
|
|
2381
|
+
const storedSecrets = secretsHex?.length ?? 0;
|
|
2215
2382
|
if (!secretsHex || cached?.quote.settlementData.$case !== "order") trace("disclosure-skipped", { gate: "context", secrets: !!secretsHex, cached: !!cached, feedStatus: order.status });
|
|
2216
2383
|
if (secretsHex && cached?.quote.settlementData.$case === "order") {
|
|
2217
2384
|
const [lockedTo] = await store.load(bindKey(decoded.quoteId)) ?? [];
|
|
@@ -2220,6 +2387,7 @@ function omnistonProvider(opts = {}) {
|
|
|
2220
2387
|
secretsHex = void 0;
|
|
2221
2388
|
}
|
|
2222
2389
|
}
|
|
2390
|
+
const disclosedNow = /* @__PURE__ */ new Set();
|
|
2223
2391
|
if (secretsHex && cached?.quote.settlementData.$case === "order") {
|
|
2224
2392
|
const q = cached.quote;
|
|
2225
2393
|
const settlement = q.settlementData.value;
|
|
@@ -2318,11 +2486,15 @@ function omnistonProvider(opts = {}) {
|
|
|
2318
2486
|
}
|
|
2319
2487
|
await omni.orderDiscloseHtlcSecret({ quoteId: decoded.quoteId, executionIndex: i, secret: secretBytes }).then(async () => {
|
|
2320
2488
|
trace("secret-disclosed", { index: i });
|
|
2489
|
+
disclosedNow.add(i);
|
|
2321
2490
|
await store.save(disclosedKey(decoded.quoteId), ["1"]);
|
|
2322
2491
|
}, (error) => trace("disclose-failed", { index: i, error: error instanceof Error ? error.message : String(error) }));
|
|
2323
2492
|
})
|
|
2324
2493
|
);
|
|
2325
2494
|
}
|
|
2495
|
+
const disclosedBefore = (await store.load(disclosedIndicesKey(decoded.quoteId)) ?? []).map(Number).filter(Number.isSafeInteger);
|
|
2496
|
+
const disclosedAll = /* @__PURE__ */ new Set([...disclosedBefore, ...disclosedNow]);
|
|
2497
|
+
if (disclosedNow.size > 0) await store.save(disclosedIndicesKey(decoded.quoteId), [...disclosedAll].sort((a, b) => a - b).map(String));
|
|
2326
2498
|
const status = mapOrderStatus(order);
|
|
2327
2499
|
const delivered = order.executions[0]?.outputPositionAddress;
|
|
2328
2500
|
const outCase = cached?.quote.outputAsset.chain.$case;
|
|
@@ -2347,6 +2519,14 @@ function omnistonProvider(opts = {}) {
|
|
|
2347
2519
|
}).catch(() => null);
|
|
2348
2520
|
if (hash) status.destTxHash = hash;
|
|
2349
2521
|
}
|
|
2522
|
+
if (status.state === "completed" && storedSecrets > 0 && !status.destTxHash) {
|
|
2523
|
+
const legacyDisclosed = disclosedBefore.length === 0 && storedSecrets === 1 && (await store.load(disclosedKey(decoded.quoteId)) ?? []).length > 0;
|
|
2524
|
+
const allDisclosed = legacyDisclosed || (order.executions.length > 0 ? order.executions.every((execution) => disclosedAll.has(execution.index)) : disclosedAll.size > 0);
|
|
2525
|
+
if (!allDisclosed) {
|
|
2526
|
+
trace("completion-unproven", { feedStatus: order.status, executions: order.executions.length, disclosed: disclosedAll.size });
|
|
2527
|
+
return { state: "pending", depositReceived: order.executions.length > 0 || disclosedAll.size > 0 };
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2350
2530
|
if (status.state === "completed") {
|
|
2351
2531
|
await clearSecrets(decoded.quoteId);
|
|
2352
2532
|
await quotes.clear(decoded.quoteId);
|