@morpho-dev/router 0.5.0 → 0.6.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.
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-Bo1DHCg-.mjs";
2
2
  import { z } from "zod/v4";
3
- import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashMessage, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, publicActions, recoverAddress, zeroAddress } from "viem";
3
+ import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, publicActions, recoverAddress, zeroAddress } from "viem";
4
4
  import { getBlock, getLogs, multicall } from "viem/actions";
5
5
  import { anvil, base, mainnet } from "viem/chains";
6
6
  import * as z$1 from "zod";
@@ -1372,6 +1372,7 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
1372
1372
  InvalidObligationError: () => InvalidObligationError,
1373
1373
  ObligationSchema: () => ObligationSchema,
1374
1374
  from: () => from$10,
1375
+ fromOffer: () => fromOffer$1,
1375
1376
  fromSnakeCase: () => fromSnakeCase$2,
1376
1377
  id: () => id,
1377
1378
  random: () => random$2
@@ -1500,6 +1501,21 @@ function random$2() {
1500
1501
  maturity: from$11("end_of_next_quarter")
1501
1502
  });
1502
1503
  }
1504
+ /**
1505
+ * Creates an obligation from an offer.
1506
+ * @constructor
1507
+ *
1508
+ * @param offer - The offer to create the obligation from.
1509
+ * @returns The created obligation. {@link fromOffer.ReturnType}
1510
+ */
1511
+ function fromOffer$1(offer) {
1512
+ return from$10({
1513
+ chainId: offer.chainId,
1514
+ loanToken: offer.loanToken,
1515
+ collaterals: offer.collaterals,
1516
+ maturity: offer.maturity
1517
+ });
1518
+ }
1503
1519
  var InvalidObligationError = class extends BaseError {
1504
1520
  constructor(error) {
1505
1521
  super("Invalid obligation.", { cause: error });
@@ -1513,273 +1529,22 @@ var CollateralsAreNotSortedError = class extends BaseError {
1513
1529
  }
1514
1530
  };
1515
1531
 
1516
- //#endregion
1517
- //#region src/core/Tree.ts
1518
- var Tree_exports = /* @__PURE__ */ __exportAll({
1519
- DecodeError: () => DecodeError,
1520
- EncodeError: () => EncodeError,
1521
- TreeError: () => TreeError,
1522
- VERSION: () => VERSION,
1523
- decode: () => decode$1,
1524
- encode: () => encode$1,
1525
- encodeUnsigned: () => encodeUnsigned,
1526
- from: () => from$9,
1527
- proofs: () => proofs
1528
- });
1529
- const VERSION = 1;
1530
- const normalizeHash = (hash) => hash.toLowerCase();
1531
- /**
1532
- * Builds a Merkle tree from a list of offers.
1533
- *
1534
- * Leaves are the offer `hash` values as `bytes32` and are deterministically
1535
- * ordered following the StandardMerkleTree leaf ordering so that the resulting
1536
- * root is stable regardless of the input order.
1537
- *
1538
- * @param offers - Offers to include in the tree.
1539
- * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
1540
- * @throws {TreeError} If tree building fails due to offer inconsistencies.
1541
- */
1542
- const from$9 = (offers) => {
1543
- const leaves = offers.map((offer) => [hash(offer)]);
1544
- const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
1545
- const orderedOffers = orderOffers(tree, offers);
1546
- return Object.assign(tree, { offers: orderedOffers });
1547
- };
1548
- const orderOffers = (tree, offers) => {
1549
- const offerByHash = /* @__PURE__ */ new Map();
1550
- for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
1551
- const entries = tree.dump().values.map((value) => {
1552
- const hash = normalizeHash(value.value[0]);
1553
- const offer = offerByHash.get(hash);
1554
- if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
1555
- return {
1556
- offer,
1557
- treeIndex: value.treeIndex
1558
- };
1559
- });
1560
- entries.sort((a, b) => b.treeIndex - a.treeIndex);
1561
- return entries.map((item) => item.offer);
1562
- };
1563
- /**
1564
- * Generates merkle proofs for all offers in a tree.
1565
- *
1566
- * Each proof allows independent verification that an offer is included in the tree
1567
- * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
1568
- *
1569
- * @param tree - The {@link Tree} to generate proofs for.
1570
- * @returns Array of proofs - {@link Proof}
1571
- */
1572
- const proofs = (tree) => {
1573
- return tree.offers.map((offer) => {
1574
- return {
1575
- offer,
1576
- path: tree.getProof([hash(offer)])
1577
- };
1578
- });
1579
- };
1580
- const assertHex = (value, expectedBytes, name) => {
1581
- if (typeof value !== "string" || !isHex(value)) throw new DecodeError(`${name} is not a valid hex string`);
1582
- if (hexToBytes(value).length !== expectedBytes) throw new DecodeError(`${name}: expected ${expectedBytes} bytes`);
1583
- };
1584
- const verifySignatureAndRecoverAddress = async (params) => {
1585
- const { root, signature } = params;
1586
- assertHex(signature, 65, "signature");
1587
- const hash = hashMessage({ raw: root });
1588
- try {
1589
- return await recoverAddress({
1590
- hash,
1591
- signature
1592
- });
1593
- } catch {
1594
- throw new DecodeError("signature recovery failed");
1595
- }
1596
- };
1597
- /**
1598
- * Encodes a merkle tree with signature into hex calldata for onchain broadcast.
1599
- *
1600
- * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
1601
- * - `{vv}`: 1-byte version (currently 0x01)
1602
- * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1603
- * - `{root}`: 32-byte merkle root
1604
- * - `{signature}`: 65-byte EIP-191 signature over raw root bytes
1605
- *
1606
- * Validates signature authenticity and root integrity before encoding.
1607
- *
1608
- * @example
1609
- * ```typescript
1610
- * const tree = Tree.from(offers);
1611
- * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1612
- * const calldata = await Tree.encode(tree, signature);
1613
- * await broadcast(calldata);
1614
- * ```
1615
- *
1616
- * @example
1617
- * Manual construction (for advanced users):
1618
- * ```typescript
1619
- * const tree = Tree.from(offers);
1620
- * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
1621
- * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
1622
- * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1623
- * const calldata = `${partial}${signature.slice(2)}`;
1624
- * ```
1625
- *
1626
- * @param tree - Merkle tree of offers
1627
- * @param signature - EIP-191 signature over raw root bytes
1628
- * @returns Hex-encoded calldata ready for onchain broadcast
1629
- * @throws {EncodeError} If signature verification fails or root mismatch
1630
- */
1631
- const encode$1 = async (tree, signature) => {
1632
- validateTreeForEncoding(tree);
1633
- await verifySignatureAndRecoverAddress({
1634
- root: tree.root,
1635
- signature
1636
- });
1637
- const unsigned = encodeUnsignedBytes(tree);
1638
- const sigBytes = hexToBytes(signature);
1639
- const encoded = new Uint8Array(unsigned.length + sigBytes.length);
1640
- encoded.set(unsigned, 0);
1641
- encoded.set(sigBytes, unsigned.length);
1642
- return bytesToHex(encoded);
1643
- };
1644
- /**
1645
- * Encodes a merkle tree without a signature into hex payload for client-side signing.
1646
- *
1647
- * Layout: `0x{vv}{gzip([...offers])}{root}` where:
1648
- * - `{vv}`: 1-byte version (currently 0x01)
1649
- * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1650
- * - `{root}`: 32-byte merkle root
1651
- *
1652
- * Validates root integrity before encoding.
1653
- *
1654
- * @param tree - Merkle tree of offers
1655
- * @returns Hex-encoded unsigned payload
1656
- * @throws {EncodeError} If root mismatch
1657
- */
1658
- const encodeUnsigned = (tree) => {
1659
- validateTreeForEncoding(tree);
1660
- return bytesToHex(encodeUnsignedBytes(tree));
1661
- };
1662
- const validateTreeForEncoding = (tree) => {
1663
- if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
1664
- const computed = from$9(tree.offers);
1665
- if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
1666
- };
1667
- const encodeUnsignedBytes = (tree) => {
1668
- const offersPayload = tree.offers.map(serialize);
1669
- const compressed = gzip(JSON.stringify(offersPayload));
1670
- const rootBytes = hexToBytes(tree.root);
1671
- const encoded = new Uint8Array(1 + compressed.length + 32);
1672
- encoded[0] = VERSION;
1673
- encoded.set(compressed, 1);
1674
- encoded.set(rootBytes, 1 + compressed.length);
1675
- return encoded;
1676
- };
1677
- /**
1678
- * Decodes hex calldata into a validated merkle tree.
1679
- *
1680
- * Validates signature before decompression for fail-fast rejection of invalid payloads.
1681
- * Returns the tree with separately validated signature and recovered signer address.
1682
- *
1683
- * Validation order:
1684
- * 1. Version check
1685
- * 2. Signature verification (fail-fast, before decompression)
1686
- * 3. Decompression (only if signature valid)
1687
- * 4. Root verification (computed from offers vs embedded root)
1688
- *
1689
- * @example
1690
- * ```typescript
1691
- * const { tree, signature, signer } = await Tree.decode(calldata);
1692
- * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
1693
- * ```
1694
- *
1695
- * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
1696
- * @returns Validated tree, signature, and recovered signer address
1697
- * @throws {DecodeError} If version invalid, signature invalid, or root mismatch
1698
- */
1699
- const decode$1 = async (encoded) => {
1700
- const bytes = hexToBytes(encoded);
1701
- if (bytes.length < 98) throw new DecodeError("payload too short");
1702
- const version = bytes[0];
1703
- if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
1704
- const signature = bytesToHex(bytes.slice(-65));
1705
- const root = bytesToHex(bytes.slice(-97, -65));
1706
- assertHex(root, 32, "root");
1707
- assertHex(signature, 65, "signature");
1708
- const signer = await verifySignatureAndRecoverAddress({
1709
- root,
1710
- signature
1711
- });
1712
- const compressed = bytes.slice(1, -97);
1713
- let decoded;
1714
- try {
1715
- decoded = ungzip(compressed, { to: "string" });
1716
- } catch {
1717
- throw new DecodeError("decompression failed");
1718
- }
1719
- let rawOffers;
1720
- try {
1721
- rawOffers = JSON.parse(decoded);
1722
- } catch {
1723
- throw new DecodeError("JSON parse failed");
1724
- }
1725
- const tree = from$9(rawOffers.map((o) => OfferSchema().parse(o)));
1726
- if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
1727
- return {
1728
- tree,
1729
- signature,
1730
- signer
1731
- };
1732
- };
1733
- /**
1734
- * Error thrown during tree building operations.
1735
- * Indicates structural issues with the tree (missing offers, inconsistent state).
1736
- */
1737
- var TreeError = class extends BaseError {
1738
- constructor(reason) {
1739
- super(`Tree error: ${reason}`);
1740
- _defineProperty(this, "name", "Tree.TreeError");
1741
- }
1742
- };
1743
- /**
1744
- * Error thrown during tree encoding.
1745
- * Indicates validation failures (signature, root mismatch, mixed makers).
1746
- */
1747
- var EncodeError = class extends BaseError {
1748
- constructor(reason) {
1749
- super(`Failed to encode tree: ${reason}`);
1750
- _defineProperty(this, "name", "Tree.EncodeError");
1751
- }
1752
- };
1753
- /**
1754
- * Error thrown during tree decoding.
1755
- * Indicates payload corruption, version mismatch, or validation failures.
1756
- */
1757
- var DecodeError = class extends BaseError {
1758
- constructor(reason) {
1759
- super(`Failed to decode tree: ${reason}`);
1760
- _defineProperty(this, "name", "Tree.DecodeError");
1761
- }
1762
- };
1763
-
1764
1532
  //#endregion
1765
1533
  //#region src/core/Offer.ts
1766
1534
  var Offer_exports = /* @__PURE__ */ __exportAll({
1767
- AccountNotSetError: () => AccountNotSetError,
1768
1535
  InvalidOfferError: () => InvalidOfferError,
1769
1536
  OfferSchema: () => OfferSchema,
1770
1537
  Status: () => Status,
1771
1538
  consumedEvent: () => consumedEvent,
1772
- decode: () => decode,
1539
+ decode: () => decode$1,
1773
1540
  domain: () => domain,
1774
- encode: () => encode,
1775
- from: () => from$8,
1541
+ encode: () => encode$1,
1542
+ from: () => from$9,
1776
1543
  fromSnakeCase: () => fromSnakeCase$1,
1777
1544
  hash: () => hash,
1778
1545
  obligationId: () => obligationId,
1779
1546
  random: () => random$1,
1780
1547
  serialize: () => serialize,
1781
- sign: () => sign,
1782
- signatureMsg: () => signatureMsg,
1783
1548
  toSnakeCase: () => toSnakeCase,
1784
1549
  types: () => types
1785
1550
  });
@@ -1832,7 +1597,7 @@ const OfferSchema = () => {
1832
1597
  * @param input - The offer to create.
1833
1598
  * @returns The created offer.
1834
1599
  */
1835
- function from$8(input) {
1600
+ function from$9(input) {
1836
1601
  try {
1837
1602
  return OfferSchema().parse(input);
1838
1603
  } catch (error) {
@@ -1846,7 +1611,7 @@ function from$8(input) {
1846
1611
  * @returns The created offer.
1847
1612
  */
1848
1613
  function fromSnakeCase$1(input) {
1849
- return from$8(fromSnakeCase$3(input));
1614
+ return from$9(fromSnakeCase$3(input));
1850
1615
  }
1851
1616
  /**
1852
1617
  * Converts an offer to a snake case object.
@@ -1940,7 +1705,7 @@ function random$1(config) {
1940
1705
  })
1941
1706
  };
1942
1707
  })();
1943
- return from$8({
1708
+ return from$9({
1944
1709
  maker: config?.maker ?? address(),
1945
1710
  assets: assetsScaled,
1946
1711
  obligationUnits: config?.obligationUnits ?? 0n,
@@ -2068,23 +1833,6 @@ const types = {
2068
1833
  type: "bytes"
2069
1834
  }]
2070
1835
  };
2071
- /**
2072
- * Signs an array of offers.
2073
- * @throws {Error} If the wallet account is not set.
2074
- * @param offers - The offers to sign.
2075
- * @param wallet - The wallet to sign the offers with.
2076
- * @returns The signed offers.
2077
- */
2078
- async function sign(offers, wallet) {
2079
- if (!wallet.account) throw new AccountNotSetError();
2080
- return wallet.signMessage({
2081
- account: wallet.account,
2082
- message: { raw: signatureMsg(offers) }
2083
- });
2084
- }
2085
- function signatureMsg(offers) {
2086
- return from$9(offers).root;
2087
- }
2088
1836
  function hash(offer) {
2089
1837
  const cached = offer[HASH_CACHE];
2090
1838
  if (cached) return cached;
@@ -2211,7 +1959,7 @@ const OfferAbi = [
2211
1959
  }]
2212
1960
  }
2213
1961
  ];
2214
- function encode(offer) {
1962
+ function encode$1(offer) {
2215
1963
  return encodeAbiParameters(OfferAbi, [
2216
1964
  offer.maker,
2217
1965
  offer.assets,
@@ -2230,14 +1978,14 @@ function encode(offer) {
2230
1978
  offer.callback
2231
1979
  ]);
2232
1980
  }
2233
- function decode(data) {
1981
+ function decode$1(data) {
2234
1982
  let decoded;
2235
1983
  try {
2236
1984
  decoded = decodeAbiParameters(OfferAbi, data);
2237
1985
  } catch (error) {
2238
1986
  throw new InvalidOfferError(error);
2239
1987
  }
2240
- return from$8({
1988
+ return from$9({
2241
1989
  maker: decoded[0],
2242
1990
  assets: decoded[1],
2243
1991
  obligationUnits: decoded[2],
@@ -2316,25 +2064,22 @@ var InvalidOfferError = class InvalidOfferError extends BaseError {
2316
2064
  return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
2317
2065
  }
2318
2066
  };
2319
- var AccountNotSetError = class extends BaseError {
2320
- constructor() {
2321
- super("Account not set.");
2322
- _defineProperty(this, "name", "Offer.AccountNotSetError");
2323
- }
2324
- };
2325
2067
 
2326
2068
  //#endregion
2327
2069
  //#region src/core/Oracle.ts
2328
2070
  var Oracle_exports = /* @__PURE__ */ __exportAll({
2329
2071
  Conversion: () => Conversion,
2330
- from: () => from$7
2072
+ from: () => from$8,
2073
+ fromCollateral: () => fromCollateral,
2074
+ fromOffer: () => fromOffer,
2075
+ fromOffers: () => fromOffers
2331
2076
  });
2332
2077
  /**
2333
2078
  * Create an Oracle from a plain object.
2334
2079
  * @param data - The data to create the oracle from.
2335
2080
  * @returns The created oracle.
2336
2081
  */
2337
- function from$7(data) {
2082
+ function from$8(data) {
2338
2083
  return {
2339
2084
  chainId: data.chainId,
2340
2085
  address: data.address.toLowerCase(),
@@ -2342,8 +2087,61 @@ function from$7(data) {
2342
2087
  blockNumber: data.blockNumber
2343
2088
  };
2344
2089
  }
2345
- let Conversion;
2346
- (function(_Conversion) {
2090
+ /**
2091
+ * Creates an oracle from a collateral.
2092
+ * @constructor
2093
+ *
2094
+ * @param parameters - {@link fromCollateral.Parameters}
2095
+ * @returns The created oracle. {@link fromCollateral.ReturnType}
2096
+ */
2097
+ function fromCollateral(parameters) {
2098
+ const { chainId, collateral, blockNumber, price = null } = parameters;
2099
+ return {
2100
+ chainId,
2101
+ address: collateral.oracle.toLowerCase(),
2102
+ price,
2103
+ blockNumber
2104
+ };
2105
+ }
2106
+ /**
2107
+ * Creates oracles from a single offer.
2108
+ * @constructor
2109
+ *
2110
+ * @param parameters - {@link fromOffer.Parameters}
2111
+ * @returns The created oracles. {@link fromOffer.ReturnType}
2112
+ */
2113
+ function fromOffer(parameters) {
2114
+ const { offer, blockNumber, price = null } = parameters;
2115
+ return fromOffers({
2116
+ offers: [offer],
2117
+ blockNumber,
2118
+ price
2119
+ });
2120
+ }
2121
+ /**
2122
+ * Creates oracles from a list of offers.
2123
+ * @constructor
2124
+ *
2125
+ * @param parameters - {@link fromOffers.Parameters}
2126
+ * @returns The created oracles. {@link fromOffers.ReturnType}
2127
+ */
2128
+ function fromOffers(parameters) {
2129
+ const { offers, blockNumber, price = null } = parameters;
2130
+ const rowsByKey = /* @__PURE__ */ new Map();
2131
+ for (const offer of offers) for (const collateral of offer.collaterals) {
2132
+ const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();
2133
+ if (rowsByKey.has(key)) continue;
2134
+ rowsByKey.set(key, fromCollateral({
2135
+ chainId: offer.chainId,
2136
+ collateral,
2137
+ blockNumber,
2138
+ price
2139
+ }));
2140
+ }
2141
+ return Array.from(rowsByKey.values());
2142
+ }
2143
+ let Conversion;
2144
+ (function(_Conversion) {
2347
2145
  function collateralToLoan(amount, params) {
2348
2146
  return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
2349
2147
  }
@@ -2359,7 +2157,7 @@ let Conversion;
2359
2157
  //#region src/core/Position.ts
2360
2158
  var Position_exports = /* @__PURE__ */ __exportAll({
2361
2159
  Type: () => Type,
2362
- from: () => from$6
2160
+ from: () => from$7
2363
2161
  });
2364
2162
  let Type = /* @__PURE__ */ function(Type) {
2365
2163
  Type["ERC20"] = "erc20";
@@ -2372,7 +2170,7 @@ let Type = /* @__PURE__ */ function(Type) {
2372
2170
  * @param parameters - {@link from.Parameters}
2373
2171
  * @returns The created Position. {@link from.ReturnType}
2374
2172
  */
2375
- function from$6(parameters) {
2173
+ function from$7(parameters) {
2376
2174
  return {
2377
2175
  chainId: parameters.chainId,
2378
2176
  contract: parameters.contract.toLowerCase(),
@@ -2389,7 +2187,7 @@ function from$6(parameters) {
2389
2187
  var Quote_exports = /* @__PURE__ */ __exportAll({
2390
2188
  InvalidQuoteError: () => InvalidQuoteError,
2391
2189
  QuoteSchema: () => QuoteSchema,
2392
- from: () => from$5,
2190
+ from: () => from$6,
2393
2191
  fromSnakeCase: () => fromSnakeCase,
2394
2192
  random: () => random
2395
2193
  });
@@ -2410,7 +2208,7 @@ const QuoteSchema = z$1.object({
2410
2208
  * const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
2411
2209
  * ```
2412
2210
  */
2413
- function from$5(parameters) {
2211
+ function from$6(parameters) {
2414
2212
  try {
2415
2213
  const parsedQuote = QuoteSchema.parse(parameters);
2416
2214
  return {
@@ -2429,7 +2227,7 @@ function from$5(parameters) {
2429
2227
  * @returns The created quote. {@link fromSnakeCase.ReturnType}
2430
2228
  */
2431
2229
  function fromSnakeCase(snake) {
2432
- return from$5(fromSnakeCase$3(snake));
2230
+ return from$6(fromSnakeCase$3(snake));
2433
2231
  }
2434
2232
  /**
2435
2233
  * Generates a random quote.
@@ -2441,7 +2239,7 @@ function fromSnakeCase(snake) {
2441
2239
  * ```
2442
2240
  */
2443
2241
  function random() {
2444
- return from$5({
2242
+ return from$6({
2445
2243
  obligationId: id(random$2()),
2446
2244
  ask: { price: BigInt(int(1e6)) },
2447
2245
  bid: { price: BigInt(int(1e6)) }
@@ -2464,7 +2262,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
2464
2262
  activate: () => activate,
2465
2263
  compute: () => compute,
2466
2264
  deactivate: () => deactivate,
2467
- from: () => from$4,
2265
+ from: () => from$5,
2468
2266
  getFees: () => getFees,
2469
2267
  isActivated: () => isActivated
2470
2268
  });
@@ -2490,7 +2288,7 @@ const WAD = 10n ** 18n;
2490
2288
  * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
2491
2289
  * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
2492
2290
  */
2493
- function from$4(activated, fees) {
2291
+ function from$5(activated, fees) {
2494
2292
  if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
2495
2293
  for (let i = 0; i < 6; i++) {
2496
2294
  const fee = fees[i];
@@ -2595,40 +2393,371 @@ var InvalidFeeError = class extends BaseError {
2595
2393
  _defineProperty(this, "name", "TradingFee.InvalidFeeError");
2596
2394
  }
2597
2395
  };
2598
- /** Error thrown when fees array doesn't have exactly 6 elements. */
2599
- var InvalidFeesLengthError = class extends BaseError {
2600
- constructor(length) {
2601
- super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
2602
- _defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
2396
+ /** Error thrown when fees array doesn't have exactly 6 elements. */
2397
+ var InvalidFeesLengthError = class extends BaseError {
2398
+ constructor(length) {
2399
+ super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
2400
+ _defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
2401
+ }
2402
+ };
2403
+
2404
+ //#endregion
2405
+ //#region src/core/Transfer.ts
2406
+ var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$4 });
2407
+ /**
2408
+ * @constructor
2409
+ *
2410
+ * Creates a {@link Transfer}.
2411
+ * @param parameters - {@link from.Parameters}
2412
+ * @returns The created Transfer. {@link from.ReturnType}
2413
+ *
2414
+ * @example
2415
+ * ```ts
2416
+ * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2417
+ * ```
2418
+ */
2419
+ function from$4(parameters) {
2420
+ return {
2421
+ id: parameters.id,
2422
+ chainId: parameters.chainId,
2423
+ contract: parameters.contract.toLowerCase(),
2424
+ from: parameters.from.toLowerCase(),
2425
+ to: parameters.to.toLowerCase(),
2426
+ value: parameters.value,
2427
+ blockNumber: parameters.blockNumber
2428
+ };
2429
+ }
2430
+
2431
+ //#endregion
2432
+ //#region src/core/Tree.ts
2433
+ var Tree_exports = /* @__PURE__ */ __exportAll({
2434
+ DecodeError: () => DecodeError,
2435
+ EncodeError: () => EncodeError,
2436
+ SignatureDomainError: () => SignatureDomainError,
2437
+ TreeError: () => TreeError,
2438
+ VERSION: () => VERSION,
2439
+ decode: () => decode,
2440
+ encode: () => encode,
2441
+ encodeUnsigned: () => encodeUnsigned,
2442
+ from: () => from$3,
2443
+ proofs: () => proofs,
2444
+ signatureDomain: () => signatureDomain,
2445
+ signatureTypes: () => signatureTypes
2446
+ });
2447
+ const VERSION = 1;
2448
+ /**
2449
+ * EIP-712 types for signing the tree root (Root(bytes32 root)).
2450
+ */
2451
+ const signatureTypes = {
2452
+ EIP712Domain: [{
2453
+ name: "chainId",
2454
+ type: "uint256"
2455
+ }, {
2456
+ name: "verifyingContract",
2457
+ type: "address"
2458
+ }],
2459
+ Root: [{
2460
+ name: "root",
2461
+ type: "bytes32"
2462
+ }]
2463
+ };
2464
+ const normalizeHash = (hash) => hash.toLowerCase();
2465
+ /**
2466
+ * Builds a Merkle tree from a list of offers.
2467
+ *
2468
+ * Leaves are the offer `hash` values as `bytes32` and are deterministically
2469
+ * ordered following the StandardMerkleTree leaf ordering so that the resulting
2470
+ * root is stable regardless of the input order.
2471
+ *
2472
+ * @param offers - Offers to include in the tree.
2473
+ * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
2474
+ * @throws {TreeError} If tree building fails due to offer inconsistencies.
2475
+ */
2476
+ const from$3 = (offers) => {
2477
+ const leaves = offers.map((offer) => [hash(offer)]);
2478
+ const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
2479
+ const orderedOffers = orderOffers(tree, offers);
2480
+ return Object.assign(tree, { offers: orderedOffers });
2481
+ };
2482
+ const orderOffers = (tree, offers) => {
2483
+ const offerByHash = /* @__PURE__ */ new Map();
2484
+ for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
2485
+ const entries = tree.dump().values.map((value) => {
2486
+ const hash = normalizeHash(value.value[0]);
2487
+ const offer = offerByHash.get(hash);
2488
+ if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
2489
+ return {
2490
+ offer,
2491
+ treeIndex: value.treeIndex
2492
+ };
2493
+ });
2494
+ entries.sort((a, b) => b.treeIndex - a.treeIndex);
2495
+ return entries.map((item) => item.offer);
2496
+ };
2497
+ /**
2498
+ * Generates merkle proofs for all offers in a tree.
2499
+ *
2500
+ * Each proof allows independent verification that an offer is included in the tree
2501
+ * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
2502
+ *
2503
+ * @param tree - The {@link Tree} to generate proofs for.
2504
+ * @returns Array of proofs - {@link Proof}
2505
+ */
2506
+ const proofs = (tree) => {
2507
+ return tree.offers.map((offer) => {
2508
+ return {
2509
+ offer,
2510
+ path: tree.getProof([hash(offer)])
2511
+ };
2512
+ });
2513
+ };
2514
+ /**
2515
+ * Normalizes a Root signature domain (BigInt chain id, lowercase address).
2516
+ * @throws {SignatureDomainError} When the domain is invalid.
2517
+ */
2518
+ const signatureDomain = (domain) => {
2519
+ return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));
2520
+ };
2521
+ const normalizeSignatureDomain = (domain, errorFactory) => {
2522
+ let chainId;
2523
+ try {
2524
+ chainId = typeof domain.chainId === "bigint" ? domain.chainId : BigInt(domain.chainId);
2525
+ } catch {
2526
+ throw errorFactory("invalid chainId");
2527
+ }
2528
+ if (chainId < 0n) throw errorFactory("invalid chainId");
2529
+ if (!isAddress(domain.verifyingContract)) throw errorFactory("invalid verifyingContract");
2530
+ return {
2531
+ chainId,
2532
+ verifyingContract: domain.verifyingContract.toLowerCase()
2533
+ };
2534
+ };
2535
+ const assertHex = (value, expectedBytes, name, errorFactory = (reason) => new DecodeError(reason)) => {
2536
+ if (typeof value !== "string" || !isHex(value)) throw errorFactory(`${name} is not a valid hex string`);
2537
+ if (hexToBytes(value).length !== expectedBytes) throw errorFactory(`${name}: expected ${expectedBytes} bytes`);
2538
+ };
2539
+ const verifySignatureAndRecoverAddress = async (params) => {
2540
+ const { root, signature, domain, errorFactory } = params;
2541
+ assertHex(root, 32, "root", errorFactory);
2542
+ assertHex(signature, 65, "signature", errorFactory);
2543
+ const hash = hashTypedData({
2544
+ domain,
2545
+ types: signatureTypes,
2546
+ primaryType: "Root",
2547
+ message: { root }
2548
+ });
2549
+ try {
2550
+ return await recoverAddress({
2551
+ hash,
2552
+ signature
2553
+ });
2554
+ } catch {
2555
+ throw errorFactory("signature recovery failed");
2556
+ }
2557
+ };
2558
+ /**
2559
+ * Encodes a merkle tree with signature into hex calldata for onchain broadcast.
2560
+ *
2561
+ * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
2562
+ * - `{vv}`: 1-byte version (currently 0x01)
2563
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
2564
+ * - `{root}`: 32-byte merkle root
2565
+ * - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)
2566
+ *
2567
+ * Validates signature authenticity and root integrity before encoding.
2568
+ *
2569
+ * @example
2570
+ * ```typescript
2571
+ * const tree = Tree.from(offers);
2572
+ * const signature = await wallet.signTypedData({
2573
+ * account: wallet.account,
2574
+ * domain: Tree.signatureDomain({ chainId, verifyingContract }),
2575
+ * types: Tree.signatureTypes,
2576
+ * primaryType: "Root",
2577
+ * message: { root: tree.root },
2578
+ * });
2579
+ * const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });
2580
+ * await broadcast(calldata);
2581
+ * ```
2582
+ *
2583
+ * @example
2584
+ * Manual construction (for advanced users):
2585
+ * ```typescript
2586
+ * const tree = Tree.from(offers);
2587
+ * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
2588
+ * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
2589
+ * const signature = await wallet.signTypedData({
2590
+ * account: wallet.account,
2591
+ * domain: Tree.signatureDomain({ chainId, verifyingContract }),
2592
+ * types: Tree.signatureTypes,
2593
+ * primaryType: "Root",
2594
+ * message: { root: tree.root },
2595
+ * });
2596
+ * const calldata = `${partial}${signature.slice(2)}`;
2597
+ * ```
2598
+ *
2599
+ * @param tree - Merkle tree of offers
2600
+ * @param signature - EIP-712 signature over Root(bytes32 root)
2601
+ * @param domain - EIP-712 domain with chain id and verifying contract
2602
+ * @returns Hex-encoded calldata ready for onchain broadcast
2603
+ * @throws {EncodeError} If signature verification fails or root mismatch
2604
+ */
2605
+ const encode = async (tree, signature, domain) => {
2606
+ const errorFactory = (reason) => new EncodeError(reason);
2607
+ const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
2608
+ validateTreeForEncoding(tree, normalizedDomain);
2609
+ await verifySignatureAndRecoverAddress({
2610
+ root: tree.root,
2611
+ signature,
2612
+ domain: normalizedDomain,
2613
+ errorFactory
2614
+ });
2615
+ const unsigned = encodeUnsignedBytes(tree);
2616
+ const sigBytes = hexToBytes(signature);
2617
+ const encoded = new Uint8Array(unsigned.length + sigBytes.length);
2618
+ encoded.set(unsigned, 0);
2619
+ encoded.set(sigBytes, unsigned.length);
2620
+ return bytesToHex(encoded);
2621
+ };
2622
+ /**
2623
+ * Encodes a merkle tree without a signature into hex payload for client-side signing.
2624
+ *
2625
+ * Layout: `0x{vv}{gzip([...offers])}{root}` where:
2626
+ * - `{vv}`: 1-byte version (currently 0x01)
2627
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
2628
+ * - `{root}`: 32-byte merkle root
2629
+ *
2630
+ * Validates root integrity before encoding.
2631
+ *
2632
+ * @param tree - Merkle tree of offers
2633
+ * @returns Hex-encoded unsigned payload
2634
+ * @throws {EncodeError} If root mismatch
2635
+ */
2636
+ const encodeUnsigned = (tree) => {
2637
+ validateTreeForEncoding(tree);
2638
+ return bytesToHex(encodeUnsignedBytes(tree));
2639
+ };
2640
+ const validateTreeForEncoding = (tree, domain) => {
2641
+ if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
2642
+ const computed = from$3(tree.offers);
2643
+ if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
2644
+ if (domain) {
2645
+ const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);
2646
+ if (mismatched) throw new EncodeError(`chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`);
2647
+ }
2648
+ };
2649
+ const encodeUnsignedBytes = (tree) => {
2650
+ const offersPayload = tree.offers.map(serialize);
2651
+ const compressed = gzip(JSON.stringify(offersPayload));
2652
+ const rootBytes = hexToBytes(tree.root);
2653
+ const encoded = new Uint8Array(1 + compressed.length + 32);
2654
+ encoded[0] = VERSION;
2655
+ encoded.set(compressed, 1);
2656
+ encoded.set(rootBytes, 1 + compressed.length);
2657
+ return encoded;
2658
+ };
2659
+ /**
2660
+ * Decodes hex calldata into a validated merkle tree.
2661
+ *
2662
+ * Validates signature before decompression for fail-fast rejection of invalid payloads.
2663
+ * Returns the tree with separately validated signature and recovered signer address.
2664
+ *
2665
+ * Validation order:
2666
+ * 1. Version check
2667
+ * 2. Signature verification (fail-fast, before decompression)
2668
+ * 3. Decompression (only if signature valid)
2669
+ * 4. Root verification (computed from offers vs embedded root)
2670
+ *
2671
+ * @example
2672
+ * ```typescript
2673
+ * const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });
2674
+ * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
2675
+ * ```
2676
+ *
2677
+ * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
2678
+ * @param domain - EIP-712 domain with chain id and verifying contract
2679
+ * @returns Validated tree, signature, and recovered signer address
2680
+ * @throws {DecodeError} If version invalid, signature invalid, or root mismatch
2681
+ */
2682
+ const decode = async (encoded, domain) => {
2683
+ const errorFactory = (reason) => new DecodeError(reason);
2684
+ const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
2685
+ const bytes = hexToBytes(encoded);
2686
+ if (bytes.length < 98) throw new DecodeError("payload too short");
2687
+ const version = bytes[0];
2688
+ if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
2689
+ const signature = bytesToHex(bytes.slice(-65));
2690
+ const root = bytesToHex(bytes.slice(-97, -65));
2691
+ assertHex(root, 32, "root");
2692
+ assertHex(signature, 65, "signature");
2693
+ const signer = await verifySignatureAndRecoverAddress({
2694
+ root,
2695
+ signature,
2696
+ domain: normalizedDomain,
2697
+ errorFactory
2698
+ });
2699
+ const compressed = bytes.slice(1, -97);
2700
+ let decoded;
2701
+ try {
2702
+ decoded = ungzip(compressed, { to: "string" });
2703
+ } catch {
2704
+ throw new DecodeError("decompression failed");
2705
+ }
2706
+ let rawOffers;
2707
+ try {
2708
+ rawOffers = JSON.parse(decoded);
2709
+ } catch {
2710
+ throw new DecodeError("JSON parse failed");
2711
+ }
2712
+ const tree = from$3(rawOffers.map((o) => OfferSchema().parse(o)));
2713
+ if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
2714
+ const chainIdMismatch = tree.offers.find((offer) => BigInt(offer.chainId) !== normalizedDomain.chainId);
2715
+ if (chainIdMismatch) throw new DecodeError(`chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`);
2716
+ return {
2717
+ tree,
2718
+ signature,
2719
+ signer
2720
+ };
2721
+ };
2722
+ /**
2723
+ * Error thrown during tree building operations.
2724
+ * Indicates structural issues with the tree (missing offers, inconsistent state).
2725
+ */
2726
+ var TreeError = class extends BaseError {
2727
+ constructor(reason) {
2728
+ super(`Tree error: ${reason}`);
2729
+ _defineProperty(this, "name", "Tree.TreeError");
2730
+ }
2731
+ };
2732
+ /**
2733
+ * Error thrown during tree encoding.
2734
+ * Indicates validation failures (signature, root mismatch, mixed makers).
2735
+ */
2736
+ var EncodeError = class extends BaseError {
2737
+ constructor(reason) {
2738
+ super(`Failed to encode tree: ${reason}`);
2739
+ _defineProperty(this, "name", "Tree.EncodeError");
2740
+ }
2741
+ };
2742
+ /**
2743
+ * Error thrown during tree decoding.
2744
+ * Indicates payload corruption, version mismatch, or validation failures.
2745
+ */
2746
+ var DecodeError = class extends BaseError {
2747
+ constructor(reason) {
2748
+ super(`Failed to decode tree: ${reason}`);
2749
+ _defineProperty(this, "name", "Tree.DecodeError");
2603
2750
  }
2604
2751
  };
2605
-
2606
- //#endregion
2607
- //#region src/core/Transfer.ts
2608
- var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
2609
2752
  /**
2610
- * @constructor
2611
- *
2612
- * Creates a {@link Transfer}.
2613
- * @param parameters - {@link from.Parameters}
2614
- * @returns The created Transfer. {@link from.ReturnType}
2615
- *
2616
- * @example
2617
- * ```ts
2618
- * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2619
- * ```
2753
+ * Error thrown when an invalid signature domain is supplied.
2620
2754
  */
2621
- function from$3(parameters) {
2622
- return {
2623
- id: parameters.id,
2624
- chainId: parameters.chainId,
2625
- contract: parameters.contract.toLowerCase(),
2626
- from: parameters.from.toLowerCase(),
2627
- to: parameters.to.toLowerCase(),
2628
- value: parameters.value,
2629
- blockNumber: parameters.blockNumber
2630
- };
2631
- }
2755
+ var SignatureDomainError = class extends BaseError {
2756
+ constructor(reason) {
2757
+ super(`Invalid signature domain: ${reason}`);
2758
+ _defineProperty(this, "name", "Tree.SignatureDomainError");
2759
+ }
2760
+ };
2632
2761
 
2633
2762
  //#endregion
2634
2763
  //#region src/core/types.ts
@@ -2795,6 +2924,21 @@ const validateOfferExample = {
2795
2924
  data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2796
2925
  }
2797
2926
  };
2927
+ const callbackTypesRequestExample = { callbacks: [{
2928
+ chain_id: 1,
2929
+ addresses: [
2930
+ "0x1111111111111111111111111111111111111111",
2931
+ "0x3333333333333333333333333333333333333333",
2932
+ "0x9999999999999999999999999999999999999999"
2933
+ ]
2934
+ }] };
2935
+ const callbackTypesResponseExample = [{
2936
+ chain_id: 1,
2937
+ sell_erc20_callback: ["0x1111111111111111111111111111111111111111"],
2938
+ buy_erc20: ["0x5555555555555555555555555555555555555555"],
2939
+ buy_vault_v1_callback: ["0x3333333333333333333333333333333333333333"],
2940
+ not_supported: ["0x9999999999999999999999999999999999999999"]
2941
+ }];
2798
2942
  const routerStatusExample = {
2799
2943
  status: "live",
2800
2944
  initialized: true,
@@ -2863,6 +3007,55 @@ __decorate([ApiProperty({
2863
3007
  type: "string",
2864
3008
  example: validateOfferExample.callback.data
2865
3009
  })], ValidateCallbackRequest.prototype, "data", void 0);
3010
+ var CallbackTypesChainRequest = class {};
3011
+ __decorate([ApiProperty({
3012
+ type: "number",
3013
+ example: callbackTypesRequestExample.callbacks[0].chain_id
3014
+ })], CallbackTypesChainRequest.prototype, "chain_id", void 0);
3015
+ __decorate([ApiProperty({
3016
+ type: () => [String],
3017
+ example: callbackTypesRequestExample.callbacks[0].addresses
3018
+ })], CallbackTypesChainRequest.prototype, "addresses", void 0);
3019
+ var CallbackTypesRequest = class {};
3020
+ __decorate([ApiProperty({
3021
+ type: () => [CallbackTypesChainRequest],
3022
+ example: callbackTypesRequestExample.callbacks
3023
+ })], CallbackTypesRequest.prototype, "callbacks", void 0);
3024
+ var CallbackTypesChainResponse = class {};
3025
+ __decorate([ApiProperty({
3026
+ type: "number",
3027
+ example: callbackTypesResponseExample[0].chain_id
3028
+ })], CallbackTypesChainResponse.prototype, "chain_id", void 0);
3029
+ __decorate([ApiProperty({
3030
+ type: () => [String],
3031
+ required: false,
3032
+ example: callbackTypesResponseExample[0].buy_vault_v1_callback
3033
+ })], CallbackTypesChainResponse.prototype, "buy_vault_v1_callback", void 0);
3034
+ __decorate([ApiProperty({
3035
+ type: () => [String],
3036
+ required: false,
3037
+ example: callbackTypesResponseExample[0].sell_erc20_callback
3038
+ })], CallbackTypesChainResponse.prototype, "sell_erc20_callback", void 0);
3039
+ __decorate([ApiProperty({
3040
+ type: () => [String],
3041
+ required: false,
3042
+ example: callbackTypesResponseExample[0].buy_erc20
3043
+ })], CallbackTypesChainResponse.prototype, "buy_erc20", void 0);
3044
+ __decorate([ApiProperty({
3045
+ type: () => [String],
3046
+ example: callbackTypesResponseExample[0].not_supported
3047
+ })], CallbackTypesChainResponse.prototype, "not_supported", void 0);
3048
+ var CallbackTypesSuccessResponse = class extends SuccessResponse {};
3049
+ __decorate([ApiProperty({
3050
+ type: "string",
3051
+ nullable: true,
3052
+ example: "maturity:1:1730415600:end_of_next_month"
3053
+ })], CallbackTypesSuccessResponse.prototype, "cursor", void 0);
3054
+ __decorate([ApiProperty({
3055
+ type: () => [CallbackTypesChainResponse],
3056
+ description: "Callback types grouped by chain.",
3057
+ example: callbackTypesResponseExample
3058
+ })], CallbackTypesSuccessResponse.prototype, "data", void 0);
2866
3059
  var AskResponse = class {};
2867
3060
  __decorate([ApiProperty({
2868
3061
  type: "string",
@@ -3398,6 +3591,28 @@ ValidateController = __decorate([ApiTags("Make"), ApiResponse({
3398
3591
  description: "Bad Request",
3399
3592
  type: BadRequestResponse
3400
3593
  })], ValidateController);
3594
+ let CallbacksController = class CallbacksController {
3595
+ async resolveCallbackTypes() {}
3596
+ };
3597
+ __decorate([
3598
+ ApiOperation({
3599
+ methods: ["post"],
3600
+ path: "/v1/callbacks",
3601
+ summary: "Resolve callback types",
3602
+ description: "Returns callback types for callback addresses grouped by chain."
3603
+ }),
3604
+ ApiBody({ type: CallbackTypesRequest }),
3605
+ ApiResponse({
3606
+ status: 200,
3607
+ description: "Success",
3608
+ type: CallbackTypesSuccessResponse
3609
+ })
3610
+ ], CallbacksController.prototype, "resolveCallbackTypes", null);
3611
+ CallbacksController = __decorate([ApiTags("Make"), ApiResponse({
3612
+ status: 400,
3613
+ description: "Bad Request",
3614
+ type: BadRequestResponse
3615
+ })], CallbacksController);
3401
3616
  let OffersController = class OffersController {
3402
3617
  async getOffers() {}
3403
3618
  };
@@ -3519,54 +3734,221 @@ __decorate([
3519
3734
  })
3520
3735
  ], HealthController.prototype, "getChainsHealth", null);
3521
3736
  HealthController = __decorate([ApiTags("System")], HealthController);
3522
- const callbacksExample = [Type$1.BuyWithEmptyCallback];
3523
- const chainConfigExample = {
3737
+ const configContractsExample = {
3524
3738
  chain_id: 505050505,
3525
- contracts: { mempool: "0xD946246695A9259F3B33a78629026F61B3Ab40aF" },
3526
- callbacks: callbacksExample
3739
+ address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
3740
+ name: "mempool"
3741
+ };
3742
+ const configContractsPayloadExample = [
3743
+ {
3744
+ chain_id: 505050505,
3745
+ address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
3746
+ name: "mempool"
3747
+ },
3748
+ {
3749
+ chain_id: 505050505,
3750
+ address: "0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d",
3751
+ name: "multicall"
3752
+ },
3753
+ {
3754
+ chain_id: 505050505,
3755
+ address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
3756
+ name: "v2"
3757
+ }
3758
+ ];
3759
+ const configRulesMaturityExample = {
3760
+ type: "maturity",
3761
+ chain_id: 1,
3762
+ name: "end_of_next_month",
3763
+ timestamp: 1730415600
3764
+ };
3765
+ const configRulesCallbackExample = {
3766
+ type: "callback",
3767
+ chain_id: 1,
3768
+ address: "0x1111111111111111111111111111111111111111",
3769
+ callback_type: "sell_erc20_callback"
3527
3770
  };
3528
- var ConfigContractsResponse = class {};
3771
+ const configRulesLoanTokenExample = {
3772
+ type: "loan_token",
3773
+ chain_id: 1,
3774
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
3775
+ };
3776
+ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
3777
+ const configRulesPayloadExample = [
3778
+ configRulesMaturityExample,
3779
+ configRulesCallbackExample,
3780
+ configRulesLoanTokenExample
3781
+ ];
3782
+ const configContractNames = [
3783
+ "mempool",
3784
+ "multicall",
3785
+ "v2"
3786
+ ];
3787
+ const configContractsCursorExample = "505050505:0xd946246695a9259f3b33a78629026f61b3ab40af";
3788
+ var ConfigContractResponse = class {};
3789
+ __decorate([ApiProperty({
3790
+ type: "number",
3791
+ example: configContractsExample.chain_id
3792
+ })], ConfigContractResponse.prototype, "chain_id", void 0);
3793
+ __decorate([ApiProperty({
3794
+ type: "string",
3795
+ example: configContractsExample.address
3796
+ })], ConfigContractResponse.prototype, "address", void 0);
3529
3797
  __decorate([ApiProperty({
3530
3798
  type: "string",
3531
- example: chainConfigExample.contracts.mempool
3532
- })], ConfigContractsResponse.prototype, "mempool", void 0);
3533
- var ConfigDataResponse = class {};
3799
+ enum: configContractNames,
3800
+ example: configContractsExample.name
3801
+ })], ConfigContractResponse.prototype, "name", void 0);
3802
+ var ConfigContractsSuccessResponse = class extends SuccessResponse {};
3803
+ __decorate([ApiProperty({
3804
+ type: "string",
3805
+ nullable: true,
3806
+ example: null
3807
+ })], ConfigContractsSuccessResponse.prototype, "cursor", void 0);
3808
+ __decorate([ApiProperty({
3809
+ type: () => [ConfigContractResponse],
3810
+ description: "Indexer contract configuration for all indexed chains.",
3811
+ example: configContractsPayloadExample
3812
+ })], ConfigContractsSuccessResponse.prototype, "data", void 0);
3813
+ var ConfigRulesMeta = class {};
3814
+ __decorate([ApiProperty({
3815
+ type: "string",
3816
+ example: timestampExample
3817
+ })], ConfigRulesMeta.prototype, "timestamp", void 0);
3818
+ __decorate([ApiProperty({
3819
+ type: "string",
3820
+ example: configRulesChecksumExample
3821
+ })], ConfigRulesMeta.prototype, "checksum", void 0);
3822
+ var ConfigRulesRuleResponse = class {};
3823
+ __decorate([ApiProperty({
3824
+ type: "string",
3825
+ example: configRulesMaturityExample.type
3826
+ })], ConfigRulesRuleResponse.prototype, "type", void 0);
3534
3827
  __decorate([ApiProperty({
3535
3828
  type: "number",
3536
- example: chainConfigExample.chain_id
3537
- })], ConfigDataResponse.prototype, "chain_id", void 0);
3538
- __decorate([ApiProperty({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
3829
+ example: configRulesMaturityExample.chain_id
3830
+ })], ConfigRulesRuleResponse.prototype, "chain_id", void 0);
3539
3831
  __decorate([ApiProperty({
3540
- type: () => [String],
3541
- enum: Object.values(Type$1),
3542
- description: "Supported callback types for this chain.",
3543
- example: callbacksExample
3544
- })], ConfigDataResponse.prototype, "callbacks", void 0);
3545
- var ConfigSuccessResponse = class extends SuccessResponse {};
3832
+ type: "string",
3833
+ example: configRulesMaturityExample.name,
3834
+ required: false
3835
+ })], ConfigRulesRuleResponse.prototype, "name", void 0);
3836
+ __decorate([ApiProperty({
3837
+ type: "number",
3838
+ example: configRulesMaturityExample.timestamp,
3839
+ required: false
3840
+ })], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
3841
+ __decorate([ApiProperty({
3842
+ type: "string",
3843
+ example: configRulesCallbackExample.address,
3844
+ required: false
3845
+ })], ConfigRulesRuleResponse.prototype, "address", void 0);
3846
+ __decorate([ApiProperty({
3847
+ type: "string",
3848
+ example: configRulesCallbackExample.callback_type,
3849
+ required: false
3850
+ })], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
3851
+ var ConfigRulesSuccessResponse = class {};
3852
+ __decorate([ApiProperty({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
3546
3853
  __decorate([ApiProperty({
3547
3854
  type: "string",
3548
3855
  nullable: true,
3549
3856
  example: null
3550
- })], ConfigSuccessResponse.prototype, "cursor", void 0);
3551
- __decorate([ApiProperty({
3552
- type: () => [ConfigDataResponse],
3553
- description: "Array of chain configurations for all indexed chains.",
3554
- example: [chainConfigExample]
3555
- })], ConfigSuccessResponse.prototype, "data", void 0);
3556
- let ConfigController = class ConfigController {
3557
- async getConfig() {}
3857
+ })], ConfigRulesSuccessResponse.prototype, "cursor", void 0);
3858
+ __decorate([ApiProperty({
3859
+ type: () => [ConfigRulesRuleResponse],
3860
+ description: "Configured rules returned by the router API.",
3861
+ example: configRulesPayloadExample
3862
+ })], ConfigRulesSuccessResponse.prototype, "data", void 0);
3863
+ let ConfigContractsController = class ConfigContractsController {
3864
+ async getConfigContracts() {}
3865
+ };
3866
+ __decorate([
3867
+ ApiOperation({
3868
+ methods: ["get"],
3869
+ path: "/v1/config/contracts",
3870
+ summary: "Get indexer contract configuration",
3871
+ description: "Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains."
3872
+ }),
3873
+ ApiQuery({
3874
+ name: "cursor",
3875
+ type: "string",
3876
+ required: false,
3877
+ example: configContractsCursorExample,
3878
+ description: "Pagination cursor in chain_id:address format (lowercase address)."
3879
+ }),
3880
+ ApiQuery({
3881
+ name: "limit",
3882
+ type: "number",
3883
+ required: false,
3884
+ example: 1e3,
3885
+ description: "Maximum number of contracts to return (max 1000)."
3886
+ }),
3887
+ ApiQuery({
3888
+ name: "chains",
3889
+ type: ["number"],
3890
+ required: false,
3891
+ example: "1,8453",
3892
+ description: "Filter by chain IDs (comma-separated).",
3893
+ style: "form",
3894
+ explode: false
3895
+ }),
3896
+ ApiResponse({
3897
+ status: 200,
3898
+ description: "Success",
3899
+ type: ConfigContractsSuccessResponse
3900
+ })
3901
+ ], ConfigContractsController.prototype, "getConfigContracts", null);
3902
+ ConfigContractsController = __decorate([ApiTags("System")], ConfigContractsController);
3903
+ let ConfigRulesController = class ConfigRulesController {
3904
+ async getConfigRules() {}
3558
3905
  };
3559
- __decorate([ApiOperation({
3560
- methods: ["get"],
3561
- path: "/v1/config",
3562
- summary: "Get router configuration",
3563
- description: "Returns chain configurations including contract addresses and supported callback types."
3564
- }), ApiResponse({
3565
- status: 200,
3566
- description: "Success",
3567
- type: ConfigSuccessResponse
3568
- })], ConfigController.prototype, "getConfig", null);
3569
- ConfigController = __decorate([ApiTags("System")], ConfigController);
3906
+ __decorate([
3907
+ ApiOperation({
3908
+ methods: ["get"],
3909
+ path: "/v1/config/rules",
3910
+ summary: "Get config rules",
3911
+ description: "Returns configured rules for supported chains."
3912
+ }),
3913
+ ApiQuery({
3914
+ name: "cursor",
3915
+ type: "string",
3916
+ required: false,
3917
+ example: "maturity:1:1730415600:end_of_next_month",
3918
+ description: "Pagination cursor in type:chain_id:<value> format."
3919
+ }),
3920
+ ApiQuery({
3921
+ name: "limit",
3922
+ type: "number",
3923
+ required: false,
3924
+ example: 100,
3925
+ description: "Maximum number of rules to return (max 1000)."
3926
+ }),
3927
+ ApiQuery({
3928
+ name: "types",
3929
+ type: ["string"],
3930
+ required: false,
3931
+ example: "maturity,loan_token",
3932
+ description: "Filter by rule types (comma-separated).",
3933
+ style: "form",
3934
+ explode: false
3935
+ }),
3936
+ ApiQuery({
3937
+ name: "chains",
3938
+ type: ["number"],
3939
+ required: false,
3940
+ example: "1,8453",
3941
+ description: "Filter by chain IDs (comma-separated).",
3942
+ style: "form",
3943
+ explode: false
3944
+ }),
3945
+ ApiResponse({
3946
+ status: 200,
3947
+ description: "Success",
3948
+ type: ConfigRulesSuccessResponse
3949
+ })
3950
+ ], ConfigRulesController.prototype, "getConfigRules", null);
3951
+ ConfigRulesController = __decorate([ApiTags("System")], ConfigRulesController);
3570
3952
  let ObligationsController = class ObligationsController {
3571
3953
  async getObligations() {}
3572
3954
  async getObligation() {}
@@ -3695,16 +4077,18 @@ UsersController = __decorate([ApiTags("Make"), ApiResponse({
3695
4077
  description: "Bad Request",
3696
4078
  type: BadRequestResponse
3697
4079
  })], UsersController);
3698
- const OpenApi = async (options = {}) => {
3699
- const document = await generateDocument({
4080
+ const OpenApi = async () => {
4081
+ return await generateDocument({
3700
4082
  controllers: [
3701
4083
  BooksController,
3702
- ConfigController,
4084
+ ConfigContractsController,
4085
+ ConfigRulesController,
3703
4086
  OffersController,
3704
4087
  ObligationsController,
3705
4088
  HealthController,
3706
4089
  UsersController,
3707
- ValidateController
4090
+ ValidateController,
4091
+ CallbacksController
3708
4092
  ],
3709
4093
  document: {
3710
4094
  openapi: "3.1.0",
@@ -3736,12 +4120,6 @@ const OpenApi = async (options = {}) => {
3736
4120
  ]
3737
4121
  }
3738
4122
  });
3739
- if (options.rules && options.rules.length > 0) {
3740
- const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
3741
- const validatePath = document.paths?.["/v1/validate"];
3742
- if (validatePath && "post" in validatePath && validatePath.post) validatePath.post.description = `Validates offers against router validation rules. Returns unsigned payload + root on success, or issues only on validation failure.\n\n**Available validation rules:**\n${rulesDescription}`;
3743
- }
3744
- return document;
3745
4123
  };
3746
4124
 
3747
4125
  //#endregion
@@ -3766,6 +4144,10 @@ function from$1(position) {
3766
4144
  //#region src/api/Schema/requests.ts
3767
4145
  const MAX_LIMIT = 100;
3768
4146
  const DEFAULT_LIMIT = 20;
4147
+ const CONFIG_RULES_MAX_LIMIT = 1e3;
4148
+ const CONFIG_RULES_DEFAULT_LIMIT = 100;
4149
+ const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
4150
+ const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
3769
4151
  /** Validate cursor is a valid base64url-encoded JSON object.
3770
4152
  * Domain layer handles semantic validation of cursor fields. */
3771
4153
  function isValidBase64urlJson(val) {
@@ -3799,6 +4181,43 @@ const PaginationQueryParams = z$1.object({
3799
4181
  example: 10
3800
4182
  })
3801
4183
  });
4184
+ const ConfigRuleTypes = z$1.enum([
4185
+ "maturity",
4186
+ "callback",
4187
+ "loan_token"
4188
+ ]);
4189
+ const GetConfigRulesQueryParams = z$1.object({
4190
+ cursor: z$1.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4191
+ description: "Pagination cursor in type:chain_id:<value> format",
4192
+ example: "maturity:1:1730415600:end_of_next_month"
4193
+ }),
4194
+ limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(CONFIG_RULES_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}` })).optional().default(CONFIG_RULES_DEFAULT_LIMIT).meta({
4195
+ description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,
4196
+ example: 100
4197
+ }),
4198
+ types: csvArray(ConfigRuleTypes).meta({
4199
+ description: "Filter by rule types (comma-separated).",
4200
+ example: "maturity,loan_token"
4201
+ }),
4202
+ chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4203
+ description: "Filter by chain IDs (comma-separated).",
4204
+ example: "1,8453"
4205
+ })
4206
+ });
4207
+ const GetConfigContractsQueryParams = z$1.object({
4208
+ cursor: z$1.string().regex(/^[1-9]\d*:0x[a-fA-F0-9]{40}$/, { message: "Cursor must be in the format chain_id:0x..." }).optional().meta({
4209
+ description: "Pagination cursor in chain_id:address format (lowercase address).",
4210
+ example: "1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4211
+ }),
4212
+ limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(CONFIG_CONTRACTS_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}` })).optional().default(CONFIG_CONTRACTS_DEFAULT_LIMIT).meta({
4213
+ description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,
4214
+ example: 1e3
4215
+ }),
4216
+ chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4217
+ description: "Filter by chain IDs (comma-separated).",
4218
+ example: "1,8453"
4219
+ })
4220
+ });
3802
4221
  const GetOffersQueryParams = z$1.object({
3803
4222
  ...PaginationQueryParams.shape,
3804
4223
  side: z$1.enum(["buy", "sell"]).optional().meta({
@@ -3901,6 +4320,16 @@ const GetBookParams = z$1.object({
3901
4320
  })
3902
4321
  });
3903
4322
  const ValidateOffersBody = z$1.object({ offers: z$1.array(z$1.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
4323
+ const CallbackTypesBody = z$1.object({ callbacks: z$1.array(z$1.object({
4324
+ chain_id: z$1.number().int().positive().meta({
4325
+ description: "Chain id.",
4326
+ example: 1
4327
+ }),
4328
+ addresses: z$1.array(z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Callback address must be a valid 20-byte address" }).transform((val) => val.toLowerCase())).meta({
4329
+ description: "Callback contract addresses.",
4330
+ example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
4331
+ })
4332
+ }).strict()) }).strict();
3904
4333
  const GetUserPositionsParams = z$1.object({
3905
4334
  ...PaginationQueryParams.shape,
3906
4335
  user_address: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
@@ -3912,11 +4341,14 @@ const schemas = {
3912
4341
  get_health: HealthQueryParams,
3913
4342
  get_health_collectors: HealthQueryParams,
3914
4343
  get_health_chains: HealthQueryParams,
4344
+ get_config_contracts: GetConfigContractsQueryParams,
4345
+ get_config_rules: GetConfigRulesQueryParams,
3915
4346
  get_offers: GetOffersQueryParams,
3916
4347
  get_obligations: GetObligationsQueryParams,
3917
4348
  get_obligation: GetObligationParams,
3918
4349
  get_book: GetBookParams,
3919
4350
  validate_offers: ValidateOffersBody,
4351
+ callback_types: CallbackTypesBody,
3920
4352
  get_user_positions: GetUserPositionsParams
3921
4353
  };
3922
4354
  function parse(action, query) {
@@ -3931,11 +4363,13 @@ function safeParse(action, query, error) {
3931
4363
  var Schema_exports = /* @__PURE__ */ __exportAll({
3932
4364
  BookResponse: () => BookResponse_exports,
3933
4365
  BooksController: () => BooksController,
4366
+ CallbacksController: () => CallbacksController,
3934
4367
  ChainHealth: () => ChainHealth,
3935
4368
  ChainsHealthResponse: () => ChainsHealthResponse,
3936
4369
  CollectorHealth: () => CollectorHealth,
3937
4370
  CollectorsHealthResponse: () => CollectorsHealthResponse,
3938
- ConfigController: () => ConfigController,
4371
+ ConfigContractsController: () => ConfigContractsController,
4372
+ ConfigRulesController: () => ConfigRulesController,
3939
4373
  HealthController: () => HealthController,
3940
4374
  ObligationResponse: () => ObligationResponse_exports,
3941
4375
  ObligationsController: () => ObligationsController,
@@ -4141,12 +4575,14 @@ function createHttpClient(config) {
4141
4575
  const fetchFn = config.fetchFn ?? fetch;
4142
4576
  const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
4143
4577
  const baseUrl = normalizeBaseUrl(config.baseUrl);
4578
+ const baseHeaders = config.originSecret ? { "x-origin-verify": config.originSecret } : void 0;
4144
4579
  const request = async (path, init) => {
4145
4580
  const controller = new AbortController();
4146
4581
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
4147
4582
  try {
4148
4583
  return await fetchFn(`${baseUrl}${path}`, {
4149
4584
  ...init,
4585
+ headers: mergeHeaders(baseHeaders, init.headers),
4150
4586
  signal: controller.signal
4151
4587
  });
4152
4588
  } finally {
@@ -4165,12 +4601,20 @@ function createHttpClient(config) {
4165
4601
  body: json
4166
4602
  };
4167
4603
  };
4168
- const getRules = async () => {
4169
- const response = await request("/v1/rules", { method: "GET" });
4604
+ const getConfigRules = async (query) => {
4605
+ const params = new URLSearchParams();
4606
+ if (query?.cursor) params.set("cursor", query.cursor);
4607
+ if (query?.limit !== void 0) params.set("limit", query.limit.toString());
4608
+ if (query?.types !== void 0) {
4609
+ const typesValue = Array.isArray(query.types) ? query.types.join(",") : query.types;
4610
+ if (typesValue.length > 0) params.set("types", typesValue);
4611
+ }
4612
+ const response = await request(params.size > 0 ? `/v1/config/rules?${params.toString()}` : "/v1/config/rules", { method: "GET" });
4170
4613
  const json = await response.json();
4171
- if (!response.ok) throw new Error(`Gatekeeper rules request failed: ${extractErrorMessage(json) ?? response.statusText}`);
4172
- if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper rules response is invalid.");
4173
- return json.data;
4614
+ return {
4615
+ statusCode: response.status,
4616
+ body: json
4617
+ };
4174
4618
  };
4175
4619
  const isAllowed = async (offers) => {
4176
4620
  const { statusCode, body } = await validate({ offers: offers.map((offer) => toSnakeCase(offer)) });
@@ -4198,13 +4642,31 @@ function createHttpClient(config) {
4198
4642
  issues: []
4199
4643
  };
4200
4644
  };
4645
+ const getCallbackTypes = async (requestPayload) => {
4646
+ const response = await request("/v1/callbacks", {
4647
+ method: "POST",
4648
+ headers: { "content-type": "application/json" },
4649
+ body: JSON.stringify(requestPayload)
4650
+ });
4651
+ const json = await response.json();
4652
+ if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
4653
+ if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
4654
+ return json.data;
4655
+ };
4201
4656
  return {
4202
4657
  baseUrl,
4203
4658
  validate,
4659
+ getConfigRules,
4204
4660
  isAllowed,
4205
- getRules
4661
+ getCallbackTypes
4206
4662
  };
4207
4663
  }
4664
+ function mergeHeaders(base, extra) {
4665
+ if (!base && !extra) return void 0;
4666
+ const merged = new Headers(base ?? void 0);
4667
+ if (extra) for (const [key, value] of new Headers(extra).entries()) merged.set(key, value);
4668
+ return merged;
4669
+ }
4208
4670
  function normalizeBaseUrl(url) {
4209
4671
  return url.trim().replace(/\/+$/, "");
4210
4672
  }
@@ -4300,16 +4762,26 @@ async function run(parameters) {
4300
4762
  };
4301
4763
  }
4302
4764
 
4765
+ //#endregion
4766
+ //#region src/gatekeeper/Gatekeeper.ts
4767
+ var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
4768
+ /**
4769
+ * Create a gatekeeper instance with the provided rules.
4770
+ * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
4771
+ * @returns Gatekeeper instance. {@link Gatekeeper}
4772
+ */
4773
+ function create(parameters) {
4774
+ const { rules } = parameters;
4775
+ return { isAllowed: async (offers) => {
4776
+ return await run({
4777
+ items: offers,
4778
+ rules
4779
+ });
4780
+ } };
4781
+ }
4782
+
4303
4783
  //#endregion
4304
4784
  //#region src/gatekeeper/GateConfig.ts
4305
- var GateConfig_exports = /* @__PURE__ */ __exportAll({
4306
- assets: () => assets,
4307
- configs: () => configs,
4308
- getCallback: () => getCallback,
4309
- getCallbackAddresses: () => getCallbackAddresses,
4310
- getCallbackType: () => getCallbackType,
4311
- getCallbackTypeAddresses: () => getCallbackTypeAddresses
4312
- });
4313
4785
  /**
4314
4786
  * Returns the callback configuration for a given chain and callback type, if it exists.
4315
4787
  *
@@ -4332,17 +4804,6 @@ function getCallbackType(chain, address) {
4332
4804
  return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
4333
4805
  }
4334
4806
  /**
4335
- * Returns the callback addresses for a given chain and callback type, if it exists.
4336
- * @param chain - Chain name for which to read the validation configuration
4337
- * @param type - Callback type to retrieve
4338
- * @returns The matching callback addresses or an empty array if not configured
4339
- */
4340
- function getCallbackTypeAddresses(chain, type) {
4341
- if (type === Type$1.BuyWithEmptyCallback) return [];
4342
- const match = configs[chain].callbacks?.find((c) => c.type === type);
4343
- return match && "addresses" in match ? match.addresses : [];
4344
- }
4345
- /**
4346
4807
  * Returns the list of allowed non-empty callback addresses for a chain.
4347
4808
  *
4348
4809
  * @param chain - Chain name
@@ -4441,30 +4902,6 @@ const configs = {
4441
4902
  }
4442
4903
  };
4443
4904
 
4444
- //#endregion
4445
- //#region src/gatekeeper/Gatekeeper.ts
4446
- var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
4447
- /**
4448
- * Create a gatekeeper instance with the provided rules.
4449
- * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
4450
- * @returns Gatekeeper instance. {@link Gatekeeper}
4451
- */
4452
- function create(parameters) {
4453
- const { rules } = parameters;
4454
- return {
4455
- isAllowed: async (offers) => {
4456
- return await run({
4457
- items: offers,
4458
- rules
4459
- });
4460
- },
4461
- getRules: async () => rules.map((rule) => ({
4462
- name: rule.name,
4463
- description: rule.description
4464
- }))
4465
- };
4466
- }
4467
-
4468
4905
  //#endregion
4469
4906
  //#region src/gatekeeper/Rules.ts
4470
4907
  var Rules_exports = /* @__PURE__ */ __exportAll({
@@ -4665,6 +5102,7 @@ function from(parameters) {
4665
5102
  const config = {
4666
5103
  client: parameters.client,
4667
5104
  mempoolAddress: parameters.mempoolAddress,
5105
+ morphoAddress: parameters.morphoAddress,
4668
5106
  blockWindow: parameters.blockWindow
4669
5107
  };
4670
5108
  return {
@@ -4682,11 +5120,18 @@ function from(parameters) {
4682
5120
  */
4683
5121
  async function add(config, offers) {
4684
5122
  if (!config.client.account) throw new WalletAccountNotSetError();
4685
- const tree = from$9(offers.map((o) => from$8(o)));
5123
+ const tree = from$3(offers.map((o) => from$9(o)));
4686
5124
  const chainId = await getChainId(config.client);
4687
5125
  for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
4688
- const signature = await sign(tree.offers, config.client);
4689
- const encoded = await encode$1(tree, signature);
5126
+ const signatureDomain$1 = resolveSignatureDomain(config, chainId);
5127
+ const signature = await config.client.signTypedData({
5128
+ account: config.client.account,
5129
+ domain: signatureDomain(signatureDomain$1),
5130
+ types: signatureTypes,
5131
+ primaryType: "Root",
5132
+ message: { root: tree.root }
5133
+ });
5134
+ const encoded = await encode(tree, signature, signatureDomain$1);
4690
5135
  try {
4691
5136
  return await config.client.sendTransaction({
4692
5137
  chain: config.client.chain,
@@ -4725,6 +5170,7 @@ const getChainId = async (client) => {
4725
5170
  };
4726
5171
  async function* streamOffers(config, parameters) {
4727
5172
  const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
5173
+ const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));
4728
5174
  const stream = streamLogs({
4729
5175
  client: config.client.extend(publicActions),
4730
5176
  contractAddress: config.mempoolAddress,
@@ -4756,7 +5202,7 @@ async function* streamOffers(config, parameters) {
4756
5202
  if (!log) continue;
4757
5203
  const [payload] = decodeAbiParameters([{ type: "bytes" }], log.data);
4758
5204
  try {
4759
- const { tree } = await decode$1(payload);
5205
+ const { tree } = await decode(payload, signatureDomain);
4760
5206
  for (const offer of tree.offers) {
4761
5207
  if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
4762
5208
  offers.push(offer);
@@ -4791,6 +5237,21 @@ var ChainIdMismatchError = class extends BaseError {
4791
5237
  _defineProperty(this, "name", "Mempool.ChainIdMismatchError");
4792
5238
  }
4793
5239
  };
5240
+ const resolveSignatureDomain = (config, chainId) => {
5241
+ const chain = config.client.chain;
5242
+ const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
5243
+ if (!verifyingContract || verifyingContract.toLowerCase() === zeroAddress) throw new MissingMorphoAddressError();
5244
+ return {
5245
+ chainId,
5246
+ verifyingContract
5247
+ };
5248
+ };
5249
+ var MissingMorphoAddressError = class extends BaseError {
5250
+ constructor() {
5251
+ super("Morpho address is required to verify root signatures (zero address is invalid).");
5252
+ _defineProperty(this, "name", "Mempool.MissingMorphoAddressError");
5253
+ }
5254
+ };
4794
5255
 
4795
5256
  //#endregion
4796
5257
  //#region src/mempool/MempoolClient.ts
@@ -4955,5 +5416,5 @@ var utils_exports = /* @__PURE__ */ __exportAll({
4955
5416
  });
4956
5417
 
4957
5418
  //#endregion
4958
- export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainRegistry_exports as ChainRegistry, Collateral_exports as Collateral, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, GateConfig_exports as GateConfig, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Oracle_exports as Oracle, Position_exports as Position, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports$1 as RouterClient, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation, morphoRules };
5419
+ export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainRegistry_exports as ChainRegistry, Collateral_exports as Collateral, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Oracle_exports as Oracle, Position_exports as Position, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports$1 as RouterClient, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation, morphoRules };
4959
5420
  //# sourceMappingURL=index.browser.mjs.map