@morpho-dev/router 0.1.1 → 0.1.3

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.
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var mempool = require('@morpho-dev/mempool');
4
- var chains$1 = require('viem/chains');
5
4
  var viem = require('viem');
6
5
  var v4 = require('zod/v4');
7
6
  var zodOpenapi = require('zod-openapi');
@@ -15,85 +14,6 @@ var __export = (target, all) => {
15
14
  };
16
15
  var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
17
16
 
18
- // src/Chain.ts
19
- var Chain_exports = {};
20
- __export(Chain_exports, {
21
- ChainId: () => ChainId,
22
- chainIds: () => chainIds,
23
- chainNames: () => chainNames,
24
- chains: () => chains,
25
- getChain: () => getChain,
26
- getWhitelistedChains: () => getWhitelistedChains
27
- });
28
- var chainNames = ["ethereum", "base", "ethereum-virtual-testnet"];
29
- var ChainId = {
30
- ETHEREUM: BigInt(chains$1.mainnet.id),
31
- BASE: BigInt(chains$1.base.id),
32
- "ETHEREUM-VIRTUAL-TESTNET": 109111114n
33
- };
34
- var chainIds = new Set(Object.values(ChainId));
35
- var chainNameLookup = new Map(Object.entries(ChainId).map(([key, value]) => [value, key]));
36
- function getChain(chainId) {
37
- const chainName = chainNameLookup.get(chainId)?.toLowerCase();
38
- if (!chainName) {
39
- return void 0;
40
- }
41
- return chains[chainName];
42
- }
43
- var getWhitelistedChains = () => {
44
- return [chains.ethereum, chains.base, chains["ethereum-virtual-testnet"]];
45
- };
46
- var chains = {
47
- ethereum: {
48
- ...chains$1.mainnet,
49
- id: ChainId.ETHEREUM,
50
- name: "ethereum",
51
- whitelistedAssets: new Set(
52
- [
53
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
54
- // USDC
55
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
56
- // DAI
57
- ].map((address) => address.toLowerCase())
58
- ),
59
- morpho: "0x0000000000000000000000000000000000000000"
60
- },
61
- base: {
62
- ...chains$1.base,
63
- id: ChainId.BASE,
64
- name: "base",
65
- whitelistedAssets: new Set(
66
- [
67
- "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
68
- // USDC
69
- "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
70
- // DAI
71
- ].map((address) => address.toLowerCase())
72
- ),
73
- morpho: "0x0000000000000000000000000000000000000000"
74
- },
75
- "ethereum-virtual-testnet": {
76
- ...chains$1.mainnet,
77
- id: 109111114n,
78
- name: "ethereum-virtual-testnet",
79
- whitelistedAssets: new Set(
80
- [
81
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
82
- // USDC
83
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
84
- // DAI
85
- ].map((address) => address.toLowerCase())
86
- ),
87
- morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
88
- // @TODO: This is mock Consumed contract, update with Terms once stable
89
- mempool: {
90
- address: "0x7be3164eeee8b35092f6128ec32c2e6ff8f6c890",
91
- deploymentBlock: 23223727,
92
- reindexBuffer: 10
93
- }
94
- }
95
- };
96
-
97
17
  // src/core/router/Client.ts
98
18
  var Client_exports = {};
99
19
  __export(Client_exports, {
@@ -1081,7 +1001,6 @@ function memory(parameters) {
1081
1001
  const map = parameters.offers;
1082
1002
  const filled = parameters.filled;
1083
1003
  const consumedIds = /* @__PURE__ */ new Set();
1084
- const indexingProgress = /* @__PURE__ */ new Map();
1085
1004
  const create = async (parameters2) => {
1086
1005
  if (map.has(parameters2.offer.hash.toLowerCase())) return parameters2.offer.hash;
1087
1006
  map.set(parameters2.offer.hash.toLowerCase(), {
@@ -1152,7 +1071,7 @@ function memory(parameters) {
1152
1071
  let {
1153
1072
  creators,
1154
1073
  side,
1155
- chains: chains2,
1074
+ chains,
1156
1075
  loanTokens,
1157
1076
  status = ["valid"],
1158
1077
  callbackAddresses,
@@ -1223,7 +1142,7 @@ function memory(parameters) {
1223
1142
  offers = offers.filter((o) => o.expiry >= now);
1224
1143
  creators && (offers = offers.filter((o) => creators.includes(o.offering.toLowerCase())));
1225
1144
  side && (offers = offers.filter((o) => o.buy === buy));
1226
- chains2 && (offers = offers.filter((o) => chains2.includes(Number(o.chainId))));
1145
+ chains && (offers = offers.filter((o) => chains.includes(Number(o.chainId))));
1227
1146
  loanTokens && (offers = offers.filter((o) => loanTokens.includes(o.loanToken.toLowerCase())));
1228
1147
  status && (offers = offers.filter((o) => status.includes(o.status)));
1229
1148
  callbackAddresses && (offers = offers.filter(
@@ -1429,31 +1348,10 @@ function memory(parameters) {
1429
1348
  filledForOffering.set(nonce, current + parameters2.consumed);
1430
1349
  filledForChain.set(address, filledForOffering);
1431
1350
  filled.set(chainId, filledForChain);
1432
- },
1433
- saveLatestBlockNumberProcessed: async (parameters2) => {
1434
- const key = `${parameters2.chainId.toString()}:${parameters2.eventType}`;
1435
- indexingProgress.set(key, parameters2.latestBlockNumber);
1436
- },
1437
- getLatestBlockNumberProcessed: async (parameters2) => {
1438
- const key = `${parameters2.chainId.toString()}:${parameters2.eventType}`;
1439
- const value = indexingProgress.get(key);
1440
- return value === void 0 ? null : { latestBlockNumber: value };
1441
1351
  }
1442
1352
  };
1443
1353
  }
1444
1354
 
1445
- // src/RouterEvent.ts
1446
- var RouterEvent_exports = {};
1447
- __export(RouterEvent_exports, {
1448
- from: () => from2,
1449
- types: () => types
1450
- });
1451
- var types = ["offer_created", "offer_consumed", "offer_validation"];
1452
- function from2(base) {
1453
- const id = base.type === "offer_consumed" ? `${base.type}:${base.offerConsumed.id}` : `${base.type}:${base.offer.hash.toLowerCase()}`;
1454
- return { id, ...base };
1455
- }
1456
-
1457
1355
  // src/Validation.ts
1458
1356
  var Validation_exports = {};
1459
1357
  __export(Validation_exports, {
@@ -1514,25 +1412,19 @@ function single(name, run2) {
1514
1412
  function batch2(name, run2) {
1515
1413
  return { kind: "batch", name, run: run2 };
1516
1414
  }
1517
- function morpho(parameters) {
1518
- const { whitelistedChains } = parameters;
1519
- const whitelistedChainIds = new Set(whitelistedChains.map((chain) => chain.id));
1520
- const whitelistedLoanTokensPerChain = new Map(
1521
- whitelistedChains.map((chain) => [
1522
- chain.id,
1523
- new Set(Array.from(chain.whitelistedAssets).map((a) => a.toLowerCase()))
1524
- ])
1525
- );
1526
- const morphoPerChain = new Map(
1527
- whitelistedChains.map((chain) => [chain.id, chain.morpho.toLowerCase()])
1528
- );
1529
- const chainId = single("chain_id", (offer, _) => {
1530
- if (!whitelistedChainIds.has(offer.chainId)) {
1531
- return { message: `Chain ID ${offer.chainId} is not whitelisted` };
1415
+ function morpho() {
1416
+ const chainId = single("chain_id", (offer, { chain }) => {
1417
+ if (chain.id !== offer.chainId) {
1418
+ return {
1419
+ message: `Chain ID ${offer.chainId} is not the same as the chain ID in the context (${chain.id})`
1420
+ };
1532
1421
  }
1533
1422
  });
1534
- const loanToken = single("loan_token", (offer, _) => {
1535
- if (!whitelistedLoanTokensPerChain.get(offer.chainId)?.has(offer.loanToken.toLowerCase())) {
1423
+ const loanToken = single("loan_token", (offer, { chain }) => {
1424
+ const tokens = new Set(
1425
+ Array.from(chain.whitelistedAssets.values()).map((a) => a.toLowerCase())
1426
+ );
1427
+ if (!tokens.has(offer.loanToken.toLowerCase())) {
1536
1428
  return {
1537
1429
  message: `Loan token ${offer.loanToken} is not whitelisted on chain ${offer.chainId}`
1538
1430
  };
@@ -1543,134 +1435,23 @@ function morpho(parameters) {
1543
1435
  return { message: "Expiry mismatch" };
1544
1436
  }
1545
1437
  });
1546
- const emptyCallback = single("empty_callback", (offer, _) => {
1547
- if (offer.callback.data !== "0x") {
1548
- return { message: "Callback data is not empty. Not supported yet." };
1438
+ const callback = single("empty_callback", (offer, _) => {
1439
+ if (!offer.buy || offer.callback.data !== "0x") {
1440
+ return { message: "Callback not supported yet." };
1549
1441
  }
1550
1442
  });
1551
- const sellOffersEmptyCallback = single(
1552
- "sell_offers_empty_callback",
1553
- (offer, _) => {
1554
- if (!offer.buy && offer.callback.data === "0x") {
1555
- return { message: "Sell offers with empty callback are not supported yet." };
1556
- }
1557
- }
1558
- );
1559
- const buyOffersEmptyCallback = batch2(
1560
- "buy_offers_empty_callback",
1561
- async (offers, { publicClients }) => {
1562
- const issues = /* @__PURE__ */ new Map();
1563
- const hashToIndex = /* @__PURE__ */ new Map();
1564
- for (let i = 0; i < offers.length; i++) {
1565
- const offer = offers[i];
1566
- hashToIndex.set(offer.hash, i);
1567
- }
1568
- const { buyOffers, sellOffers: _sellOffers } = offers.reduce(
1569
- (acc, offer) => {
1570
- offer.buy ? acc.buyOffers.push(offer) : issues.set(hashToIndex.get(offer.hash), {
1571
- message: "Onchain callback for sell offers is not supported yet."
1572
- });
1573
- return acc;
1574
- },
1575
- { buyOffers: [], sellOffers: [] }
1576
- );
1577
- const buyOffersPerLoanAsset = /* @__PURE__ */ new Map();
1578
- for (const offer of buyOffers) {
1579
- const chainName = getChain(offer.chainId)?.name;
1580
- const loanTokens = buyOffersPerLoanAsset.get(chainName) ?? /* @__PURE__ */ new Map();
1581
- const offers2 = loanTokens.get(offer.loanToken.toLowerCase()) ?? [];
1582
- offers2.push(offer);
1583
- loanTokens.set(offer.loanToken.toLowerCase(), offers2);
1584
- buyOffersPerLoanAsset.set(chainName, loanTokens);
1585
- }
1586
- await Promise.all(
1587
- Array.from(buyOffersPerLoanAsset.entries()).map(async ([name, loanTokens]) => {
1588
- const chainName = name;
1589
- const publicClient = publicClients[chainName];
1590
- const morpho2 = morphoPerChain.get(chains[chainName].id);
1591
- if (!publicClient) {
1592
- const offers2 = Array.from(loanTokens.values()).flat();
1593
- for (const offer of offers2) {
1594
- issues.set(hashToIndex.get(offer.hash), {
1595
- message: `Public client for chain "${chainName}" is not available`
1596
- });
1597
- }
1598
- return;
1599
- }
1600
- const balances = /* @__PURE__ */ new Map();
1601
- const allowances = /* @__PURE__ */ new Map();
1602
- for (const [loanToken2, offers2] of loanTokens) {
1603
- const data = await Promise.all(
1604
- offers2.flatMap((offer) => [
1605
- publicClient.readContract({
1606
- address: loanToken2,
1607
- abi: viem.parseAbi([
1608
- "function balanceOf(address owner) view returns (uint256 balance)"
1609
- ]),
1610
- functionName: "balanceOf",
1611
- args: [offer.offering]
1612
- }),
1613
- publicClient.readContract({
1614
- address: loanToken2,
1615
- abi: viem.parseAbi([
1616
- "function allowance(address owner, address spender) public view returns (uint256 remaining)"
1617
- ]),
1618
- functionName: "allowance",
1619
- args: [offer.offering, morpho2]
1620
- })
1621
- ])
1622
- );
1623
- for (let i = 0; i < offers2.length; i++) {
1624
- const user = offers2[i].offering.toLowerCase();
1625
- const balance = data[i * 2] || 0n;
1626
- const allowance = data[i * 2 + 1] || 0n;
1627
- const userBalances = balances.get(user) ?? /* @__PURE__ */ new Map();
1628
- userBalances.set(loanToken2.toLowerCase(), balance);
1629
- const userAllowances = allowances.get(user) ?? /* @__PURE__ */ new Map();
1630
- userAllowances.set(loanToken2.toLowerCase(), allowance);
1631
- balances.set(user, userBalances);
1632
- allowances.set(user, userAllowances);
1633
- }
1634
- }
1635
- for (const offer of Array.from(loanTokens.values()).flat()) {
1636
- const user = offer.offering.toLowerCase();
1637
- const userBalances = balances.get(user);
1638
- const balance = userBalances?.get(offer.loanToken.toLowerCase());
1639
- if (balance < offer.assets) {
1640
- issues.set(hashToIndex.get(offer.hash), {
1641
- message: `Insufficient balance for ${offer.loanToken} on chain ${offer.chainId} (${balance.toString()} < ${offer.assets.toString()})`
1642
- });
1643
- continue;
1644
- }
1645
- const userAllowances = allowances.get(user);
1646
- const allowance = userAllowances?.get(offer.loanToken.toLowerCase());
1647
- if (allowance < offer.assets) {
1648
- issues.set(hashToIndex.get(offer.hash), {
1649
- message: `Insufficient allowance for ${offer.loanToken} on chain ${offer.chainId} (${allowance.toString()} < ${offer.assets.toString()})`
1650
- });
1651
- }
1652
- }
1653
- })
1654
- );
1655
- return issues;
1656
- }
1657
- );
1658
1443
  return [
1659
1444
  chainId,
1660
1445
  loanToken,
1661
1446
  expiry,
1662
- // note: callback onchain check should be done last since it does not mean that the offer is forever invalid
1663
- // integrators should be able to keep the offers that have an invalid callback onchain and be sure that is the only check that is not valid
1664
- emptyCallback,
1665
- sellOffersEmptyCallback,
1666
- buyOffersEmptyCallback
1447
+ // note: callback rule should be the last one, since it does not mean that the offer is forever invalid
1448
+ // integrators should be able to choose if they want to keep the offer or not
1449
+ callback
1667
1450
  ];
1668
1451
  }
1669
1452
 
1670
- exports.Chain = Chain_exports;
1671
1453
  exports.OfferStore = OfferStore_exports;
1672
1454
  exports.Router = Client_exports;
1673
- exports.RouterEvent = RouterEvent_exports;
1674
1455
  exports.RouterOffer = RouterOffer_exports;
1675
1456
  exports.Utils = utils_exports;
1676
1457
  exports.Validation = Validation_exports;