@morpho-dev/router 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -93,7 +93,7 @@ const MorphoV2 = parseAbi([
93
93
  "function obligationCreated(bytes32 id) view returns (bool)",
94
94
  "function obligationState(bytes32 id) view returns (uint128 totalUnits, uint256 withdrawable, uint128 lossIndex, bool created)",
95
95
  "function owner() view returns (address)",
96
- "function repay((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 obligationUnits, address onBehalf)",
96
+ "function repay((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 units, address onBehalf)",
97
97
  "function session(address user) view returns (bytes32)",
98
98
  "function setConsumed(bytes32 group, uint256 amount, address onBehalf)",
99
99
  "function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
@@ -108,7 +108,7 @@ const MorphoV2 = parseAbi([
108
108
  "function shuffleSession(address onBehalf)",
109
109
  "function slash(bytes32 id, address user)",
110
110
  "function supplyCollateral((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 assets, address onBehalf)",
111
- "function take(uint256 obligationUnits, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, bool buy, address maker, uint256 obligationUnits, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller, bool exitOnly) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256)",
111
+ "function take(uint256 units, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, bool buy, address maker, uint256 maxUnits, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller, bool exitOnly) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256)",
112
112
  "function toId((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation) view returns (bytes32)",
113
113
  "function toObligation(bytes32 id) view returns ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold))",
114
114
  "function totalUnits(bytes32 id) view returns (uint256)",
@@ -116,14 +116,14 @@ const MorphoV2 = parseAbi([
116
116
  "function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
117
117
  "function tradingFeeRecipient() view returns (address)",
118
118
  "function userLossIndex(bytes32 id, address user) view returns (uint128)",
119
- "function withdraw((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 obligationUnits, address onBehalf, address receiver)",
119
+ "function withdraw((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 units, address onBehalf, address receiver)",
120
120
  "function withdrawCollateral((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 assets, address onBehalf, address receiver)",
121
121
  "function withdrawable(bytes32 id) view returns (uint256)",
122
122
  "event Constructor(address indexed owner)",
123
123
  "event FlashLoan(address indexed caller, address indexed token, uint256 assets)",
124
124
  "event Liquidate(address indexed caller, bytes32 indexed id_, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address indexed borrower, uint256 badDebt, uint256 latestLossIndex)",
125
125
  "event ObligationCreated(bytes32 indexed id_, (address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation)",
126
- "event Repay(address indexed caller, bytes32 indexed id_, uint256 obligationUnits, address indexed onBehalf)",
126
+ "event Repay(address indexed caller, bytes32 indexed id_, uint256 units, address indexed onBehalf)",
127
127
  "event SetConsumed(address indexed caller, address indexed onBehalf, bytes32 indexed group, uint256 amount)",
128
128
  "event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
129
129
  "event SetFeeSetter(address indexed feeSetter)",
@@ -137,8 +137,8 @@ const MorphoV2 = parseAbi([
137
137
  "event ShuffleSession(address indexed caller, address indexed onBehalf, bytes32 session)",
138
138
  "event Slash(address caller, bytes32 indexed id_, address indexed user, uint256 credit, uint256 latestLossIndex)",
139
139
  "event SupplyCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf)",
140
- "event Take(address caller, bytes32 indexed id_, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, address sellerReceiver, bytes32 group, uint256 consumed, uint256 totalUnits)",
141
- "event Withdraw(address caller, bytes32 indexed id_, uint256 obligationUnits, address indexed onBehalf, address indexed receiver)",
140
+ "event Take(address caller, bytes32 indexed id_, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 units, address sellerReceiver, bytes32 group, uint256 consumed, uint256 totalUnits)",
141
+ "event Withdraw(address caller, bytes32 indexed id_, uint256 units, address indexed onBehalf, address indexed receiver)",
142
142
  "event WithdrawCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
143
143
  ]);
144
144
 
@@ -489,8 +489,8 @@ const chains$1 = {
489
489
  name: "base",
490
490
  custom: {
491
491
  morpho: {
492
- address: "0xee437005ba0a3d0e9bc6510775c41f23ed2909e1",
493
- blockCreated: 43515847
492
+ address: "0x26378861d9c740fe86e7472752aef5b1a783c60b",
493
+ blockCreated: 43606117
494
494
  },
495
495
  morphoBlue: {
496
496
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -519,8 +519,8 @@ const chains$1 = {
519
519
  name: "ethereum-virtual-testnet",
520
520
  custom: {
521
521
  morpho: {
522
- address: "0xc1c6e6fa308eeef18e96be420d8ccb218215a26c",
523
- blockCreated: 23244321
522
+ address: "0x94c576ee728ee290116ee65c0d1e9fed4a1b5041",
523
+ blockCreated: 23244323
524
524
  },
525
525
  morphoBlue: {
526
526
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -941,6 +941,7 @@ const transformAddress = (val, ctx) => {
941
941
  });
942
942
  return z$1.NEVER;
943
943
  };
944
+ const AddressSchema = z$1.string().transform(transformAddress);
944
945
 
945
946
  //#endregion
946
947
  //#region src/core/LLTV.ts
@@ -1025,10 +1026,10 @@ const abi$1 = [
1025
1026
  }
1026
1027
  ];
1027
1028
  const CollateralSchema = z$1.object({
1028
- asset: z$1.string().transform(transformAddress),
1029
- oracle: z$1.string().transform(transformAddress),
1029
+ asset: AddressSchema,
1030
+ oracle: AddressSchema,
1030
1031
  lltv: LLTVSchema,
1031
- maxLif: z$1.bigint({ coerce: true }).min(0n).optional().default(0n)
1032
+ maxLif: z$1.bigint({ coerce: true }).min(0n)
1032
1033
  });
1033
1034
  const CollateralsSchema = z$1.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine((collaterals) => {
1034
1035
  for (let i = 1; i < collaterals.length; i++) if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) return false;
@@ -1046,7 +1047,7 @@ const from$16 = (parameters) => {
1046
1047
  return {
1047
1048
  asset: parameters.asset.toLowerCase(),
1048
1049
  lltv: from$17(parameters.lltv),
1049
- maxLif: parameters.maxLif ?? 0n,
1050
+ maxLif: parameters.maxLif,
1050
1051
  oracle: parameters.oracle.toLowerCase()
1051
1052
  };
1052
1053
  };
@@ -1186,14 +1187,8 @@ var Maturity_exports = /* @__PURE__ */ __exportAll({
1186
1187
  MaturityType: () => MaturityType,
1187
1188
  from: () => from$15
1188
1189
  });
1189
- const MaturitySchema = z$1.number().int().refine((maturity) => {
1190
- try {
1191
- from$15(maturity);
1192
- return true;
1193
- } catch (_e) {
1194
- return false;
1195
- }
1196
- }, { error: (issue) => {
1190
+ const MAX_TIMESTAMP_SECONDS = 999999999999;
1191
+ const MaturitySchema = z$1.number().int().max(MAX_TIMESTAMP_SECONDS).refine(isAt15UTC, { error: (issue) => {
1197
1192
  try {
1198
1193
  return `The maturity is set to ${/* @__PURE__ */ new Date(issue.input * 1e3)}. It must be at 15:00:00 UTC.`;
1199
1194
  } catch (_) {
@@ -1228,7 +1223,7 @@ function from$15(ts) {
1228
1223
  if (ts in MaturityOptions) return MaturityOptions[ts]();
1229
1224
  throw new InvalidOptionError(ts);
1230
1225
  }
1231
- if (typeof ts === "number" && ts > 0xe8d4a51000) throw new InvalidFormatError();
1226
+ if (typeof ts === "number" && ts > MAX_TIMESTAMP_SECONDS) throw new InvalidFormatError();
1232
1227
  if (!isAt15UTC(ts)) throw new InvalidDateError(ts);
1233
1228
  return ts;
1234
1229
  }
@@ -1322,7 +1317,7 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
1322
1317
  tupleAbi: () => tupleAbi
1323
1318
  });
1324
1319
  const ObligationSchema = z$1.object({
1325
- loanToken: z$1.string().transform(transformAddress),
1320
+ loanToken: AddressSchema,
1326
1321
  collaterals: CollateralsSchema,
1327
1322
  maturity: MaturitySchema,
1328
1323
  rcfThreshold: z$1.bigint({ coerce: true }).min(0n)
@@ -1365,7 +1360,8 @@ const tupleAbi = [{
1365
1360
  * Collateral.from({
1366
1361
  * asset: privateKeyToAccount(generatePrivateKey()).address,
1367
1362
  * oracle: privateKeyToAccount(generatePrivateKey()).address,
1368
- * lltv: 0.965
1363
+ * lltv: 0.965,
1364
+ * maxLif: 0n,
1369
1365
  * }),
1370
1366
  * ],
1371
1367
  * maturity: Maturity.from("end_of_next_quarter"),
@@ -1424,7 +1420,7 @@ function key(parameters) {
1424
1420
  parameters.collaterals.map((c) => ({
1425
1421
  token: c.asset.toLowerCase(),
1426
1422
  lltv: c.lltv,
1427
- maxLif: c.maxLif ?? 0n,
1423
+ maxLif: c.maxLif,
1428
1424
  oracle: c.oracle.toLowerCase()
1429
1425
  })),
1430
1426
  BigInt(parameters.maturity),
@@ -1497,7 +1493,7 @@ function creationCode(parameters) {
1497
1493
  collaterals: parameters.obligation.collaterals.map((collateral) => ({
1498
1494
  token: collateral.asset.toLowerCase(),
1499
1495
  lltv: collateral.lltv,
1500
- maxLif: collateral.maxLif ?? 0n,
1496
+ maxLif: collateral.maxLif,
1501
1497
  oracle: collateral.oracle.toLowerCase()
1502
1498
  })),
1503
1499
  maturity: BigInt(parameters.obligation.maturity),
@@ -1624,8 +1620,8 @@ let Status = /* @__PURE__ */ function(Status) {
1624
1620
  }({});
1625
1621
  const OfferSchema = () => {
1626
1622
  return z$1.object({
1627
- maker: z$1.string().transform(transformAddress),
1628
- obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
1623
+ maker: AddressSchema,
1624
+ maxUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
1629
1625
  tick: z$1.coerce.number().int().min(0).max(990),
1630
1626
  maturity: MaturitySchema,
1631
1627
  rcfThreshold: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
@@ -1642,13 +1638,13 @@ const OfferSchema = () => {
1642
1638
  z$1.bigint()
1643
1639
  ]).optional().default("0x0000000000000000000000000000000000000000000000000000000000000000").transform(transformBytes32),
1644
1640
  buy: z$1.boolean(),
1645
- loanToken: z$1.string().transform(transformAddress),
1641
+ loanToken: AddressSchema,
1646
1642
  collaterals: CollateralsSchema,
1647
1643
  callback: z$1.object({
1648
- address: z$1.string().transform(transformAddress),
1644
+ address: AddressSchema,
1649
1645
  data: z$1.string().transform(transformHex)
1650
1646
  }),
1651
- receiverIfMakerIsSeller: z$1.string().transform(transformAddress),
1647
+ receiverIfMakerIsSeller: AddressSchema,
1652
1648
  exitOnly: z$1.boolean().optional().default(false)
1653
1649
  }).refine((data) => data.start < data.expiry, {
1654
1650
  message: "start must be before expiry",
@@ -1701,7 +1697,7 @@ function toSnakeCase(offer) {
1701
1697
  */
1702
1698
  const serialize = (offer) => ({
1703
1699
  maker: offer.maker,
1704
- obligationUnits: offer.obligationUnits.toString(),
1700
+ maxUnits: offer.maxUnits.toString(),
1705
1701
  tick: offer.tick,
1706
1702
  maturity: Number(offer.maturity),
1707
1703
  rcfThreshold: offer.rcfThreshold.toString(),
@@ -1759,7 +1755,7 @@ function random$1(config) {
1759
1755
  const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
1760
1756
  const unit = BigInt(10) ** BigInt(loanTokenDecimals);
1761
1757
  const amountBase = BigInt(100 + int(999901));
1762
- const obligationUnitsScaled = config?.obligationUnits ?? amountBase * unit;
1758
+ const maxUnitsScaled = config?.maxUnits ?? amountBase * unit;
1763
1759
  const emptyCallback = {
1764
1760
  address: zeroAddress,
1765
1761
  data: "0x"
@@ -1767,7 +1763,7 @@ function random$1(config) {
1767
1763
  const maker = config?.maker ?? address();
1768
1764
  return from$13({
1769
1765
  maker,
1770
- obligationUnits: obligationUnitsScaled,
1766
+ maxUnits: maxUnitsScaled,
1771
1767
  tick,
1772
1768
  maturity,
1773
1769
  rcfThreshold: config?.rcfThreshold ?? 0n,
@@ -1821,7 +1817,7 @@ function hash$1(offer) {
1821
1817
  * Obligation obligation; // nested tuple
1822
1818
  * bool buy;
1823
1819
  * address maker;
1824
- * uint256 obligationUnits;
1820
+ * uint256 maxUnits;
1825
1821
  * uint256 start;
1826
1822
  * uint256 expiry;
1827
1823
  * uint256 tick;
@@ -1887,7 +1883,7 @@ const OfferAbi = [{
1887
1883
  type: "address"
1888
1884
  },
1889
1885
  {
1890
- name: "obligationUnits",
1886
+ name: "maxUnits",
1891
1887
  type: "uint256"
1892
1888
  },
1893
1889
  {
@@ -1935,7 +1931,7 @@ function encode$1(offer) {
1935
1931
  collaterals: offer.collaterals.map((c) => ({
1936
1932
  token: c.asset,
1937
1933
  lltv: c.lltv,
1938
- maxLif: c.maxLif ?? 0n,
1934
+ maxLif: c.maxLif,
1939
1935
  oracle: c.oracle
1940
1936
  })),
1941
1937
  maturity: BigInt(offer.maturity),
@@ -1943,7 +1939,7 @@ function encode$1(offer) {
1943
1939
  },
1944
1940
  buy: offer.buy,
1945
1941
  maker: offer.maker,
1946
- obligationUnits: offer.obligationUnits,
1942
+ maxUnits: offer.maxUnits,
1947
1943
  start: BigInt(offer.start),
1948
1944
  expiry: BigInt(offer.expiry),
1949
1945
  tick: BigInt(offer.tick),
@@ -1977,7 +1973,7 @@ function decode$1(data) {
1977
1973
  rcfThreshold: s.obligation.rcfThreshold,
1978
1974
  buy: s.buy,
1979
1975
  maker: s.maker,
1980
- obligationUnits: s.obligationUnits,
1976
+ maxUnits: s.maxUnits,
1981
1977
  start: Number(s.start),
1982
1978
  expiry: Number(s.expiry),
1983
1979
  tick: Number(s.tick),
@@ -2041,7 +2037,7 @@ const takeEvent = {
2041
2037
  internalType: "uint256"
2042
2038
  },
2043
2039
  {
2044
- name: "obligationUnits",
2040
+ name: "units",
2045
2041
  type: "uint256",
2046
2042
  indexed: false,
2047
2043
  internalType: "uint256"
@@ -2127,7 +2123,7 @@ const repayEvent = {
2127
2123
  internalType: "bytes32"
2128
2124
  },
2129
2125
  {
2130
- name: "obligationUnits",
2126
+ name: "units",
2131
2127
  type: "uint256",
2132
2128
  indexed: false,
2133
2129
  internalType: "uint256"
@@ -2444,10 +2440,10 @@ var Tick_exports = /* @__PURE__ */ __exportAll({
2444
2440
  InvalidTickError: () => InvalidTickError,
2445
2441
  MAX_PRICE: () => MAX_PRICE,
2446
2442
  TICK_RANGE: () => TICK_RANGE,
2447
- assetsToObligationUnits: () => assetsToObligationUnits,
2448
- obligationUnitsToAssets: () => obligationUnitsToAssets,
2443
+ assetsToUnits: () => assetsToUnits,
2449
2444
  priceToTick: () => priceToTick,
2450
- tickToPrice: () => tickToPrice
2445
+ tickToPrice: () => tickToPrice,
2446
+ unitsToAssets: () => unitsToAssets
2451
2447
  });
2452
2448
  /** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
2453
2449
  const LN_ONE_PLUS_DELTA = 24692612590371501n;
@@ -2506,24 +2502,79 @@ function assertPrice(price) {
2506
2502
  if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
2507
2503
  }
2508
2504
  /**
2509
- * Converts obligation units to assets using the tick price (mulDivDown).
2510
- * @param obligationUnits - The obligation units to convert.
2505
+ * Converts units into maker-side assets using the raw tick price surface.
2506
+ * This is the public forward conversion used by the router for lot sizing and other maker-facing capacity math.
2507
+ * - `buy = true` -> `floor(units * price / WAD)`
2508
+ * - `buy = false` -> `ceil(units * price / WAD)`
2509
+ * @param units - The units to convert.
2511
2510
  * @param tick - The offer tick.
2512
- * @returns The equivalent amount in assets.
2511
+ * @param buy - Whether the maker side of the offer is buy (`true`) or sell (`false`).
2512
+ * @returns The equivalent amount in maker-side assets.
2513
2513
  */
2514
- function obligationUnitsToAssets(obligationUnits, tick) {
2515
- return obligationUnits * tickToPrice(tick) / WAD$1;
2514
+ function unitsToAssets(units, tick, buy) {
2515
+ const price = tickToPrice(tick);
2516
+ return buy ? unitsToFloorAssets(units, price) : unitsToCeilAssets(units, price);
2516
2517
  }
2517
2518
  /**
2518
- * Converts assets to obligation units using the tick price (mulDivUp).
2519
- * @param assets - The asset amount to convert.
2519
+ * Converts a maker-side asset cap into a safe units cap using the raw tick price.
2520
+ * Buy offers use the max-safe inverse of `floor(units * price / WAD)`.
2521
+ * Sell offers use the max-safe inverse of `ceil(units * price / WAD)`.
2522
+ * The result is clamped to the remaining offer size because the asset cap may have been rounded before inversion.
2523
+ * Zero integer asset caps can still admit positive units on floor-rounded sub-WAD buy ticks, and tick=0 keeps the
2524
+ * whole remaining interval safe because the raw maker-asset surface stays at zero.
2525
+ * @param assets - The integer maker-side asset cap.
2520
2526
  * @param tick - The offer tick.
2521
- * @returns The equivalent amount in obligation units.
2527
+ * @param buy - Whether the maker side of the offer is buy (`true`) or sell (`false`).
2528
+ * @param remainingUnits - The maximum units still available on the offer.
2529
+ * @returns The greatest safe units amount under the maker-side raw-price surface.
2522
2530
  */
2523
- function assetsToObligationUnits(assets, tick) {
2531
+ function assetsToUnits(assets, tick, buy, remainingUnits) {
2532
+ if (remainingUnits <= 0n) return 0n;
2533
+ if (assets < 0n) return 0n;
2524
2534
  const price = tickToPrice(tick);
2525
- if (price === 0n) return 0n;
2526
- return (assets * WAD$1 + price - 1n) / price;
2535
+ if (price === 0n) return remainingUnits;
2536
+ const units = buy ? floorAssetsToUnits(assets, price) : ceilAssetsToUnits(assets, price);
2537
+ return units > remainingUnits ? remainingUnits : units;
2538
+ }
2539
+ /**
2540
+ * Forward conversion for raw-price floor surfaces.
2541
+ * This matches buy-side maker assets and the legacy floor-only helper.
2542
+ * @param units - The units to convert.
2543
+ * @param price - The raw tick price.
2544
+ * @returns The floor-rounded maker-side assets.
2545
+ */
2546
+ function unitsToFloorAssets(units, price) {
2547
+ return units * price / WAD$1;
2548
+ }
2549
+ /**
2550
+ * Forward conversion for raw-price ceil surfaces.
2551
+ * This matches sell-side maker assets, where the maker receives `sellerAssets` rounded up onchain.
2552
+ * @param units - The units to convert.
2553
+ * @param price - The raw tick price.
2554
+ * @returns The ceil-rounded maker-side assets.
2555
+ */
2556
+ function unitsToCeilAssets(units, price) {
2557
+ return (units * price + WAD$1 - 1n) / WAD$1;
2558
+ }
2559
+ /**
2560
+ * Max-safe inverse for floor surfaces.
2561
+ * It returns the greatest units value whose floor-rounded maker assets stay within `assets`.
2562
+ * @param assets - The maker-side asset cap.
2563
+ * @param price - The raw tick price.
2564
+ * @returns The greatest safe obligation-units amount under `floor(units * price / WAD) <= assets`.
2565
+ */
2566
+ function floorAssetsToUnits(assets, price) {
2567
+ return ((assets + 1n) * WAD$1 - 1n) / price;
2568
+ }
2569
+ /**
2570
+ * Max-safe inverse for ceil surfaces.
2571
+ * It returns the greatest units value whose ceil-rounded maker assets stay within `assets`.
2572
+ * @param assets - The maker-side asset cap.
2573
+ * @param price - The raw tick price.
2574
+ * @returns The greatest safe obligation-units amount under `ceil(units * price / WAD) <= assets`.
2575
+ */
2576
+ function ceilAssetsToUnits(assets, price) {
2577
+ return assets * WAD$1 / price;
2527
2578
  }
2528
2579
  var InvalidTickError = class extends BaseError {
2529
2580
  name = "Tick.InvalidTickError";
@@ -4069,6 +4120,10 @@ function* ask(operation) {
4069
4120
 
4070
4121
  //#endregion
4071
4122
  //#region src/indexer/engine/adapter/appliers/applyChainState.ts
4123
+ const emptyOutcome = () => ({
4124
+ stats: [],
4125
+ dbRows: []
4126
+ });
4072
4127
  function isChainUninitializedError$1(error) {
4073
4128
  return error instanceof Error && error.message.includes("Chain state not initialized");
4074
4129
  }
@@ -4117,7 +4172,7 @@ const chainStateAppliers = {
4117
4172
  context.chainMutationState.expectedTipHashForWrite = advanceParameters.tipHash;
4118
4173
  }
4119
4174
  context.chainMutationState.expectedChainState = nextChainState;
4120
- return [];
4175
+ return emptyOutcome();
4121
4176
  },
4122
4177
  collector: async ({ mutation, dbTx, context }) => {
4123
4178
  const collectorName = context.toCollectorName(mutation.name);
@@ -4131,7 +4186,7 @@ const chainStateAppliers = {
4131
4186
  blockNumber: mutation.cursor,
4132
4187
  epoch: BigInt(mutation.epoch)
4133
4188
  });
4134
- return [];
4189
+ return emptyOutcome();
4135
4190
  }
4136
4191
  };
4137
4192
 
@@ -4144,33 +4199,66 @@ const LOTS_PENDING_LINK_TYPE = "offers_lots_missing_group";
4144
4199
 
4145
4200
  //#endregion
4146
4201
  //#region src/indexer/engine/adapter/appliers/applyMorphoV2.ts
4202
+ const outcome$3 = (parameters) => ({
4203
+ stats: parameters.stats ?? [],
4204
+ dbRows: parameters.dbRows ?? []
4205
+ });
4147
4206
  const morphoV2Appliers = {
4148
4207
  transfers_create: async ({ mutation, dbTx }) => {
4149
- await dbTx.transfers.create(mutation.rows);
4150
- return mutation.rows.length > 0 ? [{
4151
- entity: "transfer",
4152
- operation: "inserted",
4153
- count: mutation.rows.length
4154
- }] : [];
4208
+ const insertedTransfers = await dbTx.transfers.create(mutation.rows);
4209
+ return outcome$3({
4210
+ stats: mutation.rows.length > 0 ? [{
4211
+ entity: "transfer",
4212
+ operation: "inserted",
4213
+ count: mutation.rows.length
4214
+ }] : [],
4215
+ dbRows: insertedTransfers > 0 ? [{
4216
+ table: "transfers",
4217
+ operation: "inserted",
4218
+ count: insertedTransfers
4219
+ }] : []
4220
+ });
4155
4221
  },
4156
4222
  consumed_create: async ({ mutation, dbTx }) => {
4157
- await dbTx.consumed.create(mutation.rows);
4158
- return mutation.rows.length > 0 ? [{
4159
- entity: "consumed_event",
4160
- operation: "inserted",
4161
- count: mutation.rows.length
4162
- }] : [];
4223
+ const inserted = await dbTx.consumed.create(mutation.rows);
4224
+ return outcome$3({
4225
+ stats: mutation.rows.length > 0 ? [{
4226
+ entity: "consumed_event",
4227
+ operation: "inserted",
4228
+ count: mutation.rows.length
4229
+ }] : [],
4230
+ dbRows: [...inserted.groupsInserted > 0 ? [{
4231
+ table: "groups",
4232
+ operation: "inserted",
4233
+ count: inserted.groupsInserted
4234
+ }] : [], ...inserted.consumedEventsInserted > 0 ? [{
4235
+ table: "consumed_events",
4236
+ operation: "inserted",
4237
+ count: inserted.consumedEventsInserted
4238
+ }] : []]
4239
+ });
4163
4240
  },
4164
4241
  seizures_record: async ({ mutation, dbTx, context }) => {
4165
- await context.pendingStore.applySeizureFacts({
4242
+ const materialized = await context.pendingStore.applySeizureFacts({
4166
4243
  dbTx,
4167
4244
  seizureFacts: mutation.rows
4168
4245
  });
4169
- return mutation.rows.length > 0 ? [{
4170
- entity: "seizure_fact",
4171
- operation: "inserted",
4172
- count: mutation.rows.length
4173
- }] : [];
4246
+ return outcome$3({
4247
+ stats: mutation.rows.length > 0 ? [{
4248
+ entity: "seizure_fact",
4249
+ operation: "inserted",
4250
+ count: mutation.rows.length
4251
+ }] : [],
4252
+ dbRows: [...materialized.positionsUpserted > 0 ? [{
4253
+ table: "positions",
4254
+ operation: "upserted",
4255
+ count: materialized.positionsUpserted
4256
+ }] : [], ...materialized.transfersInserted > 0 ? [{
4257
+ table: "transfers",
4258
+ operation: "inserted",
4259
+ count: materialized.transfersInserted
4260
+ }] : []]
4261
+ });
4174
4262
  },
4175
4263
  morpho_v2_rewind: async ({ mutation, dbTx, context }) => {
4176
4264
  const deletedConsumedEvents = await dbTx.consumed.delete({
@@ -4194,23 +4282,41 @@ const morphoV2Appliers = {
4194
4282
  });
4195
4283
  const deletedTransfers = deletedDebtTransfers + deletedCollateralTransfers;
4196
4284
  const stats = [];
4197
- if (deletedConsumedEvents > 0) stats.push({
4198
- entity: "consumed_event",
4199
- operation: "deleted",
4200
- count: deletedConsumedEvents
4201
- });
4202
- if (deletedTransfers > 0) stats.push({
4203
- entity: "transfer",
4204
- operation: "deleted",
4205
- count: deletedTransfers
4285
+ const dbRows = [];
4286
+ if (deletedConsumedEvents > 0) {
4287
+ stats.push({
4288
+ entity: "consumed_event",
4289
+ operation: "deleted",
4290
+ count: deletedConsumedEvents
4291
+ });
4292
+ dbRows.push({
4293
+ table: "consumed_events",
4294
+ operation: "deleted",
4295
+ count: deletedConsumedEvents
4296
+ });
4297
+ }
4298
+ if (deletedTransfers > 0) {
4299
+ stats.push({
4300
+ entity: "transfer",
4301
+ operation: "deleted",
4302
+ count: deletedTransfers
4303
+ });
4304
+ dbRows.push({
4305
+ table: "transfers",
4306
+ operation: "deleted",
4307
+ count: deletedTransfers
4308
+ });
4309
+ }
4310
+ return outcome$3({
4311
+ stats,
4312
+ dbRows
4206
4313
  });
4207
- return stats;
4208
4314
  }
4209
4315
  };
4210
4316
 
4211
4317
  //#endregion
4212
4318
  //#region src/database/drizzle/VERSION.ts
4213
- const VERSION = "router_v1.15";
4319
+ const VERSION = "router_v1.16";
4214
4320
 
4215
4321
  //#endregion
4216
4322
  //#region src/database/drizzle/schema.ts
@@ -4358,7 +4464,7 @@ const oracles$1 = s.table(EnumTableName.ORACLES, {
4358
4464
  const offers = s.table(EnumTableName.OFFERS, {
4359
4465
  hash: varchar("hash", { length: 66 }).notNull(),
4360
4466
  obligationId: varchar("obligation_id", { length: 66 }).notNull().references(() => obligationIdKeys.obligationId, { onDelete: "cascade" }),
4361
- obligationUnits: numeric("obligation_units", {
4467
+ maxUnits: numeric("max_units", {
4362
4468
  precision: 78,
4363
4469
  scale: 0
4364
4470
  }).notNull().default("0"),
@@ -4399,8 +4505,8 @@ const offers = s.table(EnumTableName.OFFERS, {
4399
4505
  index("offers_obligation_side_tick_idx").on(table.obligationId, table.buy, table.tick),
4400
4506
  index("offers_obligation_active_tick_idx").on(table.obligationId, table.buy, table.expiry, table.maturity, table.start, table.tick),
4401
4507
  index("offers_group_maker_idx").on(table.groupMaker, table.hash, table.obligationId),
4402
- index("offers_group_winner_expr_idx").on(table.groupChainId, table.groupMaker, table.group, table.obligationId, table.buy, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"obligation_units" DESC`, table.hash),
4403
- index("offers_book_winners_covering_idx").on(table.obligationId, table.buy, table.groupChainId, table.groupMaker, table.group, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"obligation_units" DESC`, table.hash)
4508
+ index("offers_group_winner_expr_idx").on(table.groupChainId, table.groupMaker, table.group, table.obligationId, table.buy, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"max_units" DESC`, table.hash),
4509
+ index("offers_book_winners_covering_idx").on(table.obligationId, table.buy, table.groupChainId, table.groupMaker, table.group, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"max_units" DESC`, table.hash)
4404
4510
  ]);
4405
4511
  const offersCallbacks = s.table(EnumTableName.OFFERS_CALLBACKS, {
4406
4512
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
@@ -4701,7 +4807,12 @@ const buildGroupReferenceKey = (chainId, maker, group) => `${chainId}:${maker.to
4701
4807
  const buildCallbacksMissingOfferReference = (row) => `${row.offerHash.toLowerCase()}:${row.obligationId.toLowerCase()}`;
4702
4808
  const buildMerklePathMissingOfferReference = (row) => `${row.offerHash.toLowerCase()}:${row.obligationId.toLowerCase()}:${row.treeRoot.toLowerCase()}`;
4703
4809
  const buildLotMissingGroupReference = (row) => `${row.positionChainId}:${row.positionUser.toLowerCase()}:${row.group.toLowerCase()}:${row.obligationId.toLowerCase()}`;
4704
- const stat = (parameters) => parameters.count > 0 ? [parameters] : [];
4810
+ const entityStat = (parameters) => parameters.count > 0 ? [parameters] : [];
4811
+ const dbRowStat = (parameters) => parameters.count > 0 ? [parameters] : [];
4812
+ const outcome$2 = (parameters) => ({
4813
+ stats: parameters.stats ?? [],
4814
+ dbRows: parameters.dbRows ?? []
4815
+ });
4705
4816
  async function selectExistingOfferKeys(parameters) {
4706
4817
  const { context, dbTx, references } = parameters;
4707
4818
  if (references.length === 0) return /* @__PURE__ */ new Set();
@@ -4782,45 +4893,93 @@ async function partitionLotsByGroupExistence(parameters) {
4782
4893
  }
4783
4894
  const offersAppliers = {
4784
4895
  obligations_create: async ({ mutation, dbTx }) => {
4785
- await dbTx.obligations.create(mutation.rows);
4786
- return stat({
4787
- entity: "obligation",
4788
- operation: "inserted",
4789
- count: mutation.rows.length
4896
+ const inserted = await dbTx.obligations.create(mutation.rows);
4897
+ return outcome$2({
4898
+ stats: entityStat({
4899
+ entity: "obligation",
4900
+ operation: "inserted",
4901
+ count: mutation.rows.length
4902
+ }),
4903
+ dbRows: [
4904
+ ...dbRowStat({
4905
+ table: "obligations",
4906
+ operation: "inserted",
4907
+ count: inserted.obligationsInserted
4908
+ }),
4909
+ ...dbRowStat({
4910
+ table: "obligation_id_keys",
4911
+ operation: "inserted",
4912
+ count: inserted.obligationIdKeysInserted
4913
+ }),
4914
+ ...dbRowStat({
4915
+ table: "obligation_collaterals_v2",
4916
+ operation: "inserted",
4917
+ count: inserted.obligationCollateralsInserted
4918
+ })
4919
+ ]
4790
4920
  });
4791
4921
  },
4792
4922
  groups_create: async ({ mutation, dbTx }) => {
4793
- await dbTx.groups.create(mutation.rows);
4794
- return stat({
4795
- entity: "group",
4796
- operation: "inserted",
4797
- count: mutation.rows.length
4923
+ const insertedGroups = await dbTx.groups.create(mutation.rows);
4924
+ return outcome$2({
4925
+ stats: entityStat({
4926
+ entity: "group",
4927
+ operation: "inserted",
4928
+ count: mutation.rows.length
4929
+ }),
4930
+ dbRows: dbRowStat({
4931
+ table: "groups",
4932
+ operation: "inserted",
4933
+ count: insertedGroups
4934
+ })
4798
4935
  });
4799
4936
  },
4800
4937
  offers_create: async ({ mutation, dbTx }) => {
4801
- await dbTx.offers.create(mutation.batches);
4802
- return stat({
4803
- entity: "offer",
4804
- operation: "inserted",
4805
- count: mutation.batches.reduce((total, batch) => total + batch.offers.length, 0)
4938
+ const insertedOffers = await dbTx.offers.create(mutation.batches);
4939
+ return outcome$2({
4940
+ stats: entityStat({
4941
+ entity: "offer",
4942
+ operation: "inserted",
4943
+ count: insertedOffers.length
4944
+ }),
4945
+ dbRows: dbRowStat({
4946
+ table: "offers",
4947
+ operation: "inserted",
4948
+ count: insertedOffers.length
4949
+ })
4806
4950
  });
4807
4951
  },
4808
4952
  offers_rewind: async ({ mutation, dbTx, context }) => {
4809
- return stat({
4810
- entity: "offer",
4811
- operation: "deleted",
4812
- count: await dbTx.offers.delete({
4813
- chainId: context.chainId,
4814
- blockNumberGte: mutation.blockNumberGte
4953
+ const deletedOffers = await dbTx.offers.delete({
4954
+ chainId: context.chainId,
4955
+ blockNumberGte: mutation.blockNumberGte
4956
+ });
4957
+ return outcome$2({
4958
+ stats: entityStat({
4959
+ entity: "offer",
4960
+ operation: "deleted",
4961
+ count: deletedOffers
4962
+ }),
4963
+ dbRows: dbRowStat({
4964
+ table: "offers",
4965
+ operation: "deleted",
4966
+ count: deletedOffers
4815
4967
  })
4816
4968
  });
4817
4969
  },
4818
4970
  trees_upsert: async ({ mutation, dbTx }) => {
4819
- await dbTx.trees.upsert(mutation.rows);
4820
- return stat({
4821
- entity: "tree",
4822
- operation: "upserted",
4823
- count: mutation.rows.length
4971
+ const upsertedRoots = await dbTx.trees.upsert(mutation.rows);
4972
+ return outcome$2({
4973
+ stats: entityStat({
4974
+ entity: "tree",
4975
+ operation: "upserted",
4976
+ count: mutation.rows.length
4977
+ }),
4978
+ dbRows: dbRowStat({
4979
+ table: "trees",
4980
+ operation: "upserted",
4981
+ count: upsertedRoots.length
4982
+ })
4824
4983
  });
4825
4984
  },
4826
4985
  trees_upsert_paths: async ({ mutation, dbTx, context }) => {
@@ -4841,15 +5000,22 @@ const offersAppliers = {
4841
5000
  blockNumber: context.pendingLinkReferenceBlockNumber()
4842
5001
  }))
4843
5002
  });
4844
- return [...stat({
4845
- entity: "tree_path",
4846
- operation: "upserted",
4847
- count: resolvableRows.length
4848
- }), ...stat({
4849
- entity: "tree_path",
4850
- operation: "ignored",
4851
- count: missingRows.length
4852
- })];
5003
+ return outcome$2({
5004
+ stats: [...entityStat({
5005
+ entity: "tree_path",
5006
+ operation: "upserted",
5007
+ count: resolvableRows.length
5008
+ }), ...entityStat({
5009
+ entity: "tree_path",
5010
+ operation: "ignored",
5011
+ count: missingRows.length
5012
+ })],
5013
+ dbRows: dbRowStat({
5014
+ table: "merkle_paths",
5015
+ operation: "upserted",
5016
+ count: resolvableRows.length
5017
+ })
5018
+ });
4853
5019
  },
4854
5020
  callbacks_upsert: async ({ mutation, dbTx, context }) => {
4855
5021
  const { resolvableRows, missingRows } = await partitionCallbacksByOfferExistence({
@@ -4857,7 +5023,10 @@ const offersAppliers = {
4857
5023
  dbTx,
4858
5024
  rows: mutation.rows
4859
5025
  });
4860
- if (resolvableRows.length > 0) await dbTx.callbacks.upsert(resolvableRows);
5026
+ const inserted = resolvableRows.length > 0 ? await dbTx.callbacks.upsert(resolvableRows) : {
5027
+ callbacksInserted: 0,
5028
+ offersCallbacksInserted: 0
5029
+ };
4861
5030
  await context.pendingStore.recordIgnoredLinks({
4862
5031
  dbTx,
4863
5032
  records: missingRows.map((row) => ({
@@ -4869,22 +5038,36 @@ const offersAppliers = {
4869
5038
  blockNumber: context.pendingLinkReferenceBlockNumber()
4870
5039
  }))
4871
5040
  });
4872
- return [...stat({
4873
- entity: "callback",
4874
- operation: "upserted",
4875
- count: resolvableRows.length
4876
- }), ...stat({
4877
- entity: "callback",
4878
- operation: "ignored",
4879
- count: missingRows.length
4880
- })];
5041
+ return outcome$2({
5042
+ stats: [...entityStat({
5043
+ entity: "callback",
5044
+ operation: "upserted",
5045
+ count: resolvableRows.length
5046
+ }), ...entityStat({
5047
+ entity: "callback",
5048
+ operation: "ignored",
5049
+ count: missingRows.length
5050
+ })],
5051
+ dbRows: [...dbRowStat({
5052
+ table: "callbacks",
5053
+ operation: "inserted",
5054
+ count: inserted.callbacksInserted
5055
+ }), ...dbRowStat({
5056
+ table: "offers_callbacks",
5057
+ operation: "inserted",
5058
+ count: inserted.offersCallbacksInserted
5059
+ })]
5060
+ });
4881
5061
  },
4882
5062
  lots_create: async ({ mutation, dbTx, context }) => {
4883
5063
  const { resolvableRows, missingRows } = await partitionLotsByGroupExistence({
4884
5064
  dbTx,
4885
5065
  rows: mutation.rows
4886
5066
  });
4887
- if (resolvableRows.length > 0) await dbTx.lots.create(resolvableRows);
5067
+ const inserted = resolvableRows.length > 0 ? await dbTx.lots.create(resolvableRows) : {
5068
+ lotsPositionsInserted: 0,
5069
+ lotsInserted: 0
5070
+ };
4888
5071
  await context.pendingStore.recordIgnoredLinks({
4889
5072
  dbTx,
4890
5073
  records: missingRows.map((row) => ({
@@ -4896,43 +5079,76 @@ const offersAppliers = {
4896
5079
  blockNumber: context.pendingLinkReferenceBlockNumber()
4897
5080
  }))
4898
5081
  });
4899
- return [...stat({
4900
- entity: "lot",
4901
- operation: "inserted",
4902
- count: resolvableRows.length
4903
- }), ...stat({
4904
- entity: "lot",
4905
- operation: "ignored",
4906
- count: missingRows.length
4907
- })];
5082
+ return outcome$2({
5083
+ stats: [...entityStat({
5084
+ entity: "lot",
5085
+ operation: "inserted",
5086
+ count: resolvableRows.length
5087
+ }), ...entityStat({
5088
+ entity: "lot",
5089
+ operation: "ignored",
5090
+ count: missingRows.length
5091
+ })],
5092
+ dbRows: [...dbRowStat({
5093
+ table: "lots_positions",
5094
+ operation: "inserted",
5095
+ count: inserted.lotsPositionsInserted
5096
+ }), ...dbRowStat({
5097
+ table: "lots",
5098
+ operation: "inserted",
5099
+ count: inserted.lotsInserted
5100
+ })]
5101
+ });
4908
5102
  }
4909
5103
  };
4910
5104
 
4911
5105
  //#endregion
4912
5106
  //#region src/indexer/engine/adapter/appliers/applyOracle.ts
5107
+ const outcome$1 = (parameters) => ({
5108
+ stats: parameters.stats ?? [],
5109
+ dbRows: parameters.dbRows ?? []
5110
+ });
4913
5111
  const oracleApplier = { oracle: async ({ mutation, dbTx, context }) => {
4914
- await dbTx.oracles.upsert(mutation.rows.map((row) => ({
5112
+ const upsertedOracles = await dbTx.oracles.upsert(mutation.rows.map((row) => ({
4915
5113
  chainId: context.chainId,
4916
5114
  ...row,
4917
5115
  address: row.address
4918
5116
  })));
4919
- return mutation.rows.length > 0 ? [{
4920
- entity: "oracle",
4921
- operation: "upserted",
4922
- count: mutation.rows.length
4923
- }] : [];
5117
+ return outcome$1({
5118
+ stats: mutation.rows.length > 0 ? [{
5119
+ entity: "oracle",
5120
+ operation: "upserted",
5121
+ count: mutation.rows.length
5122
+ }] : [],
5123
+ dbRows: upsertedOracles > 0 ? [{
5124
+ table: "oracles",
5125
+ operation: "upserted",
5126
+ count: upsertedOracles
5127
+ }] : []
5128
+ });
4924
5129
  } };
4925
5130
 
4926
5131
  //#endregion
4927
5132
  //#region src/indexer/engine/adapter/appliers/applyPositions.ts
5133
+ const outcome = (parameters) => ({
5134
+ stats: parameters.stats ?? [],
5135
+ dbRows: parameters.dbRows ?? []
5136
+ });
4928
5137
  const positionsAppliers = {
4929
5138
  positions_upsert: async ({ mutation, dbTx }) => {
4930
- await dbTx.positions.upsert(mutation.rows);
4931
- return mutation.rows.length > 0 ? [{
4932
- entity: "position",
4933
- operation: "upserted",
4934
- count: mutation.rows.length
4935
- }] : [];
5139
+ const upsertedPositions = await dbTx.positions.upsert(mutation.rows);
5140
+ return outcome({
5141
+ stats: mutation.rows.length > 0 ? [{
5142
+ entity: "position",
5143
+ operation: "upserted",
5144
+ count: mutation.rows.length
5145
+ }] : [],
5146
+ dbRows: upsertedPositions > 0 ? [{
5147
+ table: "positions",
5148
+ operation: "upserted",
5149
+ count: upsertedPositions
5150
+ }] : []
5151
+ });
4936
5152
  },
4937
5153
  positions_rewind: async ({ mutation, dbTx, context }) => {
4938
5154
  const deletedPositions = await dbTx.positions.setEmptyAfter({
@@ -4940,11 +5156,11 @@ const positionsAppliers = {
4940
5156
  blockNumber: mutation.blockNumberGte,
4941
5157
  type: Type.ERC20
4942
5158
  });
4943
- return deletedPositions > 0 ? [{
5159
+ return outcome({ stats: deletedPositions > 0 ? [{
4944
5160
  entity: "position",
4945
5161
  operation: "deleted",
4946
5162
  count: deletedPositions
4947
- }] : [];
5163
+ }] : [] });
4948
5164
  }
4949
5165
  };
4950
5166
 
@@ -5257,7 +5473,9 @@ async function materializeSeizureFacts(parameters) {
5257
5473
  if (seizureFacts.length === 0) return {
5258
5474
  unresolvedFacts: [],
5259
5475
  transfersCreate: [],
5260
- positionsUpsert: []
5476
+ positionsUpsert: [],
5477
+ transfersInserted: 0,
5478
+ positionsUpserted: 0
5261
5479
  };
5262
5480
  const resolutionMap = await resolveCollateralAssetRefs({
5263
5481
  dbTx,
@@ -5285,9 +5503,11 @@ async function materializeSeizureFacts(parameters) {
5285
5503
  }));
5286
5504
  }
5287
5505
  const positionsUpsert = toCollateralPositionRows(resolvedTransfers);
5506
+ let positionsUpserted = 0;
5507
+ let transfersInserted = 0;
5288
5508
  if (resolvedTransfers.length > 0) {
5289
- await dbTx.positions.upsert(positionsUpsert);
5290
- await dbTx.transfers.create(resolvedTransfers);
5509
+ positionsUpserted = await dbTx.positions.upsert(positionsUpsert);
5510
+ transfersInserted = await dbTx.transfers.create(resolvedTransfers);
5291
5511
  await recomputeBackfilledCollateralBalances({
5292
5512
  dbTx,
5293
5513
  transfers: resolvedTransfers
@@ -5296,7 +5516,9 @@ async function materializeSeizureFacts(parameters) {
5296
5516
  return {
5297
5517
  unresolvedFacts,
5298
5518
  transfersCreate: resolvedTransfers,
5299
- positionsUpsert
5519
+ positionsUpsert,
5520
+ transfersInserted,
5521
+ positionsUpserted
5300
5522
  };
5301
5523
  }
5302
5524
  const toFactsFromPendingRows = (chainId, rows) => rows.map((row) => ({
@@ -5546,15 +5768,20 @@ const createPendingLinkStore = (parameters) => {
5546
5768
  const resolverTypes = resolverEntries.map((resolver) => resolver.type);
5547
5769
  return {
5548
5770
  applySeizureFacts: async ({ dbTx, seizureFacts }) => {
5771
+ const materialized = await materializeSeizureFacts({
5772
+ dbTx,
5773
+ chainId,
5774
+ seizureFacts
5775
+ });
5549
5776
  await recordUnresolvedSeizures({
5550
5777
  dbTx,
5551
5778
  chainId,
5552
- seizureFacts: (await materializeSeizureFacts({
5553
- dbTx,
5554
- chainId,
5555
- seizureFacts
5556
- })).unresolvedFacts
5779
+ seizureFacts: materialized.unresolvedFacts
5557
5780
  });
5781
+ return {
5782
+ positionsUpserted: materialized.positionsUpserted,
5783
+ transfersInserted: materialized.transfersInserted
5784
+ };
5558
5785
  },
5559
5786
  recordIgnoredLinks: async ({ dbTx, records }) => {
5560
5787
  if (records.length === 0) return;
@@ -5903,6 +6130,7 @@ const create$29 = (parameters) => {
5903
6130
  chainMutationState
5904
6131
  };
5905
6132
  const commitAppliedStats = [];
6133
+ const commitAppliedDbRows = [];
5906
6134
  const collectorsInCommit = /* @__PURE__ */ new Set();
5907
6135
  const dispatchMutation = async (parameters) => {
5908
6136
  const applier = mutationAppliers[parameters.mutation.t];
@@ -5915,18 +6143,24 @@ const create$29 = (parameters) => {
5915
6143
  try {
5916
6144
  await db.transaction(async (dbTx) => {
5917
6145
  for (const mutation of tx.muts) {
5918
- const mutationApplyStats = await dispatchMutation({
6146
+ const mutationApplyOutcome = await dispatchMutation({
5919
6147
  mutation,
5920
6148
  dbTx
5921
6149
  });
5922
6150
  if (mutation.collector === void 0) continue;
5923
6151
  collectorsInCommit.add(mutation.collector);
5924
- for (const stat of mutationApplyStats) commitAppliedStats.push({
6152
+ for (const stat of mutationApplyOutcome.stats) commitAppliedStats.push({
5925
6153
  collector: mutation.collector,
5926
6154
  entity: stat.entity,
5927
6155
  operation: stat.operation,
5928
6156
  count: stat.count
5929
6157
  });
6158
+ for (const dbRow of mutationApplyOutcome.dbRows) commitAppliedDbRows.push({
6159
+ collector: mutation.collector,
6160
+ table: dbRow.table,
6161
+ operation: dbRow.operation,
6162
+ count: dbRow.count
6163
+ });
5930
6164
  }
5931
6165
  });
5932
6166
  } catch (error) {
@@ -5941,6 +6175,7 @@ const create$29 = (parameters) => {
5941
6175
  chainId,
5942
6176
  collectors: [...collectorsInCommit],
5943
6177
  stats: commitAppliedStats,
6178
+ dbRows: commitAppliedDbRows,
5944
6179
  onCommitApplied
5945
6180
  });
5946
6181
  const nowBlock = state.chain.checkpoints[state.chain.checkpoints.length - 1]?.n ?? 0;
@@ -5988,19 +6223,21 @@ const create$29 = (parameters) => {
5988
6223
  function emitCommitAppliedObservation(parameters) {
5989
6224
  if (parameters.collectors.length === 0) return;
5990
6225
  const aggregatedStats = aggregateCommitAppliedStats(parameters.stats);
6226
+ const aggregatedDbRows = aggregateCommitAppliedDbRows(parameters.dbRows);
5991
6227
  try {
5992
6228
  parameters.onCommitApplied({
5993
6229
  chainId: parameters.chainId,
5994
6230
  collectors: parameters.collectors,
5995
6231
  committedAtUnixMs: Date.now(),
5996
- stats: aggregatedStats
6232
+ stats: aggregatedStats,
6233
+ dbRows: aggregatedDbRows
5997
6234
  });
5998
6235
  } catch {}
5999
6236
  }
6000
6237
  function aggregateCommitAppliedStats(stats) {
6001
6238
  const aggregatedByKey = /* @__PURE__ */ new Map();
6002
6239
  for (const stat of stats) {
6003
- const count = normalizeMutationApplyStatCount(stat.count);
6240
+ const count = normalizePositiveCount(stat.count);
6004
6241
  if (count === null) continue;
6005
6242
  const key = `${stat.collector}\u0000${stat.entity}\u0000${stat.operation}`;
6006
6243
  const previous = aggregatedByKey.get(key);
@@ -6021,7 +6258,31 @@ function aggregateCommitAppliedStats(stats) {
6021
6258
  return left.operation.localeCompare(right.operation);
6022
6259
  });
6023
6260
  }
6024
- function normalizeMutationApplyStatCount(value) {
6261
+ function aggregateCommitAppliedDbRows(dbRows) {
6262
+ const aggregatedByKey = /* @__PURE__ */ new Map();
6263
+ for (const dbRow of dbRows) {
6264
+ const count = normalizePositiveCount(dbRow.count);
6265
+ if (count === null) continue;
6266
+ const key = `${dbRow.collector}\u0000${dbRow.table}\u0000${dbRow.operation}`;
6267
+ const previous = aggregatedByKey.get(key);
6268
+ if (previous === void 0) {
6269
+ aggregatedByKey.set(key, {
6270
+ collector: dbRow.collector,
6271
+ table: dbRow.table,
6272
+ operation: dbRow.operation,
6273
+ count
6274
+ });
6275
+ continue;
6276
+ }
6277
+ previous.count += count;
6278
+ }
6279
+ return [...aggregatedByKey.values()].sort((left, right) => {
6280
+ if (left.collector !== right.collector) return left.collector.localeCompare(right.collector);
6281
+ if (left.table !== right.table) return left.table.localeCompare(right.table);
6282
+ return left.operation.localeCompare(right.operation);
6283
+ });
6284
+ }
6285
+ function normalizePositiveCount(value) {
6025
6286
  if (!Number.isFinite(value)) return null;
6026
6287
  const normalized = Math.trunc(value);
6027
6288
  return normalized > 0 ? normalized : null;
@@ -6251,7 +6512,7 @@ function processConsumedLogs(parameters) {
6251
6512
  * A debt is modeled as a negative position: borrowing = transfer FROM user TO zeroAddress,
6252
6513
  * repayment = FROM zeroAddress TO user. The contract field is the obligationId.
6253
6514
  *
6254
- * **Take event** — Every take is bilateral when obligationUnits > 0:
6515
+ * **Take event** — Every take is bilateral when units > 0:
6255
6516
  * - Buyer (maker if offerIsBuy, taker otherwise): debt decreases (repaid) → from: 0x0 → to: buyer
6256
6517
  * - Seller (taker if offerIsBuy, maker otherwise): debt increases (borrows) → from: seller → to: 0x0
6257
6518
  *
@@ -6283,14 +6544,14 @@ function processDebtTransfers(parameters) {
6283
6544
  if (eventName === takeEvent.name) {
6284
6545
  const args = rawLog.args;
6285
6546
  const obligationId = args?.id_;
6286
- if (obligationId === void 0 || args?.maker === void 0 || args?.taker === void 0 || args?.offerIsBuy === void 0 || args?.obligationUnits === void 0) {
6547
+ if (obligationId === void 0 || args?.maker === void 0 || args?.taker === void 0 || args?.offerIsBuy === void 0 || args?.units === void 0) {
6287
6548
  logger.debug({
6288
6549
  event: INDEXER_COLLECTOR_LOG_SKIPPED,
6289
6550
  msg: "Skipping Take log because it is missing required args for debt"
6290
6551
  });
6291
6552
  continue;
6292
6553
  }
6293
- if (args.obligationUnits === 0n) continue;
6554
+ if (args.units === 0n) continue;
6294
6555
  const buyer = args.offerIsBuy ? args.maker : args.taker;
6295
6556
  const seller = args.offerIsBuy ? args.taker : args.maker;
6296
6557
  const blockNumber = Number(rawLog.blockNumber);
@@ -6300,7 +6561,7 @@ function processDebtTransfers(parameters) {
6300
6561
  contract: obligationId,
6301
6562
  from: zeroAddress,
6302
6563
  to: buyer,
6303
- value: args.obligationUnits,
6564
+ value: args.units,
6304
6565
  type: Type.DEBT_OF,
6305
6566
  asset: zeroAddress,
6306
6567
  blockNumber
@@ -6311,7 +6572,7 @@ function processDebtTransfers(parameters) {
6311
6572
  contract: obligationId,
6312
6573
  from: seller,
6313
6574
  to: zeroAddress,
6314
- value: args.obligationUnits,
6575
+ value: args.units,
6315
6576
  type: Type.DEBT_OF,
6316
6577
  asset: zeroAddress,
6317
6578
  blockNumber
@@ -6321,21 +6582,21 @@ function processDebtTransfers(parameters) {
6321
6582
  if (eventName === repayEvent.name) {
6322
6583
  const args = rawLog.args;
6323
6584
  const obligationId = args?.id_;
6324
- if (obligationId === void 0 || args?.obligationUnits === void 0 || args?.onBehalf === void 0) {
6585
+ if (obligationId === void 0 || args?.units === void 0 || args?.onBehalf === void 0) {
6325
6586
  logger.debug({
6326
6587
  event: INDEXER_COLLECTOR_LOG_SKIPPED,
6327
6588
  msg: "Skipping Repay log because it is missing required args"
6328
6589
  });
6329
6590
  continue;
6330
6591
  }
6331
- if (args.obligationUnits === 0n) continue;
6592
+ if (args.units === 0n) continue;
6332
6593
  transfers.push(from$8({
6333
6594
  id: `${baseId}-debt-repay`,
6334
6595
  chainId,
6335
6596
  contract: obligationId,
6336
6597
  from: zeroAddress,
6337
6598
  to: args.onBehalf,
6338
- value: args.obligationUnits,
6599
+ value: args.units,
6339
6600
  type: Type.DEBT_OF,
6340
6601
  asset: zeroAddress,
6341
6602
  blockNumber: Number(rawLog.blockNumber)
@@ -6659,6 +6920,15 @@ const processBatchesUntilCursorAdvance = async (stream, cursor, processBatch, op
6659
6920
  const collectorName$7 = "morpho_v2";
6660
6921
  const RESOLVE_CONSUMED_YIELD_EVERY_ITEMS = 256;
6661
6922
  const RESOLVE_CONSUMED_YIELD_EVERY_MS = 8;
6923
+ const MORPHO_DERIVED_LOG_ID_SUFFIXES = [
6924
+ "-debt-buyer",
6925
+ "-debt-seller",
6926
+ "-debt-repay",
6927
+ "-debt-liquidate",
6928
+ "-collateral-supply",
6929
+ "-collateral-withdraw",
6930
+ "-collateral-liquidate"
6931
+ ];
6662
6932
  const runNativeStep$2 = async (parameters) => {
6663
6933
  const { request, client, db, logger } = parameters;
6664
6934
  const consumedEvents = [];
@@ -6666,7 +6936,6 @@ const runNativeStep$2 = async (parameters) => {
6666
6936
  const collateralTransfers = [];
6667
6937
  const seizureFacts = [];
6668
6938
  let logsIngestedCount = 0;
6669
- let logsIndexedCount = 0;
6670
6939
  const streamStep = await processBatchesUntilCursorAdvance(streamLogs({
6671
6940
  client,
6672
6941
  contractAddress: client.chain.custom.morpho.address,
@@ -6691,7 +6960,13 @@ const runNativeStep$2 = async (parameters) => {
6691
6960
  logs,
6692
6961
  strict: false
6693
6962
  });
6694
- logsIndexedCount += parsedLogs.length;
6963
+ const untrackedLogsCount = logs.length - parsedLogs.length;
6964
+ if (untrackedLogsCount > 0) logger.debug({
6965
+ event: INDEXER_COLLECTOR_LOG_SKIPPED,
6966
+ msg: "Skipping logs because they do not match tracked Morpho V2 events",
6967
+ reason: "untracked_event",
6968
+ count: untrackedLogsCount
6969
+ });
6695
6970
  consumedEvents.push(...processConsumedLogs({
6696
6971
  logs: parsedLogs,
6697
6972
  chainId: client.chain.id
@@ -6720,14 +6995,21 @@ const runNativeStep$2 = async (parameters) => {
6720
6995
  logsIndexedCount: 0
6721
6996
  };
6722
6997
  const { nextCursor } = streamStep;
6998
+ const resolvedConsumedEvents = await resolveConsumedEvents({
6999
+ db,
7000
+ consumedEvents,
7001
+ logger
7002
+ });
7003
+ const logsIndexedCount = countIndexedMorphoLogs({
7004
+ consumedEvents: resolvedConsumedEvents,
7005
+ debtTransfers,
7006
+ collateralTransfers,
7007
+ seizureFacts
7008
+ });
6723
7009
  const domainMutations = buildDomainMutations$1({
6724
7010
  debtTransfers,
6725
7011
  collateralTransfers,
6726
- consumedEvents: await resolveConsumedEvents({
6727
- db,
6728
- consumedEvents,
6729
- logger
6730
- }),
7012
+ consumedEvents: resolvedConsumedEvents,
6731
7013
  seizureFacts
6732
7014
  });
6733
7015
  return {
@@ -6763,6 +7045,18 @@ const create$28 = (parameters) => {
6763
7045
  });
6764
7046
  };
6765
7047
  };
7048
+ function countIndexedMorphoLogs(parameters) {
7049
+ const indexedLogIds = /* @__PURE__ */ new Set();
7050
+ for (const consumedEvent of parameters.consumedEvents) indexedLogIds.add(consumedEvent.id);
7051
+ for (const transfer of parameters.debtTransfers) indexedLogIds.add(stripMorphoDerivedLogIdSuffix(transfer.id));
7052
+ for (const transfer of parameters.collateralTransfers) indexedLogIds.add(stripMorphoDerivedLogIdSuffix(transfer.id));
7053
+ for (const seizureFact of parameters.seizureFacts) indexedLogIds.add(stripMorphoDerivedLogIdSuffix(seizureFact.id));
7054
+ return indexedLogIds.size;
7055
+ }
7056
+ function stripMorphoDerivedLogIdSuffix(id) {
7057
+ for (const suffix of MORPHO_DERIVED_LOG_ID_SUFFIXES) if (id.endsWith(suffix)) return id.slice(0, -suffix.length);
7058
+ return id;
7059
+ }
6766
7060
  async function resolveConsumedEvents(parameters) {
6767
7061
  const { db, consumedEvents, logger } = parameters;
6768
7062
  if (consumedEvents.length === 0) return [];
@@ -7018,7 +7312,7 @@ const decodeCallbacks = (parameters) => {
7018
7312
  if (!isEmptyCallback(offer)) continue;
7019
7313
  if (offer.buy) {
7020
7314
  const loanToken = offer.loanToken.toLowerCase();
7021
- const positionTypeId$2 = positionTypeId(Type.ERC20);
7315
+ const positionTypeId$3 = positionTypeId(Type.ERC20);
7022
7316
  positions.push(from$11({
7023
7317
  chainId,
7024
7318
  contract: loanToken,
@@ -7031,10 +7325,10 @@ const decodeCallbacks = (parameters) => {
7031
7325
  positionChainId: chainId,
7032
7326
  positionContract: loanToken,
7033
7327
  positionUser: offer.maker,
7034
- positionTypeId: positionTypeId$2,
7328
+ positionTypeId: positionTypeId$3,
7035
7329
  group: offer.group,
7036
7330
  obligationId,
7037
- size: obligationUnitsToAssets(offer.obligationUnits, offer.tick)
7331
+ size: unitsToAssets(offer.maxUnits, offer.tick, offer.buy)
7038
7332
  });
7039
7333
  callbacks.push({
7040
7334
  offerHash: hash$1(offer),
@@ -7043,22 +7337,22 @@ const decodeCallbacks = (parameters) => {
7043
7337
  chainId,
7044
7338
  contract: loanToken,
7045
7339
  user: offer.maker,
7046
- positionTypeId: positionTypeId$2,
7340
+ positionTypeId: positionTypeId$3,
7047
7341
  type: CallbackType.Empty
7048
7342
  }]
7049
7343
  });
7050
7344
  continue;
7051
7345
  }
7052
7346
  const contract = obligationId;
7053
- const positionTypeId$3 = positionTypeId(Type.COLLATERAL_OF);
7347
+ const positionTypeId$2 = positionTypeId(Type.COLLATERAL_OF);
7054
7348
  lots.push({
7055
7349
  positionChainId: chainId,
7056
7350
  positionContract: contract,
7057
7351
  positionUser: offer.maker,
7058
- positionTypeId: positionTypeId$3,
7352
+ positionTypeId: positionTypeId$2,
7059
7353
  group: offer.group,
7060
7354
  obligationId,
7061
- size: obligationUnitsToAssets(offer.obligationUnits, offer.tick)
7355
+ size: unitsToAssets(offer.maxUnits, offer.tick, offer.buy)
7062
7356
  });
7063
7357
  callbacks.push({
7064
7358
  offerHash: hash$1(offer),
@@ -7067,7 +7361,7 @@ const decodeCallbacks = (parameters) => {
7067
7361
  chainId,
7068
7362
  contract,
7069
7363
  user: offer.maker,
7070
- positionTypeId: positionTypeId$3,
7364
+ positionTypeId: positionTypeId$2,
7071
7365
  type: CallbackType.Empty
7072
7366
  }]
7073
7367
  });
@@ -7707,9 +8001,11 @@ const runNativeStep = async (parameters) => {
7707
8001
  });
7708
8002
  transfers.push(...stepTransfers.transfers);
7709
8003
  logsIndexedCount += stepTransfers.transfers.length;
7710
- for (let index = 0; index < stepTransfers.skippedInvalidLogs; index += 1) logger.debug({
8004
+ if (stepTransfers.skippedInvalidLogs > 0) logger.debug({
7711
8005
  event: INDEXER_COLLECTOR_LOG_SKIPPED,
7712
- msg: "Skipping log because it is missing required fields"
8006
+ msg: "Skipping transfer logs because they are missing required fields",
8007
+ reason: "missing_required_fields",
8008
+ count: stepTransfers.skippedInvalidLogs
7713
8009
  });
7714
8010
  if (shouldContinueStream({
7715
8011
  pendingPositionsCount: pendingNewPositions.length,
@@ -9112,7 +9408,7 @@ const init$1 = (parameters) => {
9112
9408
  maker: item.offer.maker,
9113
9409
  group: item.offer.group,
9114
9410
  tick: item.offer.tick,
9115
- assets: item.offer.obligationUnits.toString(),
9411
+ max_units: item.offer.maxUnits.toString(),
9116
9412
  buy: item.offer.buy
9117
9413
  });
9118
9414
  }
@@ -9624,7 +9920,7 @@ function create$19(parameters) {
9624
9920
  });
9625
9921
  }
9626
9922
  },
9627
- onCommitApplied: ({ collectors, stats, committedAtUnixMs }) => {
9923
+ onCommitApplied: ({ collectors, stats, dbRows, committedAtUnixMs }) => {
9628
9924
  if (sinks.length === 0) return;
9629
9925
  try {
9630
9926
  emitObservation(sinks, {
@@ -9632,6 +9928,7 @@ function create$19(parameters) {
9632
9928
  chainId,
9633
9929
  collectors,
9634
9930
  stats,
9931
+ dbRows,
9635
9932
  committedAtUnixMs
9636
9933
  });
9637
9934
  } catch (error) {
@@ -9687,12 +9984,14 @@ function createObservedLogger(parameters) {
9687
9984
  const wrap = (level, emit) => {
9688
9985
  const enabled = isLogFnEnabled(emit);
9689
9986
  return (entry) => {
9690
- if (enabled && isIndexerComponent(entry.component)) try {
9987
+ if (isIndexerComponent(entry.component) && (enabled || isStructuredCollectorDropLog(entry))) try {
9691
9988
  const chainId = parseChainId(entry.chain_id);
9692
9989
  if (chainId !== null) parameters.onLogEntry({
9693
9990
  type: "runtime.log",
9694
9991
  chainId,
9695
- level
9992
+ level,
9993
+ ...extractRuntimeLogMetadata(entry),
9994
+ ...enabled ? {} : { emitted: false }
9696
9995
  });
9697
9996
  } catch {}
9698
9997
  emit(entry);
@@ -9707,6 +10006,18 @@ function createObservedLogger(parameters) {
9707
10006
  fatal: wrap("fatal", parameters.logger.fatal)
9708
10007
  };
9709
10008
  }
10009
+ function extractRuntimeLogMetadata(entry) {
10010
+ const event = typeof entry.event === "string" ? entry.event : void 0;
10011
+ const fields = Object.fromEntries(Object.entries(entry).filter(([key]) => key !== "msg" && key !== "component" && key !== "chain_id" && key !== "event"));
10012
+ return {
10013
+ ...event === void 0 ? {} : { event },
10014
+ ...Object.keys(fields).length === 0 ? {} : { fields }
10015
+ };
10016
+ }
10017
+ function isStructuredCollectorDropLog(entry) {
10018
+ if (entry.event !== INDEXER_COLLECTOR_OFFER_TREE_DECODE_FAILED && entry.event !== INDEXER_COLLECTOR_OFFER_TREE_REJECTED && entry.event !== INDEXER_COLLECTOR_LOG_SKIPPED) return false;
10019
+ return typeof entry.collector === "string" && typeof entry.reason === "string";
10020
+ }
9710
10021
  function emitObservation(sinks, observation) {
9711
10022
  for (const sink of sinks) sink.observe(observation);
9712
10023
  }
@@ -10349,7 +10660,7 @@ function from$5(level) {
10349
10660
  return {
10350
10661
  tick: level.tick,
10351
10662
  price: price.toString(),
10352
- obligation_units: level.obligationUnits.toString(),
10663
+ max_units: level.maxUnits.toString(),
10353
10664
  count: level.count
10354
10665
  };
10355
10666
  }
@@ -10460,7 +10771,7 @@ function from$3(input) {
10460
10771
  },
10461
10772
  buy: input.buy,
10462
10773
  maker: input.maker,
10463
- obligation_units: input.obligationUnits.toString(),
10774
+ max_units: input.maxUnits.toString(),
10464
10775
  start: input.start,
10465
10776
  expiry: input.expiry,
10466
10777
  tick: input.tick,
@@ -10619,7 +10930,7 @@ const offerExample = {
10619
10930
  },
10620
10931
  buy: false,
10621
10932
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
10622
- obligation_units: "369216000000000000000000",
10933
+ max_units: "369216000000000000000000",
10623
10934
  start: 1761922790,
10624
10935
  expiry: 1761922799,
10625
10936
  tick: 495,
@@ -10662,7 +10973,7 @@ const missingCollectorExample = {
10662
10973
  };
10663
10974
  const validateOfferExample = {
10664
10975
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
10665
- obligation_units: "369216000000000000000000",
10976
+ max_units: "369216000000000000000000",
10666
10977
  tick: 495,
10667
10978
  maturity: 1761922799,
10668
10979
  rcf_threshold: "0",
@@ -10816,8 +11127,8 @@ __decorate([ApiProperty({
10816
11127
  })], OfferDataResponse.prototype, "maker", void 0);
10817
11128
  __decorate([ApiProperty({
10818
11129
  type: "string",
10819
- example: offerExample.offer.obligation_units
10820
- })], OfferDataResponse.prototype, "obligation_units", void 0);
11130
+ example: offerExample.offer.max_units
11131
+ })], OfferDataResponse.prototype, "max_units", void 0);
10821
11132
  __decorate([ApiProperty({
10822
11133
  type: "number",
10823
11134
  example: offerExample.offer.start
@@ -11071,9 +11382,9 @@ __decorate([ApiProperty({
11071
11382
  })], ValidateOfferRequest.prototype, "maker", void 0);
11072
11383
  __decorate([ApiProperty({
11073
11384
  type: "string",
11074
- example: validateOfferExample.obligation_units,
11385
+ example: validateOfferExample.max_units,
11075
11386
  required: false
11076
- })], ValidateOfferRequest.prototype, "obligation_units", void 0);
11387
+ })], ValidateOfferRequest.prototype, "max_units", void 0);
11077
11388
  __decorate([ApiProperty({
11078
11389
  type: "number",
11079
11390
  example: validateOfferExample.tick,
@@ -11207,7 +11518,7 @@ __decorate([ApiProperty({
11207
11518
  __decorate([ApiProperty({
11208
11519
  type: "string",
11209
11520
  example: "369216000000000000000000"
11210
- })], BookLevelResponse.prototype, "obligation_units", void 0);
11521
+ })], BookLevelResponse.prototype, "max_units", void 0);
11211
11522
  __decorate([ApiProperty({
11212
11523
  type: "number",
11213
11524
  example: 5
@@ -12184,7 +12495,7 @@ async function getBook(params, db) {
12184
12495
  levels_count: levels.length,
12185
12496
  has_next_cursor: nextCursor != null,
12186
12497
  first_level_tick: firstLevel?.tick ?? null,
12187
- first_level_obligation_units: firstLevel?.obligationUnits.toString() ?? null,
12498
+ first_level_max_units: firstLevel?.maxUnits.toString() ?? null,
12188
12499
  first_level_count: firstLevel?.count ?? null
12189
12500
  });
12190
12501
  return success({
@@ -12318,7 +12629,6 @@ const assets = {
12318
12629
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
12319
12630
  "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
12320
12631
  "0x4200000000000000000000000000000000000006",
12321
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
12322
12632
  "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
12323
12633
  "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
12324
12634
  "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
@@ -12933,7 +13243,7 @@ function create$16(parameters) {
12933
13243
  obligationId: obligationIdKeys.obligationId,
12934
13244
  chainId: obligationIdKeys.chainId,
12935
13245
  loanToken: obligations.loanToken,
12936
- collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
13246
+ collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}::text, 'maxLif', ${obligationCollateralsV2.maxLif}::text))`.as("collaterals"),
12937
13247
  maturity: obligations.maturity,
12938
13248
  rcfThreshold: obligations.rcfThreshold,
12939
13249
  askTick: sql`MAX(${bestQuotes.askTick})`.as("ask_tick"),
@@ -12966,7 +13276,8 @@ function create$16(parameters) {
12966
13276
  collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$16({
12967
13277
  asset: collateral.asset,
12968
13278
  oracle: collateral.oracle,
12969
- lltv: from$17(BigInt(collateral.lltv))
13279
+ lltv: from$17(BigInt(collateral.lltv)),
13280
+ maxLif: BigInt(collateral.maxLif)
12970
13281
  })),
12971
13282
  maturity: row.maturity,
12972
13283
  rcfThreshold: BigInt(row.rcfThreshold)
@@ -13235,11 +13546,11 @@ function offerBalanceTerm(balance, price, lltv) {
13235
13546
  * @param lotLower - Lot lower bound (in assets).
13236
13547
  * @param lotUpper - Lot upper bound (in assets).
13237
13548
  * @param consumed - Group consumed amount (in obligation units).
13238
- * @param obligationUnits - Offer obligation units.
13549
+ * @param maxUnits - Offer obligation units.
13239
13550
  */
13240
- function lotBalance(offerBalance, offset, positionConsumed, lotLower, lotUpper, consumed, obligationUnits) {
13551
+ function lotBalance(offerBalance, offset, positionConsumed, lotLower, lotUpper, consumed, maxUnits) {
13241
13552
  const lotSize = sql`(COALESCE(${lotUpper}::numeric, 0) - COALESCE(${lotLower}::numeric, 0))`;
13242
- return sql`GREATEST(0, LEAST(COALESCE(${offerBalance}, 0) + COALESCE(${offset}, 0) + COALESCE(${positionConsumed}, 0) - COALESCE(${lotLower}::numeric, 0), ${lotSize} - ${sql`CASE WHEN ${obligationUnits}::numeric > 0 THEN COALESCE(${consumed}::numeric, 0) * ${lotSize} / ${obligationUnits}::numeric ELSE 0 END`}))`;
13553
+ return sql`GREATEST(0, LEAST(COALESCE(${offerBalance}, 0) + COALESCE(${offset}, 0) + COALESCE(${positionConsumed}, 0) - COALESCE(${lotLower}::numeric, 0), ${lotSize} - ${sql`CASE WHEN ${maxUnits}::numeric > 0 THEN COALESCE(${consumed}::numeric, 0) * ${lotSize} / ${maxUnits}::numeric ELSE 0 END`}))`;
13243
13554
  }
13244
13555
  /**
13245
13556
  * Callback contribution: amount contributed by one callback in loan terms.
@@ -13251,17 +13562,23 @@ function contribution(lotBalance, lotLower) {
13251
13562
  return sql`CASE WHEN ${lotLower} IS NULL THEN 0 ELSE ${lotBalance} END`;
13252
13563
  }
13253
13564
  /**
13254
- * Takeable amount in assets.
13255
- * Converts the obligation-unit capacity to assets using the tick price,
13256
- * then compares with available (already in assets from lot balance).
13257
- * @param obligationUnits - Offer obligation units.
13565
+ * Takeable amount in maker-side assets.
13566
+ * Buy offers use the floor maker-asset surface for remaining obligation units.
13567
+ * Sell offers use the ceil maker-asset surface for remaining obligation units.
13568
+ * The result is then compared with available (already in assets from lot balance).
13569
+ * @param maxUnits - Offer obligation units.
13258
13570
  * @param consumed - Group consumed amount (in obligation units).
13259
13571
  * @param available - Total available from callbacks/positions (in assets).
13260
13572
  * @param price - Tick price (from tick_prices CTE).
13573
+ * @param buy - Offer side (`true` for buy, `false` for sell).
13261
13574
  */
13262
- function takeable(obligationUnits, consumed, available, price) {
13575
+ function takeable(maxUnits, consumed, available, price, buy) {
13263
13576
  const WAD_SQL = sql`(10::numeric ^ 18)`;
13264
- return sql`GREATEST(0, LEAST(${sql`(${sql`(${obligationUnits}::numeric * ${price} / ${WAD_SQL})`} - ${sql`(${consumed}::numeric * ${price} / ${WAD_SQL})`})`}, ${available}))`;
13577
+ const remainingUnits = sql`GREATEST(COALESCE(${maxUnits}::numeric, 0) - COALESCE(${consumed}::numeric, 0), 0)`;
13578
+ return sql`GREATEST(0, LEAST(${sql`CASE WHEN ${buy}
13579
+ THEN TRUNC(${remainingUnits} * COALESCE(${price}::numeric, 0) / ${WAD_SQL})
13580
+ ELSE CEIL(${remainingUnits} * COALESCE(${price}::numeric, 0) / ${WAD_SQL})
13581
+ END`}, ${available}))`;
13265
13582
  }
13266
13583
  /** Precomputed tick→price lookup (all 991 ticks). */
13267
13584
  const TICK_PRICES = Array.from({ length: TICK_RANGE + 1 }, (_, i) => [i, tickToPrice(i).toString()]);
@@ -13293,7 +13610,7 @@ function offerAvailabilityCTEs(params) {
13293
13610
  return sql`
13294
13611
  , group_winners AS (
13295
13612
  SELECT DISTINCT ON (o.group_chain_id, o.group_maker, o.group_group, o.obligation_id, o.buy)
13296
- o.group_chain_id, o.group_maker, o.group_group, o.obligation_id, o.buy, o.obligation_units
13613
+ o.group_chain_id, o.group_maker, o.group_group, o.obligation_id, o.buy, o.max_units
13297
13614
  FROM ${offers} o
13298
13615
  LEFT JOIN ${validations} v
13299
13616
  ON v.offer_hash = o.hash
@@ -13310,7 +13627,7 @@ function offerAvailabilityCTEs(params) {
13310
13627
  ORDER BY
13311
13628
  o.group_chain_id, o.group_maker, o.group_group, o.obligation_id, o.buy,
13312
13629
  CASE WHEN o.buy THEN -o.tick ELSE o.tick END ASC,
13313
- o.block_number ASC, o.obligation_units DESC, o.hash ASC
13630
+ o.block_number ASC, o.max_units DESC, o.hash ASC
13314
13631
  ),
13315
13632
  relevant_positions AS (
13316
13633
  SELECT DISTINCT c.position_chain_id, c.position_contract, c.position_user
@@ -13335,8 +13652,8 @@ function offerAvailabilityCTEs(params) {
13335
13652
  COALESCE(
13336
13653
  SUM(
13337
13654
  CASE
13338
- WHEN wo.obligation_units::numeric > 0
13339
- THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / wo.obligation_units::numeric
13655
+ WHEN wo.max_units::numeric > 0
13656
+ THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / wo.max_units::numeric
13340
13657
  ELSE 0
13341
13658
  END
13342
13659
  ) OVER (
@@ -13383,14 +13700,14 @@ function offerAvailabilityCTEs(params) {
13383
13700
  src.obligation_id,
13384
13701
  src.group_group,
13385
13702
  src.consumed,
13386
- src.obligation_units,
13703
+ src.max_units,
13387
13704
  c.id AS callback_id,
13388
13705
  c.position_chain_id,
13389
13706
  c.position_contract,
13390
13707
  c.position_user,
13391
13708
  l.lower AS lot_lower,
13392
13709
  l.upper AS lot_upper,
13393
- ${lotBalance(sql`vb.offer_balance`, sql`pos_offsets.total_offset`, sql`pc.consumed`, sql`l.lower`, sql`l.upper`, sql`src.consumed`, sql`src.obligation_units`)} AS lot_balance
13710
+ ${lotBalance(sql`vb.offer_balance`, sql`pos_offsets.total_offset`, sql`pc.consumed`, sql`l.lower`, sql`l.upper`, sql`src.consumed`, sql`src.max_units`)} AS lot_balance
13394
13711
  FROM ${source} src
13395
13712
  LEFT JOIN ${offersCallbacks} oc
13396
13713
  ON oc.offer_hash = src.hash
@@ -13458,7 +13775,7 @@ function offerTakeabilityCTEs(params) {
13458
13775
  offer_takeable AS (
13459
13776
  SELECT src.hash, src.obligation_id,
13460
13777
  COALESCE(oa.available, 0) AS available,
13461
- ${takeable(sql`src.obligation_units`, sql`src.consumed`, sql`COALESCE(oa.available, 0)`, sql`tp.price`)} AS takeable
13778
+ ${takeable(sql`src.max_units`, sql`src.consumed`, sql`COALESCE(oa.available, 0)`, sql`tp.price`, sql`src.buy`)} AS takeable
13462
13779
  FROM ${source} src
13463
13780
  LEFT JOIN offer_available oa ON oa.hash = src.hash AND oa.obligation_id = src.obligation_id
13464
13781
  LEFT JOIN tick_prices tp ON tp.tick = src.tick
@@ -13555,8 +13872,8 @@ function create$15(config) {
13555
13872
  jsonb_build_object(
13556
13873
  'asset', ${obligationCollateralsV2.asset},
13557
13874
  'oracle', ${obligationCollateralsV2.oracleAddress},
13558
- 'lltv', ${obligationCollateralsV2.lltv},
13559
- 'maxLif', ${obligationCollateralsV2.maxLif}
13875
+ 'lltv', ${obligationCollateralsV2.lltv}::text,
13876
+ 'maxLif', ${obligationCollateralsV2.maxLif}::text
13560
13877
  )
13561
13878
  ),
13562
13879
  '[]'::jsonb
@@ -13565,7 +13882,7 @@ function create$15(config) {
13565
13882
  hash: offers.hash,
13566
13883
  obligationId: offers.obligationId,
13567
13884
  maker: offers.groupMaker,
13568
- obligationUnits: offers.obligationUnits,
13885
+ maxUnits: offers.maxUnits,
13569
13886
  tick: offers.tick,
13570
13887
  maturity: offers.maturity,
13571
13888
  rcfThreshold: obligations.rcfThreshold,
@@ -13588,7 +13905,7 @@ function create$15(config) {
13588
13905
  hash: row.hash,
13589
13906
  obligationId: row.obligationId,
13590
13907
  maker: row.maker,
13591
- obligationUnits: BigInt(row.obligationUnits),
13908
+ maxUnits: BigInt(row.maxUnits),
13592
13909
  tick: row.tick,
13593
13910
  maturity: from$15(row.maturity),
13594
13911
  rcfThreshold: BigInt(row.rcfThreshold),
@@ -13603,7 +13920,7 @@ function create$15(config) {
13603
13920
  asset: c.asset,
13604
13921
  oracle: c.oracle,
13605
13922
  lltv: BigInt(c.lltv),
13606
- maxLif: BigInt(c.maxLif ?? 0)
13923
+ maxLif: BigInt(c.maxLif)
13607
13924
  })).sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),
13608
13925
  callback: {
13609
13926
  address: row.callbackAddress,
@@ -13859,8 +14176,8 @@ async function getOffersQuery(db, parameters) {
13859
14176
  COALESCE(jsonb_agg(jsonb_build_object(
13860
14177
  'asset', oc.asset,
13861
14178
  'oracle', oc.oracle_address,
13862
- 'lltv', oc.lltv,
13863
- 'maxLif', oc.max_lif
14179
+ 'lltv', oc.lltv::text,
14180
+ 'maxLif', oc.max_lif::text
13864
14181
  ) ORDER BY oc.asset), '[]'::jsonb) AS collaterals
13865
14182
  FROM ${obligationIdKeys} oia
13866
14183
  JOIN ${obligationCollateralsV2} oc
@@ -13877,7 +14194,7 @@ async function getOffersQuery(db, parameters) {
13877
14194
  mo.hash,
13878
14195
  mo.obligation_id,
13879
14196
  mo.group_maker,
13880
- mo.obligation_units,
14197
+ mo.max_units,
13881
14198
  mo.consumed,
13882
14199
  mo.tick,
13883
14200
  mo.maturity,
@@ -13909,11 +14226,14 @@ async function getOffersQuery(db, parameters) {
13909
14226
  ORDER BY mo.hash ASC, mo.obligation_id ASC;
13910
14227
  `)).rows.map((row) => {
13911
14228
  const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
14229
+ const maxUnits = BigInt(row.max_units ?? 0);
14230
+ const consumed = BigInt(row.consumed ?? 0);
14231
+ const remainingUnits = maxUnits > consumed ? maxUnits - consumed : 0n;
13912
14232
  return {
13913
14233
  hash: row.hash,
13914
14234
  obligationId: row.obligation_id,
13915
14235
  maker: row.group_maker,
13916
- obligationUnits: BigInt(row.obligation_units ?? 0),
14236
+ maxUnits,
13917
14237
  tick: row.tick,
13918
14238
  maturity: row.maturity,
13919
14239
  expiry: row.expiry,
@@ -13928,7 +14248,7 @@ async function getOffersQuery(db, parameters) {
13928
14248
  asset: c.asset,
13929
14249
  oracle: c.oracle,
13930
14250
  lltv: BigInt(c.lltv),
13931
- maxLif: BigInt(c.maxLif ?? 0)
14251
+ maxLif: BigInt(c.maxLif)
13932
14252
  })).sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),
13933
14253
  callback: {
13934
14254
  address: row.callback_address,
@@ -13936,9 +14256,9 @@ async function getOffersQuery(db, parameters) {
13936
14256
  },
13937
14257
  receiverIfMakerIsSeller,
13938
14258
  exitOnly: row.exit_only,
13939
- consumed: BigInt(row.consumed ?? 0),
14259
+ consumed,
13940
14260
  available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
13941
- takeable: assetsToObligationUnits(BigInt(String(row.takeable ?? "0").split(".")[0] ?? "0"), row.tick),
14261
+ takeable: assetsToUnits(BigInt(String(row.takeable ?? "0").split(".")[0] ?? "0"), row.tick, row.buy, remainingUnits),
13942
14262
  blockNumber: row.block_number,
13943
14263
  root: row.tree_root ? row.tree_root.toLowerCase() : void 0,
13944
14264
  signature: row.root_signature ? row.root_signature.toLowerCase() : void 0,
@@ -13982,7 +14302,8 @@ async function getOffers$1(queryParameters, db) {
13982
14302
  side: query.side,
13983
14303
  obligationId: query.obligation_id,
13984
14304
  cursor: query.cursor,
13985
- limit: query.limit
14305
+ limit: query.limit,
14306
+ requirePositiveTakeableAssets: true
13986
14307
  });
13987
14308
  logger.debug({
13988
14309
  service: "api_controller",
@@ -14229,6 +14550,7 @@ function createApp(parameters) {
14229
14550
  origin: "*",
14230
14551
  exposeHeaders: ["x-request-id"]
14231
14552
  }));
14553
+ app.get("/", (c) => c.redirect("/docs"));
14232
14554
  app.get("/v1/offers", async (c) => {
14233
14555
  const { statusCode, body } = await services.getOffers(c.req.query());
14234
14556
  return c.json(body, statusCode);
@@ -14416,7 +14738,7 @@ async function getOffers(apiClient, parameters) {
14416
14738
  return {
14417
14739
  ...fromSnakeCase$1({
14418
14740
  maker: offerData.maker,
14419
- obligation_units: offerData.obligation_units,
14741
+ max_units: offerData.max_units,
14420
14742
  tick: offerData.tick,
14421
14743
  maturity: from$15(offerData.obligation.maturity),
14422
14744
  rcf_threshold: offerData.obligation.rcf_threshold,
@@ -14790,7 +15112,7 @@ function create$11(config) {
14790
15112
  const db = config.db;
14791
15113
  const logger = getLogger();
14792
15114
  const getOffers = async (parameters) => {
14793
- const { side, obligationId, cursor: cursorString } = parameters;
15115
+ const { side, obligationId, cursor: cursorString, requirePositiveTakeableAssets = false } = parameters;
14794
15116
  const requestedLimit = parameters.limit ?? DEFAULT_LIMIT$2;
14795
15117
  const priceSortDirection = side === "sell" ? "asc" : "desc";
14796
15118
  const inputCursor = Cursor.decode(cursorString, logger);
@@ -14811,7 +15133,8 @@ function create$11(config) {
14811
15133
  now,
14812
15134
  priceSortDirection,
14813
15135
  cursor: inputCursor,
14814
- limit: Math.min(requestedLimit, MAX_TOTAL_OFFERS - previouslyReturned)
15136
+ limit: Math.min(requestedLimit, MAX_TOTAL_OFFERS - previouslyReturned),
15137
+ requirePositiveTakeableAssets
14815
15138
  });
14816
15139
  const lastReturnedOffer = rows[rows.length - 1];
14817
15140
  const newTotalReturned = previouslyReturned + rows.length;
@@ -14843,16 +15166,16 @@ function create$11(config) {
14843
15166
  for (const row of rows) {
14844
15167
  const existing = tickMap.get(row.tick);
14845
15168
  if (existing) {
14846
- existing.obligationUnits += row.takeable;
15169
+ existing.maxUnits += row.takeable;
14847
15170
  existing.count += 1;
14848
15171
  } else tickMap.set(row.tick, {
14849
- obligationUnits: row.takeable,
15172
+ maxUnits: row.takeable,
14850
15173
  count: 1
14851
15174
  });
14852
15175
  }
14853
15176
  const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
14854
15177
  tick,
14855
- obligationUnits: level.obligationUnits,
15178
+ maxUnits: level.maxUnits,
14856
15179
  count: level.count
14857
15180
  }));
14858
15181
  levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
@@ -14869,15 +15192,15 @@ function create$11(config) {
14869
15192
  }
14870
15193
  /** Get offers with computed takeable based on lot balance. */
14871
15194
  async function _getOffers(db, params) {
14872
- const { obligationId, side, now, priceSortDirection, cursor, limit } = params;
15195
+ const { obligationId, side, now, priceSortDirection, cursor, limit, requirePositiveTakeableAssets } = params;
14873
15196
  const raw = await db.execute(sql`
14874
15197
  WITH collats AS MATERIALIZED (
14875
15198
  SELECT oia.obligation_id,
14876
15199
  COALESCE(jsonb_agg(jsonb_build_object(
14877
15200
  'asset', oc.asset,
14878
15201
  'oracle', oc.oracle_address,
14879
- 'lltv', oc.lltv,
14880
- 'maxLif', oc.max_lif
15202
+ 'lltv', oc.lltv::text,
15203
+ 'maxLif', oc.max_lif::text
14881
15204
  ) ORDER BY oc.asset), '[]'::jsonb) AS collaterals
14882
15205
  FROM ${obligationIdKeys} oia
14883
15206
  JOIN ${obligationCollateralsV2} oc
@@ -14902,7 +15225,7 @@ async function _getOffers(db, params) {
14902
15225
  AND (s.code IS NULL OR s.code = ${Status.VALID})
14903
15226
  ORDER BY
14904
15227
  o.group_chain_id, o.group_maker, o."group_group",
14905
- CASE WHEN o.buy THEN -o.tick ELSE o.tick END ASC, o.block_number ASC, o.obligation_units DESC, o.hash ASC
15228
+ CASE WHEN o.buy THEN -o.tick ELSE o.tick END ASC, o.block_number ASC, o.max_units DESC, o.hash ASC
14906
15229
  ),
14907
15230
  enriched AS (
14908
15231
  SELECT
@@ -14911,7 +15234,7 @@ async function _getOffers(db, params) {
14911
15234
  CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
14912
15235
  THEN w.tick ELSE -w.tick END AS tick_norm,
14913
15236
  w.block_number AS block_norm,
14914
- -w.obligation_units AS obligation_units_norm,
15237
+ -w.max_units AS max_units_norm,
14915
15238
  w.hash AS hash_norm
14916
15239
  FROM winners w
14917
15240
  JOIN ${groups} g
@@ -14932,24 +15255,34 @@ async function _getOffers(db, params) {
14932
15255
  SELECT e.*, COALESCE(ot.available, 0) AS available, ot.takeable
14933
15256
  FROM enriched e
14934
15257
  JOIN offer_takeable ot ON ot.hash = e.hash AND ot.obligation_id = e.obligation_id
14935
- WHERE ot.takeable > 0
15258
+ WHERE (
15259
+ ot.takeable > 0
15260
+ OR (
15261
+ COALESCE(e.max_units::numeric, 0) > COALESCE(e.consumed::numeric, 0)
15262
+ AND (
15263
+ e.tick = 0
15264
+ OR (e.buy AND e.tick < ${TICK_RANGE})
15265
+ )
15266
+ )
15267
+ )
15268
+ ${requirePositiveTakeableAssets ? sql`AND TRUNC(COALESCE(ot.takeable, 0)::numeric) > 0` : sql``}
14936
15269
  ${cursor != null ? sql`
14937
- AND (e.tick_norm, e.block_norm, e.obligation_units_norm, e.hash_norm)
15270
+ AND (e.tick_norm, e.block_norm, e.max_units_norm, e.hash_norm)
14938
15271
  > (
14939
15272
  CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
14940
15273
  THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
14941
15274
  ${cursor.blockNumber},
14942
- -${cursor.obligationUnits}::numeric,
15275
+ -${cursor.maxUnits}::numeric,
14943
15276
  ${cursor.hash}
14944
15277
  )` : sql``}
14945
- ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.obligation_units DESC, e.hash ASC
15278
+ ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.max_units DESC, e.hash ASC
14946
15279
  LIMIT ${limit}
14947
15280
  )
14948
15281
  SELECT
14949
15282
  p.hash,
14950
15283
  p.obligation_id,
14951
15284
  p.group_maker,
14952
- p.obligation_units,
15285
+ p.max_units,
14953
15286
  p.consumed,
14954
15287
  p.tick,
14955
15288
  p.maturity,
@@ -14979,17 +15312,20 @@ async function _getOffers(db, params) {
14979
15312
  ORDER BY
14980
15313
  p.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`},
14981
15314
  p.block_number ASC,
14982
- p.obligation_units DESC,
15315
+ p.max_units DESC,
14983
15316
  p.hash ASC;
14984
15317
  `);
14985
15318
  return {
14986
15319
  rows: raw.rows.map((row) => {
14987
15320
  const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
15321
+ const maxUnits = BigInt(row.max_units ?? 0);
15322
+ const consumed = BigInt(row.consumed ?? 0);
15323
+ const remainingUnits = maxUnits > consumed ? maxUnits - consumed : 0n;
14988
15324
  return {
14989
15325
  hash: row.hash,
14990
15326
  obligationId: row.obligation_id,
14991
15327
  maker: row.group_maker,
14992
- obligationUnits: BigInt(row.obligation_units ?? 0),
15328
+ maxUnits,
14993
15329
  tick: row.tick,
14994
15330
  maturity: row.maturity,
14995
15331
  expiry: row.expiry,
@@ -15004,7 +15340,7 @@ async function _getOffers(db, params) {
15004
15340
  asset: c.asset,
15005
15341
  oracle: c.oracle,
15006
15342
  lltv: BigInt(c.lltv),
15007
- maxLif: BigInt(c.maxLif ?? 0)
15343
+ maxLif: BigInt(c.maxLif)
15008
15344
  })),
15009
15345
  callback: {
15010
15346
  address: row.callback_address,
@@ -15013,9 +15349,9 @@ async function _getOffers(db, params) {
15013
15349
  receiverIfMakerIsSeller,
15014
15350
  exitOnly: row.exit_only,
15015
15351
  blockNumber: row.block_number,
15016
- consumed: BigInt(row.consumed ?? 0),
15352
+ consumed,
15017
15353
  available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
15018
- takeable: assetsToObligationUnits(BigInt(String(row.takeable).split(".")[0] ?? "0"), row.tick),
15354
+ takeable: assetsToUnits(BigInt(String(row.takeable).split(".")[0] ?? "0"), row.tick, row.buy, remainingUnits),
15019
15355
  root: row.tree_root ? row.tree_root.toLowerCase() : void 0,
15020
15356
  signature: row.root_signature ? row.root_signature.toLowerCase() : void 0,
15021
15357
  proof: row.proof_nodes ? splitProofs(row.proof_nodes) : void 0
@@ -15031,7 +15367,7 @@ let Cursor;
15031
15367
  side,
15032
15368
  tick: row.tick,
15033
15369
  blockNumber: row.blockNumber,
15034
- obligationUnits: row.obligationUnits.toString(),
15370
+ maxUnits: row.maxUnits.toString(),
15035
15371
  hash: row.hash,
15036
15372
  totalReturned,
15037
15373
  now
@@ -15042,7 +15378,7 @@ let Cursor;
15042
15378
  if (cursorString == null) return null;
15043
15379
  try {
15044
15380
  const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
15045
- if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.obligationUnits === "string" && /^-?\d+$/.test(v.obligationUnits) && isHex(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
15381
+ if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.maxUnits === "string" && /^-?\d+$/.test(v.maxUnits) && isHex(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
15046
15382
  throw new Error("Invalid cursor");
15047
15383
  } catch {
15048
15384
  logger.error({
@@ -15094,7 +15430,10 @@ let LevelCursor;
15094
15430
  function create$10(db) {
15095
15431
  return {
15096
15432
  upsert: async (inputs) => {
15097
- if (inputs.length === 0) return;
15433
+ if (inputs.length === 0) return {
15434
+ callbacksInserted: 0,
15435
+ offersCallbacksInserted: 0
15436
+ };
15098
15437
  const idCache = /* @__PURE__ */ new Map();
15099
15438
  const seenCallbackIds = /* @__PURE__ */ new Set();
15100
15439
  const callbacksRows = [];
@@ -15134,7 +15473,10 @@ function create$10(db) {
15134
15473
  });
15135
15474
  }
15136
15475
  }
15137
- if (offersCallbacksRows.length === 0) return;
15476
+ if (offersCallbacksRows.length === 0) return {
15477
+ callbacksInserted: 0,
15478
+ offersCallbacksInserted: 0
15479
+ };
15138
15480
  const offerHashes = [...new Set(offersCallbacksRows.map((r) => r.offerHash))];
15139
15481
  const existingOffers = await db.select({
15140
15482
  hash: offers.hash,
@@ -15142,10 +15484,25 @@ function create$10(db) {
15142
15484
  }).from(offers).where(inArray(offers.hash, offerHashes));
15143
15485
  const existingKeys = new Set(existingOffers.map((r) => `${String(r.hash).toLowerCase()}:${String(r.obligationId).toLowerCase()}`));
15144
15486
  const filteredOffersCallbacksRows = offersCallbacksRows.filter((r) => existingKeys.has(`${r.offerHash}:${r.obligationId}`));
15145
- if (filteredOffersCallbacksRows.length === 0) return;
15146
- await db.transaction(async (dbTx) => {
15147
- for (const batch of batch$1(callbacksRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(callbacks).values(batch).onConflictDoNothing();
15148
- for (const batch of batch$1(filteredOffersCallbacksRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(offersCallbacks).values(batch).onConflictDoNothing();
15487
+ if (filteredOffersCallbacksRows.length === 0) return {
15488
+ callbacksInserted: 0,
15489
+ offersCallbacksInserted: 0
15490
+ };
15491
+ return await db.transaction(async (dbTx) => {
15492
+ let callbacksInserted = 0;
15493
+ for (const batch of batch$1(callbacksRows, DEFAULT_BATCH_SIZE$1)) {
15494
+ const inserted = await dbTx.insert(callbacks).values(batch).onConflictDoNothing().returning();
15495
+ callbacksInserted += inserted.length;
15496
+ }
15497
+ let offersCallbacksInserted = 0;
15498
+ for (const batch of batch$1(filteredOffersCallbacksRows, DEFAULT_BATCH_SIZE$1)) {
15499
+ const inserted = await dbTx.insert(offersCallbacks).values(batch).onConflictDoNothing().returning();
15500
+ offersCallbacksInserted += inserted.length;
15501
+ }
15502
+ return {
15503
+ callbacksInserted,
15504
+ offersCallbacksInserted
15505
+ };
15149
15506
  });
15150
15507
  },
15151
15508
  delete: async ({ offers }) => {
@@ -15161,7 +15518,10 @@ function create$10(db) {
15161
15518
  function create$9(db) {
15162
15519
  return {
15163
15520
  create: async (events) => {
15164
- if (events.length === 0) return;
15521
+ if (events.length === 0) return {
15522
+ groupsInserted: 0,
15523
+ consumedEventsInserted: 0
15524
+ };
15165
15525
  const groups$3 = /* @__PURE__ */ new Map();
15166
15526
  for (const event of events) {
15167
15527
  const groupId = `${event.chainId}-${event.maker}-${event.group}`.toLowerCase();
@@ -15172,7 +15532,7 @@ function create$9(db) {
15172
15532
  blockNumber: event.blockNumber
15173
15533
  });
15174
15534
  }
15175
- await db.transaction(async (dbTx) => {
15535
+ return await db.transaction(async (dbTx) => {
15176
15536
  const groupsRows = Array.from(groups$3.values()).map((group) => ({
15177
15537
  chainId: group.chainId,
15178
15538
  maker: group.maker.toLowerCase(),
@@ -15180,7 +15540,11 @@ function create$9(db) {
15180
15540
  consumed: "0",
15181
15541
  blockNumber: group.blockNumber
15182
15542
  }));
15183
- for (const batch of batch$1(groupsRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(groups).values(batch).onConflictDoNothing();
15543
+ let groupsInserted = 0;
15544
+ for (const batch of batch$1(groupsRows, DEFAULT_BATCH_SIZE$1)) {
15545
+ const inserted = await dbTx.insert(groups).values(batch).onConflictDoNothing().returning();
15546
+ groupsInserted += inserted.length;
15547
+ }
15184
15548
  const eventsRows = events.map((event) => ({
15185
15549
  eventId: event.id,
15186
15550
  chainId: event.chainId,
@@ -15189,7 +15553,15 @@ function create$9(db) {
15189
15553
  amount: event.amount.toString(),
15190
15554
  blockNumber: event.blockNumber
15191
15555
  }));
15192
- for (const batch of batch$1(eventsRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(consumedEvents).values(batch).onConflictDoNothing();
15556
+ let consumedEventsInserted = 0;
15557
+ for (const batch of batch$1(eventsRows, DEFAULT_BATCH_SIZE$1)) {
15558
+ const inserted = await dbTx.insert(consumedEvents).values(batch).onConflictDoNothing().returning();
15559
+ consumedEventsInserted += inserted.length;
15560
+ }
15561
+ return {
15562
+ groupsInserted,
15563
+ consumedEventsInserted
15564
+ };
15193
15565
  });
15194
15566
  },
15195
15567
  delete: async (parameters) => {
@@ -15213,7 +15585,7 @@ function compositeKey(g) {
15213
15585
  function create$8(db) {
15214
15586
  return {
15215
15587
  create: async (groups$1) => {
15216
- if (groups$1.length === 0) return;
15588
+ if (groups$1.length === 0) return 0;
15217
15589
  const rows = groups$1.map((group) => ({
15218
15590
  chainId: group.chainId,
15219
15591
  maker: group.maker.toLowerCase(),
@@ -15221,7 +15593,12 @@ function create$8(db) {
15221
15593
  consumed: (group.consumed ?? 0n).toString(),
15222
15594
  blockNumber: group.blockNumber
15223
15595
  }));
15224
- for (const batch of batch$1(rows, DEFAULT_BATCH_SIZE$1)) await db.insert(groups).values(batch).onConflictDoNothing();
15596
+ let insertedCount = 0;
15597
+ for (const batch of batch$1(rows, DEFAULT_BATCH_SIZE$1)) {
15598
+ const inserted = await db.insert(groups).values(batch).onConflictDoNothing().returning();
15599
+ insertedCount += inserted.length;
15600
+ }
15601
+ return insertedCount;
15225
15602
  },
15226
15603
  exists: async (groups$2) => {
15227
15604
  if (groups$2.length === 0) return [];
@@ -15262,7 +15639,10 @@ function create$7(db) {
15262
15639
  }));
15263
15640
  },
15264
15641
  create: async (parameters) => {
15265
- if (parameters.length === 0) return;
15642
+ if (parameters.length === 0) return {
15643
+ lotsPositionsInserted: 0,
15644
+ lotsInserted: 0
15645
+ };
15266
15646
  const lotsByKey = /* @__PURE__ */ new Map();
15267
15647
  for (const offer of parameters) {
15268
15648
  const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
@@ -15280,7 +15660,10 @@ function create$7(db) {
15280
15660
  const groupKey = `${offer.positionChainId}-${offer.positionUser.toLowerCase()}-${offer.group.toLowerCase()}`;
15281
15661
  if (!existingGroupKeys.has(groupKey)) lotsByKey.delete(key);
15282
15662
  }
15283
- if (lotsByKey.size === 0) return;
15663
+ if (lotsByKey.size === 0) return {
15664
+ lotsPositionsInserted: 0,
15665
+ lotsInserted: 0
15666
+ };
15284
15667
  const positionsByKey = /* @__PURE__ */ new Map();
15285
15668
  for (const offer of lotsByKey.values()) {
15286
15669
  const posKey = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}`.toLowerCase();
@@ -15291,12 +15674,17 @@ function create$7(db) {
15291
15674
  positionTypeId: offer.positionTypeId
15292
15675
  });
15293
15676
  }
15294
- for (const row of positionsByKey.values()) await db.insert(lotsPositions).values(row).onConflictDoNothing();
15677
+ let lotsPositionsInserted = 0;
15678
+ for (const row of positionsByKey.values()) {
15679
+ const inserted = await db.insert(lotsPositions).values(row).onConflictDoNothing().returning();
15680
+ lotsPositionsInserted += inserted.length;
15681
+ }
15682
+ let lotsInserted = 0;
15295
15683
  for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.group, offer.group.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
15296
15684
  const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase())));
15297
15685
  const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
15298
15686
  const newUpper = newLower + offer.size;
15299
- await db.insert(lots).values({
15687
+ const inserted = await db.insert(lots).values({
15300
15688
  chainId: offer.positionChainId,
15301
15689
  user: offer.positionUser.toLowerCase(),
15302
15690
  contract: offer.positionContract.toLowerCase(),
@@ -15304,8 +15692,13 @@ function create$7(db) {
15304
15692
  obligationId: offer.obligationId.toLowerCase(),
15305
15693
  lower: newLower.toString(),
15306
15694
  upper: newUpper.toString()
15307
- });
15695
+ }).returning();
15696
+ lotsInserted += inserted.length;
15308
15697
  }
15698
+ return {
15699
+ lotsPositionsInserted,
15700
+ lotsInserted
15701
+ };
15309
15702
  }
15310
15703
  };
15311
15704
  }
@@ -15327,7 +15720,7 @@ function create$6(db) {
15327
15720
  chainId: obligationIdKeys.chainId,
15328
15721
  morphoV2: obligationIdKeys.morphoV2,
15329
15722
  loanToken: obligations.loanToken,
15330
- collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}, 'maxLif', ${obligationCollateralsV2.maxLif}))`.as("collaterals"),
15723
+ collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}::text, 'maxLif', ${obligationCollateralsV2.maxLif}::text))`.as("collaterals"),
15331
15724
  maturity: obligations.maturity,
15332
15725
  rcfThreshold: obligations.rcfThreshold
15333
15726
  }).from(obligationIdKeys).innerJoin(obligations, eq(obligationIdKeys.obligationKey, obligations.obligationKey)).innerJoin(obligationCollateralsV2, eq(obligations.obligationKey, obligationCollateralsV2.obligationKey)).groupBy(obligationIdKeys.obligationId, obligationIdKeys.chainId, obligationIdKeys.morphoV2, obligations.loanToken, obligations.maturity, obligations.rcfThreshold).where(and(chainIds !== void 0 && chainIds.length > 0 ? inArray(obligationIdKeys.chainId, chainIds) : void 0, gte(obligations.maturity, now$1))).orderBy(asc(obligationIdKeys.obligationId))).map((row) => ({
@@ -15340,7 +15733,7 @@ function create$6(db) {
15340
15733
  asset: collateral.asset,
15341
15734
  oracle: collateral.oracle,
15342
15735
  lltv: from$17(BigInt(collateral.lltv)),
15343
- maxLif: BigInt(collateral.maxLif ?? 0)
15736
+ maxLif: BigInt(collateral.maxLif)
15344
15737
  })),
15345
15738
  maturity: row.maturity,
15346
15739
  rcfThreshold: BigInt(row.rcfThreshold)
@@ -15348,7 +15741,11 @@ function create$6(db) {
15348
15741
  }));
15349
15742
  },
15350
15743
  create: async (obligations$1) => {
15351
- if (obligations$1.length === 0) return;
15744
+ if (obligations$1.length === 0) return {
15745
+ obligationsInserted: 0,
15746
+ obligationIdKeysInserted: 0,
15747
+ obligationCollateralsInserted: 0
15748
+ };
15352
15749
  const obligationsByKey = /* @__PURE__ */ new Map();
15353
15750
  const obligationIdKeysById = /* @__PURE__ */ new Map();
15354
15751
  for (const input of obligations$1) {
@@ -15358,32 +15755,49 @@ function create$6(db) {
15358
15755
  if (!obligationIdKeysById.has(obligationId)) obligationIdKeysById.set(obligationId, input);
15359
15756
  }
15360
15757
  try {
15361
- await db.transaction(async (dbTx) => {
15758
+ return await db.transaction(async (dbTx) => {
15362
15759
  const obligationRows = Array.from(obligationsByKey.entries()).map(([obligationKey, item]) => ({
15363
15760
  obligationKey,
15364
15761
  loanToken: item.loanToken.toLowerCase(),
15365
15762
  maturity: item.maturity,
15366
15763
  rcfThreshold: item.rcfThreshold.toString()
15367
15764
  }));
15368
- for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligations).values(batch).onConflictDoNothing();
15765
+ let obligationsInserted = 0;
15766
+ for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE$1)) {
15767
+ const inserted = await dbTx.insert(obligations).values(batch).onConflictDoNothing().returning();
15768
+ obligationsInserted += inserted.length;
15769
+ }
15369
15770
  const obligationIdKeyRows = Array.from(obligationIdKeysById.entries()).map(([obligationId, input]) => ({
15370
15771
  obligationId,
15371
15772
  obligationKey: key(input.obligation).toLowerCase(),
15372
15773
  chainId: input.chainId,
15373
15774
  morphoV2: input.morphoV2.toLowerCase()
15374
15775
  }));
15375
- for (const batch of batch$1(obligationIdKeyRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationIdKeys).values(batch).onConflictDoNothing();
15776
+ let obligationIdKeysInserted = 0;
15777
+ for (const batch of batch$1(obligationIdKeyRows, DEFAULT_BATCH_SIZE$1)) {
15778
+ const inserted = await dbTx.insert(obligationIdKeys).values(batch).onConflictDoNothing().returning();
15779
+ obligationIdKeysInserted += inserted.length;
15780
+ }
15376
15781
  const collateralRows = Array.from(obligationsByKey.entries()).flatMap(([obligationKey, item]) => {
15377
15782
  return [...item.collaterals].sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())).map((collateral, collateralIndex) => ({
15378
15783
  obligationKey,
15379
15784
  asset: collateral.asset.toLowerCase(),
15380
15785
  oracleAddress: collateral.oracle.toLowerCase(),
15381
15786
  lltv: collateral.lltv,
15382
- maxLif: collateral.maxLif ?? 0n,
15787
+ maxLif: collateral.maxLif,
15383
15788
  collateralIndex
15384
15789
  }));
15385
15790
  });
15386
- for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing();
15791
+ let obligationCollateralsInserted = 0;
15792
+ for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE$1)) {
15793
+ const inserted = await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing().returning();
15794
+ obligationCollateralsInserted += inserted.length;
15795
+ }
15796
+ return {
15797
+ obligationsInserted,
15798
+ obligationIdKeysInserted,
15799
+ obligationCollateralsInserted
15800
+ };
15387
15801
  });
15388
15802
  } catch (err) {
15389
15803
  const error = err instanceof Error ? err : new Error(String(err));
@@ -15433,25 +15847,30 @@ function create$4(db) {
15433
15847
  }));
15434
15848
  },
15435
15849
  upsert: async (oracles) => {
15436
- if (oracles.length === 0) return;
15850
+ if (oracles.length === 0) return 0;
15437
15851
  const rows = oracles.map((o) => ({
15438
15852
  chainId: o.chainId,
15439
15853
  address: o.address.toLowerCase(),
15440
15854
  price: o.price !== null ? o.price.toString() : null,
15441
15855
  blockNumber: o.blockNumber
15442
15856
  }));
15443
- await db.transaction(async (dbTx) => {
15444
- for (const batch of batch$1(rows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(oracles$1).values(batch).onConflictDoUpdate({
15445
- target: [oracles$1.chainId, oracles$1.address],
15446
- set: {
15447
- price: sql`COALESCE(EXCLUDED.price, ${oracles$1.price})`,
15448
- blockNumber: sql`CASE
15857
+ return await db.transaction(async (dbTx) => {
15858
+ let upsertedCount = 0;
15859
+ for (const batch of batch$1(rows, DEFAULT_BATCH_SIZE$1)) {
15860
+ const upserted = await dbTx.insert(oracles$1).values(batch).onConflictDoUpdate({
15861
+ target: [oracles$1.chainId, oracles$1.address],
15862
+ set: {
15863
+ price: sql`COALESCE(EXCLUDED.price, ${oracles$1.price})`,
15864
+ blockNumber: sql`CASE
15449
15865
  WHEN EXCLUDED.price IS NULL THEN ${oracles$1.blockNumber}
15450
15866
  ELSE EXCLUDED.block_number
15451
15867
  END`,
15452
- updatedAt: sql`NOW()`
15453
- }
15454
- });
15868
+ updatedAt: sql`NOW()`
15869
+ }
15870
+ }).returning();
15871
+ upsertedCount += upserted.length;
15872
+ }
15873
+ return upsertedCount;
15455
15874
  });
15456
15875
  }
15457
15876
  };
@@ -15590,8 +16009,8 @@ const create$3 = (db) => {
15590
16009
  l.obligation_id,
15591
16010
  SUM(
15592
16011
  CASE
15593
- WHEN offer_agg.obligation_units > 0
15594
- THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / offer_agg.obligation_units
16012
+ WHEN offer_agg.max_units > 0
16013
+ THEN COALESCE(g.consumed::numeric, 0) * (l.upper::numeric - l.lower::numeric) / offer_agg.max_units
15595
16014
  ELSE 0
15596
16015
  END
15597
16016
  ) AS consumed
@@ -15606,7 +16025,7 @@ const create$3 = (db) => {
15606
16025
  group_maker,
15607
16026
  "group_group",
15608
16027
  obligation_id,
15609
- MAX(obligation_units::numeric) AS obligation_units
16028
+ MAX(max_units::numeric) AS max_units
15610
16029
  FROM ${offers}
15611
16030
  GROUP BY group_chain_id, group_maker, "group_group", obligation_id
15612
16031
  ) offer_agg
@@ -16308,7 +16727,7 @@ async function postMigrate(driver) {
16308
16727
  WHERE o.group_chain_id = t.chain_id
16309
16728
  AND o.group_maker = t.maker
16310
16729
  AND o.group_group = t."group"
16311
- AND o.obligation_units <= t.consumed;
16730
+ AND o.max_units <= t.consumed;
16312
16731
  RETURN NULL;
16313
16732
  END;
16314
16733
  $$;
@@ -16337,7 +16756,7 @@ async function postMigrate(driver) {
16337
16756
  AND g.chain_id = t.group_chain_id
16338
16757
  AND g.maker = t.group_maker
16339
16758
  AND g."group" = t."group"
16340
- AND o.obligation_units <= g.consumed;
16759
+ AND o.max_units <= g.consumed;
16341
16760
  RETURN NULL;
16342
16761
  END;
16343
16762
  $$;`);
@@ -16812,16 +17231,16 @@ const maxCollaterals = ({ max }) => single("max_collaterals", `Validates that an
16812
17231
  if (offer.collaterals.length > max) return { message: `Offer has ${offer.collaterals.length} collaterals, exceeding the maximum of ${max}` };
16813
17232
  });
16814
17233
  /**
16815
- * A validation rule that checks if the offer's obligationUnits is non-zero.
17234
+ * A validation rule that checks if the offer's maxUnits is non-zero.
16816
17235
  * The contract requires a positive amount; this rule rejects early.
16817
17236
  * @returns The issue that was found. If the offer is valid, this will be undefined.
16818
17237
  */
16819
- const amountNonZero = () => single("amount_non_zero", "Validates that obligationUnits is non-zero", (offer) => {
16820
- if (offer.obligationUnits === 0n) return { message: "obligationUnits must be non-zero" };
17238
+ const amountNonZero = () => single("amount_non_zero", "Validates that maxUnits is non-zero", (offer) => {
17239
+ if (offer.maxUnits === 0n) return { message: "maxUnits must be non-zero" };
16821
17240
  });
16822
17241
  /**
16823
17242
  * A batch validation rule that ensures all offers within the same group are consistent.
16824
- * All offers sharing the same group must have the same loan token, obligationUnits,
17243
+ * All offers sharing the same group must have the same loan token, maxUnits,
16825
17244
  * and side (buy/sell). The contract tracks consumed per group and requires these to match.
16826
17245
  */
16827
17246
  const groupConsistency = () => batch("group_consistency", "Validates that all offers in a group have the same loan token, obligation amounts, and side", (offers) => {
@@ -16838,13 +17257,13 @@ const groupConsistency = () => batch("group_consistency", "Validates that all of
16838
17257
  if (indices.length <= 1) continue;
16839
17258
  const reference = offers[indices[0]];
16840
17259
  const refLoanToken = reference.loanToken.toLowerCase();
16841
- const refUnits = reference.obligationUnits;
17260
+ const refUnits = reference.maxUnits;
16842
17261
  const refBuy = reference.buy;
16843
17262
  for (let j = 1; j < indices.length; j++) {
16844
17263
  const idx = indices[j];
16845
17264
  const offer = offers[idx];
16846
17265
  if (offer.loanToken.toLowerCase() !== refLoanToken) issues.set(idx, { message: `All offers in a group must have the same loan token. Expected ${reference.loanToken}, got ${offer.loanToken}` });
16847
- else if (offer.obligationUnits !== refUnits) issues.set(idx, { message: `All offers in a group must have the same obligationUnits. Expected ${refUnits}, got ${offer.obligationUnits}` });
17266
+ else if (offer.maxUnits !== refUnits) issues.set(idx, { message: `All offers in a group must have the same maxUnits. Expected ${refUnits}, got ${offer.maxUnits}` });
16848
17267
  else if (offer.buy !== refBuy) issues.set(idx, { message: `All offers in a group must be on the same side. Expected ${refBuy ? "buy" : "sell"}, got ${offer.buy ? "buy" : "sell"}` });
16849
17268
  }
16850
17269
  }