@morpho-dev/router 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3261,7 +3261,8 @@ var OfferListResponse = class extends SuccessResponse {};
3261
3261
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3262
3262
  type: "string",
3263
3263
  nullable: true,
3264
- example: offerCursorExample
3264
+ example: offerCursorExample,
3265
+ description: "Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries."
3265
3266
  })], OfferListResponse.prototype, "cursor", void 0);
3266
3267
  __decorate([(0, openapi_metadata_decorators.ApiProperty)({
3267
3268
  type: () => [OfferListItemResponse],
@@ -3814,11 +3815,17 @@ const configRulesLoanTokenExample = {
3814
3815
  chain_id: 1,
3815
3816
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
3816
3817
  };
3818
+ const configRulesOracleExample = {
3819
+ type: "oracle",
3820
+ chain_id: 1,
3821
+ address: "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83"
3822
+ };
3817
3823
  const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
3818
3824
  const configRulesPayloadExample = [
3819
3825
  configRulesMaturityExample,
3820
3826
  configRulesCallbackExample,
3821
- configRulesLoanTokenExample
3827
+ configRulesLoanTokenExample,
3828
+ configRulesOracleExample
3822
3829
  ];
3823
3830
  const configContractNames = [
3824
3831
  "mempool",
@@ -3969,7 +3976,7 @@ __decorate([
3969
3976
  name: "types",
3970
3977
  type: ["string"],
3971
3978
  required: false,
3972
- example: "maturity,loan_token",
3979
+ example: "maturity,loan_token,oracle",
3973
3980
  description: "Filter by rule types (comma-separated).",
3974
3981
  style: "form",
3975
3982
  explode: false
@@ -4200,6 +4207,9 @@ function isValidBase64urlJson(val) {
4200
4207
  return false;
4201
4208
  }
4202
4209
  }
4210
+ function isValidOfferHashCursor(val) {
4211
+ return /^0x[a-f0-9]{64}$/i.test(val);
4212
+ }
4203
4213
  const csvArray = (schema) => zod.preprocess((value) => {
4204
4214
  if (value === void 0) return void 0;
4205
4215
  if (Array.isArray(value)) {
@@ -4225,10 +4235,11 @@ const PaginationQueryParams = zod.object({
4225
4235
  const ConfigRuleTypes = zod.enum([
4226
4236
  "maturity",
4227
4237
  "callback",
4228
- "loan_token"
4238
+ "loan_token",
4239
+ "oracle"
4229
4240
  ]);
4230
4241
  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({
4242
+ 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
4243
  description: "Pagination cursor in type:chain_id:<value> format",
4233
4244
  example: "maturity:1:1730415600:end_of_next_month"
4234
4245
  }),
@@ -4238,7 +4249,7 @@ const GetConfigRulesQueryParams = zod.object({
4238
4249
  }),
4239
4250
  types: csvArray(ConfigRuleTypes).meta({
4240
4251
  description: "Filter by rule types (comma-separated).",
4241
- example: "maturity,loan_token"
4252
+ example: "maturity,loan_token,oracle"
4242
4253
  }),
4243
4254
  chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4244
4255
  description: "Filter by chain IDs (comma-separated).",
@@ -4259,8 +4270,11 @@ const GetConfigContractsQueryParams = zod.object({
4259
4270
  example: "1,8453"
4260
4271
  })
4261
4272
  });
4262
- const GetOffersQueryParams = zod.object({
4263
- ...PaginationQueryParams.shape,
4273
+ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend({
4274
+ cursor: zod.string().optional().meta({
4275
+ description: "Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.",
4276
+ example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
4277
+ }),
4264
4278
  side: zod.enum(["buy", "sell"]).optional().meta({
4265
4279
  description: "Side of the offer. Required when using obligation_id.",
4266
4280
  example: "buy"
@@ -4284,11 +4298,29 @@ const GetOffersQueryParams = zod.object({
4284
4298
  });
4285
4299
  return;
4286
4300
  }
4287
- if (hasMaker) return;
4301
+ if (hasMaker) {
4302
+ if (val.cursor !== void 0 && !isValidOfferHashCursor(val.cursor)) ctx.addIssue({
4303
+ code: "custom",
4304
+ path: ["cursor"],
4305
+ message: "Cursor must be a 32-byte hex offer hash when filtering by maker"
4306
+ });
4307
+ return;
4308
+ }
4288
4309
  if (!hasObligation || !hasSide) ctx.addIssue({
4289
4310
  code: "custom",
4290
4311
  message: "Must provide either maker or both obligation_id and side"
4291
4312
  });
4313
+ if (val.cursor !== void 0 && !isValidBase64urlJson(val.cursor)) ctx.addIssue({
4314
+ code: "custom",
4315
+ path: ["cursor"],
4316
+ message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
4317
+ });
4318
+ }).transform((val) => {
4319
+ if (val.maker && val.cursor) return {
4320
+ ...val,
4321
+ cursor: val.cursor.toLowerCase()
4322
+ };
4323
+ return val;
4292
4324
  });
4293
4325
  const GetObligationsQueryParams = zod.object({
4294
4326
  ...PaginationQueryParams.shape,
@@ -4858,13 +4890,18 @@ const assets = {
4858
4890
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
4859
4891
  "0x6B175474E89094C44Da98b954EedeAC495271d0F",
4860
4892
  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
4861
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4893
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4894
+ "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
4895
+ "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
4862
4896
  ],
4863
4897
  [ChainId.BASE.toString()]: [
4864
4898
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
4865
4899
  "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
4866
4900
  "0x4200000000000000000000000000000000000006",
4867
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4901
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4902
+ "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
4903
+ "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
4904
+ "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
4868
4905
  ],
4869
4906
  [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4870
4907
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
@@ -4880,6 +4917,43 @@ const assets = {
4880
4917
  "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4881
4918
  ]
4882
4919
  };
4920
+ const oracles = {
4921
+ [ChainId.ETHEREUM.toString()]: [
4922
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4923
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4924
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4925
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4926
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4927
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4928
+ ],
4929
+ [ChainId.BASE.toString()]: [
4930
+ "0xD09048c8B568Dbf5f189302beA26c9edABFC4858",
4931
+ "0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4",
4932
+ "0x05D2618404668D725B66c0f32B39e4EC15B393dC",
4933
+ "0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37",
4934
+ "0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9",
4935
+ "0x10b95702a0ce895972C91e432C4f7E19811D320E",
4936
+ "0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F",
4937
+ "0x4A11590e5326138B514E08A9B52202D42077Ca65",
4938
+ "0xa54122f0E0766258377Ffe732e454A3248f454F4"
4939
+ ],
4940
+ [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4941
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4942
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4943
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4944
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4945
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4946
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4947
+ ],
4948
+ [ChainId.ANVIL.toString()]: [
4949
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4950
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4951
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4952
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4953
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4954
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4955
+ ]
4956
+ };
4883
4957
  const configs = {
4884
4958
  ethereum: {
4885
4959
  callbacks: [
@@ -4950,6 +5024,7 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
4950
5024
  callback: () => callback,
4951
5025
  chains: () => chains,
4952
5026
  maturity: () => maturity,
5027
+ oracle: () => oracle,
4953
5028
  sameMaker: () => sameMaker,
4954
5029
  token: () => token,
4955
5030
  validity: () => validity
@@ -5088,6 +5163,16 @@ const token = ({ assetsByChainId }) => single("token", "Validates that offer loa
5088
5163
  if (offer.collaterals.some((collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()))) return { message: "Collateral is not allowed" };
5089
5164
  });
5090
5165
  /**
5166
+ * A validation rule that checks if the offer's oracle addresses are allowed for its chain.
5167
+ * @param oraclesByChainId - Allowed oracles indexed by chain id.
5168
+ * @returns The issue that was found. If the offer is valid, this will be undefined.
5169
+ */
5170
+ const oracle = ({ oraclesByChainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the offer chain", (offer) => {
5171
+ const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());
5172
+ if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${offer.chainId}` };
5173
+ if (offer.collaterals.some((collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()))) return { message: "Oracle is not allowed" };
5174
+ });
5175
+ /**
5091
5176
  * A batch validation rule that ensures all offers in a tree have the same maker address.
5092
5177
  * Returns an issue only for the first non-conforming offer.
5093
5178
  * This rule is signing-agnostic; signer verification is handled at the collector level.
@@ -5118,7 +5203,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
5118
5203
  //#region src/gatekeeper/morphoRules.ts
5119
5204
  const morphoRules = (chains$2) => {
5120
5205
  const assetsByChainId = {};
5121
- for (const chain of chains$2) assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
5206
+ const oraclesByChainId = {};
5207
+ for (const chain of chains$2) {
5208
+ assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
5209
+ oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
5210
+ }
5122
5211
  return [
5123
5212
  sameMaker(),
5124
5213
  amountMutualExclusivity(),
@@ -5132,7 +5221,8 @@ const morphoRules = (chains$2) => {
5132
5221
  ],
5133
5222
  allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
5134
5223
  }),
5135
- token({ assetsByChainId })
5224
+ token({ assetsByChainId }),
5225
+ oracle({ oraclesByChainId })
5136
5226
  ];
5137
5227
  };
5138
5228