@morpho-dev/router 0.6.0 → 0.7.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.
@@ -294,107 +294,14 @@ const Morpho = [
294
294
  //#region src/core/Callback.ts
295
295
  var Callback_exports = /* @__PURE__ */ __exportAll({
296
296
  Type: () => Type$1,
297
- decode: () => decode$2,
298
- decodeBuyERC20: () => decodeBuyERC20,
299
- decodeBuyVaultV1Callback: () => decodeBuyVaultV1Callback,
300
- decodeSellERC20Callback: () => decodeSellERC20Callback,
301
- encode: () => encode$2,
302
- encodeBuyERC20: () => encodeBuyERC20,
303
- encodeBuyVaultV1Callback: () => encodeBuyVaultV1Callback,
304
- encodeSellERC20Callback: () => encodeSellERC20Callback,
305
297
  isEmptyCallback: () => isEmptyCallback
306
298
  });
307
299
  let Type$1 = /* @__PURE__ */ function(Type) {
308
300
  Type["BuyWithEmptyCallback"] = "buy_with_empty_callback";
309
- Type["BuyERC20"] = "buy_erc20";
310
- Type["BuyVaultV1Callback"] = "buy_vault_v1_callback";
311
- Type["SellERC20Callback"] = "sell_erc20_callback";
301
+ Type["SellWithEmptyCallback"] = "sell_with_empty_callback";
312
302
  return Type;
313
303
  }({});
314
304
  const isEmptyCallback = (offer) => offer.callback.data === "0x";
315
- function decode$2(type, data) {
316
- switch (type) {
317
- case Type$1.BuyERC20: return decodeBuyERC20(data);
318
- case Type$1.BuyVaultV1Callback: return decodeBuyVaultV1Callback(data);
319
- case Type$1.SellERC20Callback: return decodeSellERC20Callback(data);
320
- default: throw new Error("Invalid callback type");
321
- }
322
- }
323
- function encode$2(type, data) {
324
- switch (type) {
325
- case Type$1.BuyERC20:
326
- if (!("tokens" in data)) throw new Error("Invalid callback data");
327
- return encodeBuyERC20(data);
328
- case Type$1.BuyVaultV1Callback:
329
- if (!("vaults" in data)) throw new Error("Invalid callback data");
330
- return encodeBuyVaultV1Callback(data);
331
- case Type$1.SellERC20Callback:
332
- if (!("collaterals" in data)) throw new Error("Invalid callback data");
333
- return encodeSellERC20Callback(data);
334
- default: throw new Error("Invalid callback type");
335
- }
336
- }
337
- /**
338
- * Decodes BuyERC20 callback data into positions.
339
- * @param data - The ABI-encoded callback data containing token addresses and amounts.
340
- * @returns Array of positions with contract address and amount.
341
- * @throws If data is empty, malformed, or arrays have mismatched lengths.
342
- */
343
- function decodeBuyERC20(data) {
344
- if (!data || data === "0x") throw new Error("Empty callback data");
345
- let tokens;
346
- let amounts;
347
- try {
348
- [tokens, amounts] = (0, viem.decodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], data);
349
- } catch (_) {
350
- throw new Error("Invalid BuyERC20 callback data");
351
- }
352
- if (tokens.length !== amounts.length) throw new Error("Mismatched array lengths");
353
- return tokens.map((token, index) => ({
354
- contract: token,
355
- amount: amounts[index]
356
- }));
357
- }
358
- /**
359
- * Encodes BuyERC20 callback parameters into ABI-encoded data.
360
- * @param parameters - The tokens and amounts to encode.
361
- * @returns ABI-encoded hex string.
362
- */
363
- function encodeBuyERC20(parameters) {
364
- return (0, viem.encodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], [parameters.tokens, parameters.amounts]);
365
- }
366
- function decodeBuyVaultV1Callback(data) {
367
- if (!data || data === "0x") throw new Error("Empty callback data");
368
- try {
369
- const [vaults, amounts] = (0, viem.decodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], data);
370
- if (vaults.length !== amounts.length) throw new Error("Mismatched array lengths");
371
- return vaults.map((v, i) => ({
372
- contract: v,
373
- amount: amounts[i]
374
- }));
375
- } catch (_) {
376
- throw new Error("Invalid BuyVaultV1Callback callback data");
377
- }
378
- }
379
- function decodeSellERC20Callback(data) {
380
- if (!data || data === "0x") throw new Error("Empty callback data");
381
- try {
382
- const [collaterals, amounts] = (0, viem.decodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], data);
383
- if (collaterals.length !== amounts.length) throw new Error("Mismatched array lengths");
384
- return collaterals.map((c, i) => ({
385
- contract: c,
386
- amount: amounts[i]
387
- }));
388
- } catch (_) {
389
- throw new Error("Invalid SellERC20Callback callback data");
390
- }
391
- }
392
- function encodeBuyVaultV1Callback(parameters) {
393
- return (0, viem.encodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], [parameters.vaults, parameters.amounts]);
394
- }
395
- function encodeSellERC20Callback(parameters) {
396
- return (0, viem.encodeAbiParameters)([{ type: "address[]" }, { type: "uint256[]" }], [parameters.collaterals, parameters.amounts]);
397
- }
398
305
 
399
306
  //#endregion
400
307
  //#region src/utils/BigMath.ts
@@ -1150,11 +1057,9 @@ var Liquidity_exports = /* @__PURE__ */ __exportAll({
1150
1057
  calculateMaxDebt: () => calculateMaxDebt,
1151
1058
  generateAllowancePoolId: () => generateAllowancePoolId,
1152
1059
  generateBalancePoolId: () => generateBalancePoolId,
1153
- generateBuyVaultCallbackPoolId: () => generateBuyVaultCallbackPoolId,
1154
1060
  generateDebtPoolId: () => generateDebtPoolId,
1155
1061
  generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
1156
1062
  generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
1157
- generateSellERC20CallbackPoolId: () => generateSellERC20CallbackPoolId,
1158
1063
  generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
1159
1064
  generateVaultPositionPoolId: () => generateVaultPositionPoolId
1160
1065
  });
@@ -1183,14 +1088,6 @@ function generateAllowancePoolId(parameters) {
1183
1088
  return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
1184
1089
  }
1185
1090
  /**
1186
- * Generate pool ID for sell ERC20 callback pools.
1187
- * Each offer has its own callback pool to prevent liquidity conflicts.
1188
- */
1189
- function generateSellERC20CallbackPoolId(parameters) {
1190
- const { user, chainId, obligationId, token, offerHash } = parameters;
1191
- return `${user}-${chainId.toString()}-${obligationId}-${token}-${offerHash}-sell_erc20_callback`.toLowerCase();
1192
- }
1193
- /**
1194
1091
  * Generate pool ID for obligation collateral pools.
1195
1092
  * Obligation collateral pools represent collateral already deposited in the obligation.
1196
1093
  * These pools are shared across all offers with the same obligation.
@@ -1200,13 +1097,6 @@ function generateObligationCollateralPoolId(parameters) {
1200
1097
  return `${user}-${chainId.toString()}-${obligationId}-${token}-obligation-collateral`.toLowerCase();
1201
1098
  }
1202
1099
  /**
1203
- * Generate pool ID for buy vault callback pools.
1204
- */
1205
- function generateBuyVaultCallbackPoolId(parameters) {
1206
- const { user, chainId, vault, offerHash } = parameters;
1207
- return `${user}-${chainId.toString()}-${vault}-${offerHash}-${Type$1.BuyVaultV1Callback}`.toLowerCase();
1208
- }
1209
- /**
1210
1100
  * Generate pool ID for debt pools.
1211
1101
  */
1212
1102
  function generateDebtPoolId(parameters) {
@@ -1586,6 +1476,7 @@ var Offer_exports = /* @__PURE__ */ __exportAll({
1586
1476
  obligationId: () => obligationId,
1587
1477
  random: () => random$1,
1588
1478
  serialize: () => serialize,
1479
+ takeEvent: () => takeEvent,
1589
1480
  toSnakeCase: () => toSnakeCase,
1590
1481
  types: () => types
1591
1482
  });
@@ -1704,7 +1595,7 @@ function random$1(config) {
1704
1595
  const chain = config?.chains ? config.chains[int(config.chains.length)] : chains$1.ethereum;
1705
1596
  const loanToken = config?.loanTokens ? config.loanTokens[int(config.loanTokens.length)] : address();
1706
1597
  const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [address()];
1707
- const collateralAsset = collateralCandidates[int(collateralCandidates.length)];
1598
+ collateralCandidates[int(collateralCandidates.length)];
1708
1599
  const maturityOption = weightedChoice([["end_of_month", 1], ["end_of_next_month", 1]]);
1709
1600
  const maturity = config?.maturity ?? from$11(maturityOption);
1710
1601
  const lltv = from$13(weightedChoice([
@@ -1731,21 +1622,10 @@ function random$1(config) {
1731
1622
  const unit = BigInt(10) ** BigInt(loanTokenDecimals);
1732
1623
  const amountBase = BigInt(100 + int(999901));
1733
1624
  const assetsScaled = config?.assets ?? amountBase * unit;
1734
- const callbackBySide = (() => {
1735
- if (buy) return {
1736
- address: viem.zeroAddress,
1737
- data: "0x"
1738
- };
1739
- const sellCallbackAddress = "0x3333333333333333333333333333333333333333";
1740
- const amount = assetsScaled * 1000000000000000000000n;
1741
- return {
1742
- address: sellCallbackAddress,
1743
- data: encodeSellERC20Callback({
1744
- collaterals: [collateralAsset],
1745
- amounts: [amount]
1746
- })
1747
- };
1748
- })();
1625
+ const emptyCallback = {
1626
+ address: viem.zeroAddress,
1627
+ data: "0x"
1628
+ };
1749
1629
  return from$9({
1750
1630
  maker: config?.maker ?? address(),
1751
1631
  assets: assetsScaled,
@@ -1764,7 +1644,7 @@ function random$1(config) {
1764
1644
  ...random$3(),
1765
1645
  lltv
1766
1646
  })).sort((a, b) => a.asset.localeCompare(b.asset)),
1767
- callback: config?.callback ?? callbackBySide
1647
+ callback: config?.callback ?? emptyCallback
1768
1648
  });
1769
1649
  }
1770
1650
  const weightedChoice = (pairs) => {
@@ -2054,6 +1934,94 @@ function decode$1(data) {
2054
1934
  });
2055
1935
  }
2056
1936
  /**
1937
+ * ABI for the Take event emitted by the Morpho V2 contract.
1938
+ */
1939
+ const takeEvent = {
1940
+ type: "event",
1941
+ name: "Take",
1942
+ inputs: [
1943
+ {
1944
+ name: "caller",
1945
+ type: "address",
1946
+ indexed: false,
1947
+ internalType: "address"
1948
+ },
1949
+ {
1950
+ name: "id",
1951
+ type: "bytes32",
1952
+ indexed: true,
1953
+ internalType: "bytes32"
1954
+ },
1955
+ {
1956
+ name: "maker",
1957
+ type: "address",
1958
+ indexed: true,
1959
+ internalType: "address"
1960
+ },
1961
+ {
1962
+ name: "taker",
1963
+ type: "address",
1964
+ indexed: true,
1965
+ internalType: "address"
1966
+ },
1967
+ {
1968
+ name: "offerIsBuy",
1969
+ type: "bool",
1970
+ indexed: false,
1971
+ internalType: "bool"
1972
+ },
1973
+ {
1974
+ name: "buyerAssets",
1975
+ type: "uint256",
1976
+ indexed: false,
1977
+ internalType: "uint256"
1978
+ },
1979
+ {
1980
+ name: "sellerAssets",
1981
+ type: "uint256",
1982
+ indexed: false,
1983
+ internalType: "uint256"
1984
+ },
1985
+ {
1986
+ name: "obligationUnits",
1987
+ type: "uint256",
1988
+ indexed: false,
1989
+ internalType: "uint256"
1990
+ },
1991
+ {
1992
+ name: "obligationShares",
1993
+ type: "uint256",
1994
+ indexed: false,
1995
+ internalType: "uint256"
1996
+ },
1997
+ {
1998
+ name: "buyerIsLender",
1999
+ type: "bool",
2000
+ indexed: false,
2001
+ internalType: "bool"
2002
+ },
2003
+ {
2004
+ name: "sellerIsBorrower",
2005
+ type: "bool",
2006
+ indexed: false,
2007
+ internalType: "bool"
2008
+ },
2009
+ {
2010
+ name: "group",
2011
+ type: "bytes32",
2012
+ indexed: false,
2013
+ internalType: "bytes32"
2014
+ },
2015
+ {
2016
+ name: "consumed",
2017
+ type: "uint256",
2018
+ indexed: false,
2019
+ internalType: "uint256"
2020
+ }
2021
+ ],
2022
+ anonymous: false
2023
+ };
2024
+ /**
2057
2025
  * ABI for the Consume event emitted by the Obligation contract.
2058
2026
  */
2059
2027
  const consumedEvent = {
@@ -2908,8 +2876,8 @@ const offerExample = {
2908
2876
  price: "2750000000000000000",
2909
2877
  group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
2910
2878
  session: "0x0000000000000000000000000000000000000000000000000000000000000000",
2911
- callback: "0x1111111111111111111111111111111111111111",
2912
- callback_data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2879
+ callback: "0x0000000000000000000000000000000000000000",
2880
+ callback_data: "0x"
2913
2881
  },
2914
2882
  offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
2915
2883
  obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc",
@@ -2961,25 +2929,10 @@ const validateOfferExample = {
2961
2929
  lltv: "860000000000000000"
2962
2930
  }],
2963
2931
  callback: {
2964
- address: "0x1111111111111111111111111111111111111111",
2965
- data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2932
+ address: "0x0000000000000000000000000000000000000000",
2933
+ data: "0x"
2966
2934
  }
2967
2935
  };
2968
- const callbackTypesRequestExample = { callbacks: [{
2969
- chain_id: 1,
2970
- addresses: [
2971
- "0x1111111111111111111111111111111111111111",
2972
- "0x3333333333333333333333333333333333333333",
2973
- "0x9999999999999999999999999999999999999999"
2974
- ]
2975
- }] };
2976
- const callbackTypesResponseExample = [{
2977
- chain_id: 1,
2978
- sell_erc20_callback: ["0x1111111111111111111111111111111111111111"],
2979
- buy_erc20: ["0x5555555555555555555555555555555555555555"],
2980
- buy_vault_v1_callback: ["0x3333333333333333333333333333333333333333"],
2981
- not_supported: ["0x9999999999999999999999999999999999999999"]
2982
- }];
2983
2936
  const routerStatusExample = {
2984
2937
  status: "live",
2985
2938
  initialized: true,
@@ -3048,55 +3001,6 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3048
3001
  type: "string",
3049
3002
  example: validateOfferExample.callback.data
3050
3003
  })], ValidateCallbackRequest.prototype, "data", void 0);
3051
- var CallbackTypesChainRequest = class {};
3052
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3053
- type: "number",
3054
- example: callbackTypesRequestExample.callbacks[0].chain_id
3055
- })], CallbackTypesChainRequest.prototype, "chain_id", void 0);
3056
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3057
- type: () => [String],
3058
- example: callbackTypesRequestExample.callbacks[0].addresses
3059
- })], CallbackTypesChainRequest.prototype, "addresses", void 0);
3060
- var CallbackTypesRequest = class {};
3061
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3062
- type: () => [CallbackTypesChainRequest],
3063
- example: callbackTypesRequestExample.callbacks
3064
- })], CallbackTypesRequest.prototype, "callbacks", void 0);
3065
- var CallbackTypesChainResponse = class {};
3066
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3067
- type: "number",
3068
- example: callbackTypesResponseExample[0].chain_id
3069
- })], CallbackTypesChainResponse.prototype, "chain_id", void 0);
3070
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3071
- type: () => [String],
3072
- required: false,
3073
- example: callbackTypesResponseExample[0].buy_vault_v1_callback
3074
- })], CallbackTypesChainResponse.prototype, "buy_vault_v1_callback", void 0);
3075
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3076
- type: () => [String],
3077
- required: false,
3078
- example: callbackTypesResponseExample[0].sell_erc20_callback
3079
- })], CallbackTypesChainResponse.prototype, "sell_erc20_callback", void 0);
3080
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3081
- type: () => [String],
3082
- required: false,
3083
- example: callbackTypesResponseExample[0].buy_erc20
3084
- })], CallbackTypesChainResponse.prototype, "buy_erc20", void 0);
3085
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3086
- type: () => [String],
3087
- example: callbackTypesResponseExample[0].not_supported
3088
- })], CallbackTypesChainResponse.prototype, "not_supported", void 0);
3089
- var CallbackTypesSuccessResponse = class extends SuccessResponse {};
3090
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3091
- type: "string",
3092
- nullable: true,
3093
- example: "maturity:1:1730415600:end_of_next_month"
3094
- })], CallbackTypesSuccessResponse.prototype, "cursor", void 0);
3095
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3096
- type: () => [CallbackTypesChainResponse],
3097
- description: "Callback types grouped by chain.",
3098
- example: callbackTypesResponseExample
3099
- })], CallbackTypesSuccessResponse.prototype, "data", void 0);
3100
3004
  var AskResponse = class {};
3101
3005
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3102
3006
  type: "string",
@@ -3261,7 +3165,8 @@ var OfferListResponse = class extends SuccessResponse {};
3261
3165
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3262
3166
  type: "string",
3263
3167
  nullable: true,
3264
- example: offerCursorExample
3168
+ example: offerCursorExample,
3169
+ description: "Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries."
3265
3170
  })], OfferListResponse.prototype, "cursor", void 0);
3266
3171
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3267
3172
  type: () => [OfferListItemResponse],
@@ -3613,7 +3518,7 @@ __decorate([
3613
3518
  methods: ["post"],
3614
3519
  path: "/v1/validate",
3615
3520
  summary: "Validate offers",
3616
- description: "Validates offers against router validation rules. Returns unsigned payload + root on success, or issues only on validation failure."
3521
+ description: "Validates offers against router validation rules. Only empty callbacks (zero address, 0x data) are accepted. Returns unsigned payload + root on success, or issues only on validation failure."
3617
3522
  }),
3618
3523
  (0, openapi_metadata_decorators.ApiBody)({ type: ValidateOffersRequest }),
3619
3524
  (0, openapi_metadata_decorators.ApiResponse)({
@@ -3632,28 +3537,6 @@ ValidateController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"
3632
3537
  description: "Bad Request",
3633
3538
  type: BadRequestResponse
3634
3539
  })], ValidateController);
3635
- let CallbacksController = class CallbacksController {
3636
- async resolveCallbackTypes() {}
3637
- };
3638
- __decorate([
3639
- (0, openapi_metadata_decorators.ApiOperation)({
3640
- methods: ["post"],
3641
- path: "/v1/callbacks",
3642
- summary: "Resolve callback types",
3643
- description: "Returns callback types for callback addresses grouped by chain."
3644
- }),
3645
- (0, openapi_metadata_decorators.ApiBody)({ type: CallbackTypesRequest }),
3646
- (0, openapi_metadata_decorators.ApiResponse)({
3647
- status: 200,
3648
- description: "Success",
3649
- type: CallbackTypesSuccessResponse
3650
- })
3651
- ], CallbacksController.prototype, "resolveCallbackTypes", null);
3652
- CallbacksController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"), (0, openapi_metadata_decorators.ApiResponse)({
3653
- status: 400,
3654
- description: "Bad Request",
3655
- type: BadRequestResponse
3656
- })], CallbacksController);
3657
3540
  let OffersController = class OffersController {
3658
3541
  async getOffers() {}
3659
3542
  };
@@ -3803,22 +3686,21 @@ const configRulesMaturityExample = {
3803
3686
  name: "end_of_next_month",
3804
3687
  timestamp: 1730415600
3805
3688
  };
3806
- const configRulesCallbackExample = {
3807
- type: "callback",
3808
- chain_id: 1,
3809
- address: "0x1111111111111111111111111111111111111111",
3810
- callback_type: "sell_erc20_callback"
3811
- };
3812
3689
  const configRulesLoanTokenExample = {
3813
3690
  type: "loan_token",
3814
3691
  chain_id: 1,
3815
3692
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
3816
3693
  };
3694
+ const configRulesOracleExample = {
3695
+ type: "oracle",
3696
+ chain_id: 1,
3697
+ address: "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83"
3698
+ };
3817
3699
  const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
3818
3700
  const configRulesPayloadExample = [
3819
3701
  configRulesMaturityExample,
3820
- configRulesCallbackExample,
3821
- configRulesLoanTokenExample
3702
+ configRulesLoanTokenExample,
3703
+ configRulesOracleExample
3822
3704
  ];
3823
3705
  const configContractNames = [
3824
3706
  "mempool",
@@ -3881,14 +3763,9 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3881
3763
  })], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
3882
3764
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3883
3765
  type: "string",
3884
- example: configRulesCallbackExample.address,
3766
+ example: configRulesLoanTokenExample.address,
3885
3767
  required: false
3886
3768
  })], ConfigRulesRuleResponse.prototype, "address", void 0);
3887
- __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3888
- type: "string",
3889
- example: configRulesCallbackExample.callback_type,
3890
- required: false
3891
- })], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
3892
3769
  var ConfigRulesSuccessResponse = class {};
3893
3770
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
3894
3771
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
@@ -3949,7 +3826,7 @@ __decorate([
3949
3826
  methods: ["get"],
3950
3827
  path: "/v1/config/rules",
3951
3828
  summary: "Get config rules",
3952
- description: "Returns configured rules for supported chains."
3829
+ description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
3953
3830
  }),
3954
3831
  (0, openapi_metadata_decorators.ApiQuery)({
3955
3832
  name: "cursor",
@@ -3969,7 +3846,7 @@ __decorate([
3969
3846
  name: "types",
3970
3847
  type: ["string"],
3971
3848
  required: false,
3972
- example: "maturity,loan_token",
3849
+ example: "maturity,loan_token,oracle",
3973
3850
  description: "Filter by rule types (comma-separated).",
3974
3851
  style: "form",
3975
3852
  explode: false
@@ -4128,8 +4005,7 @@ const OpenApi = async () => {
4128
4005
  ObligationsController,
4129
4006
  HealthController,
4130
4007
  UsersController,
4131
- ValidateController,
4132
- CallbacksController
4008
+ ValidateController
4133
4009
  ],
4134
4010
  document: {
4135
4011
  openapi: "3.1.0",
@@ -4200,6 +4076,9 @@ function isValidBase64urlJson(val) {
4200
4076
  return false;
4201
4077
  }
4202
4078
  }
4079
+ function isValidOfferHashCursor(val) {
4080
+ return /^0x[a-f0-9]{64}$/i.test(val);
4081
+ }
4203
4082
  const csvArray = (schema) => zod.preprocess((value) => {
4204
4083
  if (value === void 0) return void 0;
4205
4084
  if (Array.isArray(value)) {
@@ -4225,10 +4104,11 @@ const PaginationQueryParams = zod.object({
4225
4104
  const ConfigRuleTypes = zod.enum([
4226
4105
  "maturity",
4227
4106
  "callback",
4228
- "loan_token"
4107
+ "loan_token",
4108
+ "oracle"
4229
4109
  ]);
4230
4110
  const GetConfigRulesQueryParams = zod.object({
4231
- cursor: zod.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4111
+ cursor: zod.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4232
4112
  description: "Pagination cursor in type:chain_id:<value> format",
4233
4113
  example: "maturity:1:1730415600:end_of_next_month"
4234
4114
  }),
@@ -4238,7 +4118,7 @@ const GetConfigRulesQueryParams = zod.object({
4238
4118
  }),
4239
4119
  types: csvArray(ConfigRuleTypes).meta({
4240
4120
  description: "Filter by rule types (comma-separated).",
4241
- example: "maturity,loan_token"
4121
+ example: "maturity,loan_token,oracle"
4242
4122
  }),
4243
4123
  chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4244
4124
  description: "Filter by chain IDs (comma-separated).",
@@ -4259,8 +4139,11 @@ const GetConfigContractsQueryParams = zod.object({
4259
4139
  example: "1,8453"
4260
4140
  })
4261
4141
  });
4262
- const GetOffersQueryParams = zod.object({
4263
- ...PaginationQueryParams.shape,
4142
+ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend({
4143
+ cursor: zod.string().optional().meta({
4144
+ description: "Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.",
4145
+ example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
4146
+ }),
4264
4147
  side: zod.enum(["buy", "sell"]).optional().meta({
4265
4148
  description: "Side of the offer. Required when using obligation_id.",
4266
4149
  example: "buy"
@@ -4284,11 +4167,29 @@ const GetOffersQueryParams = zod.object({
4284
4167
  });
4285
4168
  return;
4286
4169
  }
4287
- if (hasMaker) return;
4170
+ if (hasMaker) {
4171
+ if (val.cursor !== void 0 && !isValidOfferHashCursor(val.cursor)) ctx.addIssue({
4172
+ code: "custom",
4173
+ path: ["cursor"],
4174
+ message: "Cursor must be a 32-byte hex offer hash when filtering by maker"
4175
+ });
4176
+ return;
4177
+ }
4288
4178
  if (!hasObligation || !hasSide) ctx.addIssue({
4289
4179
  code: "custom",
4290
4180
  message: "Must provide either maker or both obligation_id and side"
4291
4181
  });
4182
+ if (val.cursor !== void 0 && !isValidBase64urlJson(val.cursor)) ctx.addIssue({
4183
+ code: "custom",
4184
+ path: ["cursor"],
4185
+ message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
4186
+ });
4187
+ }).transform((val) => {
4188
+ if (val.maker && val.cursor) return {
4189
+ ...val,
4190
+ cursor: val.cursor.toLowerCase()
4191
+ };
4192
+ return val;
4292
4193
  });
4293
4194
  const GetObligationsQueryParams = zod.object({
4294
4195
  ...PaginationQueryParams.shape,
@@ -4361,16 +4262,6 @@ const GetBookParams = zod.object({
4361
4262
  })
4362
4263
  });
4363
4264
  const ValidateOffersBody = zod.object({ offers: zod.array(zod.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
4364
- const CallbackTypesBody = zod.object({ callbacks: zod.array(zod.object({
4365
- chain_id: zod.number().int().positive().meta({
4366
- description: "Chain id.",
4367
- example: 1
4368
- }),
4369
- addresses: zod.array(zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Callback address must be a valid 20-byte address" }).transform((val) => val.toLowerCase())).meta({
4370
- description: "Callback contract addresses.",
4371
- example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
4372
- })
4373
- }).strict()) }).strict();
4374
4265
  const GetUserPositionsParams = zod.object({
4375
4266
  ...PaginationQueryParams.shape,
4376
4267
  user_address: zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
@@ -4389,7 +4280,6 @@ const schemas = {
4389
4280
  get_obligation: GetObligationParams,
4390
4281
  get_book: GetBookParams,
4391
4282
  validate_offers: ValidateOffersBody,
4392
- callback_types: CallbackTypesBody,
4393
4283
  get_user_positions: GetUserPositionsParams
4394
4284
  };
4395
4285
  function parse(action, query) {
@@ -4404,7 +4294,6 @@ function safeParse(action, query, error) {
4404
4294
  var Schema_exports = /* @__PURE__ */ __exportAll({
4405
4295
  BookResponse: () => BookResponse_exports,
4406
4296
  BooksController: () => BooksController,
4407
- CallbacksController: () => CallbacksController,
4408
4297
  ChainHealth: () => ChainHealth,
4409
4298
  ChainsHealthResponse: () => ChainsHealthResponse,
4410
4299
  CollectorHealth: () => CollectorHealth,
@@ -4683,23 +4572,11 @@ function createHttpClient(config) {
4683
4572
  issues: []
4684
4573
  };
4685
4574
  };
4686
- const getCallbackTypes = async (requestPayload) => {
4687
- const response = await request("/v1/callbacks", {
4688
- method: "POST",
4689
- headers: { "content-type": "application/json" },
4690
- body: JSON.stringify(requestPayload)
4691
- });
4692
- const json = await response.json();
4693
- if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
4694
- if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
4695
- return json.data;
4696
- };
4697
4575
  return {
4698
4576
  baseUrl,
4699
4577
  validate,
4700
4578
  getConfigRules,
4701
- isAllowed,
4702
- getCallbackTypes
4579
+ isAllowed
4703
4580
  };
4704
4581
  }
4705
4582
  function mergeHeaders(base, extra) {
@@ -4823,48 +4700,23 @@ function create(parameters) {
4823
4700
 
4824
4701
  //#endregion
4825
4702
  //#region src/gatekeeper/GateConfig.ts
4826
- /**
4827
- * Returns the callback configuration for a given chain and callback type, if it exists.
4828
- *
4829
- * @param chain - Chain name for which to read the validation configuration
4830
- * @param type - Callback type to retrieve
4831
- * @returns The matching callback configuration or undefined if not configured
4832
- */
4833
- function getCallback(chain, type) {
4834
- return configs[chain].callbacks?.find((c) => c.type === type);
4835
- }
4836
- /**
4837
- * Attempts to infer the configured callback type from a callback address on a chain.
4838
- * Skips the empty callback type as it does not carry addresses.
4839
- *
4840
- * @param chain - Chain name for which to infer the callback type
4841
- * @param address - Callback contract address
4842
- * @returns The callback type when found, otherwise undefined
4843
- */
4844
- function getCallbackType(chain, address) {
4845
- return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
4846
- }
4847
- /**
4848
- * Returns the list of allowed non-empty callback addresses for a chain.
4849
- *
4850
- * @param chain - Chain name
4851
- * @returns Array of allowed callback addresses (lowercased). Empty when none configured
4852
- */
4853
- const getCallbackAddresses = (chain) => {
4854
- return configs[chain].callbacks?.filter((c) => c.type !== Type$1.BuyWithEmptyCallback).flatMap((c) => c.addresses) ?? [];
4855
- };
4856
4703
  const assets = {
4857
4704
  [ChainId.ETHEREUM.toString()]: [
4858
4705
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
4859
4706
  "0x6B175474E89094C44Da98b954EedeAC495271d0F",
4860
4707
  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
4861
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4708
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4709
+ "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
4710
+ "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
4862
4711
  ],
4863
4712
  [ChainId.BASE.toString()]: [
4864
4713
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
4865
4714
  "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
4866
4715
  "0x4200000000000000000000000000000000000006",
4867
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4716
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4717
+ "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
4718
+ "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
4719
+ "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
4868
4720
  ],
4869
4721
  [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4870
4722
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
@@ -4880,65 +4732,58 @@ const assets = {
4880
4732
  "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4881
4733
  ]
4882
4734
  };
4735
+ const oracles = {
4736
+ [ChainId.ETHEREUM.toString()]: [
4737
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4738
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4739
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4740
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4741
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4742
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4743
+ ],
4744
+ [ChainId.BASE.toString()]: [
4745
+ "0xD09048c8B568Dbf5f189302beA26c9edABFC4858",
4746
+ "0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4",
4747
+ "0x05D2618404668D725B66c0f32B39e4EC15B393dC",
4748
+ "0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37",
4749
+ "0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9",
4750
+ "0x10b95702a0ce895972C91e432C4f7E19811D320E",
4751
+ "0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F",
4752
+ "0x4A11590e5326138B514E08A9B52202D42077Ca65",
4753
+ "0xa54122f0E0766258377Ffe732e454A3248f454F4"
4754
+ ],
4755
+ [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4756
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4757
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4758
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4759
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4760
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4761
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4762
+ ],
4763
+ [ChainId.ANVIL.toString()]: [
4764
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4765
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4766
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4767
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4768
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4769
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4770
+ ]
4771
+ };
4883
4772
  const configs = {
4884
4773
  ethereum: {
4885
- callbacks: [
4886
- {
4887
- type: Type$1.BuyVaultV1Callback,
4888
- addresses: ["0x3333333333333333333333333333333333333333", "0x4444444444444444444444444444444444444444"],
4889
- vaultFactories: ["0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101", "0x1897A8997241C1cD4bD0698647e4EB7213535c24"]
4890
- },
4891
- {
4892
- type: Type$1.SellERC20Callback,
4893
- addresses: ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"]
4894
- },
4895
- { type: Type$1.BuyWithEmptyCallback }
4896
- ],
4774
+ callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
4897
4775
  maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth]
4898
4776
  },
4899
4777
  base: {
4900
- callbacks: [
4901
- {
4902
- type: Type$1.BuyVaultV1Callback,
4903
- addresses: ["0x3333333333333333333333333333333333333333", "0x4444444444444444444444444444444444444444"],
4904
- vaultFactories: ["0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101", "0xFf62A7c278C62eD665133147129245053Bbf5918"]
4905
- },
4906
- {
4907
- type: Type$1.SellERC20Callback,
4908
- addresses: ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"]
4909
- },
4910
- { type: Type$1.BuyWithEmptyCallback }
4911
- ],
4778
+ callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
4912
4779
  maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth]
4913
4780
  },
4914
4781
  "ethereum-virtual-testnet": {
4915
- callbacks: [
4916
- {
4917
- type: Type$1.BuyVaultV1Callback,
4918
- addresses: ["0x3333333333333333333333333333333333333333", "0x4444444444444444444444444444444444444444"],
4919
- vaultFactories: ["0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101", "0x1897A8997241C1cD4bD0698647e4EB7213535c24"]
4920
- },
4921
- {
4922
- type: Type$1.SellERC20Callback,
4923
- addresses: ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"]
4924
- },
4925
- { type: Type$1.BuyWithEmptyCallback }
4926
- ],
4782
+ callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
4927
4783
  maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth]
4928
4784
  },
4929
4785
  anvil: {
4930
- callbacks: [
4931
- {
4932
- type: Type$1.BuyVaultV1Callback,
4933
- addresses: ["0x3333333333333333333333333333333333333333", "0x4444444444444444444444444444444444444444"],
4934
- vaultFactories: ["0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101", "0x1897A8997241C1cD4bD0698647e4EB7213535c24"]
4935
- },
4936
- {
4937
- type: Type$1.SellERC20Callback,
4938
- addresses: ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"]
4939
- },
4940
- { type: Type$1.BuyWithEmptyCallback }
4941
- ],
4786
+ callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
4942
4787
  maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth]
4943
4788
  }
4944
4789
  };
@@ -4950,6 +4795,7 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
4950
4795
  callback: () => callback,
4951
4796
  chains: () => chains,
4952
4797
  maturity: () => maturity,
4798
+ oracle: () => oracle,
4953
4799
  sameMaker: () => sameMaker,
4954
4800
  token: () => token,
4955
4801
  validity: () => validity
@@ -4957,109 +4803,13 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
4957
4803
  /**
4958
4804
  * set of rules to validate offers.
4959
4805
  *
4960
- * @param parameters - Validity parameters with chain and client
4806
+ * @param _parameters - Validity parameters with chain and client
4961
4807
  * @returns Array of validation rules to evaluate against offers
4962
4808
  */
4963
- function validity(parameters) {
4964
- const { client } = parameters;
4965
- const sellErc20CallbackInvalid = single("sell_erc20_callback_invalid", "Validates that sell offers have valid ERC20 callback data matching offer collaterals", (offer) => {
4966
- const callbackType = getCallbackType(client.chain.name, offer.callback.address);
4967
- if (callbackType !== Type$1.SellERC20Callback) return;
4968
- const decoded = decode$2(callbackType, offer.callback.data);
4969
- if (decoded.length === 0) return { message: "Callback data cannot be decoded or is empty." };
4970
- if (callbackType === Type$1.SellERC20Callback) {
4971
- const offerCollaterals = new Set(offer.collaterals.map((c) => c.asset.toLowerCase()));
4972
- if (decoded.length !== offer.collaterals.length) return { message: `Sell callback collateral length mismatch. Expected ${offer.collaterals.length}, got ${decoded.length}.` };
4973
- for (const { contract } of decoded) if (!offerCollaterals.has(contract.toLowerCase())) return { message: "Sell callback collateral is not part of offer collaterals." };
4974
- }
4975
- });
4976
- const buyCallbackVaultInvalid = batch("buy_offers_callback_vault_invalid", "Validates that buy offers have valid vault callbacks registered in allowed factories with matching assets", async (offers) => {
4977
- const validationIssues = /* @__PURE__ */ new Map();
4978
- const offersByVaultAddress = /* @__PURE__ */ new Map();
4979
- for (let i = 0; i < offers.length; i++) {
4980
- const offer = offers[i];
4981
- if (getCallbackType(client.chain.name, offer.callback.address) !== Type$1.BuyVaultV1Callback) continue;
4982
- try {
4983
- const callbackVaults = decodeBuyVaultV1Callback(offer.callback.data);
4984
- for (const { contract } of callbackVaults) {
4985
- const normalizedVaultAddress = contract.toLowerCase();
4986
- if (!offersByVaultAddress.has(normalizedVaultAddress)) offersByVaultAddress.set(normalizedVaultAddress, []);
4987
- offersByVaultAddress.get(normalizedVaultAddress).push({
4988
- index: i,
4989
- offer
4990
- });
4991
- }
4992
- } catch (_) {}
4993
- }
4994
- const uniqueVaultAddresses = Array.from(offersByVaultAddress.keys());
4995
- if (uniqueVaultAddresses.length === 0) return validationIssues;
4996
- const allowedFactories = getCallback(client.chain.name, Type$1.BuyVaultV1Callback)?.vaultFactories.map((f) => f.toLowerCase());
4997
- if (!allowedFactories) return validationIssues;
4998
- const multicallContracts = [];
4999
- for (const vaultAddress of uniqueVaultAddresses) {
5000
- multicallContracts.push({
5001
- address: vaultAddress,
5002
- abi: ERC4626,
5003
- functionName: "asset"
5004
- });
5005
- for (const factoryAddress of allowedFactories) multicallContracts.push({
5006
- address: factoryAddress,
5007
- abi: MetaMorphoFactory,
5008
- functionName: "isMetaMorpho",
5009
- args: [vaultAddress]
5010
- });
5011
- }
5012
- const multicallResults = await (0, viem_actions.multicall)(client, {
5013
- contracts: multicallContracts,
5014
- allowFailure: true
5015
- });
5016
- const vaultAssetByAddress = /* @__PURE__ */ new Map();
5017
- const registeredVaults = /* @__PURE__ */ new Set();
5018
- const numberOfFactories = allowedFactories.length;
5019
- let resultIndex = 0;
5020
- for (const vaultAddress of uniqueVaultAddresses) {
5021
- const assetCallResult = multicallResults[resultIndex++];
5022
- const assetAddress = assetCallResult.status === "success" ? assetCallResult.result : null;
5023
- vaultAssetByAddress.set(vaultAddress, assetAddress);
5024
- let isRegisteredInFactory = false;
5025
- for (let factoryIndex = 0; factoryIndex < numberOfFactories; factoryIndex++) {
5026
- const factoryCallResult = multicallResults[resultIndex++];
5027
- if (factoryCallResult.status === "success" && factoryCallResult.result === true) isRegisteredInFactory = true;
5028
- }
5029
- if (isRegisteredInFactory) registeredVaults.add(vaultAddress);
5030
- }
5031
- const uniqueOffers = /* @__PURE__ */ new Map();
5032
- for (const offersArray of offersByVaultAddress.values()) for (const { index, offer } of offersArray) uniqueOffers.set(index, offer);
5033
- for (const [index, offer] of uniqueOffers) try {
5034
- const callbackVaults = decodeBuyVaultV1Callback(offer.callback.data);
5035
- const vaultsWithIssues = [];
5036
- for (const { contract } of callbackVaults) {
5037
- const normalizedVaultAddress = contract.toLowerCase();
5038
- const assetAddress = vaultAssetByAddress.get(normalizedVaultAddress);
5039
- const isRegistered = registeredVaults.has(normalizedVaultAddress);
5040
- const failureReasons = [];
5041
- if (assetAddress === null) failureReasons.push("asset call failed");
5042
- else if (assetAddress && assetAddress.toLowerCase() !== offer.loanToken.toLowerCase()) failureReasons.push("asset mismatch");
5043
- if (!isRegistered) failureReasons.push("not registered in factory");
5044
- if (failureReasons.length > 0) vaultsWithIssues.push({
5045
- vaultAddress: contract,
5046
- failureReasons: failureReasons.join(", ")
5047
- });
5048
- }
5049
- if (vaultsWithIssues.length > 0) {
5050
- const failureDetails = vaultsWithIssues.map((v) => `${v.vaultAddress} (${v.failureReasons})`).join("; ");
5051
- validationIssues.set(index, { message: `Buy offer callback vaults are invalid: ${failureDetails}` });
5052
- }
5053
- } catch (_) {}
5054
- return validationIssues;
5055
- });
5056
- return [
5057
- single("expiry", "Validates that offer has not expired", (offer) => {
5058
- if (offer.expiry < Math.floor(Date.now() / 1e3)) return { message: "Expiry mismatch" };
5059
- }),
5060
- sellErc20CallbackInvalid,
5061
- buyCallbackVaultInvalid
5062
- ];
4809
+ function validity(_parameters) {
4810
+ return [single("expiry", "Validates that offer has not expired", (offer) => {
4811
+ if (offer.expiry < Math.floor(Date.now() / 1e3)) return { message: "Expiry mismatch" };
4812
+ })];
5063
4813
  }
5064
4814
  const chains = ({ chains }) => single("chain_ids", `Validates that offer chain is one of: [${chains.map((c) => c.id).join(", ")}]`, (offer) => {
5065
4815
  const allowedChainIds = chains.map((c) => c.id);
@@ -5069,12 +4819,10 @@ const maturity = ({ maturities }) => single("maturity", `Validates that offer ma
5069
4819
  const allowedMaturities = maturities.map((m) => from$11(m));
5070
4820
  if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}` };
5071
4821
  });
5072
- const callback = ({ callbacks, allowedAddresses }) => single("callback", `Validates callbacks: buy empty callback is ${callbacks.includes(Type$1.BuyWithEmptyCallback) ? "allowed" : "not allowed"}; sell offers must use a non-empty callback; non-empty callbacks must target one of [${allowedAddresses.map((a) => a.toLowerCase()).join(", ")}]`, (offer) => {
5073
- if (isEmptyCallback(offer) && offer.buy && !callbacks?.find((c) => c === Type$1.BuyWithEmptyCallback)) return { message: "Buy offers with empty callback not allowed." };
5074
- if (isEmptyCallback(offer) && !offer.buy) return { message: "Sell offers require a non-empty callback." };
5075
- if (!isEmptyCallback(offer)) {
5076
- if (!allowedAddresses.includes(offer.callback.address?.toLowerCase())) return { message: `Callback address ${offer.callback.address} is not allowed.` };
5077
- }
4822
+ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy empty callback is ${callbacks.includes(Type$1.BuyWithEmptyCallback) ? "allowed" : "not allowed"}; sell empty callback is ${callbacks.includes(Type$1.SellWithEmptyCallback) ? "allowed" : "not allowed"}; non-empty callbacks are rejected`, (offer) => {
4823
+ if (!isEmptyCallback(offer)) return { message: "Non-empty callbacks are not supported." };
4824
+ if (isEmptyCallback(offer) && offer.buy && !callbacks.includes(Type$1.BuyWithEmptyCallback)) return { message: "Buy offers with empty callback not allowed." };
4825
+ if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
5078
4826
  });
5079
4827
  /**
5080
4828
  * A validation rule that checks if the offer's tokens are allowed for its chain.
@@ -5088,6 +4836,16 @@ const token = ({ assetsByChainId }) => single("token", "Validates that offer loa
5088
4836
  if (offer.collaterals.some((collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()))) return { message: "Collateral is not allowed" };
5089
4837
  });
5090
4838
  /**
4839
+ * A validation rule that checks if the offer's oracle addresses are allowed for its chain.
4840
+ * @param oraclesByChainId - Allowed oracles indexed by chain id.
4841
+ * @returns The issue that was found. If the offer is valid, this will be undefined.
4842
+ */
4843
+ const oracle = ({ oraclesByChainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the offer chain", (offer) => {
4844
+ const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());
4845
+ if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${offer.chainId}` };
4846
+ if (offer.collaterals.some((collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()))) return { message: "Oracle is not allowed" };
4847
+ });
4848
+ /**
5091
4849
  * A batch validation rule that ensures all offers in a tree have the same maker address.
5092
4850
  * Returns an issue only for the first non-conforming offer.
5093
4851
  * This rule is signing-agnostic; signer verification is handled at the collector level.
@@ -5118,21 +4876,22 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
5118
4876
  //#region src/gatekeeper/morphoRules.ts
5119
4877
  const morphoRules = (chains$2) => {
5120
4878
  const assetsByChainId = {};
5121
- for (const chain of chains$2) assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
4879
+ const oraclesByChainId = {};
4880
+ for (const chain of chains$2) {
4881
+ assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
4882
+ oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
4883
+ }
5122
4884
  return [
5123
4885
  sameMaker(),
5124
4886
  amountMutualExclusivity(),
5125
4887
  chains({ chains: chains$2 }),
5126
4888
  maturity({ maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth] }),
5127
4889
  callback({
5128
- callbacks: [
5129
- Type$1.BuyWithEmptyCallback,
5130
- Type$1.BuyVaultV1Callback,
5131
- Type$1.SellERC20Callback
5132
- ],
5133
- allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
4890
+ callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
4891
+ allowedAddresses: []
5134
4892
  }),
5135
- token({ assetsByChainId })
4893
+ token({ assetsByChainId }),
4894
+ oracle({ oraclesByChainId })
5136
4895
  ];
5137
4896
  };
5138
4897