@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.
@@ -1413,6 +1413,7 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
1413
1413
  InvalidObligationError: () => InvalidObligationError,
1414
1414
  ObligationSchema: () => ObligationSchema,
1415
1415
  from: () => from$10,
1416
+ fromOffer: () => fromOffer$1,
1416
1417
  fromSnakeCase: () => fromSnakeCase$2,
1417
1418
  id: () => id,
1418
1419
  random: () => random$2
@@ -1541,6 +1542,21 @@ function random$2() {
1541
1542
  maturity: from$11("end_of_next_quarter")
1542
1543
  });
1543
1544
  }
1545
+ /**
1546
+ * Creates an obligation from an offer.
1547
+ * @constructor
1548
+ *
1549
+ * @param offer - The offer to create the obligation from.
1550
+ * @returns The created obligation. {@link fromOffer.ReturnType}
1551
+ */
1552
+ function fromOffer$1(offer) {
1553
+ return from$10({
1554
+ chainId: offer.chainId,
1555
+ loanToken: offer.loanToken,
1556
+ collaterals: offer.collaterals,
1557
+ maturity: offer.maturity
1558
+ });
1559
+ }
1544
1560
  var InvalidObligationError = class extends BaseError {
1545
1561
  constructor(error) {
1546
1562
  super("Invalid obligation.", { cause: error });
@@ -1554,273 +1570,22 @@ var CollateralsAreNotSortedError = class extends BaseError {
1554
1570
  }
1555
1571
  };
1556
1572
 
1557
- //#endregion
1558
- //#region src/core/Tree.ts
1559
- var Tree_exports = /* @__PURE__ */ __exportAll({
1560
- DecodeError: () => DecodeError,
1561
- EncodeError: () => EncodeError,
1562
- TreeError: () => TreeError,
1563
- VERSION: () => VERSION,
1564
- decode: () => decode$1,
1565
- encode: () => encode$1,
1566
- encodeUnsigned: () => encodeUnsigned,
1567
- from: () => from$9,
1568
- proofs: () => proofs
1569
- });
1570
- const VERSION = 1;
1571
- const normalizeHash = (hash) => hash.toLowerCase();
1572
- /**
1573
- * Builds a Merkle tree from a list of offers.
1574
- *
1575
- * Leaves are the offer `hash` values as `bytes32` and are deterministically
1576
- * ordered following the StandardMerkleTree leaf ordering so that the resulting
1577
- * root is stable regardless of the input order.
1578
- *
1579
- * @param offers - Offers to include in the tree.
1580
- * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
1581
- * @throws {TreeError} If tree building fails due to offer inconsistencies.
1582
- */
1583
- const from$9 = (offers) => {
1584
- const leaves = offers.map((offer) => [hash(offer)]);
1585
- const tree = _openzeppelin_merkle_tree.StandardMerkleTree.of(leaves, ["bytes32"]);
1586
- const orderedOffers = orderOffers(tree, offers);
1587
- return Object.assign(tree, { offers: orderedOffers });
1588
- };
1589
- const orderOffers = (tree, offers) => {
1590
- const offerByHash = /* @__PURE__ */ new Map();
1591
- for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
1592
- const entries = tree.dump().values.map((value) => {
1593
- const hash = normalizeHash(value.value[0]);
1594
- const offer = offerByHash.get(hash);
1595
- if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
1596
- return {
1597
- offer,
1598
- treeIndex: value.treeIndex
1599
- };
1600
- });
1601
- entries.sort((a, b) => b.treeIndex - a.treeIndex);
1602
- return entries.map((item) => item.offer);
1603
- };
1604
- /**
1605
- * Generates merkle proofs for all offers in a tree.
1606
- *
1607
- * Each proof allows independent verification that an offer is included in the tree
1608
- * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
1609
- *
1610
- * @param tree - The {@link Tree} to generate proofs for.
1611
- * @returns Array of proofs - {@link Proof}
1612
- */
1613
- const proofs = (tree) => {
1614
- return tree.offers.map((offer) => {
1615
- return {
1616
- offer,
1617
- path: tree.getProof([hash(offer)])
1618
- };
1619
- });
1620
- };
1621
- const assertHex = (value, expectedBytes, name) => {
1622
- if (typeof value !== "string" || !(0, viem.isHex)(value)) throw new DecodeError(`${name} is not a valid hex string`);
1623
- if ((0, viem.hexToBytes)(value).length !== expectedBytes) throw new DecodeError(`${name}: expected ${expectedBytes} bytes`);
1624
- };
1625
- const verifySignatureAndRecoverAddress = async (params) => {
1626
- const { root, signature } = params;
1627
- assertHex(signature, 65, "signature");
1628
- const hash = (0, viem.hashMessage)({ raw: root });
1629
- try {
1630
- return await (0, viem.recoverAddress)({
1631
- hash,
1632
- signature
1633
- });
1634
- } catch {
1635
- throw new DecodeError("signature recovery failed");
1636
- }
1637
- };
1638
- /**
1639
- * Encodes a merkle tree with signature into hex calldata for onchain broadcast.
1640
- *
1641
- * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
1642
- * - `{vv}`: 1-byte version (currently 0x01)
1643
- * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1644
- * - `{root}`: 32-byte merkle root
1645
- * - `{signature}`: 65-byte EIP-191 signature over raw root bytes
1646
- *
1647
- * Validates signature authenticity and root integrity before encoding.
1648
- *
1649
- * @example
1650
- * ```typescript
1651
- * const tree = Tree.from(offers);
1652
- * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1653
- * const calldata = await Tree.encode(tree, signature);
1654
- * await broadcast(calldata);
1655
- * ```
1656
- *
1657
- * @example
1658
- * Manual construction (for advanced users):
1659
- * ```typescript
1660
- * const tree = Tree.from(offers);
1661
- * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
1662
- * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
1663
- * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1664
- * const calldata = `${partial}${signature.slice(2)}`;
1665
- * ```
1666
- *
1667
- * @param tree - Merkle tree of offers
1668
- * @param signature - EIP-191 signature over raw root bytes
1669
- * @returns Hex-encoded calldata ready for onchain broadcast
1670
- * @throws {EncodeError} If signature verification fails or root mismatch
1671
- */
1672
- const encode$1 = async (tree, signature) => {
1673
- validateTreeForEncoding(tree);
1674
- await verifySignatureAndRecoverAddress({
1675
- root: tree.root,
1676
- signature
1677
- });
1678
- const unsigned = encodeUnsignedBytes(tree);
1679
- const sigBytes = (0, viem.hexToBytes)(signature);
1680
- const encoded = new Uint8Array(unsigned.length + sigBytes.length);
1681
- encoded.set(unsigned, 0);
1682
- encoded.set(sigBytes, unsigned.length);
1683
- return (0, viem.bytesToHex)(encoded);
1684
- };
1685
- /**
1686
- * Encodes a merkle tree without a signature into hex payload for client-side signing.
1687
- *
1688
- * Layout: `0x{vv}{gzip([...offers])}{root}` where:
1689
- * - `{vv}`: 1-byte version (currently 0x01)
1690
- * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1691
- * - `{root}`: 32-byte merkle root
1692
- *
1693
- * Validates root integrity before encoding.
1694
- *
1695
- * @param tree - Merkle tree of offers
1696
- * @returns Hex-encoded unsigned payload
1697
- * @throws {EncodeError} If root mismatch
1698
- */
1699
- const encodeUnsigned = (tree) => {
1700
- validateTreeForEncoding(tree);
1701
- return (0, viem.bytesToHex)(encodeUnsignedBytes(tree));
1702
- };
1703
- const validateTreeForEncoding = (tree) => {
1704
- if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
1705
- const computed = from$9(tree.offers);
1706
- if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
1707
- };
1708
- const encodeUnsignedBytes = (tree) => {
1709
- const offersPayload = tree.offers.map(serialize);
1710
- const compressed = (0, pako.gzip)(JSON.stringify(offersPayload));
1711
- const rootBytes = (0, viem.hexToBytes)(tree.root);
1712
- const encoded = new Uint8Array(1 + compressed.length + 32);
1713
- encoded[0] = VERSION;
1714
- encoded.set(compressed, 1);
1715
- encoded.set(rootBytes, 1 + compressed.length);
1716
- return encoded;
1717
- };
1718
- /**
1719
- * Decodes hex calldata into a validated merkle tree.
1720
- *
1721
- * Validates signature before decompression for fail-fast rejection of invalid payloads.
1722
- * Returns the tree with separately validated signature and recovered signer address.
1723
- *
1724
- * Validation order:
1725
- * 1. Version check
1726
- * 2. Signature verification (fail-fast, before decompression)
1727
- * 3. Decompression (only if signature valid)
1728
- * 4. Root verification (computed from offers vs embedded root)
1729
- *
1730
- * @example
1731
- * ```typescript
1732
- * const { tree, signature, signer } = await Tree.decode(calldata);
1733
- * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
1734
- * ```
1735
- *
1736
- * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
1737
- * @returns Validated tree, signature, and recovered signer address
1738
- * @throws {DecodeError} If version invalid, signature invalid, or root mismatch
1739
- */
1740
- const decode$1 = async (encoded) => {
1741
- const bytes = (0, viem.hexToBytes)(encoded);
1742
- if (bytes.length < 98) throw new DecodeError("payload too short");
1743
- const version = bytes[0];
1744
- if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
1745
- const signature = (0, viem.bytesToHex)(bytes.slice(-65));
1746
- const root = (0, viem.bytesToHex)(bytes.slice(-97, -65));
1747
- assertHex(root, 32, "root");
1748
- assertHex(signature, 65, "signature");
1749
- const signer = await verifySignatureAndRecoverAddress({
1750
- root,
1751
- signature
1752
- });
1753
- const compressed = bytes.slice(1, -97);
1754
- let decoded;
1755
- try {
1756
- decoded = (0, pako.ungzip)(compressed, { to: "string" });
1757
- } catch {
1758
- throw new DecodeError("decompression failed");
1759
- }
1760
- let rawOffers;
1761
- try {
1762
- rawOffers = JSON.parse(decoded);
1763
- } catch {
1764
- throw new DecodeError("JSON parse failed");
1765
- }
1766
- const tree = from$9(rawOffers.map((o) => OfferSchema().parse(o)));
1767
- if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
1768
- return {
1769
- tree,
1770
- signature,
1771
- signer
1772
- };
1773
- };
1774
- /**
1775
- * Error thrown during tree building operations.
1776
- * Indicates structural issues with the tree (missing offers, inconsistent state).
1777
- */
1778
- var TreeError = class extends BaseError {
1779
- constructor(reason) {
1780
- super(`Tree error: ${reason}`);
1781
- _defineProperty(this, "name", "Tree.TreeError");
1782
- }
1783
- };
1784
- /**
1785
- * Error thrown during tree encoding.
1786
- * Indicates validation failures (signature, root mismatch, mixed makers).
1787
- */
1788
- var EncodeError = class extends BaseError {
1789
- constructor(reason) {
1790
- super(`Failed to encode tree: ${reason}`);
1791
- _defineProperty(this, "name", "Tree.EncodeError");
1792
- }
1793
- };
1794
- /**
1795
- * Error thrown during tree decoding.
1796
- * Indicates payload corruption, version mismatch, or validation failures.
1797
- */
1798
- var DecodeError = class extends BaseError {
1799
- constructor(reason) {
1800
- super(`Failed to decode tree: ${reason}`);
1801
- _defineProperty(this, "name", "Tree.DecodeError");
1802
- }
1803
- };
1804
-
1805
1573
  //#endregion
1806
1574
  //#region src/core/Offer.ts
1807
1575
  var Offer_exports = /* @__PURE__ */ __exportAll({
1808
- AccountNotSetError: () => AccountNotSetError,
1809
1576
  InvalidOfferError: () => InvalidOfferError,
1810
1577
  OfferSchema: () => OfferSchema,
1811
1578
  Status: () => Status,
1812
1579
  consumedEvent: () => consumedEvent,
1813
- decode: () => decode,
1580
+ decode: () => decode$1,
1814
1581
  domain: () => domain,
1815
- encode: () => encode,
1816
- from: () => from$8,
1582
+ encode: () => encode$1,
1583
+ from: () => from$9,
1817
1584
  fromSnakeCase: () => fromSnakeCase$1,
1818
1585
  hash: () => hash,
1819
1586
  obligationId: () => obligationId,
1820
1587
  random: () => random$1,
1821
1588
  serialize: () => serialize,
1822
- sign: () => sign,
1823
- signatureMsg: () => signatureMsg,
1824
1589
  toSnakeCase: () => toSnakeCase,
1825
1590
  types: () => types
1826
1591
  });
@@ -1873,7 +1638,7 @@ const OfferSchema = () => {
1873
1638
  * @param input - The offer to create.
1874
1639
  * @returns The created offer.
1875
1640
  */
1876
- function from$8(input) {
1641
+ function from$9(input) {
1877
1642
  try {
1878
1643
  return OfferSchema().parse(input);
1879
1644
  } catch (error) {
@@ -1887,7 +1652,7 @@ function from$8(input) {
1887
1652
  * @returns The created offer.
1888
1653
  */
1889
1654
  function fromSnakeCase$1(input) {
1890
- return from$8(fromSnakeCase$3(input));
1655
+ return from$9(fromSnakeCase$3(input));
1891
1656
  }
1892
1657
  /**
1893
1658
  * Converts an offer to a snake case object.
@@ -1981,7 +1746,7 @@ function random$1(config) {
1981
1746
  })
1982
1747
  };
1983
1748
  })();
1984
- return from$8({
1749
+ return from$9({
1985
1750
  maker: config?.maker ?? address(),
1986
1751
  assets: assetsScaled,
1987
1752
  obligationUnits: config?.obligationUnits ?? 0n,
@@ -2109,23 +1874,6 @@ const types = {
2109
1874
  type: "bytes"
2110
1875
  }]
2111
1876
  };
2112
- /**
2113
- * Signs an array of offers.
2114
- * @throws {Error} If the wallet account is not set.
2115
- * @param offers - The offers to sign.
2116
- * @param wallet - The wallet to sign the offers with.
2117
- * @returns The signed offers.
2118
- */
2119
- async function sign(offers, wallet) {
2120
- if (!wallet.account) throw new AccountNotSetError();
2121
- return wallet.signMessage({
2122
- account: wallet.account,
2123
- message: { raw: signatureMsg(offers) }
2124
- });
2125
- }
2126
- function signatureMsg(offers) {
2127
- return from$9(offers).root;
2128
- }
2129
1877
  function hash(offer) {
2130
1878
  const cached = offer[HASH_CACHE];
2131
1879
  if (cached) return cached;
@@ -2252,7 +2000,7 @@ const OfferAbi = [
2252
2000
  }]
2253
2001
  }
2254
2002
  ];
2255
- function encode(offer) {
2003
+ function encode$1(offer) {
2256
2004
  return (0, viem.encodeAbiParameters)(OfferAbi, [
2257
2005
  offer.maker,
2258
2006
  offer.assets,
@@ -2271,14 +2019,14 @@ function encode(offer) {
2271
2019
  offer.callback
2272
2020
  ]);
2273
2021
  }
2274
- function decode(data) {
2022
+ function decode$1(data) {
2275
2023
  let decoded;
2276
2024
  try {
2277
2025
  decoded = (0, viem.decodeAbiParameters)(OfferAbi, data);
2278
2026
  } catch (error) {
2279
2027
  throw new InvalidOfferError(error);
2280
2028
  }
2281
- return from$8({
2029
+ return from$9({
2282
2030
  maker: decoded[0],
2283
2031
  assets: decoded[1],
2284
2032
  obligationUnits: decoded[2],
@@ -2357,25 +2105,22 @@ var InvalidOfferError = class InvalidOfferError extends BaseError {
2357
2105
  return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
2358
2106
  }
2359
2107
  };
2360
- var AccountNotSetError = class extends BaseError {
2361
- constructor() {
2362
- super("Account not set.");
2363
- _defineProperty(this, "name", "Offer.AccountNotSetError");
2364
- }
2365
- };
2366
2108
 
2367
2109
  //#endregion
2368
2110
  //#region src/core/Oracle.ts
2369
2111
  var Oracle_exports = /* @__PURE__ */ __exportAll({
2370
2112
  Conversion: () => Conversion,
2371
- from: () => from$7
2113
+ from: () => from$8,
2114
+ fromCollateral: () => fromCollateral,
2115
+ fromOffer: () => fromOffer,
2116
+ fromOffers: () => fromOffers
2372
2117
  });
2373
2118
  /**
2374
2119
  * Create an Oracle from a plain object.
2375
2120
  * @param data - The data to create the oracle from.
2376
2121
  * @returns The created oracle.
2377
2122
  */
2378
- function from$7(data) {
2123
+ function from$8(data) {
2379
2124
  return {
2380
2125
  chainId: data.chainId,
2381
2126
  address: data.address.toLowerCase(),
@@ -2383,8 +2128,61 @@ function from$7(data) {
2383
2128
  blockNumber: data.blockNumber
2384
2129
  };
2385
2130
  }
2386
- let Conversion;
2387
- (function(_Conversion) {
2131
+ /**
2132
+ * Creates an oracle from a collateral.
2133
+ * @constructor
2134
+ *
2135
+ * @param parameters - {@link fromCollateral.Parameters}
2136
+ * @returns The created oracle. {@link fromCollateral.ReturnType}
2137
+ */
2138
+ function fromCollateral(parameters) {
2139
+ const { chainId, collateral, blockNumber, price = null } = parameters;
2140
+ return {
2141
+ chainId,
2142
+ address: collateral.oracle.toLowerCase(),
2143
+ price,
2144
+ blockNumber
2145
+ };
2146
+ }
2147
+ /**
2148
+ * Creates oracles from a single offer.
2149
+ * @constructor
2150
+ *
2151
+ * @param parameters - {@link fromOffer.Parameters}
2152
+ * @returns The created oracles. {@link fromOffer.ReturnType}
2153
+ */
2154
+ function fromOffer(parameters) {
2155
+ const { offer, blockNumber, price = null } = parameters;
2156
+ return fromOffers({
2157
+ offers: [offer],
2158
+ blockNumber,
2159
+ price
2160
+ });
2161
+ }
2162
+ /**
2163
+ * Creates oracles from a list of offers.
2164
+ * @constructor
2165
+ *
2166
+ * @param parameters - {@link fromOffers.Parameters}
2167
+ * @returns The created oracles. {@link fromOffers.ReturnType}
2168
+ */
2169
+ function fromOffers(parameters) {
2170
+ const { offers, blockNumber, price = null } = parameters;
2171
+ const rowsByKey = /* @__PURE__ */ new Map();
2172
+ for (const offer of offers) for (const collateral of offer.collaterals) {
2173
+ const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();
2174
+ if (rowsByKey.has(key)) continue;
2175
+ rowsByKey.set(key, fromCollateral({
2176
+ chainId: offer.chainId,
2177
+ collateral,
2178
+ blockNumber,
2179
+ price
2180
+ }));
2181
+ }
2182
+ return Array.from(rowsByKey.values());
2183
+ }
2184
+ let Conversion;
2185
+ (function(_Conversion) {
2388
2186
  function collateralToLoan(amount, params) {
2389
2187
  return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
2390
2188
  }
@@ -2400,7 +2198,7 @@ let Conversion;
2400
2198
  //#region src/core/Position.ts
2401
2199
  var Position_exports = /* @__PURE__ */ __exportAll({
2402
2200
  Type: () => Type,
2403
- from: () => from$6
2201
+ from: () => from$7
2404
2202
  });
2405
2203
  let Type = /* @__PURE__ */ function(Type) {
2406
2204
  Type["ERC20"] = "erc20";
@@ -2413,7 +2211,7 @@ let Type = /* @__PURE__ */ function(Type) {
2413
2211
  * @param parameters - {@link from.Parameters}
2414
2212
  * @returns The created Position. {@link from.ReturnType}
2415
2213
  */
2416
- function from$6(parameters) {
2214
+ function from$7(parameters) {
2417
2215
  return {
2418
2216
  chainId: parameters.chainId,
2419
2217
  contract: parameters.contract.toLowerCase(),
@@ -2430,7 +2228,7 @@ function from$6(parameters) {
2430
2228
  var Quote_exports = /* @__PURE__ */ __exportAll({
2431
2229
  InvalidQuoteError: () => InvalidQuoteError,
2432
2230
  QuoteSchema: () => QuoteSchema,
2433
- from: () => from$5,
2231
+ from: () => from$6,
2434
2232
  fromSnakeCase: () => fromSnakeCase,
2435
2233
  random: () => random
2436
2234
  });
@@ -2451,7 +2249,7 @@ const QuoteSchema = zod.object({
2451
2249
  * const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
2452
2250
  * ```
2453
2251
  */
2454
- function from$5(parameters) {
2252
+ function from$6(parameters) {
2455
2253
  try {
2456
2254
  const parsedQuote = QuoteSchema.parse(parameters);
2457
2255
  return {
@@ -2470,7 +2268,7 @@ function from$5(parameters) {
2470
2268
  * @returns The created quote. {@link fromSnakeCase.ReturnType}
2471
2269
  */
2472
2270
  function fromSnakeCase(snake) {
2473
- return from$5(fromSnakeCase$3(snake));
2271
+ return from$6(fromSnakeCase$3(snake));
2474
2272
  }
2475
2273
  /**
2476
2274
  * Generates a random quote.
@@ -2482,7 +2280,7 @@ function fromSnakeCase(snake) {
2482
2280
  * ```
2483
2281
  */
2484
2282
  function random() {
2485
- return from$5({
2283
+ return from$6({
2486
2284
  obligationId: id(random$2()),
2487
2285
  ask: { price: BigInt(int(1e6)) },
2488
2286
  bid: { price: BigInt(int(1e6)) }
@@ -2505,7 +2303,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
2505
2303
  activate: () => activate,
2506
2304
  compute: () => compute,
2507
2305
  deactivate: () => deactivate,
2508
- from: () => from$4,
2306
+ from: () => from$5,
2509
2307
  getFees: () => getFees,
2510
2308
  isActivated: () => isActivated
2511
2309
  });
@@ -2531,7 +2329,7 @@ const WAD = 10n ** 18n;
2531
2329
  * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
2532
2330
  * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
2533
2331
  */
2534
- function from$4(activated, fees) {
2332
+ function from$5(activated, fees) {
2535
2333
  if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
2536
2334
  for (let i = 0; i < 6; i++) {
2537
2335
  const fee = fees[i];
@@ -2643,33 +2441,364 @@ var InvalidFeesLengthError = class extends BaseError {
2643
2441
  _defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
2644
2442
  }
2645
2443
  };
2646
-
2647
- //#endregion
2648
- //#region src/core/Transfer.ts
2649
- var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
2444
+
2445
+ //#endregion
2446
+ //#region src/core/Transfer.ts
2447
+ var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$4 });
2448
+ /**
2449
+ * @constructor
2450
+ *
2451
+ * Creates a {@link Transfer}.
2452
+ * @param parameters - {@link from.Parameters}
2453
+ * @returns The created Transfer. {@link from.ReturnType}
2454
+ *
2455
+ * @example
2456
+ * ```ts
2457
+ * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2458
+ * ```
2459
+ */
2460
+ function from$4(parameters) {
2461
+ return {
2462
+ id: parameters.id,
2463
+ chainId: parameters.chainId,
2464
+ contract: parameters.contract.toLowerCase(),
2465
+ from: parameters.from.toLowerCase(),
2466
+ to: parameters.to.toLowerCase(),
2467
+ value: parameters.value,
2468
+ blockNumber: parameters.blockNumber
2469
+ };
2470
+ }
2471
+
2472
+ //#endregion
2473
+ //#region src/core/Tree.ts
2474
+ var Tree_exports = /* @__PURE__ */ __exportAll({
2475
+ DecodeError: () => DecodeError,
2476
+ EncodeError: () => EncodeError,
2477
+ SignatureDomainError: () => SignatureDomainError,
2478
+ TreeError: () => TreeError,
2479
+ VERSION: () => VERSION,
2480
+ decode: () => decode,
2481
+ encode: () => encode,
2482
+ encodeUnsigned: () => encodeUnsigned,
2483
+ from: () => from$3,
2484
+ proofs: () => proofs,
2485
+ signatureDomain: () => signatureDomain,
2486
+ signatureTypes: () => signatureTypes
2487
+ });
2488
+ const VERSION = 1;
2489
+ /**
2490
+ * EIP-712 types for signing the tree root (Root(bytes32 root)).
2491
+ */
2492
+ const signatureTypes = {
2493
+ EIP712Domain: [{
2494
+ name: "chainId",
2495
+ type: "uint256"
2496
+ }, {
2497
+ name: "verifyingContract",
2498
+ type: "address"
2499
+ }],
2500
+ Root: [{
2501
+ name: "root",
2502
+ type: "bytes32"
2503
+ }]
2504
+ };
2505
+ const normalizeHash = (hash) => hash.toLowerCase();
2506
+ /**
2507
+ * Builds a Merkle tree from a list of offers.
2508
+ *
2509
+ * Leaves are the offer `hash` values as `bytes32` and are deterministically
2510
+ * ordered following the StandardMerkleTree leaf ordering so that the resulting
2511
+ * root is stable regardless of the input order.
2512
+ *
2513
+ * @param offers - Offers to include in the tree.
2514
+ * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
2515
+ * @throws {TreeError} If tree building fails due to offer inconsistencies.
2516
+ */
2517
+ const from$3 = (offers) => {
2518
+ const leaves = offers.map((offer) => [hash(offer)]);
2519
+ const tree = _openzeppelin_merkle_tree.StandardMerkleTree.of(leaves, ["bytes32"]);
2520
+ const orderedOffers = orderOffers(tree, offers);
2521
+ return Object.assign(tree, { offers: orderedOffers });
2522
+ };
2523
+ const orderOffers = (tree, offers) => {
2524
+ const offerByHash = /* @__PURE__ */ new Map();
2525
+ for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
2526
+ const entries = tree.dump().values.map((value) => {
2527
+ const hash = normalizeHash(value.value[0]);
2528
+ const offer = offerByHash.get(hash);
2529
+ if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
2530
+ return {
2531
+ offer,
2532
+ treeIndex: value.treeIndex
2533
+ };
2534
+ });
2535
+ entries.sort((a, b) => b.treeIndex - a.treeIndex);
2536
+ return entries.map((item) => item.offer);
2537
+ };
2538
+ /**
2539
+ * Generates merkle proofs for all offers in a tree.
2540
+ *
2541
+ * Each proof allows independent verification that an offer is included in the tree
2542
+ * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
2543
+ *
2544
+ * @param tree - The {@link Tree} to generate proofs for.
2545
+ * @returns Array of proofs - {@link Proof}
2546
+ */
2547
+ const proofs = (tree) => {
2548
+ return tree.offers.map((offer) => {
2549
+ return {
2550
+ offer,
2551
+ path: tree.getProof([hash(offer)])
2552
+ };
2553
+ });
2554
+ };
2555
+ /**
2556
+ * Normalizes a Root signature domain (BigInt chain id, lowercase address).
2557
+ * @throws {SignatureDomainError} When the domain is invalid.
2558
+ */
2559
+ const signatureDomain = (domain) => {
2560
+ return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));
2561
+ };
2562
+ const normalizeSignatureDomain = (domain, errorFactory) => {
2563
+ let chainId;
2564
+ try {
2565
+ chainId = typeof domain.chainId === "bigint" ? domain.chainId : BigInt(domain.chainId);
2566
+ } catch {
2567
+ throw errorFactory("invalid chainId");
2568
+ }
2569
+ if (chainId < 0n) throw errorFactory("invalid chainId");
2570
+ if (!(0, viem.isAddress)(domain.verifyingContract)) throw errorFactory("invalid verifyingContract");
2571
+ return {
2572
+ chainId,
2573
+ verifyingContract: domain.verifyingContract.toLowerCase()
2574
+ };
2575
+ };
2576
+ const assertHex = (value, expectedBytes, name, errorFactory = (reason) => new DecodeError(reason)) => {
2577
+ if (typeof value !== "string" || !(0, viem.isHex)(value)) throw errorFactory(`${name} is not a valid hex string`);
2578
+ if ((0, viem.hexToBytes)(value).length !== expectedBytes) throw errorFactory(`${name}: expected ${expectedBytes} bytes`);
2579
+ };
2580
+ const verifySignatureAndRecoverAddress = async (params) => {
2581
+ const { root, signature, domain, errorFactory } = params;
2582
+ assertHex(root, 32, "root", errorFactory);
2583
+ assertHex(signature, 65, "signature", errorFactory);
2584
+ const hash = (0, viem.hashTypedData)({
2585
+ domain,
2586
+ types: signatureTypes,
2587
+ primaryType: "Root",
2588
+ message: { root }
2589
+ });
2590
+ try {
2591
+ return await (0, viem.recoverAddress)({
2592
+ hash,
2593
+ signature
2594
+ });
2595
+ } catch {
2596
+ throw errorFactory("signature recovery failed");
2597
+ }
2598
+ };
2599
+ /**
2600
+ * Encodes a merkle tree with signature into hex calldata for onchain broadcast.
2601
+ *
2602
+ * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
2603
+ * - `{vv}`: 1-byte version (currently 0x01)
2604
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
2605
+ * - `{root}`: 32-byte merkle root
2606
+ * - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)
2607
+ *
2608
+ * Validates signature authenticity and root integrity before encoding.
2609
+ *
2610
+ * @example
2611
+ * ```typescript
2612
+ * const tree = Tree.from(offers);
2613
+ * const signature = await wallet.signTypedData({
2614
+ * account: wallet.account,
2615
+ * domain: Tree.signatureDomain({ chainId, verifyingContract }),
2616
+ * types: Tree.signatureTypes,
2617
+ * primaryType: "Root",
2618
+ * message: { root: tree.root },
2619
+ * });
2620
+ * const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });
2621
+ * await broadcast(calldata);
2622
+ * ```
2623
+ *
2624
+ * @example
2625
+ * Manual construction (for advanced users):
2626
+ * ```typescript
2627
+ * const tree = Tree.from(offers);
2628
+ * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
2629
+ * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
2630
+ * const signature = await wallet.signTypedData({
2631
+ * account: wallet.account,
2632
+ * domain: Tree.signatureDomain({ chainId, verifyingContract }),
2633
+ * types: Tree.signatureTypes,
2634
+ * primaryType: "Root",
2635
+ * message: { root: tree.root },
2636
+ * });
2637
+ * const calldata = `${partial}${signature.slice(2)}`;
2638
+ * ```
2639
+ *
2640
+ * @param tree - Merkle tree of offers
2641
+ * @param signature - EIP-712 signature over Root(bytes32 root)
2642
+ * @param domain - EIP-712 domain with chain id and verifying contract
2643
+ * @returns Hex-encoded calldata ready for onchain broadcast
2644
+ * @throws {EncodeError} If signature verification fails or root mismatch
2645
+ */
2646
+ const encode = async (tree, signature, domain) => {
2647
+ const errorFactory = (reason) => new EncodeError(reason);
2648
+ const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
2649
+ validateTreeForEncoding(tree, normalizedDomain);
2650
+ await verifySignatureAndRecoverAddress({
2651
+ root: tree.root,
2652
+ signature,
2653
+ domain: normalizedDomain,
2654
+ errorFactory
2655
+ });
2656
+ const unsigned = encodeUnsignedBytes(tree);
2657
+ const sigBytes = (0, viem.hexToBytes)(signature);
2658
+ const encoded = new Uint8Array(unsigned.length + sigBytes.length);
2659
+ encoded.set(unsigned, 0);
2660
+ encoded.set(sigBytes, unsigned.length);
2661
+ return (0, viem.bytesToHex)(encoded);
2662
+ };
2663
+ /**
2664
+ * Encodes a merkle tree without a signature into hex payload for client-side signing.
2665
+ *
2666
+ * Layout: `0x{vv}{gzip([...offers])}{root}` where:
2667
+ * - `{vv}`: 1-byte version (currently 0x01)
2668
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
2669
+ * - `{root}`: 32-byte merkle root
2670
+ *
2671
+ * Validates root integrity before encoding.
2672
+ *
2673
+ * @param tree - Merkle tree of offers
2674
+ * @returns Hex-encoded unsigned payload
2675
+ * @throws {EncodeError} If root mismatch
2676
+ */
2677
+ const encodeUnsigned = (tree) => {
2678
+ validateTreeForEncoding(tree);
2679
+ return (0, viem.bytesToHex)(encodeUnsignedBytes(tree));
2680
+ };
2681
+ const validateTreeForEncoding = (tree, domain) => {
2682
+ if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
2683
+ const computed = from$3(tree.offers);
2684
+ if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
2685
+ if (domain) {
2686
+ const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);
2687
+ if (mismatched) throw new EncodeError(`chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`);
2688
+ }
2689
+ };
2690
+ const encodeUnsignedBytes = (tree) => {
2691
+ const offersPayload = tree.offers.map(serialize);
2692
+ const compressed = (0, pako.gzip)(JSON.stringify(offersPayload));
2693
+ const rootBytes = (0, viem.hexToBytes)(tree.root);
2694
+ const encoded = new Uint8Array(1 + compressed.length + 32);
2695
+ encoded[0] = VERSION;
2696
+ encoded.set(compressed, 1);
2697
+ encoded.set(rootBytes, 1 + compressed.length);
2698
+ return encoded;
2699
+ };
2700
+ /**
2701
+ * Decodes hex calldata into a validated merkle tree.
2702
+ *
2703
+ * Validates signature before decompression for fail-fast rejection of invalid payloads.
2704
+ * Returns the tree with separately validated signature and recovered signer address.
2705
+ *
2706
+ * Validation order:
2707
+ * 1. Version check
2708
+ * 2. Signature verification (fail-fast, before decompression)
2709
+ * 3. Decompression (only if signature valid)
2710
+ * 4. Root verification (computed from offers vs embedded root)
2711
+ *
2712
+ * @example
2713
+ * ```typescript
2714
+ * const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });
2715
+ * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
2716
+ * ```
2717
+ *
2718
+ * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
2719
+ * @param domain - EIP-712 domain with chain id and verifying contract
2720
+ * @returns Validated tree, signature, and recovered signer address
2721
+ * @throws {DecodeError} If version invalid, signature invalid, or root mismatch
2722
+ */
2723
+ const decode = async (encoded, domain) => {
2724
+ const errorFactory = (reason) => new DecodeError(reason);
2725
+ const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
2726
+ const bytes = (0, viem.hexToBytes)(encoded);
2727
+ if (bytes.length < 98) throw new DecodeError("payload too short");
2728
+ const version = bytes[0];
2729
+ if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
2730
+ const signature = (0, viem.bytesToHex)(bytes.slice(-65));
2731
+ const root = (0, viem.bytesToHex)(bytes.slice(-97, -65));
2732
+ assertHex(root, 32, "root");
2733
+ assertHex(signature, 65, "signature");
2734
+ const signer = await verifySignatureAndRecoverAddress({
2735
+ root,
2736
+ signature,
2737
+ domain: normalizedDomain,
2738
+ errorFactory
2739
+ });
2740
+ const compressed = bytes.slice(1, -97);
2741
+ let decoded;
2742
+ try {
2743
+ decoded = (0, pako.ungzip)(compressed, { to: "string" });
2744
+ } catch {
2745
+ throw new DecodeError("decompression failed");
2746
+ }
2747
+ let rawOffers;
2748
+ try {
2749
+ rawOffers = JSON.parse(decoded);
2750
+ } catch {
2751
+ throw new DecodeError("JSON parse failed");
2752
+ }
2753
+ const tree = from$3(rawOffers.map((o) => OfferSchema().parse(o)));
2754
+ if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
2755
+ const chainIdMismatch = tree.offers.find((offer) => BigInt(offer.chainId) !== normalizedDomain.chainId);
2756
+ if (chainIdMismatch) throw new DecodeError(`chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`);
2757
+ return {
2758
+ tree,
2759
+ signature,
2760
+ signer
2761
+ };
2762
+ };
2763
+ /**
2764
+ * Error thrown during tree building operations.
2765
+ * Indicates structural issues with the tree (missing offers, inconsistent state).
2766
+ */
2767
+ var TreeError = class extends BaseError {
2768
+ constructor(reason) {
2769
+ super(`Tree error: ${reason}`);
2770
+ _defineProperty(this, "name", "Tree.TreeError");
2771
+ }
2772
+ };
2773
+ /**
2774
+ * Error thrown during tree encoding.
2775
+ * Indicates validation failures (signature, root mismatch, mixed makers).
2776
+ */
2777
+ var EncodeError = class extends BaseError {
2778
+ constructor(reason) {
2779
+ super(`Failed to encode tree: ${reason}`);
2780
+ _defineProperty(this, "name", "Tree.EncodeError");
2781
+ }
2782
+ };
2650
2783
  /**
2651
- * @constructor
2652
- *
2653
- * Creates a {@link Transfer}.
2654
- * @param parameters - {@link from.Parameters}
2655
- * @returns The created Transfer. {@link from.ReturnType}
2656
- *
2657
- * @example
2658
- * ```ts
2659
- * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2660
- * ```
2784
+ * Error thrown during tree decoding.
2785
+ * Indicates payload corruption, version mismatch, or validation failures.
2661
2786
  */
2662
- function from$3(parameters) {
2663
- return {
2664
- id: parameters.id,
2665
- chainId: parameters.chainId,
2666
- contract: parameters.contract.toLowerCase(),
2667
- from: parameters.from.toLowerCase(),
2668
- to: parameters.to.toLowerCase(),
2669
- value: parameters.value,
2670
- blockNumber: parameters.blockNumber
2671
- };
2672
- }
2787
+ var DecodeError = class extends BaseError {
2788
+ constructor(reason) {
2789
+ super(`Failed to decode tree: ${reason}`);
2790
+ _defineProperty(this, "name", "Tree.DecodeError");
2791
+ }
2792
+ };
2793
+ /**
2794
+ * Error thrown when an invalid signature domain is supplied.
2795
+ */
2796
+ var SignatureDomainError = class extends BaseError {
2797
+ constructor(reason) {
2798
+ super(`Invalid signature domain: ${reason}`);
2799
+ _defineProperty(this, "name", "Tree.SignatureDomainError");
2800
+ }
2801
+ };
2673
2802
 
2674
2803
  //#endregion
2675
2804
  //#region src/core/types.ts
@@ -2836,6 +2965,21 @@ const validateOfferExample = {
2836
2965
  data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2837
2966
  }
2838
2967
  };
2968
+ const callbackTypesRequestExample = { callbacks: [{
2969
+ chain_id: 1,
2970
+ addresses: [
2971
+ "0x1111111111111111111111111111111111111111",
2972
+ "0x3333333333333333333333333333333333333333",
2973
+ "0x9999999999999999999999999999999999999999"
2974
+ ]
2975
+ }] };
2976
+ const callbackTypesResponseExample = [{
2977
+ chain_id: 1,
2978
+ sell_erc20_callback: ["0x1111111111111111111111111111111111111111"],
2979
+ buy_erc20: ["0x5555555555555555555555555555555555555555"],
2980
+ buy_vault_v1_callback: ["0x3333333333333333333333333333333333333333"],
2981
+ not_supported: ["0x9999999999999999999999999999999999999999"]
2982
+ }];
2839
2983
  const routerStatusExample = {
2840
2984
  status: "live",
2841
2985
  initialized: true,
@@ -2904,6 +3048,55 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
2904
3048
  type: "string",
2905
3049
  example: validateOfferExample.callback.data
2906
3050
  })], ValidateCallbackRequest.prototype, "data", void 0);
3051
+ var CallbackTypesChainRequest = class {};
3052
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3053
+ type: "number",
3054
+ example: callbackTypesRequestExample.callbacks[0].chain_id
3055
+ })], CallbackTypesChainRequest.prototype, "chain_id", void 0);
3056
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3057
+ type: () => [String],
3058
+ example: callbackTypesRequestExample.callbacks[0].addresses
3059
+ })], CallbackTypesChainRequest.prototype, "addresses", void 0);
3060
+ var CallbackTypesRequest = class {};
3061
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3062
+ type: () => [CallbackTypesChainRequest],
3063
+ example: callbackTypesRequestExample.callbacks
3064
+ })], CallbackTypesRequest.prototype, "callbacks", void 0);
3065
+ var CallbackTypesChainResponse = class {};
3066
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3067
+ type: "number",
3068
+ example: callbackTypesResponseExample[0].chain_id
3069
+ })], CallbackTypesChainResponse.prototype, "chain_id", void 0);
3070
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3071
+ type: () => [String],
3072
+ required: false,
3073
+ example: callbackTypesResponseExample[0].buy_vault_v1_callback
3074
+ })], CallbackTypesChainResponse.prototype, "buy_vault_v1_callback", void 0);
3075
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3076
+ type: () => [String],
3077
+ required: false,
3078
+ example: callbackTypesResponseExample[0].sell_erc20_callback
3079
+ })], CallbackTypesChainResponse.prototype, "sell_erc20_callback", void 0);
3080
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3081
+ type: () => [String],
3082
+ required: false,
3083
+ example: callbackTypesResponseExample[0].buy_erc20
3084
+ })], CallbackTypesChainResponse.prototype, "buy_erc20", void 0);
3085
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3086
+ type: () => [String],
3087
+ example: callbackTypesResponseExample[0].not_supported
3088
+ })], CallbackTypesChainResponse.prototype, "not_supported", void 0);
3089
+ var CallbackTypesSuccessResponse = class extends SuccessResponse {};
3090
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3091
+ type: "string",
3092
+ nullable: true,
3093
+ example: "maturity:1:1730415600:end_of_next_month"
3094
+ })], CallbackTypesSuccessResponse.prototype, "cursor", void 0);
3095
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3096
+ type: () => [CallbackTypesChainResponse],
3097
+ description: "Callback types grouped by chain.",
3098
+ example: callbackTypesResponseExample
3099
+ })], CallbackTypesSuccessResponse.prototype, "data", void 0);
2907
3100
  var AskResponse = class {};
2908
3101
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
2909
3102
  type: "string",
@@ -3439,6 +3632,28 @@ ValidateController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"
3439
3632
  description: "Bad Request",
3440
3633
  type: BadRequestResponse
3441
3634
  })], ValidateController);
3635
+ let CallbacksController = class CallbacksController {
3636
+ async resolveCallbackTypes() {}
3637
+ };
3638
+ __decorate([
3639
+ (0, openapi_metadata_decorators.ApiOperation)({
3640
+ methods: ["post"],
3641
+ path: "/v1/callbacks",
3642
+ summary: "Resolve callback types",
3643
+ description: "Returns callback types for callback addresses grouped by chain."
3644
+ }),
3645
+ (0, openapi_metadata_decorators.ApiBody)({ type: CallbackTypesRequest }),
3646
+ (0, openapi_metadata_decorators.ApiResponse)({
3647
+ status: 200,
3648
+ description: "Success",
3649
+ type: CallbackTypesSuccessResponse
3650
+ })
3651
+ ], CallbacksController.prototype, "resolveCallbackTypes", null);
3652
+ CallbacksController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"), (0, openapi_metadata_decorators.ApiResponse)({
3653
+ status: 400,
3654
+ description: "Bad Request",
3655
+ type: BadRequestResponse
3656
+ })], CallbacksController);
3442
3657
  let OffersController = class OffersController {
3443
3658
  async getOffers() {}
3444
3659
  };
@@ -3560,54 +3775,221 @@ __decorate([
3560
3775
  })
3561
3776
  ], HealthController.prototype, "getChainsHealth", null);
3562
3777
  HealthController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], HealthController);
3563
- const callbacksExample = [Type$1.BuyWithEmptyCallback];
3564
- const chainConfigExample = {
3778
+ const configContractsExample = {
3565
3779
  chain_id: 505050505,
3566
- contracts: { mempool: "0xD946246695A9259F3B33a78629026F61B3Ab40aF" },
3567
- callbacks: callbacksExample
3780
+ address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
3781
+ name: "mempool"
3782
+ };
3783
+ const configContractsPayloadExample = [
3784
+ {
3785
+ chain_id: 505050505,
3786
+ address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
3787
+ name: "mempool"
3788
+ },
3789
+ {
3790
+ chain_id: 505050505,
3791
+ address: "0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d",
3792
+ name: "multicall"
3793
+ },
3794
+ {
3795
+ chain_id: 505050505,
3796
+ address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
3797
+ name: "v2"
3798
+ }
3799
+ ];
3800
+ const configRulesMaturityExample = {
3801
+ type: "maturity",
3802
+ chain_id: 1,
3803
+ name: "end_of_next_month",
3804
+ timestamp: 1730415600
3805
+ };
3806
+ const configRulesCallbackExample = {
3807
+ type: "callback",
3808
+ chain_id: 1,
3809
+ address: "0x1111111111111111111111111111111111111111",
3810
+ callback_type: "sell_erc20_callback"
3568
3811
  };
3569
- var ConfigContractsResponse = class {};
3812
+ const configRulesLoanTokenExample = {
3813
+ type: "loan_token",
3814
+ chain_id: 1,
3815
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
3816
+ };
3817
+ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
3818
+ const configRulesPayloadExample = [
3819
+ configRulesMaturityExample,
3820
+ configRulesCallbackExample,
3821
+ configRulesLoanTokenExample
3822
+ ];
3823
+ const configContractNames = [
3824
+ "mempool",
3825
+ "multicall",
3826
+ "v2"
3827
+ ];
3828
+ const configContractsCursorExample = "505050505:0xd946246695a9259f3b33a78629026f61b3ab40af";
3829
+ var ConfigContractResponse = class {};
3830
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3831
+ type: "number",
3832
+ example: configContractsExample.chain_id
3833
+ })], ConfigContractResponse.prototype, "chain_id", void 0);
3834
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3835
+ type: "string",
3836
+ example: configContractsExample.address
3837
+ })], ConfigContractResponse.prototype, "address", void 0);
3838
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3839
+ type: "string",
3840
+ enum: configContractNames,
3841
+ example: configContractsExample.name
3842
+ })], ConfigContractResponse.prototype, "name", void 0);
3843
+ var ConfigContractsSuccessResponse = class extends SuccessResponse {};
3844
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3845
+ type: "string",
3846
+ nullable: true,
3847
+ example: null
3848
+ })], ConfigContractsSuccessResponse.prototype, "cursor", void 0);
3849
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3850
+ type: () => [ConfigContractResponse],
3851
+ description: "Indexer contract configuration for all indexed chains.",
3852
+ example: configContractsPayloadExample
3853
+ })], ConfigContractsSuccessResponse.prototype, "data", void 0);
3854
+ var ConfigRulesMeta = class {};
3855
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3856
+ type: "string",
3857
+ example: timestampExample
3858
+ })], ConfigRulesMeta.prototype, "timestamp", void 0);
3859
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3860
+ type: "string",
3861
+ example: configRulesChecksumExample
3862
+ })], ConfigRulesMeta.prototype, "checksum", void 0);
3863
+ var ConfigRulesRuleResponse = class {};
3570
3864
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3571
3865
  type: "string",
3572
- example: chainConfigExample.contracts.mempool
3573
- })], ConfigContractsResponse.prototype, "mempool", void 0);
3574
- var ConfigDataResponse = class {};
3866
+ example: configRulesMaturityExample.type
3867
+ })], ConfigRulesRuleResponse.prototype, "type", void 0);
3575
3868
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3576
3869
  type: "number",
3577
- example: chainConfigExample.chain_id
3578
- })], ConfigDataResponse.prototype, "chain_id", void 0);
3579
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
3870
+ example: configRulesMaturityExample.chain_id
3871
+ })], ConfigRulesRuleResponse.prototype, "chain_id", void 0);
3580
3872
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3581
- type: () => [String],
3582
- enum: Object.values(Type$1),
3583
- description: "Supported callback types for this chain.",
3584
- example: callbacksExample
3585
- })], ConfigDataResponse.prototype, "callbacks", void 0);
3586
- var ConfigSuccessResponse = class extends SuccessResponse {};
3873
+ type: "string",
3874
+ example: configRulesMaturityExample.name,
3875
+ required: false
3876
+ })], ConfigRulesRuleResponse.prototype, "name", void 0);
3877
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3878
+ type: "number",
3879
+ example: configRulesMaturityExample.timestamp,
3880
+ required: false
3881
+ })], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
3882
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3883
+ type: "string",
3884
+ example: configRulesCallbackExample.address,
3885
+ required: false
3886
+ })], ConfigRulesRuleResponse.prototype, "address", void 0);
3887
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3888
+ type: "string",
3889
+ example: configRulesCallbackExample.callback_type,
3890
+ required: false
3891
+ })], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
3892
+ var ConfigRulesSuccessResponse = class {};
3893
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
3587
3894
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3588
3895
  type: "string",
3589
3896
  nullable: true,
3590
3897
  example: null
3591
- })], ConfigSuccessResponse.prototype, "cursor", void 0);
3592
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3593
- type: () => [ConfigDataResponse],
3594
- description: "Array of chain configurations for all indexed chains.",
3595
- example: [chainConfigExample]
3596
- })], ConfigSuccessResponse.prototype, "data", void 0);
3597
- let ConfigController = class ConfigController {
3598
- async getConfig() {}
3898
+ })], ConfigRulesSuccessResponse.prototype, "cursor", void 0);
3899
+ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3900
+ type: () => [ConfigRulesRuleResponse],
3901
+ description: "Configured rules returned by the router API.",
3902
+ example: configRulesPayloadExample
3903
+ })], ConfigRulesSuccessResponse.prototype, "data", void 0);
3904
+ let ConfigContractsController = class ConfigContractsController {
3905
+ async getConfigContracts() {}
3906
+ };
3907
+ __decorate([
3908
+ (0, openapi_metadata_decorators.ApiOperation)({
3909
+ methods: ["get"],
3910
+ path: "/v1/config/contracts",
3911
+ summary: "Get indexer contract configuration",
3912
+ description: "Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains."
3913
+ }),
3914
+ (0, openapi_metadata_decorators.ApiQuery)({
3915
+ name: "cursor",
3916
+ type: "string",
3917
+ required: false,
3918
+ example: configContractsCursorExample,
3919
+ description: "Pagination cursor in chain_id:address format (lowercase address)."
3920
+ }),
3921
+ (0, openapi_metadata_decorators.ApiQuery)({
3922
+ name: "limit",
3923
+ type: "number",
3924
+ required: false,
3925
+ example: 1e3,
3926
+ description: "Maximum number of contracts to return (max 1000)."
3927
+ }),
3928
+ (0, openapi_metadata_decorators.ApiQuery)({
3929
+ name: "chains",
3930
+ type: ["number"],
3931
+ required: false,
3932
+ example: "1,8453",
3933
+ description: "Filter by chain IDs (comma-separated).",
3934
+ style: "form",
3935
+ explode: false
3936
+ }),
3937
+ (0, openapi_metadata_decorators.ApiResponse)({
3938
+ status: 200,
3939
+ description: "Success",
3940
+ type: ConfigContractsSuccessResponse
3941
+ })
3942
+ ], ConfigContractsController.prototype, "getConfigContracts", null);
3943
+ ConfigContractsController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigContractsController);
3944
+ let ConfigRulesController = class ConfigRulesController {
3945
+ async getConfigRules() {}
3599
3946
  };
3600
- __decorate([(0, openapi_metadata_decorators.ApiOperation)({
3601
- methods: ["get"],
3602
- path: "/v1/config",
3603
- summary: "Get router configuration",
3604
- description: "Returns chain configurations including contract addresses and supported callback types."
3605
- }), (0, openapi_metadata_decorators.ApiResponse)({
3606
- status: 200,
3607
- description: "Success",
3608
- type: ConfigSuccessResponse
3609
- })], ConfigController.prototype, "getConfig", null);
3610
- ConfigController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigController);
3947
+ __decorate([
3948
+ (0, openapi_metadata_decorators.ApiOperation)({
3949
+ methods: ["get"],
3950
+ path: "/v1/config/rules",
3951
+ summary: "Get config rules",
3952
+ description: "Returns configured rules for supported chains."
3953
+ }),
3954
+ (0, openapi_metadata_decorators.ApiQuery)({
3955
+ name: "cursor",
3956
+ type: "string",
3957
+ required: false,
3958
+ example: "maturity:1:1730415600:end_of_next_month",
3959
+ description: "Pagination cursor in type:chain_id:<value> format."
3960
+ }),
3961
+ (0, openapi_metadata_decorators.ApiQuery)({
3962
+ name: "limit",
3963
+ type: "number",
3964
+ required: false,
3965
+ example: 100,
3966
+ description: "Maximum number of rules to return (max 1000)."
3967
+ }),
3968
+ (0, openapi_metadata_decorators.ApiQuery)({
3969
+ name: "types",
3970
+ type: ["string"],
3971
+ required: false,
3972
+ example: "maturity,loan_token",
3973
+ description: "Filter by rule types (comma-separated).",
3974
+ style: "form",
3975
+ explode: false
3976
+ }),
3977
+ (0, openapi_metadata_decorators.ApiQuery)({
3978
+ name: "chains",
3979
+ type: ["number"],
3980
+ required: false,
3981
+ example: "1,8453",
3982
+ description: "Filter by chain IDs (comma-separated).",
3983
+ style: "form",
3984
+ explode: false
3985
+ }),
3986
+ (0, openapi_metadata_decorators.ApiResponse)({
3987
+ status: 200,
3988
+ description: "Success",
3989
+ type: ConfigRulesSuccessResponse
3990
+ })
3991
+ ], ConfigRulesController.prototype, "getConfigRules", null);
3992
+ ConfigRulesController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigRulesController);
3611
3993
  let ObligationsController = class ObligationsController {
3612
3994
  async getObligations() {}
3613
3995
  async getObligation() {}
@@ -3736,16 +4118,18 @@ UsersController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"),
3736
4118
  description: "Bad Request",
3737
4119
  type: BadRequestResponse
3738
4120
  })], UsersController);
3739
- const OpenApi = async (options = {}) => {
3740
- const document = await (0, openapi_metadata.generateDocument)({
4121
+ const OpenApi = async () => {
4122
+ return await (0, openapi_metadata.generateDocument)({
3741
4123
  controllers: [
3742
4124
  BooksController,
3743
- ConfigController,
4125
+ ConfigContractsController,
4126
+ ConfigRulesController,
3744
4127
  OffersController,
3745
4128
  ObligationsController,
3746
4129
  HealthController,
3747
4130
  UsersController,
3748
- ValidateController
4131
+ ValidateController,
4132
+ CallbacksController
3749
4133
  ],
3750
4134
  document: {
3751
4135
  openapi: "3.1.0",
@@ -3777,12 +4161,6 @@ const OpenApi = async (options = {}) => {
3777
4161
  ]
3778
4162
  }
3779
4163
  });
3780
- if (options.rules && options.rules.length > 0) {
3781
- const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
3782
- const validatePath = document.paths?.["/v1/validate"];
3783
- 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}`;
3784
- }
3785
- return document;
3786
4164
  };
3787
4165
 
3788
4166
  //#endregion
@@ -3807,6 +4185,10 @@ function from$1(position) {
3807
4185
  //#region src/api/Schema/requests.ts
3808
4186
  const MAX_LIMIT = 100;
3809
4187
  const DEFAULT_LIMIT = 20;
4188
+ const CONFIG_RULES_MAX_LIMIT = 1e3;
4189
+ const CONFIG_RULES_DEFAULT_LIMIT = 100;
4190
+ const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
4191
+ const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
3810
4192
  /** Validate cursor is a valid base64url-encoded JSON object.
3811
4193
  * Domain layer handles semantic validation of cursor fields. */
3812
4194
  function isValidBase64urlJson(val) {
@@ -3840,6 +4222,43 @@ const PaginationQueryParams = zod.object({
3840
4222
  example: 10
3841
4223
  })
3842
4224
  });
4225
+ const ConfigRuleTypes = zod.enum([
4226
+ "maturity",
4227
+ "callback",
4228
+ "loan_token"
4229
+ ]);
4230
+ const GetConfigRulesQueryParams = zod.object({
4231
+ cursor: zod.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4232
+ description: "Pagination cursor in type:chain_id:<value> format",
4233
+ example: "maturity:1:1730415600:end_of_next_month"
4234
+ }),
4235
+ limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(CONFIG_RULES_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}` })).optional().default(CONFIG_RULES_DEFAULT_LIMIT).meta({
4236
+ description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,
4237
+ example: 100
4238
+ }),
4239
+ types: csvArray(ConfigRuleTypes).meta({
4240
+ description: "Filter by rule types (comma-separated).",
4241
+ example: "maturity,loan_token"
4242
+ }),
4243
+ chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4244
+ description: "Filter by chain IDs (comma-separated).",
4245
+ example: "1,8453"
4246
+ })
4247
+ });
4248
+ const GetConfigContractsQueryParams = zod.object({
4249
+ cursor: zod.string().regex(/^[1-9]\d*:0x[a-fA-F0-9]{40}$/, { message: "Cursor must be in the format chain_id:0x..." }).optional().meta({
4250
+ description: "Pagination cursor in chain_id:address format (lowercase address).",
4251
+ example: "1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4252
+ }),
4253
+ limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(CONFIG_CONTRACTS_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}` })).optional().default(CONFIG_CONTRACTS_DEFAULT_LIMIT).meta({
4254
+ description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,
4255
+ example: 1e3
4256
+ }),
4257
+ chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4258
+ description: "Filter by chain IDs (comma-separated).",
4259
+ example: "1,8453"
4260
+ })
4261
+ });
3843
4262
  const GetOffersQueryParams = zod.object({
3844
4263
  ...PaginationQueryParams.shape,
3845
4264
  side: zod.enum(["buy", "sell"]).optional().meta({
@@ -3942,6 +4361,16 @@ const GetBookParams = zod.object({
3942
4361
  })
3943
4362
  });
3944
4363
  const ValidateOffersBody = zod.object({ offers: zod.array(zod.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
4364
+ const CallbackTypesBody = zod.object({ callbacks: zod.array(zod.object({
4365
+ chain_id: zod.number().int().positive().meta({
4366
+ description: "Chain id.",
4367
+ example: 1
4368
+ }),
4369
+ addresses: zod.array(zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Callback address must be a valid 20-byte address" }).transform((val) => val.toLowerCase())).meta({
4370
+ description: "Callback contract addresses.",
4371
+ example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
4372
+ })
4373
+ }).strict()) }).strict();
3945
4374
  const GetUserPositionsParams = zod.object({
3946
4375
  ...PaginationQueryParams.shape,
3947
4376
  user_address: zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
@@ -3953,11 +4382,14 @@ const schemas = {
3953
4382
  get_health: HealthQueryParams,
3954
4383
  get_health_collectors: HealthQueryParams,
3955
4384
  get_health_chains: HealthQueryParams,
4385
+ get_config_contracts: GetConfigContractsQueryParams,
4386
+ get_config_rules: GetConfigRulesQueryParams,
3956
4387
  get_offers: GetOffersQueryParams,
3957
4388
  get_obligations: GetObligationsQueryParams,
3958
4389
  get_obligation: GetObligationParams,
3959
4390
  get_book: GetBookParams,
3960
4391
  validate_offers: ValidateOffersBody,
4392
+ callback_types: CallbackTypesBody,
3961
4393
  get_user_positions: GetUserPositionsParams
3962
4394
  };
3963
4395
  function parse(action, query) {
@@ -3972,11 +4404,13 @@ function safeParse(action, query, error) {
3972
4404
  var Schema_exports = /* @__PURE__ */ __exportAll({
3973
4405
  BookResponse: () => BookResponse_exports,
3974
4406
  BooksController: () => BooksController,
4407
+ CallbacksController: () => CallbacksController,
3975
4408
  ChainHealth: () => ChainHealth,
3976
4409
  ChainsHealthResponse: () => ChainsHealthResponse,
3977
4410
  CollectorHealth: () => CollectorHealth,
3978
4411
  CollectorsHealthResponse: () => CollectorsHealthResponse,
3979
- ConfigController: () => ConfigController,
4412
+ ConfigContractsController: () => ConfigContractsController,
4413
+ ConfigRulesController: () => ConfigRulesController,
3980
4414
  HealthController: () => HealthController,
3981
4415
  ObligationResponse: () => ObligationResponse_exports,
3982
4416
  ObligationsController: () => ObligationsController,
@@ -4182,12 +4616,14 @@ function createHttpClient(config) {
4182
4616
  const fetchFn = config.fetchFn ?? fetch;
4183
4617
  const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
4184
4618
  const baseUrl = normalizeBaseUrl(config.baseUrl);
4619
+ const baseHeaders = config.originSecret ? { "x-origin-verify": config.originSecret } : void 0;
4185
4620
  const request = async (path, init) => {
4186
4621
  const controller = new AbortController();
4187
4622
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
4188
4623
  try {
4189
4624
  return await fetchFn(`${baseUrl}${path}`, {
4190
4625
  ...init,
4626
+ headers: mergeHeaders(baseHeaders, init.headers),
4191
4627
  signal: controller.signal
4192
4628
  });
4193
4629
  } finally {
@@ -4206,12 +4642,20 @@ function createHttpClient(config) {
4206
4642
  body: json
4207
4643
  };
4208
4644
  };
4209
- const getRules = async () => {
4210
- const response = await request("/v1/rules", { method: "GET" });
4645
+ const getConfigRules = async (query) => {
4646
+ const params = new URLSearchParams();
4647
+ if (query?.cursor) params.set("cursor", query.cursor);
4648
+ if (query?.limit !== void 0) params.set("limit", query.limit.toString());
4649
+ if (query?.types !== void 0) {
4650
+ const typesValue = Array.isArray(query.types) ? query.types.join(",") : query.types;
4651
+ if (typesValue.length > 0) params.set("types", typesValue);
4652
+ }
4653
+ const response = await request(params.size > 0 ? `/v1/config/rules?${params.toString()}` : "/v1/config/rules", { method: "GET" });
4211
4654
  const json = await response.json();
4212
- if (!response.ok) throw new Error(`Gatekeeper rules request failed: ${extractErrorMessage(json) ?? response.statusText}`);
4213
- if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper rules response is invalid.");
4214
- return json.data;
4655
+ return {
4656
+ statusCode: response.status,
4657
+ body: json
4658
+ };
4215
4659
  };
4216
4660
  const isAllowed = async (offers) => {
4217
4661
  const { statusCode, body } = await validate({ offers: offers.map((offer) => toSnakeCase(offer)) });
@@ -4239,13 +4683,31 @@ function createHttpClient(config) {
4239
4683
  issues: []
4240
4684
  };
4241
4685
  };
4686
+ const getCallbackTypes = async (requestPayload) => {
4687
+ const response = await request("/v1/callbacks", {
4688
+ method: "POST",
4689
+ headers: { "content-type": "application/json" },
4690
+ body: JSON.stringify(requestPayload)
4691
+ });
4692
+ const json = await response.json();
4693
+ if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
4694
+ if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
4695
+ return json.data;
4696
+ };
4242
4697
  return {
4243
4698
  baseUrl,
4244
4699
  validate,
4700
+ getConfigRules,
4245
4701
  isAllowed,
4246
- getRules
4702
+ getCallbackTypes
4247
4703
  };
4248
4704
  }
4705
+ function mergeHeaders(base, extra) {
4706
+ if (!base && !extra) return void 0;
4707
+ const merged = new Headers(base ?? void 0);
4708
+ if (extra) for (const [key, value] of new Headers(extra).entries()) merged.set(key, value);
4709
+ return merged;
4710
+ }
4249
4711
  function normalizeBaseUrl(url) {
4250
4712
  return url.trim().replace(/\/+$/, "");
4251
4713
  }
@@ -4341,16 +4803,26 @@ async function run(parameters) {
4341
4803
  };
4342
4804
  }
4343
4805
 
4806
+ //#endregion
4807
+ //#region src/gatekeeper/Gatekeeper.ts
4808
+ var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
4809
+ /**
4810
+ * Create a gatekeeper instance with the provided rules.
4811
+ * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
4812
+ * @returns Gatekeeper instance. {@link Gatekeeper}
4813
+ */
4814
+ function create(parameters) {
4815
+ const { rules } = parameters;
4816
+ return { isAllowed: async (offers) => {
4817
+ return await run({
4818
+ items: offers,
4819
+ rules
4820
+ });
4821
+ } };
4822
+ }
4823
+
4344
4824
  //#endregion
4345
4825
  //#region src/gatekeeper/GateConfig.ts
4346
- var GateConfig_exports = /* @__PURE__ */ __exportAll({
4347
- assets: () => assets,
4348
- configs: () => configs,
4349
- getCallback: () => getCallback,
4350
- getCallbackAddresses: () => getCallbackAddresses,
4351
- getCallbackType: () => getCallbackType,
4352
- getCallbackTypeAddresses: () => getCallbackTypeAddresses
4353
- });
4354
4826
  /**
4355
4827
  * Returns the callback configuration for a given chain and callback type, if it exists.
4356
4828
  *
@@ -4373,17 +4845,6 @@ function getCallbackType(chain, address) {
4373
4845
  return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
4374
4846
  }
4375
4847
  /**
4376
- * Returns the callback addresses for a given chain and callback type, if it exists.
4377
- * @param chain - Chain name for which to read the validation configuration
4378
- * @param type - Callback type to retrieve
4379
- * @returns The matching callback addresses or an empty array if not configured
4380
- */
4381
- function getCallbackTypeAddresses(chain, type) {
4382
- if (type === Type$1.BuyWithEmptyCallback) return [];
4383
- const match = configs[chain].callbacks?.find((c) => c.type === type);
4384
- return match && "addresses" in match ? match.addresses : [];
4385
- }
4386
- /**
4387
4848
  * Returns the list of allowed non-empty callback addresses for a chain.
4388
4849
  *
4389
4850
  * @param chain - Chain name
@@ -4482,30 +4943,6 @@ const configs = {
4482
4943
  }
4483
4944
  };
4484
4945
 
4485
- //#endregion
4486
- //#region src/gatekeeper/Gatekeeper.ts
4487
- var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
4488
- /**
4489
- * Create a gatekeeper instance with the provided rules.
4490
- * @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
4491
- * @returns Gatekeeper instance. {@link Gatekeeper}
4492
- */
4493
- function create(parameters) {
4494
- const { rules } = parameters;
4495
- return {
4496
- isAllowed: async (offers) => {
4497
- return await run({
4498
- items: offers,
4499
- rules
4500
- });
4501
- },
4502
- getRules: async () => rules.map((rule) => ({
4503
- name: rule.name,
4504
- description: rule.description
4505
- }))
4506
- };
4507
- }
4508
-
4509
4946
  //#endregion
4510
4947
  //#region src/gatekeeper/Rules.ts
4511
4948
  var Rules_exports = /* @__PURE__ */ __exportAll({
@@ -4706,6 +5143,7 @@ function from(parameters) {
4706
5143
  const config = {
4707
5144
  client: parameters.client,
4708
5145
  mempoolAddress: parameters.mempoolAddress,
5146
+ morphoAddress: parameters.morphoAddress,
4709
5147
  blockWindow: parameters.blockWindow
4710
5148
  };
4711
5149
  return {
@@ -4723,11 +5161,18 @@ function from(parameters) {
4723
5161
  */
4724
5162
  async function add(config, offers) {
4725
5163
  if (!config.client.account) throw new WalletAccountNotSetError();
4726
- const tree = from$9(offers.map((o) => from$8(o)));
5164
+ const tree = from$3(offers.map((o) => from$9(o)));
4727
5165
  const chainId = await getChainId(config.client);
4728
5166
  for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
4729
- const signature = await sign(tree.offers, config.client);
4730
- const encoded = await encode$1(tree, signature);
5167
+ const signatureDomain$1 = resolveSignatureDomain(config, chainId);
5168
+ const signature = await config.client.signTypedData({
5169
+ account: config.client.account,
5170
+ domain: signatureDomain(signatureDomain$1),
5171
+ types: signatureTypes,
5172
+ primaryType: "Root",
5173
+ message: { root: tree.root }
5174
+ });
5175
+ const encoded = await encode(tree, signature, signatureDomain$1);
4731
5176
  try {
4732
5177
  return await config.client.sendTransaction({
4733
5178
  chain: config.client.chain,
@@ -4766,6 +5211,7 @@ const getChainId = async (client) => {
4766
5211
  };
4767
5212
  async function* streamOffers(config, parameters) {
4768
5213
  const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
5214
+ const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));
4769
5215
  const stream = streamLogs({
4770
5216
  client: config.client.extend(viem.publicActions),
4771
5217
  contractAddress: config.mempoolAddress,
@@ -4797,7 +5243,7 @@ async function* streamOffers(config, parameters) {
4797
5243
  if (!log) continue;
4798
5244
  const [payload] = (0, viem.decodeAbiParameters)([{ type: "bytes" }], log.data);
4799
5245
  try {
4800
- const { tree } = await decode$1(payload);
5246
+ const { tree } = await decode(payload, signatureDomain);
4801
5247
  for (const offer of tree.offers) {
4802
5248
  if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
4803
5249
  offers.push(offer);
@@ -4832,6 +5278,21 @@ var ChainIdMismatchError = class extends BaseError {
4832
5278
  _defineProperty(this, "name", "Mempool.ChainIdMismatchError");
4833
5279
  }
4834
5280
  };
5281
+ const resolveSignatureDomain = (config, chainId) => {
5282
+ const chain = config.client.chain;
5283
+ const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
5284
+ if (!verifyingContract || verifyingContract.toLowerCase() === viem.zeroAddress) throw new MissingMorphoAddressError();
5285
+ return {
5286
+ chainId,
5287
+ verifyingContract
5288
+ };
5289
+ };
5290
+ var MissingMorphoAddressError = class extends BaseError {
5291
+ constructor() {
5292
+ super("Morpho address is required to verify root signatures (zero address is invalid).");
5293
+ _defineProperty(this, "name", "Mempool.MissingMorphoAddressError");
5294
+ }
5295
+ };
4835
5296
 
4836
5297
  //#endregion
4837
5298
  //#region src/mempool/MempoolClient.ts
@@ -5045,12 +5506,6 @@ Object.defineProperty(exports, 'Format', {
5045
5506
  return Format_exports;
5046
5507
  }
5047
5508
  });
5048
- Object.defineProperty(exports, 'GateConfig', {
5049
- enumerable: true,
5050
- get: function () {
5051
- return GateConfig_exports;
5052
- }
5053
- });
5054
5509
  Object.defineProperty(exports, 'Gatekeeper', {
5055
5510
  enumerable: true,
5056
5511
  get: function () {