@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.
@@ -3220,7 +3220,8 @@ var OfferListResponse = class extends SuccessResponse {};
3220
3220
  __decorate([ApiProperty({
3221
3221
  type: "string",
3222
3222
  nullable: true,
3223
- example: offerCursorExample
3223
+ example: offerCursorExample,
3224
+ description: "Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries."
3224
3225
  })], OfferListResponse.prototype, "cursor", void 0);
3225
3226
  __decorate([ApiProperty({
3226
3227
  type: () => [OfferListItemResponse],
@@ -3773,11 +3774,17 @@ const configRulesLoanTokenExample = {
3773
3774
  chain_id: 1,
3774
3775
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
3775
3776
  };
3777
+ const configRulesOracleExample = {
3778
+ type: "oracle",
3779
+ chain_id: 1,
3780
+ address: "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83"
3781
+ };
3776
3782
  const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
3777
3783
  const configRulesPayloadExample = [
3778
3784
  configRulesMaturityExample,
3779
3785
  configRulesCallbackExample,
3780
- configRulesLoanTokenExample
3786
+ configRulesLoanTokenExample,
3787
+ configRulesOracleExample
3781
3788
  ];
3782
3789
  const configContractNames = [
3783
3790
  "mempool",
@@ -3928,7 +3935,7 @@ __decorate([
3928
3935
  name: "types",
3929
3936
  type: ["string"],
3930
3937
  required: false,
3931
- example: "maturity,loan_token",
3938
+ example: "maturity,loan_token,oracle",
3932
3939
  description: "Filter by rule types (comma-separated).",
3933
3940
  style: "form",
3934
3941
  explode: false
@@ -4159,6 +4166,9 @@ function isValidBase64urlJson(val) {
4159
4166
  return false;
4160
4167
  }
4161
4168
  }
4169
+ function isValidOfferHashCursor(val) {
4170
+ return /^0x[a-f0-9]{64}$/i.test(val);
4171
+ }
4162
4172
  const csvArray = (schema) => z$1.preprocess((value) => {
4163
4173
  if (value === void 0) return void 0;
4164
4174
  if (Array.isArray(value)) {
@@ -4184,10 +4194,11 @@ const PaginationQueryParams = z$1.object({
4184
4194
  const ConfigRuleTypes = z$1.enum([
4185
4195
  "maturity",
4186
4196
  "callback",
4187
- "loan_token"
4197
+ "loan_token",
4198
+ "oracle"
4188
4199
  ]);
4189
4200
  const GetConfigRulesQueryParams = z$1.object({
4190
- cursor: z$1.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4201
+ cursor: z$1.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
4191
4202
  description: "Pagination cursor in type:chain_id:<value> format",
4192
4203
  example: "maturity:1:1730415600:end_of_next_month"
4193
4204
  }),
@@ -4197,7 +4208,7 @@ const GetConfigRulesQueryParams = z$1.object({
4197
4208
  }),
4198
4209
  types: csvArray(ConfigRuleTypes).meta({
4199
4210
  description: "Filter by rule types (comma-separated).",
4200
- example: "maturity,loan_token"
4211
+ example: "maturity,loan_token,oracle"
4201
4212
  }),
4202
4213
  chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
4203
4214
  description: "Filter by chain IDs (comma-separated).",
@@ -4218,8 +4229,11 @@ const GetConfigContractsQueryParams = z$1.object({
4218
4229
  example: "1,8453"
4219
4230
  })
4220
4231
  });
4221
- const GetOffersQueryParams = z$1.object({
4222
- ...PaginationQueryParams.shape,
4232
+ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend({
4233
+ cursor: z$1.string().optional().meta({
4234
+ description: "Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.",
4235
+ example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
4236
+ }),
4223
4237
  side: z$1.enum(["buy", "sell"]).optional().meta({
4224
4238
  description: "Side of the offer. Required when using obligation_id.",
4225
4239
  example: "buy"
@@ -4243,11 +4257,29 @@ const GetOffersQueryParams = z$1.object({
4243
4257
  });
4244
4258
  return;
4245
4259
  }
4246
- if (hasMaker) return;
4260
+ if (hasMaker) {
4261
+ if (val.cursor !== void 0 && !isValidOfferHashCursor(val.cursor)) ctx.addIssue({
4262
+ code: "custom",
4263
+ path: ["cursor"],
4264
+ message: "Cursor must be a 32-byte hex offer hash when filtering by maker"
4265
+ });
4266
+ return;
4267
+ }
4247
4268
  if (!hasObligation || !hasSide) ctx.addIssue({
4248
4269
  code: "custom",
4249
4270
  message: "Must provide either maker or both obligation_id and side"
4250
4271
  });
4272
+ if (val.cursor !== void 0 && !isValidBase64urlJson(val.cursor)) ctx.addIssue({
4273
+ code: "custom",
4274
+ path: ["cursor"],
4275
+ message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
4276
+ });
4277
+ }).transform((val) => {
4278
+ if (val.maker && val.cursor) return {
4279
+ ...val,
4280
+ cursor: val.cursor.toLowerCase()
4281
+ };
4282
+ return val;
4251
4283
  });
4252
4284
  const GetObligationsQueryParams = z$1.object({
4253
4285
  ...PaginationQueryParams.shape,
@@ -4817,13 +4849,18 @@ const assets = {
4817
4849
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
4818
4850
  "0x6B175474E89094C44Da98b954EedeAC495271d0F",
4819
4851
  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
4820
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4852
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4853
+ "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
4854
+ "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
4821
4855
  ],
4822
4856
  [ChainId.BASE.toString()]: [
4823
4857
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
4824
4858
  "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
4825
4859
  "0x4200000000000000000000000000000000000006",
4826
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4860
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
4861
+ "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
4862
+ "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
4863
+ "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
4827
4864
  ],
4828
4865
  [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4829
4866
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
@@ -4839,6 +4876,43 @@ const assets = {
4839
4876
  "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
4840
4877
  ]
4841
4878
  };
4879
+ const oracles = {
4880
+ [ChainId.ETHEREUM.toString()]: [
4881
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4882
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4883
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4884
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4885
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4886
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4887
+ ],
4888
+ [ChainId.BASE.toString()]: [
4889
+ "0xD09048c8B568Dbf5f189302beA26c9edABFC4858",
4890
+ "0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4",
4891
+ "0x05D2618404668D725B66c0f32B39e4EC15B393dC",
4892
+ "0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37",
4893
+ "0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9",
4894
+ "0x10b95702a0ce895972C91e432C4f7E19811D320E",
4895
+ "0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F",
4896
+ "0x4A11590e5326138B514E08A9B52202D42077Ca65",
4897
+ "0xa54122f0E0766258377Ffe732e454A3248f454F4"
4898
+ ],
4899
+ [ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
4900
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4901
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4902
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4903
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4904
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4905
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4906
+ ],
4907
+ [ChainId.ANVIL.toString()]: [
4908
+ "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
4909
+ "0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
4910
+ "0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
4911
+ "0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
4912
+ "0xbD60A6770b27E084E8617335ddE769241B0e71D8",
4913
+ "0xAe12416c1F21B0698c27fe042D9309C83baC6597"
4914
+ ]
4915
+ };
4842
4916
  const configs = {
4843
4917
  ethereum: {
4844
4918
  callbacks: [
@@ -4909,6 +4983,7 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
4909
4983
  callback: () => callback,
4910
4984
  chains: () => chains,
4911
4985
  maturity: () => maturity,
4986
+ oracle: () => oracle,
4912
4987
  sameMaker: () => sameMaker,
4913
4988
  token: () => token,
4914
4989
  validity: () => validity
@@ -5047,6 +5122,16 @@ const token = ({ assetsByChainId }) => single("token", "Validates that offer loa
5047
5122
  if (offer.collaterals.some((collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()))) return { message: "Collateral is not allowed" };
5048
5123
  });
5049
5124
  /**
5125
+ * A validation rule that checks if the offer's oracle addresses are allowed for its chain.
5126
+ * @param oraclesByChainId - Allowed oracles indexed by chain id.
5127
+ * @returns The issue that was found. If the offer is valid, this will be undefined.
5128
+ */
5129
+ const oracle = ({ oraclesByChainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the offer chain", (offer) => {
5130
+ const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());
5131
+ if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${offer.chainId}` };
5132
+ if (offer.collaterals.some((collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()))) return { message: "Oracle is not allowed" };
5133
+ });
5134
+ /**
5050
5135
  * A batch validation rule that ensures all offers in a tree have the same maker address.
5051
5136
  * Returns an issue only for the first non-conforming offer.
5052
5137
  * This rule is signing-agnostic; signer verification is handled at the collector level.
@@ -5077,7 +5162,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
5077
5162
  //#region src/gatekeeper/morphoRules.ts
5078
5163
  const morphoRules = (chains$2) => {
5079
5164
  const assetsByChainId = {};
5080
- for (const chain of chains$2) assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
5165
+ const oraclesByChainId = {};
5166
+ for (const chain of chains$2) {
5167
+ assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
5168
+ oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
5169
+ }
5081
5170
  return [
5082
5171
  sameMaker(),
5083
5172
  amountMutualExclusivity(),
@@ -5091,7 +5180,8 @@ const morphoRules = (chains$2) => {
5091
5180
  ],
5092
5181
  allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
5093
5182
  }),
5094
- token({ assetsByChainId })
5183
+ token({ assetsByChainId }),
5184
+ oracle({ oraclesByChainId })
5095
5185
  ];
5096
5186
  };
5097
5187