@morpho-dev/router 0.1.8 → 0.1.10

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.
@@ -322,8 +322,10 @@ declare namespace Liquidity$1 {
322
322
  }
323
323
 
324
324
  declare enum CallbackType {
325
- BuyWithEmptyCallback = "buy_with_empty_callback"
325
+ BuyWithEmptyCallback = "buy_with_empty_callback",
326
+ SellWithdrawFromWallet = "sell_withdraw_from_wallet"
326
327
  }
328
+ declare const WhitelistedCallbackAddresses: Record<CallbackType, readonly string[]>;
327
329
  declare function buildLiquidity(parameters: {
328
330
  type: CallbackType;
329
331
  user: string;
@@ -334,13 +336,28 @@ declare function buildLiquidity(parameters: {
334
336
  updatedAt?: Date;
335
337
  }): Liquidity;
336
338
  declare function getCallbackIdForOffer(offer: Offer.Offer): string | null;
339
+ declare function decode$1(parameters: {
340
+ type: CallbackType;
341
+ data: Hex;
342
+ }): Array<{
343
+ collateral: Address;
344
+ amount: bigint;
345
+ }>;
346
+ declare function encode$1(parameters: {
347
+ type: CallbackType;
348
+ data: {
349
+ collaterals: Address[];
350
+ amounts: bigint[];
351
+ };
352
+ }): Hex;
337
353
 
338
354
  type Callback_CallbackType = CallbackType;
339
355
  declare const Callback_CallbackType: typeof CallbackType;
356
+ declare const Callback_WhitelistedCallbackAddresses: typeof WhitelistedCallbackAddresses;
340
357
  declare const Callback_buildLiquidity: typeof buildLiquidity;
341
358
  declare const Callback_getCallbackIdForOffer: typeof getCallbackIdForOffer;
342
359
  declare namespace Callback {
343
- export { Callback_CallbackType as CallbackType, Callback_buildLiquidity as buildLiquidity, Callback_getCallbackIdForOffer as getCallbackIdForOffer };
360
+ export { Callback_CallbackType as CallbackType, Callback_WhitelistedCallbackAddresses as WhitelistedCallbackAddresses, Callback_buildLiquidity as buildLiquidity, decode$1 as decode, encode$1 as encode, Callback_getCallbackIdForOffer as getCallbackIdForOffer };
344
361
  }
345
362
 
346
363
  type PgDB = ReturnType<typeof drizzle> & {
@@ -2068,7 +2085,103 @@ declare function morpho(): (Rule<{
2068
2085
  readonly hash: viem.Hex;
2069
2086
  signature?: viem.Hex;
2070
2087
  createdAt?: number;
2071
- }, "empty_callback", MorphoContext>)[];
2088
+ }, "sell_offers_empty_callback", MorphoContext> | Rule<{
2089
+ readonly offering: Address;
2090
+ readonly assets: bigint;
2091
+ readonly rate: bigint;
2092
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2093
+ readonly expiry: number;
2094
+ readonly nonce: bigint;
2095
+ readonly buy: boolean;
2096
+ readonly chainId: bigint;
2097
+ readonly loanToken: Address;
2098
+ readonly start: number;
2099
+ readonly collaterals: readonly {
2100
+ asset: Address;
2101
+ oracle: Address;
2102
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2103
+ }[];
2104
+ readonly callback: {
2105
+ readonly address: Address;
2106
+ readonly data: viem.Hex;
2107
+ readonly gasLimit: bigint;
2108
+ };
2109
+ readonly hash: viem.Hex;
2110
+ signature?: viem.Hex;
2111
+ createdAt?: number;
2112
+ }, "buy_offers_non_empty_callback", MorphoContext> | Rule<{
2113
+ readonly offering: Address;
2114
+ readonly assets: bigint;
2115
+ readonly rate: bigint;
2116
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2117
+ readonly expiry: number;
2118
+ readonly nonce: bigint;
2119
+ readonly buy: boolean;
2120
+ readonly chainId: bigint;
2121
+ readonly loanToken: Address;
2122
+ readonly start: number;
2123
+ readonly collaterals: readonly {
2124
+ asset: Address;
2125
+ oracle: Address;
2126
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2127
+ }[];
2128
+ readonly callback: {
2129
+ readonly address: Address;
2130
+ readonly data: viem.Hex;
2131
+ readonly gasLimit: bigint;
2132
+ };
2133
+ readonly hash: viem.Hex;
2134
+ signature?: viem.Hex;
2135
+ createdAt?: number;
2136
+ }, "sell_offers_non_whitelisted_callback", MorphoContext> | Rule<{
2137
+ readonly offering: Address;
2138
+ readonly assets: bigint;
2139
+ readonly rate: bigint;
2140
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2141
+ readonly expiry: number;
2142
+ readonly nonce: bigint;
2143
+ readonly buy: boolean;
2144
+ readonly chainId: bigint;
2145
+ readonly loanToken: Address;
2146
+ readonly start: number;
2147
+ readonly collaterals: readonly {
2148
+ asset: Address;
2149
+ oracle: Address;
2150
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2151
+ }[];
2152
+ readonly callback: {
2153
+ readonly address: Address;
2154
+ readonly data: viem.Hex;
2155
+ readonly gasLimit: bigint;
2156
+ };
2157
+ readonly hash: viem.Hex;
2158
+ signature?: viem.Hex;
2159
+ createdAt?: number;
2160
+ }, "sell_offers_callback_data_invalid", MorphoContext> | Rule<{
2161
+ readonly offering: Address;
2162
+ readonly assets: bigint;
2163
+ readonly rate: bigint;
2164
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2165
+ readonly expiry: number;
2166
+ readonly nonce: bigint;
2167
+ readonly buy: boolean;
2168
+ readonly chainId: bigint;
2169
+ readonly loanToken: Address;
2170
+ readonly start: number;
2171
+ readonly collaterals: readonly {
2172
+ asset: Address;
2173
+ oracle: Address;
2174
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2175
+ }[];
2176
+ readonly callback: {
2177
+ readonly address: Address;
2178
+ readonly data: viem.Hex;
2179
+ readonly gasLimit: bigint;
2180
+ };
2181
+ readonly hash: viem.Hex;
2182
+ signature?: viem.Hex;
2183
+ createdAt?: number;
2184
+ }, "sell_offers_callback_collateral_invalid", MorphoContext>)[];
2072
2185
 
2073
2186
  type ValidationRule_Batch<T, RuleName extends string, Ctx = void> = Batch<T, RuleName, Ctx>;
2074
2187
  type ValidationRule_MorphoContext = MorphoContext;
@@ -322,8 +322,10 @@ declare namespace Liquidity$1 {
322
322
  }
323
323
 
324
324
  declare enum CallbackType {
325
- BuyWithEmptyCallback = "buy_with_empty_callback"
325
+ BuyWithEmptyCallback = "buy_with_empty_callback",
326
+ SellWithdrawFromWallet = "sell_withdraw_from_wallet"
326
327
  }
328
+ declare const WhitelistedCallbackAddresses: Record<CallbackType, readonly string[]>;
327
329
  declare function buildLiquidity(parameters: {
328
330
  type: CallbackType;
329
331
  user: string;
@@ -334,13 +336,28 @@ declare function buildLiquidity(parameters: {
334
336
  updatedAt?: Date;
335
337
  }): Liquidity;
336
338
  declare function getCallbackIdForOffer(offer: Offer.Offer): string | null;
339
+ declare function decode$1(parameters: {
340
+ type: CallbackType;
341
+ data: Hex;
342
+ }): Array<{
343
+ collateral: Address;
344
+ amount: bigint;
345
+ }>;
346
+ declare function encode$1(parameters: {
347
+ type: CallbackType;
348
+ data: {
349
+ collaterals: Address[];
350
+ amounts: bigint[];
351
+ };
352
+ }): Hex;
337
353
 
338
354
  type Callback_CallbackType = CallbackType;
339
355
  declare const Callback_CallbackType: typeof CallbackType;
356
+ declare const Callback_WhitelistedCallbackAddresses: typeof WhitelistedCallbackAddresses;
340
357
  declare const Callback_buildLiquidity: typeof buildLiquidity;
341
358
  declare const Callback_getCallbackIdForOffer: typeof getCallbackIdForOffer;
342
359
  declare namespace Callback {
343
- export { Callback_CallbackType as CallbackType, Callback_buildLiquidity as buildLiquidity, Callback_getCallbackIdForOffer as getCallbackIdForOffer };
360
+ export { Callback_CallbackType as CallbackType, Callback_WhitelistedCallbackAddresses as WhitelistedCallbackAddresses, Callback_buildLiquidity as buildLiquidity, decode$1 as decode, encode$1 as encode, Callback_getCallbackIdForOffer as getCallbackIdForOffer };
344
361
  }
345
362
 
346
363
  type PgDB = ReturnType<typeof drizzle> & {
@@ -2068,7 +2085,103 @@ declare function morpho(): (Rule<{
2068
2085
  readonly hash: viem.Hex;
2069
2086
  signature?: viem.Hex;
2070
2087
  createdAt?: number;
2071
- }, "empty_callback", MorphoContext>)[];
2088
+ }, "sell_offers_empty_callback", MorphoContext> | Rule<{
2089
+ readonly offering: Address;
2090
+ readonly assets: bigint;
2091
+ readonly rate: bigint;
2092
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2093
+ readonly expiry: number;
2094
+ readonly nonce: bigint;
2095
+ readonly buy: boolean;
2096
+ readonly chainId: bigint;
2097
+ readonly loanToken: Address;
2098
+ readonly start: number;
2099
+ readonly collaterals: readonly {
2100
+ asset: Address;
2101
+ oracle: Address;
2102
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2103
+ }[];
2104
+ readonly callback: {
2105
+ readonly address: Address;
2106
+ readonly data: viem.Hex;
2107
+ readonly gasLimit: bigint;
2108
+ };
2109
+ readonly hash: viem.Hex;
2110
+ signature?: viem.Hex;
2111
+ createdAt?: number;
2112
+ }, "buy_offers_non_empty_callback", MorphoContext> | Rule<{
2113
+ readonly offering: Address;
2114
+ readonly assets: bigint;
2115
+ readonly rate: bigint;
2116
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2117
+ readonly expiry: number;
2118
+ readonly nonce: bigint;
2119
+ readonly buy: boolean;
2120
+ readonly chainId: bigint;
2121
+ readonly loanToken: Address;
2122
+ readonly start: number;
2123
+ readonly collaterals: readonly {
2124
+ asset: Address;
2125
+ oracle: Address;
2126
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2127
+ }[];
2128
+ readonly callback: {
2129
+ readonly address: Address;
2130
+ readonly data: viem.Hex;
2131
+ readonly gasLimit: bigint;
2132
+ };
2133
+ readonly hash: viem.Hex;
2134
+ signature?: viem.Hex;
2135
+ createdAt?: number;
2136
+ }, "sell_offers_non_whitelisted_callback", MorphoContext> | Rule<{
2137
+ readonly offering: Address;
2138
+ readonly assets: bigint;
2139
+ readonly rate: bigint;
2140
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2141
+ readonly expiry: number;
2142
+ readonly nonce: bigint;
2143
+ readonly buy: boolean;
2144
+ readonly chainId: bigint;
2145
+ readonly loanToken: Address;
2146
+ readonly start: number;
2147
+ readonly collaterals: readonly {
2148
+ asset: Address;
2149
+ oracle: Address;
2150
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2151
+ }[];
2152
+ readonly callback: {
2153
+ readonly address: Address;
2154
+ readonly data: viem.Hex;
2155
+ readonly gasLimit: bigint;
2156
+ };
2157
+ readonly hash: viem.Hex;
2158
+ signature?: viem.Hex;
2159
+ createdAt?: number;
2160
+ }, "sell_offers_callback_data_invalid", MorphoContext> | Rule<{
2161
+ readonly offering: Address;
2162
+ readonly assets: bigint;
2163
+ readonly rate: bigint;
2164
+ readonly maturity: number & _morpho_dev_mempool.Brand<"Maturity">;
2165
+ readonly expiry: number;
2166
+ readonly nonce: bigint;
2167
+ readonly buy: boolean;
2168
+ readonly chainId: bigint;
2169
+ readonly loanToken: Address;
2170
+ readonly start: number;
2171
+ readonly collaterals: readonly {
2172
+ asset: Address;
2173
+ oracle: Address;
2174
+ lltv: bigint & _morpho_dev_mempool.Brand<"LLTV">;
2175
+ }[];
2176
+ readonly callback: {
2177
+ readonly address: Address;
2178
+ readonly data: viem.Hex;
2179
+ readonly gasLimit: bigint;
2180
+ };
2181
+ readonly hash: viem.Hex;
2182
+ signature?: viem.Hex;
2183
+ createdAt?: number;
2184
+ }, "sell_offers_callback_collateral_invalid", MorphoContext>)[];
2072
2185
 
2073
2186
  type ValidationRule_Batch<T, RuleName extends string, Ctx = void> = Batch<T, RuleName, Ctx>;
2074
2187
  type ValidationRule_MorphoContext = MorphoContext;
@@ -724,13 +724,25 @@ function fromResponse(offerResponse) {
724
724
  var Callback_exports = {};
725
725
  __export(Callback_exports, {
726
726
  CallbackType: () => CallbackType,
727
+ WhitelistedCallbackAddresses: () => WhitelistedCallbackAddresses,
727
728
  buildLiquidity: () => buildLiquidity,
729
+ decode: () => decode2,
730
+ encode: () => encode2,
728
731
  getCallbackIdForOffer: () => getCallbackIdForOffer
729
732
  });
730
733
  var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
731
734
  CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
735
+ CallbackType2["SellWithdrawFromWallet"] = "sell_withdraw_from_wallet";
732
736
  return CallbackType2;
733
737
  })(CallbackType || {});
738
+ var WhitelistedCallbackAddresses = {
739
+ ["buy_with_empty_callback" /* BuyWithEmptyCallback */]: [],
740
+ ["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */]: [
741
+ "0x1111111111111111111111111111111111111111",
742
+ "0x2222222222222222222222222222222222222222"
743
+ // @TODO: update once deployed and add mapping per chain if needed
744
+ ]
745
+ };
734
746
  function buildLiquidity(parameters) {
735
747
  const { type, user, contract, chainId, amount, index: index2 = 0, updatedAt = /* @__PURE__ */ new Date() } = parameters;
736
748
  if (type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */)
@@ -772,6 +784,38 @@ function getCallbackIdForOffer(offer) {
772
784
  }
773
785
  return null;
774
786
  }
787
+ function decodeSellWithdrawFromWalletData(data) {
788
+ if (!data || data === "0x") throw new Error("Empty callback data");
789
+ try {
790
+ const [collaterals, amounts] = viem.decodeAbiParameters(
791
+ [{ type: "address[]" }, { type: "uint256[]" }],
792
+ data
793
+ );
794
+ if (collaterals.length !== amounts.length) {
795
+ throw new Error("Mismatched array lengths");
796
+ }
797
+ return collaterals.map((c, i) => ({ collateral: c, amount: amounts[i] }));
798
+ } catch (_) {
799
+ throw new Error("Invalid SellWithdrawFromWallet callback data");
800
+ }
801
+ }
802
+ function decode2(parameters) {
803
+ const { type, data } = parameters;
804
+ if (type === "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */) {
805
+ return decodeSellWithdrawFromWalletData(data);
806
+ }
807
+ throw new Error(`CallbackType not implemented: ${type}`);
808
+ }
809
+ function encode2(parameters) {
810
+ const { type, data } = parameters;
811
+ if (type === "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */) {
812
+ return viem.encodeAbiParameters(
813
+ [{ type: "address[]" }, { type: "uint256[]" }],
814
+ [data.collaterals, data.amounts]
815
+ );
816
+ }
817
+ throw new Error(`CallbackType not implemented: ${type}`);
818
+ }
775
819
 
776
820
  // src/core/Collector/index.ts
777
821
  var Collector_exports = {};
@@ -1391,18 +1435,89 @@ function morpho() {
1391
1435
  return { message: "Expiry mismatch" };
1392
1436
  }
1393
1437
  });
1394
- const callback = single("empty_callback", (offer, _) => {
1395
- if (!offer.buy || offer.callback.data !== "0x") {
1396
- return { message: "Callback not supported yet." };
1438
+ const sellEmptyCallback = single(
1439
+ "sell_offers_empty_callback",
1440
+ (offer, _) => {
1441
+ if (!offer.buy && offer.callback.data === "0x") {
1442
+ return { message: "Sell offers require a non-empty callback." };
1443
+ }
1397
1444
  }
1398
- });
1445
+ );
1446
+ const buyNonEmptyCallback = single(
1447
+ "buy_offers_non_empty_callback",
1448
+ (offer, _) => {
1449
+ if (offer.buy && offer.callback.data !== "0x") {
1450
+ return { message: "Buy offers must use an empty callback." };
1451
+ }
1452
+ }
1453
+ );
1454
+ const sellNonWhitelistedCallback = single(
1455
+ "sell_offers_non_whitelisted_callback",
1456
+ (offer, _) => {
1457
+ if (!offer.buy && offer.callback.data !== "0x") {
1458
+ const allowed = new Set(
1459
+ WhitelistedCallbackAddresses["sell_withdraw_from_wallet" /* SellWithdrawFromWallet */].map(
1460
+ (a) => a.toLowerCase()
1461
+ )
1462
+ );
1463
+ const callbackAddress = offer.callback.address?.toLowerCase();
1464
+ if (!callbackAddress || !allowed.has(callbackAddress)) {
1465
+ return { message: "Sell offer callback address is not whitelisted." };
1466
+ }
1467
+ }
1468
+ }
1469
+ );
1470
+ const sellCallbackDataInvalid = single(
1471
+ "sell_offers_callback_data_invalid",
1472
+ (offer, _) => {
1473
+ if (!offer.buy && offer.callback.data !== "0x") {
1474
+ try {
1475
+ const decoded = decode2({
1476
+ type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
1477
+ data: offer.callback.data
1478
+ });
1479
+ if (decoded.length === 0) {
1480
+ return { message: "Sell offer callback data must include at least one collateral." };
1481
+ }
1482
+ } catch (_2) {
1483
+ return { message: "Sell offer callback data cannot be decoded." };
1484
+ }
1485
+ }
1486
+ }
1487
+ );
1488
+ const sellCallbackCollateralInvalid = single(
1489
+ "sell_offers_callback_collateral_invalid",
1490
+ (offer, _) => {
1491
+ if (!offer.buy && offer.callback.data !== "0x") {
1492
+ try {
1493
+ const decoded = decode2({
1494
+ type: "sell_withdraw_from_wallet" /* SellWithdrawFromWallet */,
1495
+ data: offer.callback.data
1496
+ });
1497
+ const offerCollaterals2 = new Set(
1498
+ offer.collaterals.map((c) => c.asset.toLowerCase())
1499
+ );
1500
+ for (const { collateral } of decoded) {
1501
+ if (!offerCollaterals2.has(collateral.toLowerCase())) {
1502
+ return { message: "Sell callback collateral is not part of offer collaterals." };
1503
+ }
1504
+ }
1505
+ } catch (_2) {
1506
+ }
1507
+ }
1508
+ }
1509
+ );
1399
1510
  return [
1400
1511
  chainId,
1401
1512
  loanToken,
1402
1513
  expiry,
1403
- // note: callback rule should be the last one, since it does not mean that the offer is forever invalid
1514
+ // note: callback rules should be the last ones, since they do not mean that the offer is forever invalid
1404
1515
  // integrators should be able to choose if they want to keep the offer or not
1405
- callback
1516
+ sellEmptyCallback,
1517
+ buyNonEmptyCallback,
1518
+ sellNonWhitelistedCallback,
1519
+ sellCallbackDataInvalid,
1520
+ sellCallbackCollateralInvalid
1406
1521
  ];
1407
1522
  }
1408
1523
 
@@ -1451,9 +1566,11 @@ function createMempoolCollector(parameters) {
1451
1566
  });
1452
1567
  const invalidOffersToSave = [];
1453
1568
  const issueToStatus = {
1454
- empty_callback: "callback_not_supported",
1455
1569
  sell_offers_empty_callback: "callback_not_supported",
1456
- buy_offers_empty_callback: "callback_error"
1570
+ buy_offers_non_empty_callback: "callback_not_supported",
1571
+ sell_offers_non_whitelisted_callback: "callback_not_supported",
1572
+ sell_offers_callback_data_invalid: "callback_error",
1573
+ sell_offers_callback_collateral_invalid: "callback_error"
1457
1574
  };
1458
1575
  for (const issue of issues) {
1459
1576
  const status = issueToStatus[issue.ruleName];