@continuumdao/ctm-mpc-defi 0.2.26 → 0.2.28

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.
Files changed (38) hide show
  1. package/dist/agent/catalog.cjs +681 -46
  2. package/dist/agent/catalog.cjs.map +1 -1
  3. package/dist/agent/catalog.d.ts +1209 -21
  4. package/dist/agent/catalog.js +668 -47
  5. package/dist/agent/catalog.js.map +1 -1
  6. package/dist/agent/skills/morpho/SKILL.md +38 -6
  7. package/dist/agent/skills/uniswap-v4/SKILL.md +15 -0
  8. package/dist/core/index.cjs +19 -0
  9. package/dist/core/index.cjs.map +1 -1
  10. package/dist/core/index.d.ts +8 -1
  11. package/dist/core/index.js +17 -1
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/index.cjs +363 -22
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +361 -23
  17. package/dist/index.js.map +1 -1
  18. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  19. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  20. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  21. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  22. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  23. package/dist/protocols/evm/maple/index.js.map +1 -1
  24. package/dist/protocols/evm/morpho/index.cjs +1153 -142
  25. package/dist/protocols/evm/morpho/index.cjs.map +1 -1
  26. package/dist/protocols/evm/morpho/index.d.ts +314 -8
  27. package/dist/protocols/evm/morpho/index.js +1131 -144
  28. package/dist/protocols/evm/morpho/index.js.map +1 -1
  29. package/dist/protocols/evm/permit2/index.cjs.map +1 -1
  30. package/dist/protocols/evm/permit2/index.js.map +1 -1
  31. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  32. package/dist/protocols/evm/sky/index.js.map +1 -1
  33. package/dist/protocols/evm/uniswap-v4/index.cjs +863 -25
  34. package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/uniswap-v4/index.d.ts +266 -9
  36. package/dist/protocols/evm/uniswap-v4/index.js +834 -27
  37. package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
  38. package/package.json +2 -1
@@ -1,17 +1,21 @@
1
1
  'use strict';
2
2
 
3
3
  var viem = require('viem');
4
+ var api = require('@morpho-org/midnight-sdk/api');
5
+ var midnightSdk = require('@morpho-org/midnight-sdk');
4
6
  var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
5
7
 
6
- // src/core/registry.ts
7
- var modules = [];
8
- function registerProtocolModule(mod) {
9
- const existing = modules.findIndex((m) => m.id === mod.id);
10
- if (existing >= 0) {
11
- modules[existing] = mod;
12
- } else {
13
- modules.push(mod);
14
- }
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __esm = (fn, res) => function __init() {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ };
13
+ var __export = (target, all) => {
14
+ for (var name in all)
15
+ __defProp(target, name, { get: all[name], enumerable: true });
16
+ };
17
+ function getMorphoMidnightRestProxyUrl() {
18
+ return morphoMidnightRestProxyUrl;
15
19
  }
16
20
  async function postJsonViaOptionalProxy(args) {
17
21
  const r = await fetch(args.directUrl, {
@@ -25,8 +29,254 @@ async function postJsonViaOptionalProxy(args) {
25
29
  }
26
30
  return await r.json();
27
31
  }
32
+ async function getJsonViaOptionalProxy(args) {
33
+ const url = args.directUrl;
34
+ const r = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
35
+ if (!r.ok) {
36
+ const t = await r.text().catch(() => "");
37
+ throw new Error(t ? `HTTP ${r.status}: ${t.slice(0, 200)}` : `HTTP ${r.status}`);
38
+ }
39
+ return await r.json();
40
+ }
41
+ var morphoMidnightRestProxyUrl;
42
+ var init_defiProxy = __esm({
43
+ "src/core/defiProxy.ts"() {
44
+ }
45
+ });
46
+
47
+ // src/protocols/evm/morpho/midnightConstants.ts
48
+ var midnightConstants_exports = {};
49
+ __export(midnightConstants_exports, {
50
+ MORPHO_MIDNIGHT_ADDRESSES: () => exports.MORPHO_MIDNIGHT_ADDRESSES,
51
+ MORPHO_MIDNIGHT_AUTHORIZE_FALLBACK_GAS: () => exports.MORPHO_MIDNIGHT_AUTHORIZE_FALLBACK_GAS,
52
+ MORPHO_MIDNIGHT_BASE_CHAIN_ID: () => exports.MORPHO_MIDNIGHT_BASE_CHAIN_ID,
53
+ MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT: () => exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT,
54
+ MORPHO_MIDNIGHT_BORROW_FALLBACK_GAS: () => exports.MORPHO_MIDNIGHT_BORROW_FALLBACK_GAS,
55
+ MORPHO_MIDNIGHT_DEFAULT_DEADLINE_SECONDS: () => exports.MORPHO_MIDNIGHT_DEFAULT_DEADLINE_SECONDS,
56
+ MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT: () => exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT,
57
+ MORPHO_MIDNIGHT_ERC20_APPROVE_FALLBACK: () => exports.MORPHO_MIDNIGHT_ERC20_APPROVE_FALLBACK,
58
+ MORPHO_MIDNIGHT_LEND_FALLBACK_GAS: () => exports.MORPHO_MIDNIGHT_LEND_FALLBACK_GAS,
59
+ MORPHO_MIDNIGHT_REPAY_FALLBACK_GAS: () => exports.MORPHO_MIDNIGHT_REPAY_FALLBACK_GAS,
60
+ MORPHO_MIDNIGHT_REST_BASE: () => exports.MORPHO_MIDNIGHT_REST_BASE,
61
+ MORPHO_MIDNIGHT_WETH_DEPOSIT_FALLBACK: () => exports.MORPHO_MIDNIGHT_WETH_DEPOSIT_FALLBACK,
62
+ TOKEN_PERMIT_NONE: () => exports.TOKEN_PERMIT_NONE,
63
+ morphoMidnightAddressesForChain: () => morphoMidnightAddressesForChain
64
+ });
65
+ function morphoMidnightAddressesForChain(chainId) {
66
+ return exports.MORPHO_MIDNIGHT_ADDRESSES[chainId] ?? null;
67
+ }
68
+ exports.MORPHO_MIDNIGHT_REST_BASE = void 0; exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT = void 0; exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT = void 0; exports.MORPHO_MIDNIGHT_DEFAULT_DEADLINE_SECONDS = void 0; exports.MORPHO_MIDNIGHT_BASE_CHAIN_ID = void 0; exports.MORPHO_MIDNIGHT_ADDRESSES = void 0; exports.TOKEN_PERMIT_NONE = void 0; exports.MORPHO_MIDNIGHT_LEND_FALLBACK_GAS = void 0; exports.MORPHO_MIDNIGHT_BORROW_FALLBACK_GAS = void 0; exports.MORPHO_MIDNIGHT_REPAY_FALLBACK_GAS = void 0; exports.MORPHO_MIDNIGHT_AUTHORIZE_FALLBACK_GAS = void 0; exports.MORPHO_MIDNIGHT_ERC20_APPROVE_FALLBACK = void 0; exports.MORPHO_MIDNIGHT_WETH_DEPOSIT_FALLBACK = void 0;
69
+ var init_midnightConstants = __esm({
70
+ "src/protocols/evm/morpho/midnightConstants.ts"() {
71
+ exports.MORPHO_MIDNIGHT_REST_BASE = "https://api.morpho.org/v0/midnight";
72
+ exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT = 20;
73
+ exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT = "0.5";
74
+ exports.MORPHO_MIDNIGHT_DEFAULT_DEADLINE_SECONDS = 3600;
75
+ exports.MORPHO_MIDNIGHT_BASE_CHAIN_ID = 8453;
76
+ exports.MORPHO_MIDNIGHT_ADDRESSES = {
77
+ [exports.MORPHO_MIDNIGHT_BASE_CHAIN_ID]: {
78
+ midnight: "0xadedd8ab6de832766fedf0fac4992e5c4d3ea18a",
79
+ bundles: "0x6688dEc8878f43905e11B3C6Bc025E098133144f"
80
+ }
81
+ };
82
+ exports.TOKEN_PERMIT_NONE = { kind: 0, data: "0x" };
83
+ exports.MORPHO_MIDNIGHT_LEND_FALLBACK_GAS = 2500000n;
84
+ exports.MORPHO_MIDNIGHT_BORROW_FALLBACK_GAS = 3000000n;
85
+ exports.MORPHO_MIDNIGHT_REPAY_FALLBACK_GAS = 2200000n;
86
+ exports.MORPHO_MIDNIGHT_AUTHORIZE_FALLBACK_GAS = 80000n;
87
+ exports.MORPHO_MIDNIGHT_ERC20_APPROVE_FALLBACK = 100000n;
88
+ exports.MORPHO_MIDNIGHT_WETH_DEPOSIT_FALLBACK = 120000n;
89
+ }
90
+ });
91
+
92
+ // src/protocols/evm/morpho/midnightApi.ts
93
+ var midnightApi_exports = {};
94
+ __export(midnightApi_exports, {
95
+ fetchMorphoMidnightBook: () => fetchMorphoMidnightBook,
96
+ fetchMorphoMidnightBookQuote: () => fetchMorphoMidnightBookQuote,
97
+ fetchMorphoMidnightBooks: () => fetchMorphoMidnightBooks,
98
+ fetchMorphoMidnightMarketById: () => fetchMorphoMidnightMarketById,
99
+ fetchMorphoMidnightUserMarketPosition: () => fetchMorphoMidnightUserMarketPosition,
100
+ fetchMorphoMidnightUserPositions: () => fetchMorphoMidnightUserPositions,
101
+ morphoMidnightApiBaseUrl: () => morphoMidnightApiBaseUrl,
102
+ morphoMidnightBookToMarketParams: () => morphoMidnightBookToMarketParams,
103
+ morphoMidnightMarketToParams: () => morphoMidnightMarketToParams
104
+ });
105
+ function morphoMidnightApiBaseUrl() {
106
+ const proxy = getMorphoMidnightRestProxyUrl()?.replace(/\/$/, "");
107
+ return proxy || exports.MORPHO_MIDNIGHT_REST_BASE;
108
+ }
109
+ function midnightApiConfig() {
110
+ return { baseUrl: morphoMidnightApiBaseUrl() };
111
+ }
112
+ async function midnightGetJson(pathAndQuery) {
113
+ const path = pathAndQuery.startsWith("/") ? pathAndQuery : `/${pathAndQuery}`;
114
+ const directUrl = `${exports.MORPHO_MIDNIGHT_REST_BASE}${path}`;
115
+ return getJsonViaOptionalProxy({ directUrl});
116
+ }
117
+ async function fetchMorphoMidnightBooks(args) {
118
+ const limit = args.limit == null ? void 0 : Math.min(Math.max(Math.floor(args.limit), 1), exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT);
119
+ const result = await api.MidnightApi.fetchBooks({
120
+ ...midnightApiConfig(),
121
+ chainIds: [args.chainId],
122
+ loanTokens: args.loanTokens?.filter((a) => viem.isAddress(a)).map((a) => viem.getAddress(a)),
123
+ collateralTokens: args.collateralTokens?.filter((a) => viem.isAddress(a)).map((a) => viem.getAddress(a)),
124
+ sort: args.sort ? [args.sort] : ["maturity"],
125
+ limit,
126
+ cursor: args.cursor
127
+ });
128
+ return { data: [...result.data], cursor: result.cursor ?? null };
129
+ }
130
+ async function fetchMorphoMidnightBook(marketId) {
131
+ const id = marketId.trim();
132
+ if (!id) return null;
133
+ try {
134
+ const result = await api.MidnightApi.fetchBook({
135
+ ...midnightApiConfig(),
136
+ marketId: id
137
+ });
138
+ return result.data;
139
+ } catch {
140
+ return null;
141
+ }
142
+ }
143
+ async function fetchMorphoMidnightBookQuote(args) {
144
+ const quote = await api.MidnightApi.fetchBookQuote({
145
+ ...midnightApiConfig(),
146
+ marketId: args.marketId.trim(),
147
+ side: args.side,
148
+ assets: args.assets,
149
+ slippage: args.slippage?.trim() || "0.5"
150
+ });
151
+ return quote.data;
152
+ }
153
+ async function fetchMorphoMidnightMarketById(marketId) {
154
+ const id = marketId.trim();
155
+ if (!id) return null;
156
+ const j = await midnightGetJson(`/markets/${encodeURIComponent(id)}`);
157
+ const d = j.data;
158
+ if (!d?.market_id || !d.loan_token || !viem.isAddress(d.loan_token)) return null;
159
+ const midnight = d.midnight && viem.isAddress(d.midnight) ? viem.getAddress(d.midnight) : "0x0000000000000000000000000000000000000000";
160
+ const collaterals = (d.collaterals ?? []).filter((c) => c.token && viem.isAddress(c.token) && c.oracle && viem.isAddress(c.oracle)).map((c) => ({
161
+ token: viem.getAddress(c.token),
162
+ lltv: String(c.lltv ?? "0"),
163
+ liquidationCursor: String(c.liquidation_cursor ?? "0"),
164
+ oracle: viem.getAddress(c.oracle)
165
+ }));
166
+ return {
167
+ chainId: Number(d.chain_id ?? 0),
168
+ marketId: d.market_id,
169
+ midnight,
170
+ loanToken: viem.getAddress(d.loan_token),
171
+ maturity: Number(d.maturity ?? 0),
172
+ rcfThreshold: String(d.rcf_threshold ?? "0"),
173
+ enterGate: d.enter_gate && viem.isAddress(d.enter_gate) ? viem.getAddress(d.enter_gate) : viem.getAddress("0x0000000000000000000000000000000000000000"),
174
+ liquidatorGate: d.liquidator_gate && viem.isAddress(d.liquidator_gate) ? viem.getAddress(d.liquidator_gate) : viem.getAddress("0x0000000000000000000000000000000000000000"),
175
+ collaterals
176
+ };
177
+ }
178
+ function morphoMidnightMarketToParams(row) {
179
+ return {
180
+ chainId: BigInt(row.chainId),
181
+ midnight: row.midnight,
182
+ loanToken: row.loanToken,
183
+ collateralParams: row.collaterals.map((c) => ({
184
+ token: c.token,
185
+ lltv: BigInt(c.lltv),
186
+ liquidationCursor: BigInt(c.liquidationCursor),
187
+ oracle: c.oracle
188
+ })),
189
+ maturity: BigInt(row.maturity),
190
+ rcfThreshold: BigInt(row.rcfThreshold),
191
+ enterGate: row.enterGate,
192
+ liquidatorGate: row.liquidatorGate
193
+ };
194
+ }
195
+ function morphoMidnightBookToMarketParams(book) {
196
+ return {
197
+ chainId: BigInt(book.chainId),
198
+ midnight: viem.getAddress(book.midnight),
199
+ loanToken: viem.getAddress(book.loanToken),
200
+ collateralParams: book.collaterals.map((c) => ({
201
+ token: viem.getAddress(c.token),
202
+ lltv: BigInt(c.lltv),
203
+ liquidationCursor: BigInt(c.liquidationCursor),
204
+ oracle: viem.getAddress(c.oracle)
205
+ })),
206
+ maturity: BigInt(book.maturity),
207
+ rcfThreshold: BigInt(book.rcfThreshold),
208
+ enterGate: viem.getAddress(book.enterGate),
209
+ liquidatorGate: viem.getAddress(book.liquidatorGate)
210
+ };
211
+ }
212
+ async function fetchMorphoMidnightUserPositions(args) {
213
+ const user = args.user.trim();
214
+ if (!viem.isAddress(user)) return [];
215
+ const qs = new URLSearchParams();
216
+ if (args.types) qs.set("types", args.types);
217
+ if (args.activeOnly) qs.set("active_only", "true");
218
+ const q = qs.toString();
219
+ const path = `/users/${encodeURIComponent(viem.getAddress(user))}/positions${q ? `?${q}` : ""}`;
220
+ const j = await midnightGetJson(path);
221
+ const rows = [];
222
+ for (const p of j.data ?? []) {
223
+ if (!p.market_id) continue;
224
+ rows.push({
225
+ marketId: p.market_id,
226
+ type: p.type ?? "lend",
227
+ credit: String(p.credit ?? "0"),
228
+ debt: String(p.debt ?? "0"),
229
+ pendingFee: String(p.pending_fee ?? "0"),
230
+ lossFactor: String(p.loss_factor ?? "0"),
231
+ costBasis: p.cost_basis ?? null,
232
+ effectiveRateWad: p.effective_rate_wad ?? null,
233
+ maturity: p.maturity != null ? Number(p.maturity) : null,
234
+ loanToken: p.loan_token && viem.isAddress(p.loan_token) ? viem.getAddress(p.loan_token) : null,
235
+ collaterals: (p.collaterals ?? []).filter((c) => c.token && viem.isAddress(c.token)).map((c) => ({ token: viem.getAddress(c.token), amount: String(c.amount ?? "0") }))
236
+ });
237
+ }
238
+ return rows;
239
+ }
240
+ async function fetchMorphoMidnightUserMarketPosition(args) {
241
+ const marketId = args.marketId.trim();
242
+ const user = args.user.trim();
243
+ if (!marketId || !viem.isAddress(user)) return null;
244
+ const path = `/markets/${encodeURIComponent(marketId)}/users/${encodeURIComponent(viem.getAddress(user))}/position`;
245
+ const j = await midnightGetJson(path);
246
+ const p = j.data;
247
+ if (!p) return null;
248
+ return {
249
+ marketId,
250
+ type: p.type ?? "borrow",
251
+ credit: String(p.credit ?? "0"),
252
+ debt: String(p.debt ?? "0"),
253
+ pendingFee: String(p.pending_fee ?? "0"),
254
+ lossFactor: String(p.loss_factor ?? "0"),
255
+ maturity: p.maturity != null ? Number(p.maturity) : null,
256
+ loanToken: p.loan_token && viem.isAddress(p.loan_token) ? viem.getAddress(p.loan_token) : null,
257
+ collaterals: (p.collaterals ?? []).filter((c) => c.token && viem.isAddress(c.token)).map((c) => ({ token: viem.getAddress(c.token), amount: String(c.amount ?? "0") }))
258
+ };
259
+ }
260
+ var init_midnightApi = __esm({
261
+ "src/protocols/evm/morpho/midnightApi.ts"() {
262
+ init_defiProxy();
263
+ init_midnightConstants();
264
+ }
265
+ });
266
+
267
+ // src/core/registry.ts
268
+ var modules = [];
269
+ function registerProtocolModule(mod) {
270
+ const existing = modules.findIndex((m) => m.id === mod.id);
271
+ if (existing >= 0) {
272
+ modules[existing] = mod;
273
+ } else {
274
+ modules.push(mod);
275
+ }
276
+ }
28
277
 
29
278
  // src/protocols/evm/morpho/api.ts
279
+ init_defiProxy();
30
280
  var MORPHO_GRAPHQL_URL = "https://api.morpho.org/graphql";
31
281
  async function morphoGql(query, variables) {
32
282
  const body = { query, variables: variables ?? {} };
@@ -797,6 +1047,32 @@ async function ensureMorphoChainAssetCache(chainId) {
797
1047
  modes.set(k, prev);
798
1048
  }
799
1049
  }
1050
+ try {
1051
+ const { fetchMorphoMidnightBooks: fetchMorphoMidnightBooks2 } = await Promise.resolve().then(() => (init_midnightApi(), midnightApi_exports));
1052
+ const { MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT: MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT2 } = await Promise.resolve().then(() => (init_midnightConstants(), midnightConstants_exports));
1053
+ const { data: books } = await fetchMorphoMidnightBooks2({
1054
+ chainId,
1055
+ limit: MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT2
1056
+ });
1057
+ for (const book of books) {
1058
+ const loanAddr = (book.loanToken ?? "").toString().trim();
1059
+ if (viem.isAddress(loanAddr)) {
1060
+ const k = viem.getAddress(loanAddr).toLowerCase();
1061
+ const prev = modes.get(k) ?? { earn: false, borrow: false, collateral: false };
1062
+ prev.borrow = true;
1063
+ modes.set(k, prev);
1064
+ }
1065
+ for (const c of book.collaterals ?? []) {
1066
+ const colAddr = (c.token ?? "").toString().trim();
1067
+ if (!viem.isAddress(colAddr)) continue;
1068
+ const k = viem.getAddress(colAddr).toLowerCase();
1069
+ const prev = modes.get(k) ?? { earn: false, borrow: false, collateral: false };
1070
+ prev.collateral = true;
1071
+ modes.set(k, prev);
1072
+ }
1073
+ }
1074
+ } catch {
1075
+ }
800
1076
  const cache = { modesByUnderlying: modes, nativeWrapped: null };
801
1077
  chainAssetCache.set(chainId, cache);
802
1078
  return cache;
@@ -1179,111 +1455,254 @@ function formatMorphoMarketApySummary(apy) {
1179
1455
  }
1180
1456
 
1181
1457
  // src/protocols/evm/morpho/midnightTypes.ts
1182
- var MORPHO_MIDNIGHT_UNAVAILABLE_MESSAGE = "Morpho Midnight fixed-rate lending is not yet available on mainnet. This tab will activate after the progressive mainnet rollout.";
1458
+ var MORPHO_MIDNIGHT_UNAVAILABLE_MESSAGE = "Morpho Midnight fixed-rate markets are available on supported chains (starting with Base). Open the Midnight tab to browse books.";
1183
1459
  async function fetchMorphoMidnightIntents(_args) {
1184
1460
  return [];
1185
1461
  }
1186
- var erc4626Abi = viem.parseAbi([
1187
- "function asset() view returns (address)",
1188
- "function decimals() view returns (uint8)",
1189
- "function balanceOf(address account) view returns (uint256)",
1190
- "function convertToAssets(uint256 shares) view returns (uint256)",
1191
- "function maxWithdraw(address owner) view returns (uint256)"
1192
- ]);
1193
- async function fetchMorphoVaultAssetDecimals(args) {
1194
- const ch = viem.defineChain({
1195
- id: args.chainId,
1196
- name: "MorphoVault",
1197
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1198
- rpcUrls: { default: { http: [args.rpcUrl] } }
1199
- });
1200
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1201
- const vault = viem.getAddress(args.vault);
1202
- const assetAddr = await publicClient.readContract({
1203
- address: vault,
1204
- abi: erc4626Abi,
1205
- functionName: "asset"
1206
- });
1207
- const d = await publicClient.readContract({
1208
- address: viem.getAddress(assetAddr),
1209
- abi: viem.parseAbi(["function decimals() view returns (uint8)"]),
1210
- functionName: "decimals"
1211
- });
1212
- const n = typeof d === "bigint" ? Number(d) : Number(d);
1213
- return !Number.isFinite(n) || n < 0 || n > 36 ? 18 : n;
1462
+
1463
+ // src/protocols/evm/morpho/index.ts
1464
+ init_midnightConstants();
1465
+ init_midnightApi();
1466
+
1467
+ // src/protocols/evm/morpho/midnightMath.ts
1468
+ function morphoMidnightAprFromPriceWad(priceWad, ttmSeconds) {
1469
+ const raw = typeof priceWad === "bigint" ? priceWad : BigInt(priceWad.split(".")[0] || "0");
1470
+ if (raw <= 0n || !Number.isFinite(ttmSeconds) || ttmSeconds <= 0) return null;
1471
+ const p = Number(raw) / 1e18;
1472
+ if (!Number.isFinite(p) || p <= 0) return null;
1473
+ const apr = (1 / p - 1) * (365 * 86400 / ttmSeconds);
1474
+ return Number.isFinite(apr) ? apr : null;
1475
+ }
1476
+ function formatMorphoMidnightAprPct(apr, digits = 2) {
1477
+ if (apr == null || !Number.isFinite(apr)) return "\u2014";
1478
+ return `${(apr * 100).toFixed(digits)}%`;
1479
+ }
1480
+ function morphoMidnightTtmSeconds(maturityUnix, nowMs = Date.now()) {
1481
+ return Math.max(0, maturityUnix - nowMs / 1e3);
1482
+ }
1483
+ function morphoMidnightUnitsFromAssets(targetAssets, priceWad) {
1484
+ if (priceWad <= 0n || targetAssets <= 0n) return 0n;
1485
+ return (targetAssets * 10n ** 18n + priceWad - 1n) / priceWad;
1214
1486
  }
1215
- async function fetchMorphoVaultMaxWithdrawWei(args) {
1216
- const ch = viem.defineChain({
1217
- id: args.chainId,
1218
- name: "MorphoVault",
1219
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1220
- rpcUrls: { default: { http: [args.rpcUrl] } }
1221
- });
1222
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1223
- return publicClient.readContract({
1224
- address: viem.getAddress(args.vault),
1225
- abi: erc4626Abi,
1226
- functionName: "maxWithdraw",
1227
- args: [viem.getAddress(args.owner)]
1228
- });
1487
+
1488
+ // src/protocols/evm/morpho/midnightDiscovery.ts
1489
+ init_midnightApi();
1490
+ init_midnightConstants();
1491
+ function shortAddr(a) {
1492
+ return a.length > 10 ? `${a.slice(0, 6)}\u2026${a.slice(-4)}` : a;
1493
+ }
1494
+ function maturityIso(maturity) {
1495
+ if (!maturity || maturity <= 0) return "\u2014";
1496
+ try {
1497
+ return new Date(maturity * 1e3).toISOString().slice(0, 10);
1498
+ } catch {
1499
+ return "\u2014";
1500
+ }
1229
1501
  }
1230
- var morphoBlueAbi = viem.parseAbi([
1231
- "function position(bytes32 id, address user) view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)",
1232
- "function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
1233
- "function idToMarketParams(bytes32 id) view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)"
1234
- ]);
1235
- var oracleAbi = viem.parseAbi(["function price() view returns (uint256)"]);
1236
- var WAD = 10n ** 18n;
1237
- var ORACLE_PRICE_SCALE = 10n ** 36n;
1238
- async function previewMorphoBlueHealthAfterCollateralWithdraw(args) {
1239
- const ch = viem.defineChain({
1240
- id: args.chainId,
1241
- name: "MorphoBlue",
1242
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1243
- rpcUrls: { default: { http: [args.rpcUrl] } }
1502
+ function morphoMidnightBookToDiscoveryRow(book) {
1503
+ const ttm = morphoMidnightTtmSeconds(book.maturity);
1504
+ const bestAsk = book.asks[0];
1505
+ const bestBid = book.bids[0];
1506
+ const lendAprN = bestAsk ? morphoMidnightAprFromPriceWad(bestAsk.price, ttm) : null;
1507
+ const borrowAprN = bestBid ? morphoMidnightAprFromPriceWad(bestBid.price, ttm) : null;
1508
+ const loan = viem.getAddress(book.loanToken);
1509
+ const collaterals = book.collaterals.map((c) => viem.getAddress(c.token));
1510
+ const primary = book.collaterals[0];
1511
+ const primaryAddr = primary ? viem.getAddress(primary.token) : null;
1512
+ const marketLabel = `${shortAddr(primaryAddr ?? "\u2014")}/${shortAddr(loan)} \xB7 ${maturityIso(book.maturity)}`;
1513
+ return {
1514
+ marketId: book.marketId,
1515
+ chainId: book.chainId,
1516
+ midnightAddress: viem.getAddress(book.midnight),
1517
+ loanTokenAddress: loan,
1518
+ maturity: book.maturity,
1519
+ maturityIso: maturityIso(book.maturity),
1520
+ collateralTokenAddresses: collaterals,
1521
+ primaryCollateralTokenAddress: primaryAddr,
1522
+ primaryCollateralLltv: primary?.lltv ?? null,
1523
+ bestAskPriceWad: bestAsk?.price ?? null,
1524
+ bestBidPriceWad: bestBid?.price ?? null,
1525
+ bestAskAssets: bestAsk?.assets ?? null,
1526
+ bestBidAssets: bestBid?.assets ?? null,
1527
+ lendApr: formatMorphoMidnightAprPct(lendAprN),
1528
+ borrowApr: formatMorphoMidnightAprPct(borrowAprN),
1529
+ lendAprNumeric: lendAprN,
1530
+ borrowAprNumeric: borrowAprN,
1531
+ marketLabel
1532
+ };
1533
+ }
1534
+ async function morphoFetchMidnightBooksSummary(args) {
1535
+ const limit = Math.min(Math.max(args.limit ?? exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT, 1), exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT);
1536
+ const loan = args.loan?.trim();
1537
+ const collateral = args.collateral?.trim();
1538
+ const loanTokens = loan && viem.isAddress(loan) ? [viem.getAddress(loan)] : void 0;
1539
+ const collateralTokens = collateral && viem.isAddress(collateral) ? [viem.getAddress(collateral)] : void 0;
1540
+ const { data } = await fetchMorphoMidnightBooks({
1541
+ chainId: args.chainId,
1542
+ loanTokens,
1543
+ collateralTokens,
1544
+ sort: "maturity",
1545
+ limit
1244
1546
  });
1245
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1246
- const morpho = viem.getAddress(args.morphoBlue);
1247
- const user = viem.getAddress(args.user);
1248
- const id = args.marketId;
1249
- const [pos, mkt, params] = await Promise.all([
1250
- publicClient.readContract({
1251
- address: morpho,
1252
- abi: morphoBlueAbi,
1253
- functionName: "position",
1254
- args: [id, user]
1255
- }),
1256
- publicClient.readContract({
1257
- address: morpho,
1258
- abi: morphoBlueAbi,
1259
- functionName: "market",
1260
- args: [id]
1547
+ let rows = data.map(morphoMidnightBookToDiscoveryRow);
1548
+ if (collateral && viem.isAddress(collateral)) {
1549
+ const col = viem.getAddress(collateral).toLowerCase();
1550
+ rows = rows.filter((r) => r.collateralTokenAddresses.some((a) => a.toLowerCase() === col));
1551
+ }
1552
+ const side = args.side ?? "either";
1553
+ if (side === "bids") {
1554
+ rows = rows.filter((r) => r.bestBidPriceWad != null);
1555
+ } else if (side === "asks") {
1556
+ rows = rows.filter((r) => r.bestAskPriceWad != null);
1557
+ }
1558
+ const q = (args.query ?? "").trim().toLowerCase();
1559
+ if (q) {
1560
+ rows = rows.filter((r) => {
1561
+ const hay = [
1562
+ r.marketId,
1563
+ r.marketLabel,
1564
+ r.loanTokenAddress,
1565
+ r.primaryCollateralTokenAddress ?? "",
1566
+ ...r.collateralTokenAddresses
1567
+ ].join(" ").toLowerCase();
1568
+ return hay.includes(q);
1569
+ });
1570
+ }
1571
+ return { books: rows.slice(0, limit) };
1572
+ }
1573
+ async function fetchMorphoMidnightBooksForAsset(args) {
1574
+ const asset = args.assetAddress.trim();
1575
+ if (!viem.isAddress(asset)) return [];
1576
+ const mode = args.mode ?? "any";
1577
+ if (mode === "lend") {
1578
+ const { books } = await morphoFetchMidnightBooksSummary({
1579
+ chainId: args.chainId,
1580
+ loan: asset,
1581
+ side: "asks",
1582
+ limit: exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT
1583
+ });
1584
+ return books;
1585
+ }
1586
+ if (mode === "borrow") {
1587
+ const asCollateral = await morphoFetchMidnightBooksSummary({
1588
+ chainId: args.chainId,
1589
+ collateral: asset,
1590
+ side: "bids",
1591
+ limit: exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT
1592
+ });
1593
+ const asLoan2 = await morphoFetchMidnightBooksSummary({
1594
+ chainId: args.chainId,
1595
+ loan: asset,
1596
+ side: "bids",
1597
+ limit: exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT
1598
+ });
1599
+ const byId2 = /* @__PURE__ */ new Map();
1600
+ for (const b of [...asCollateral.books, ...asLoan2.books]) byId2.set(b.marketId.toLowerCase(), b);
1601
+ return [...byId2.values()];
1602
+ }
1603
+ const [asLoan, asCol] = await Promise.all([
1604
+ morphoFetchMidnightBooksSummary({
1605
+ chainId: args.chainId,
1606
+ loan: asset,
1607
+ limit: exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT
1261
1608
  }),
1262
- publicClient.readContract({
1263
- address: morpho,
1264
- abi: morphoBlueAbi,
1265
- functionName: "idToMarketParams",
1266
- args: [id]
1609
+ morphoFetchMidnightBooksSummary({
1610
+ chainId: args.chainId,
1611
+ collateral: asset,
1612
+ limit: exports.MORPHO_MIDNIGHT_BOOKS_MAX_LIMIT
1267
1613
  })
1268
1614
  ]);
1269
- const borrowShares = BigInt(pos[1]);
1270
- if (borrowShares === 0n) return { healthy: true, healthFactor: null };
1271
- const collateral = BigInt(pos[2]) - args.withdrawCollateralWei;
1272
- const oracle = viem.getAddress(params[2]);
1273
- const lltv = BigInt(params[4]);
1274
- const price = await publicClient.readContract({
1275
- address: oracle,
1276
- abi: oracleAbi,
1277
- functionName: "price"
1615
+ const byId = /* @__PURE__ */ new Map();
1616
+ for (const b of [...asLoan.books, ...asCol.books]) byId.set(b.marketId.toLowerCase(), b);
1617
+ return [...byId.values()];
1618
+ }
1619
+
1620
+ // src/protocols/evm/morpho/midnightQuote.ts
1621
+ init_midnightApi();
1622
+ init_midnightConstants();
1623
+ async function morphoFetchMidnightQuote(args) {
1624
+ const assets = typeof args.assets === "bigint" ? args.assets : BigInt(String(args.assets).split(".")[0] || "0");
1625
+ if (assets <= 0n) throw new Error("Quote assets must be > 0.");
1626
+ const slippage = (args.slippagePct ?? exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT).trim() || exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT;
1627
+ const [quote, book] = await Promise.all([
1628
+ fetchMorphoMidnightBookQuote({
1629
+ marketId: args.marketId,
1630
+ side: args.side,
1631
+ assets,
1632
+ slippage
1633
+ }),
1634
+ fetchMorphoMidnightBook(args.marketId)
1635
+ ]);
1636
+ const maturity = book?.maturity ?? null;
1637
+ const ttm = maturity != null ? morphoMidnightTtmSeconds(maturity) : 0;
1638
+ const aprN = morphoMidnightAprFromPriceWad(quote.averageBestPrice, ttm);
1639
+ return {
1640
+ marketId: args.marketId.trim(),
1641
+ side: args.side,
1642
+ averageBestPriceWad: quote.averageBestPrice,
1643
+ averageWorstPriceWad: quote.averageWorstPrice,
1644
+ availableAssets: quote.availableAssets,
1645
+ availableUnits: quote.availableUnits,
1646
+ impliedApr: formatMorphoMidnightAprPct(aprN),
1647
+ impliedAprNumeric: aprN,
1648
+ maturity,
1649
+ takeableOfferCount: quote.takeableOffers.length,
1650
+ takeableOffers: quote.takeableOffers
1651
+ };
1652
+ }
1653
+ async function morphoFetchMidnightQuoteSummary(args) {
1654
+ const { takeableOffers: _takes, ...rest } = await morphoFetchMidnightQuote(args);
1655
+ return rest;
1656
+ }
1657
+
1658
+ // src/protocols/evm/morpho/midnightPositions.ts
1659
+ init_midnightApi();
1660
+ function maturityIso2(maturity) {
1661
+ if (maturity == null || maturity <= 0) return "\u2014";
1662
+ try {
1663
+ return new Date(maturity * 1e3).toISOString().slice(0, 10);
1664
+ } catch {
1665
+ return "\u2014";
1666
+ }
1667
+ }
1668
+ function effectiveRateLabel(wad) {
1669
+ if (!wad) return "\u2014";
1670
+ try {
1671
+ const n = Number(BigInt(wad.split(".")[0] || "0")) / 1e18;
1672
+ return formatMorphoMidnightAprPct(Number.isFinite(n) ? n : null);
1673
+ } catch {
1674
+ return "\u2014";
1675
+ }
1676
+ }
1677
+ function morphoMidnightPositionToDiscoveryRow(p) {
1678
+ const debt = BigInt(p.debt || "0");
1679
+ const fee = BigInt(p.pendingFee || "0");
1680
+ return {
1681
+ marketId: p.marketId,
1682
+ type: p.type,
1683
+ credit: p.credit,
1684
+ debt: p.debt,
1685
+ pendingFee: p.pendingFee,
1686
+ repayAssets: (debt + fee).toString(),
1687
+ maturity: p.maturity ?? null,
1688
+ maturityIso: maturityIso2(p.maturity ?? null),
1689
+ loanTokenAddress: p.loanToken ?? null,
1690
+ collateralTokenAddresses: p.collaterals.map((c) => c.token),
1691
+ collateralAmounts: p.collaterals.map((c) => ({ token: c.token, amount: c.amount })),
1692
+ effectiveRate: effectiveRateLabel(p.effectiveRateWad),
1693
+ costBasis: p.costBasis ?? null
1694
+ };
1695
+ }
1696
+ async function morphoFetchMidnightPositionsSummary(args) {
1697
+ if (!viem.isAddress(args.user)) {
1698
+ throw new Error("user must be a valid EVM address.");
1699
+ }
1700
+ const rows = await fetchMorphoMidnightUserPositions({
1701
+ user: viem.getAddress(args.user),
1702
+ types: args.types,
1703
+ activeOnly: args.activeOnly
1278
1704
  });
1279
- const totalBorrowAssets = BigInt(mkt[2]);
1280
- const totalBorrowShares = BigInt(mkt[3]);
1281
- if (totalBorrowShares === 0n) return { healthy: true, healthFactor: null };
1282
- const borrowed = (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares;
1283
- const maxBorrow = collateral * price / ORACLE_PRICE_SCALE * lltv / WAD;
1284
- const healthy = maxBorrow >= borrowed;
1285
- const hf = borrowed === 0n ? null : Number(maxBorrow * WAD / borrowed) / Number(WAD);
1286
- return { healthy, healthFactor: hf != null && Number.isFinite(hf) ? hf : null };
1705
+ return { positions: rows.map(morphoMidnightPositionToDiscoveryRow) };
1287
1706
  }
1288
1707
 
1289
1708
  // src/core/purpose.ts
@@ -1520,40 +1939,603 @@ async function buildEvmMultisignBatch(args) {
1520
1939
  return result;
1521
1940
  }
1522
1941
 
1523
- // src/protocols/evm/morpho/vaultDepositMultisign.ts
1524
- var MORPHO_VAULT_DEPOSIT_FALLBACK_GAS = 950000n;
1525
- var MORPHO_ERC20_APPROVE_FALLBACK = 100000n;
1526
- var MORPHO_WETH_DEPOSIT_FALLBACK = 120000n;
1942
+ // src/protocols/evm/morpho/midnightMultisign.ts
1943
+ init_midnightConstants();
1944
+ init_midnightApi();
1527
1945
  var wethDepositAbi = viem.parseAbi(["function deposit() payable"]);
1528
- var erc20AllowanceAbi = viem.parseAbi([
1529
- "function allowance(address owner, address spender) view returns (uint256)"
1530
- ]);
1531
- var erc20ApproveAbi = viem.parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]);
1532
- var vaultDepositAbi = viem.parseAbi([
1533
- "function deposit(uint256 assets, address onBehalf) returns (uint256 shares)"
1946
+ var erc20Abi = viem.parseAbi([
1947
+ "function allowance(address owner, address spender) view returns (uint256)",
1948
+ "function decimals() view returns (uint8)",
1949
+ "function approve(address spender, uint256 amount) returns (bool)"
1534
1950
  ]);
1535
- async function buildEvmMultisignBodyMorphoVaultDepositBatch(args) {
1536
- const asset = viem.getAddress(args.underlying);
1537
- const vault = viem.getAddress(args.vault);
1538
- const weth = viem.getAddress(args.nativeWrapped);
1539
- const executor = viem.getAddress(args.executorAddress);
1540
- const onBehalf = viem.getAddress(args.onBehalf);
1541
- if (args.isNativeIn && asset.toLowerCase() !== weth.toLowerCase()) {
1542
- throw new Error("Native deposit path: underlying asset must match the chain wrapped native token.");
1543
- }
1951
+ function publicClientFor(rpcUrl, chainId) {
1544
1952
  const ch = viem.defineChain({
1545
- id: args.chainId,
1546
- name: "MorphoVaultDeposit",
1953
+ id: chainId,
1954
+ name: "MorphoMidnight",
1547
1955
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1548
- rpcUrls: { default: { http: [args.rpcUrl] } }
1956
+ rpcUrls: { default: { http: [rpcUrl] } }
1549
1957
  });
1550
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1551
- const dec = await fetchMorphoVaultAssetDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, vault });
1552
- const amountWei = viem.parseUnits(args.amountHuman, dec);
1553
- if (amountWei === 0n) throw new Error("Deposit amount is zero after converting with token decimals.");
1554
- const steps = [];
1958
+ return viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
1959
+ }
1960
+ async function readTokenDecimals(args) {
1961
+ const publicClient = publicClientFor(args.rpcUrl, args.chainId);
1962
+ const d = await publicClient.readContract({
1963
+ address: args.token,
1964
+ abi: erc20Abi,
1965
+ functionName: "decimals"
1966
+ });
1967
+ const n = typeof d === "bigint" ? Number(d) : Number(d);
1968
+ return !Number.isFinite(n) || n < 0 || n > 36 ? 18 : n;
1969
+ }
1970
+ async function buildApproveSteps(args) {
1971
+ const steps = [];
1972
+ let spendToken = args.token;
1973
+ if (args.isNativeIn && args.nativeWrapped) {
1974
+ const weth = viem.getAddress(args.nativeWrapped);
1975
+ if (spendToken.toLowerCase() !== weth.toLowerCase()) {
1976
+ throw new Error("Native path: token must match wrapped native.");
1977
+ }
1978
+ steps.push({
1979
+ kind: "weth_deposit",
1980
+ to: weth,
1981
+ data: viem.encodeFunctionData({ abi: wethDepositAbi, functionName: "deposit" }),
1982
+ value: args.amountWei
1983
+ });
1984
+ spendToken = weth;
1985
+ }
1986
+ const publicClient = publicClientFor(args.rpcUrl, args.chainId);
1987
+ const currentAllowance = await publicClient.readContract({
1988
+ address: spendToken,
1989
+ abi: erc20Abi,
1990
+ functionName: "allowance",
1991
+ args: [args.executor, args.spender]
1992
+ });
1993
+ if (currentAllowance < args.amountWei) {
1994
+ if (currentAllowance > 0n) {
1995
+ steps.push({
1996
+ kind: "approve",
1997
+ to: spendToken,
1998
+ data: viem.encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [args.spender, 0n] }),
1999
+ value: 0n
2000
+ });
2001
+ }
2002
+ steps.push({
2003
+ kind: "approve",
2004
+ to: spendToken,
2005
+ data: viem.encodeFunctionData({
2006
+ abi: erc20Abi,
2007
+ functionName: "approve",
2008
+ args: [args.spender, args.amountWei]
2009
+ }),
2010
+ value: 0n
2011
+ });
2012
+ }
2013
+ return steps;
2014
+ }
2015
+ async function ensureBundlesAuthorizedSteps(args) {
2016
+ const publicClient = publicClientFor(args.rpcUrl, args.chainId);
2017
+ const authorized = await publicClient.readContract({
2018
+ address: args.midnight,
2019
+ abi: midnightSdk.midnightAbi,
2020
+ functionName: "isAuthorized",
2021
+ args: [args.onBehalf, args.bundles]
2022
+ });
2023
+ if (authorized) return [];
2024
+ return [
2025
+ {
2026
+ to: args.midnight,
2027
+ data: viem.encodeFunctionData({
2028
+ abi: midnightSdk.midnightAbi,
2029
+ functionName: "setIsAuthorized",
2030
+ args: [args.bundles, true, args.onBehalf]
2031
+ }),
2032
+ value: 0n,
2033
+ fallbackGas: exports.MORPHO_MIDNIGHT_AUTHORIZE_FALLBACK_GAS
2034
+ }
2035
+ ];
2036
+ }
2037
+ function approveStepsToEvm(steps) {
2038
+ return steps.map((s) => ({
2039
+ to: s.to,
2040
+ data: s.data,
2041
+ value: s.value,
2042
+ fallbackGas: s.kind === "weth_deposit" ? exports.MORPHO_MIDNIGHT_WETH_DEPOSIT_FALLBACK : exports.MORPHO_MIDNIGHT_ERC20_APPROVE_FALLBACK
2043
+ }));
2044
+ }
2045
+ function offerFillsFromTakes(takes) {
2046
+ return takes.map((t) => ({
2047
+ offer: t.offer,
2048
+ ratifierData: t.ratifierData,
2049
+ units: t.units
2050
+ }));
2051
+ }
2052
+ function resolveAddresses(args) {
2053
+ const known = morphoMidnightAddressesForChain(args.chainId);
2054
+ const midnight = args.midnight ? viem.getAddress(args.midnight) : args.marketMidnight ? viem.getAddress(args.marketMidnight) : known?.midnight;
2055
+ const bundles = args.bundles ? viem.getAddress(args.bundles) : known?.bundles;
2056
+ if (!midnight || !bundles) {
2057
+ throw new Error(
2058
+ `Morpho Midnight addresses unknown for chain ${args.chainId}. Pass midnight/bundles or use a supported chain.`
2059
+ );
2060
+ }
2061
+ return { midnight, bundles };
2062
+ }
2063
+ function deadlineFromNow(seconds) {
2064
+ const s = seconds && seconds > 0 ? seconds : exports.MORPHO_MIDNIGHT_DEFAULT_DEADLINE_SECONDS;
2065
+ return BigInt(Math.floor(Date.now() / 1e3) + s);
2066
+ }
2067
+ function collateralIndex(market, collateralToken) {
2068
+ const idx = market.collateralParams.findIndex(
2069
+ (c) => c.token.toLowerCase() === collateralToken.toLowerCase()
2070
+ );
2071
+ if (idx < 0) {
2072
+ throw new Error(`Collateral ${collateralToken} is not in market collateralParams.`);
2073
+ }
2074
+ return BigInt(idx);
2075
+ }
2076
+ async function buildEvmMultisignBodyMorphoMidnightLendBatch(args) {
2077
+ const taker = viem.getAddress(args.taker);
2078
+ const executor = viem.getAddress(args.executorAddress);
2079
+ const book = await fetchMorphoMidnightBook(args.marketId);
2080
+ if (!book) throw new Error(`Midnight book not found: ${args.marketId}`);
2081
+ const market = morphoMidnightBookToMarketParams(book);
2082
+ const { midnight, bundles } = resolveAddresses({
2083
+ chainId: args.chainId,
2084
+ midnight: args.midnight,
2085
+ bundles: args.bundles,
2086
+ marketMidnight: market.midnight
2087
+ });
2088
+ const loanToken = args.loanToken ? viem.getAddress(args.loanToken) : viem.getAddress(market.loanToken);
2089
+ if (loanToken.toLowerCase() !== market.loanToken.toLowerCase()) {
2090
+ throw new Error("loanToken does not match Midnight market loan token.");
2091
+ }
2092
+ const dec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loanToken });
2093
+ const targetBuyerAssets = viem.parseUnits(args.amountHuman, dec);
2094
+ if (targetBuyerAssets === 0n) throw new Error("Lend amount is zero.");
2095
+ const slippage = (args.slippagePct ?? exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT).trim();
2096
+ const quote = await fetchMorphoMidnightBookQuote({
2097
+ marketId: args.marketId,
2098
+ side: "asks",
2099
+ assets: targetBuyerAssets,
2100
+ slippage
2101
+ });
2102
+ if (!quote.takeableOffers.length) {
2103
+ throw new Error("No takeable Midnight asks for this size. Try a smaller amount or another maturity.");
2104
+ }
2105
+ const worst = BigInt(quote.averageWorstPrice.split(".")[0] || "0");
2106
+ const minUnits = morphoMidnightUnitsFromAssets(targetBuyerAssets, worst);
2107
+ const deadline = deadlineFromNow(args.deadlineSeconds);
2108
+ const offerFills = offerFillsFromTakes(quote.takeableOffers);
2109
+ const approveSteps = await buildApproveSteps({
2110
+ rpcUrl: args.rpcUrl,
2111
+ chainId: args.chainId,
2112
+ token: loanToken,
2113
+ spender: bundles,
2114
+ amountWei: targetBuyerAssets,
2115
+ executor,
2116
+ isNativeIn: args.isNativeIn,
2117
+ nativeWrapped: args.nativeWrapped
2118
+ });
2119
+ const authSteps = await ensureBundlesAuthorizedSteps({
2120
+ rpcUrl: args.rpcUrl,
2121
+ chainId: args.chainId,
2122
+ midnight,
2123
+ bundles,
2124
+ onBehalf: taker
2125
+ });
2126
+ const lendData = viem.encodeFunctionData({
2127
+ abi: midnightSdk.midnightBundlesAbi,
2128
+ functionName: "midnightBundlesV1BuyWithAssetsTargetAndWithdrawCollateral",
2129
+ args: [
2130
+ targetBuyerAssets,
2131
+ minUnits,
2132
+ taker,
2133
+ false,
2134
+ exports.TOKEN_PERMIT_NONE,
2135
+ offerFills,
2136
+ [],
2137
+ taker,
2138
+ 0n,
2139
+ viem.zeroAddress,
2140
+ viem.maxUint256,
2141
+ deadline
2142
+ ]
2143
+ });
2144
+ const marketLabel = (args.marketLabel ?? "").trim() || `Midnight ${args.marketId.slice(0, 10)}\u2026`;
2145
+ const evmSteps = [
2146
+ ...approveStepsToEvm(approveSteps),
2147
+ ...authSteps,
2148
+ { to: bundles, data: lendData, value: 0n, fallbackGas: exports.MORPHO_MIDNIGHT_LEND_FALLBACK_GAS }
2149
+ ];
2150
+ return buildEvmMultisignBatch({
2151
+ context: {
2152
+ chainCategory: "evm",
2153
+ keyGen: args.keyGen,
2154
+ purposeText: args.purposeText,
2155
+ chainId: args.chainId,
2156
+ rpcUrl: args.rpcUrl,
2157
+ executorAddress: executor,
2158
+ chainDetail: args.chainDetail,
2159
+ useCustomGas: args.useCustomGas,
2160
+ customGasChainDetails: args.customGasChainDetails
2161
+ },
2162
+ steps: evmSteps,
2163
+ purposeSuffix: `Morpho Midnight: lend (${args.amountHuman}) on "${marketLabel}".`,
2164
+ firstMsgRawNo0x: evmSteps[0].data.slice(2),
2165
+ destinationAddress: bundles,
2166
+ buildBatchMeta: ({ gasLimit }) => ({
2167
+ signatureText: JSON.stringify({
2168
+ kind: "MorphoMidnight",
2169
+ name: "lend",
2170
+ marketLabel,
2171
+ amountHuman: args.amountHuman
2172
+ }),
2173
+ evm: { type: "morpho_midnight_lend", version: 1, chainId: String(args.chainId) },
2174
+ morpho: {
2175
+ marketId: args.marketId,
2176
+ marketLabel,
2177
+ amountHuman: args.amountHuman,
2178
+ gasBuild: { baseGasUnits: gasLimit.toString() }
2179
+ }
2180
+ })
2181
+ });
2182
+ }
2183
+ async function buildEvmMultisignBodyMorphoMidnightBorrowBatch(args) {
2184
+ const taker = viem.getAddress(args.taker);
2185
+ const receiver = viem.getAddress(args.receiver ?? args.taker);
2186
+ const executor = viem.getAddress(args.executorAddress);
2187
+ const collateralToken = viem.getAddress(args.collateralToken);
2188
+ const book = await fetchMorphoMidnightBook(args.marketId);
2189
+ if (!book) throw new Error(`Midnight book not found: ${args.marketId}`);
2190
+ const market = morphoMidnightBookToMarketParams(book);
2191
+ const { midnight, bundles } = resolveAddresses({
2192
+ chainId: args.chainId,
2193
+ midnight: args.midnight,
2194
+ bundles: args.bundles,
2195
+ marketMidnight: market.midnight
2196
+ });
2197
+ const loanToken = args.loanToken ? viem.getAddress(args.loanToken) : viem.getAddress(market.loanToken);
2198
+ const loanDec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loanToken });
2199
+ const colDec = await readTokenDecimals({
2200
+ rpcUrl: args.rpcUrl,
2201
+ chainId: args.chainId,
2202
+ token: collateralToken
2203
+ });
2204
+ const targetSellerAssets = viem.parseUnits(args.borrowAmountHuman, loanDec);
2205
+ const collateralAmount = viem.parseUnits(args.collateralAmountHuman, colDec);
2206
+ if (targetSellerAssets === 0n) throw new Error("Borrow amount is zero.");
2207
+ if (collateralAmount === 0n) throw new Error("Collateral amount is zero.");
2208
+ const colIdx = args.collateralIndex != null && args.collateralIndex >= 0 ? BigInt(args.collateralIndex) : collateralIndex(market, collateralToken);
2209
+ const slippage = (args.slippagePct ?? exports.MORPHO_MIDNIGHT_DEFAULT_SLIPPAGE_PCT).trim();
2210
+ const quote = await fetchMorphoMidnightBookQuote({
2211
+ marketId: args.marketId,
2212
+ side: "bids",
2213
+ assets: targetSellerAssets,
2214
+ slippage
2215
+ });
2216
+ if (!quote.takeableOffers.length) {
2217
+ throw new Error("No takeable Midnight bids for this size. Try a smaller amount or another maturity.");
2218
+ }
2219
+ const worst = BigInt(quote.averageWorstPrice.split(".")[0] || "0");
2220
+ const maxUnits = morphoMidnightUnitsFromAssets(targetSellerAssets, worst);
2221
+ const deadline = deadlineFromNow(args.deadlineSeconds);
2222
+ const offerFills = offerFillsFromTakes(quote.takeableOffers);
2223
+ const approveSteps = await buildApproveSteps({
2224
+ rpcUrl: args.rpcUrl,
2225
+ chainId: args.chainId,
2226
+ token: collateralToken,
2227
+ spender: bundles,
2228
+ amountWei: collateralAmount,
2229
+ executor,
2230
+ isNativeIn: args.isNativeIn,
2231
+ nativeWrapped: args.nativeWrapped
2232
+ });
2233
+ const authSteps = await ensureBundlesAuthorizedSteps({
2234
+ rpcUrl: args.rpcUrl,
2235
+ chainId: args.chainId,
2236
+ midnight,
2237
+ bundles,
2238
+ onBehalf: taker
2239
+ });
2240
+ const borrowData = viem.encodeFunctionData({
2241
+ abi: midnightSdk.midnightBundlesAbi,
2242
+ functionName: "midnightBundlesV1SupplyCollateralAndSellWithAssetsTarget",
2243
+ args: [
2244
+ targetSellerAssets,
2245
+ maxUnits,
2246
+ taker,
2247
+ false,
2248
+ receiver,
2249
+ [{ collateralIndex: colIdx, assets: collateralAmount, permit: exports.TOKEN_PERMIT_NONE }],
2250
+ offerFills,
2251
+ 0n,
2252
+ viem.zeroAddress,
2253
+ viem.maxUint256,
2254
+ deadline
2255
+ ]
2256
+ });
2257
+ const marketLabel = (args.marketLabel ?? "").trim() || `Midnight ${args.marketId.slice(0, 10)}\u2026`;
2258
+ const evmSteps = [
2259
+ ...approveStepsToEvm(approveSteps),
2260
+ ...authSteps,
2261
+ { to: bundles, data: borrowData, value: 0n, fallbackGas: exports.MORPHO_MIDNIGHT_BORROW_FALLBACK_GAS }
2262
+ ];
2263
+ return buildEvmMultisignBatch({
2264
+ context: {
2265
+ chainCategory: "evm",
2266
+ keyGen: args.keyGen,
2267
+ purposeText: args.purposeText,
2268
+ chainId: args.chainId,
2269
+ rpcUrl: args.rpcUrl,
2270
+ executorAddress: executor,
2271
+ chainDetail: args.chainDetail,
2272
+ useCustomGas: args.useCustomGas,
2273
+ customGasChainDetails: args.customGasChainDetails
2274
+ },
2275
+ steps: evmSteps,
2276
+ purposeSuffix: `Morpho Midnight: borrow (${args.borrowAmountHuman}) on "${marketLabel}".`,
2277
+ firstMsgRawNo0x: evmSteps[0].data.slice(2),
2278
+ destinationAddress: bundles,
2279
+ buildBatchMeta: ({ gasLimit }) => ({
2280
+ signatureText: JSON.stringify({
2281
+ kind: "MorphoMidnight",
2282
+ name: "borrow",
2283
+ marketLabel,
2284
+ borrowAmountHuman: args.borrowAmountHuman,
2285
+ collateralAmountHuman: args.collateralAmountHuman
2286
+ }),
2287
+ evm: { type: "morpho_midnight_borrow", version: 1, chainId: String(args.chainId) },
2288
+ morpho: {
2289
+ marketId: args.marketId,
2290
+ marketLabel,
2291
+ amountHuman: args.borrowAmountHuman,
2292
+ gasBuild: { baseGasUnits: gasLimit.toString() }
2293
+ }
2294
+ })
2295
+ });
2296
+ }
2297
+ async function buildEvmMultisignBodyMorphoMidnightRepayBatch(args) {
2298
+ const onBehalf = viem.getAddress(args.onBehalf);
2299
+ const collateralReceiver = viem.getAddress(args.collateralReceiver ?? args.onBehalf);
2300
+ const executor = viem.getAddress(args.executorAddress);
2301
+ const [marketRow, position] = await Promise.all([
2302
+ fetchMorphoMidnightMarketById(args.marketId),
2303
+ fetchMorphoMidnightUserMarketPosition({ marketId: args.marketId, user: onBehalf })
2304
+ ]);
2305
+ if (!marketRow) throw new Error(`Midnight market not found: ${args.marketId}`);
2306
+ if (!position) throw new Error(`No Midnight position for ${onBehalf} in ${args.marketId}`);
2307
+ const baseMarket = morphoMidnightMarketToParams(marketRow);
2308
+ let midnightAddr = baseMarket.midnight;
2309
+ if (midnightAddr === viem.zeroAddress) {
2310
+ const book = await fetchMorphoMidnightBook(args.marketId);
2311
+ if (book) midnightAddr = viem.getAddress(book.midnight);
2312
+ }
2313
+ const { midnight, bundles } = resolveAddresses({
2314
+ chainId: args.chainId,
2315
+ midnight: args.midnight ?? (midnightAddr !== viem.zeroAddress ? midnightAddr : void 0),
2316
+ bundles: args.bundles,
2317
+ marketMidnight: midnightAddr !== viem.zeroAddress ? midnightAddr : void 0
2318
+ });
2319
+ const market = { ...baseMarket, midnight };
2320
+ const loanToken = args.loanToken ? viem.getAddress(args.loanToken) : viem.getAddress(market.loanToken);
2321
+ const dec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loanToken });
2322
+ const debt = BigInt(position.debt || "0");
2323
+ const fee = BigInt(position.pendingFee || "0");
2324
+ const buffer = viem.parseUnits("1", Math.min(dec, 6));
2325
+ let repayAssets;
2326
+ if (args.repayAmountHuman?.trim()) {
2327
+ repayAssets = viem.parseUnits(args.repayAmountHuman.trim(), dec);
2328
+ } else {
2329
+ repayAssets = debt + fee + buffer;
2330
+ }
2331
+ if (repayAssets === 0n) throw new Error("Repay amount is zero.");
2332
+ const withdrawAll = args.withdrawAllCollateral !== false;
2333
+ const collateralWithdrawals = withdrawAll ? position.collaterals.map((c) => {
2334
+ const idx = market.collateralParams.findIndex(
2335
+ (cp) => cp.token.toLowerCase() === c.token.toLowerCase()
2336
+ );
2337
+ if (idx < 0) throw new Error(`Collateral ${c.token} missing from market params.`);
2338
+ return { collateralIndex: BigInt(idx), assets: BigInt(c.amount || "0") };
2339
+ }) : [];
2340
+ const deadline = deadlineFromNow(args.deadlineSeconds);
2341
+ const approveSteps = await buildApproveSteps({
2342
+ rpcUrl: args.rpcUrl,
2343
+ chainId: args.chainId,
2344
+ token: loanToken,
2345
+ spender: bundles,
2346
+ amountWei: repayAssets,
2347
+ executor
2348
+ });
2349
+ const authSteps = await ensureBundlesAuthorizedSteps({
2350
+ rpcUrl: args.rpcUrl,
2351
+ chainId: args.chainId,
2352
+ midnight,
2353
+ bundles,
2354
+ onBehalf
2355
+ });
2356
+ const repayData = viem.encodeFunctionData({
2357
+ abi: midnightSdk.midnightBundlesAbi,
2358
+ functionName: "midnightBundlesV1RepayAndWithdrawCollateral",
2359
+ args: [
2360
+ market,
2361
+ repayAssets,
2362
+ onBehalf,
2363
+ exports.TOKEN_PERMIT_NONE,
2364
+ collateralWithdrawals,
2365
+ collateralReceiver,
2366
+ 0n,
2367
+ viem.zeroAddress,
2368
+ deadline
2369
+ ]
2370
+ });
2371
+ const marketLabel = (args.marketLabel ?? "").trim() || `Midnight ${args.marketId.slice(0, 10)}\u2026`;
2372
+ const evmSteps = [
2373
+ ...approveStepsToEvm(approveSteps),
2374
+ ...authSteps,
2375
+ { to: bundles, data: repayData, value: 0n, fallbackGas: exports.MORPHO_MIDNIGHT_REPAY_FALLBACK_GAS }
2376
+ ];
2377
+ return buildEvmMultisignBatch({
2378
+ context: {
2379
+ chainCategory: "evm",
2380
+ keyGen: args.keyGen,
2381
+ purposeText: args.purposeText,
2382
+ chainId: args.chainId,
2383
+ rpcUrl: args.rpcUrl,
2384
+ executorAddress: executor,
2385
+ chainDetail: args.chainDetail,
2386
+ useCustomGas: args.useCustomGas,
2387
+ customGasChainDetails: args.customGasChainDetails
2388
+ },
2389
+ steps: evmSteps,
2390
+ purposeSuffix: `Morpho Midnight: repay + withdraw on "${marketLabel}".`,
2391
+ firstMsgRawNo0x: evmSteps[0].data.slice(2),
2392
+ destinationAddress: bundles,
2393
+ buildBatchMeta: ({ gasLimit }) => ({
2394
+ signatureText: JSON.stringify({ kind: "MorphoMidnight", name: "repay", marketLabel }),
2395
+ evm: { type: "morpho_midnight_repay", version: 1, chainId: String(args.chainId) },
2396
+ morpho: {
2397
+ marketId: args.marketId,
2398
+ marketLabel,
2399
+ gasBuild: { baseGasUnits: gasLimit.toString() }
2400
+ }
2401
+ })
2402
+ });
2403
+ }
2404
+ var erc4626Abi = viem.parseAbi([
2405
+ "function asset() view returns (address)",
2406
+ "function decimals() view returns (uint8)",
2407
+ "function balanceOf(address account) view returns (uint256)",
2408
+ "function convertToAssets(uint256 shares) view returns (uint256)",
2409
+ "function maxWithdraw(address owner) view returns (uint256)"
2410
+ ]);
2411
+ async function fetchMorphoVaultAssetDecimals(args) {
2412
+ const ch = viem.defineChain({
2413
+ id: args.chainId,
2414
+ name: "MorphoVault",
2415
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2416
+ rpcUrls: { default: { http: [args.rpcUrl] } }
2417
+ });
2418
+ const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
2419
+ const vault = viem.getAddress(args.vault);
2420
+ const assetAddr = await publicClient.readContract({
2421
+ address: vault,
2422
+ abi: erc4626Abi,
2423
+ functionName: "asset"
2424
+ });
2425
+ const d = await publicClient.readContract({
2426
+ address: viem.getAddress(assetAddr),
2427
+ abi: viem.parseAbi(["function decimals() view returns (uint8)"]),
2428
+ functionName: "decimals"
2429
+ });
2430
+ const n = typeof d === "bigint" ? Number(d) : Number(d);
2431
+ return !Number.isFinite(n) || n < 0 || n > 36 ? 18 : n;
2432
+ }
2433
+ async function fetchMorphoVaultMaxWithdrawWei(args) {
2434
+ const ch = viem.defineChain({
2435
+ id: args.chainId,
2436
+ name: "MorphoVault",
2437
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2438
+ rpcUrls: { default: { http: [args.rpcUrl] } }
2439
+ });
2440
+ const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
2441
+ return publicClient.readContract({
2442
+ address: viem.getAddress(args.vault),
2443
+ abi: erc4626Abi,
2444
+ functionName: "maxWithdraw",
2445
+ args: [viem.getAddress(args.owner)]
2446
+ });
2447
+ }
2448
+ var morphoBlueAbi = viem.parseAbi([
2449
+ "function position(bytes32 id, address user) view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)",
2450
+ "function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
2451
+ "function idToMarketParams(bytes32 id) view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)"
2452
+ ]);
2453
+ var oracleAbi = viem.parseAbi(["function price() view returns (uint256)"]);
2454
+ var WAD = 10n ** 18n;
2455
+ var ORACLE_PRICE_SCALE = 10n ** 36n;
2456
+ async function previewMorphoBlueHealthAfterCollateralWithdraw(args) {
2457
+ const ch = viem.defineChain({
2458
+ id: args.chainId,
2459
+ name: "MorphoBlue",
2460
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2461
+ rpcUrls: { default: { http: [args.rpcUrl] } }
2462
+ });
2463
+ const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
2464
+ const morpho = viem.getAddress(args.morphoBlue);
2465
+ const user = viem.getAddress(args.user);
2466
+ const id = args.marketId;
2467
+ const [pos, mkt, params] = await Promise.all([
2468
+ publicClient.readContract({
2469
+ address: morpho,
2470
+ abi: morphoBlueAbi,
2471
+ functionName: "position",
2472
+ args: [id, user]
2473
+ }),
2474
+ publicClient.readContract({
2475
+ address: morpho,
2476
+ abi: morphoBlueAbi,
2477
+ functionName: "market",
2478
+ args: [id]
2479
+ }),
2480
+ publicClient.readContract({
2481
+ address: morpho,
2482
+ abi: morphoBlueAbi,
2483
+ functionName: "idToMarketParams",
2484
+ args: [id]
2485
+ })
2486
+ ]);
2487
+ const borrowShares = BigInt(pos[1]);
2488
+ if (borrowShares === 0n) return { healthy: true, healthFactor: null };
2489
+ const collateral = BigInt(pos[2]) - args.withdrawCollateralWei;
2490
+ const oracle = viem.getAddress(params[2]);
2491
+ const lltv = BigInt(params[4]);
2492
+ const price = await publicClient.readContract({
2493
+ address: oracle,
2494
+ abi: oracleAbi,
2495
+ functionName: "price"
2496
+ });
2497
+ const totalBorrowAssets = BigInt(mkt[2]);
2498
+ const totalBorrowShares = BigInt(mkt[3]);
2499
+ if (totalBorrowShares === 0n) return { healthy: true, healthFactor: null };
2500
+ const borrowed = (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares;
2501
+ const maxBorrow = collateral * price / ORACLE_PRICE_SCALE * lltv / WAD;
2502
+ const healthy = maxBorrow >= borrowed;
2503
+ const hf = borrowed === 0n ? null : Number(maxBorrow * WAD / borrowed) / Number(WAD);
2504
+ return { healthy, healthFactor: hf != null && Number.isFinite(hf) ? hf : null };
2505
+ }
2506
+ var MORPHO_VAULT_DEPOSIT_FALLBACK_GAS = 950000n;
2507
+ var MORPHO_ERC20_APPROVE_FALLBACK = 100000n;
2508
+ var MORPHO_WETH_DEPOSIT_FALLBACK = 120000n;
2509
+ var wethDepositAbi2 = viem.parseAbi(["function deposit() payable"]);
2510
+ var erc20AllowanceAbi = viem.parseAbi([
2511
+ "function allowance(address owner, address spender) view returns (uint256)"
2512
+ ]);
2513
+ var erc20ApproveAbi = viem.parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]);
2514
+ var vaultDepositAbi = viem.parseAbi([
2515
+ "function deposit(uint256 assets, address onBehalf) returns (uint256 shares)"
2516
+ ]);
2517
+ async function buildEvmMultisignBodyMorphoVaultDepositBatch(args) {
2518
+ const asset = viem.getAddress(args.underlying);
2519
+ const vault = viem.getAddress(args.vault);
2520
+ const weth = viem.getAddress(args.nativeWrapped);
2521
+ const executor = viem.getAddress(args.executorAddress);
2522
+ const onBehalf = viem.getAddress(args.onBehalf);
2523
+ if (args.isNativeIn && asset.toLowerCase() !== weth.toLowerCase()) {
2524
+ throw new Error("Native deposit path: underlying asset must match the chain wrapped native token.");
2525
+ }
2526
+ const ch = viem.defineChain({
2527
+ id: args.chainId,
2528
+ name: "MorphoVaultDeposit",
2529
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2530
+ rpcUrls: { default: { http: [args.rpcUrl] } }
2531
+ });
2532
+ const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
2533
+ const dec = await fetchMorphoVaultAssetDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, vault });
2534
+ const amountWei = viem.parseUnits(args.amountHuman, dec);
2535
+ if (amountWei === 0n) throw new Error("Deposit amount is zero after converting with token decimals.");
2536
+ const steps = [];
1555
2537
  if (args.isNativeIn) {
1556
- const wethData = viem.encodeFunctionData({ abi: wethDepositAbi, functionName: "deposit" });
2538
+ const wethData = viem.encodeFunctionData({ abi: wethDepositAbi2, functionName: "deposit" });
1557
2539
  steps.push({ kind: "weth_deposit", to: weth, data: wethData, value: amountWei });
1558
2540
  }
1559
2541
  const spendToken = args.isNativeIn ? weth : asset;
@@ -1705,7 +2687,7 @@ var MORPHO_BLUE_REPAY_FALLBACK_GAS = 1000000n;
1705
2687
  var MORPHO_BLUE_COLLATERAL_WITHDRAW_FALLBACK_GAS = 900000n;
1706
2688
  var MORPHO_ERC20_APPROVE_FALLBACK2 = 100000n;
1707
2689
  var MORPHO_WETH_DEPOSIT_FALLBACK2 = 120000n;
1708
- var wethDepositAbi2 = viem.parseAbi(["function deposit() payable"]);
2690
+ var wethDepositAbi3 = viem.parseAbi(["function deposit() payable"]);
1709
2691
  var erc20AllowanceAbi2 = viem.parseAbi([
1710
2692
  "function allowance(address owner, address spender) view returns (uint256)",
1711
2693
  "function decimals() view returns (uint8)"
@@ -1726,7 +2708,7 @@ function marketParamsTuple(p) {
1726
2708
  lltv: p.lltv
1727
2709
  };
1728
2710
  }
1729
- async function readTokenDecimals(args) {
2711
+ async function readTokenDecimals2(args) {
1730
2712
  const ch = viem.defineChain({
1731
2713
  id: args.chainId,
1732
2714
  name: "MorphoToken",
@@ -1742,7 +2724,7 @@ async function readTokenDecimals(args) {
1742
2724
  const n = typeof d === "bigint" ? Number(d) : Number(d);
1743
2725
  return !Number.isFinite(n) || n < 0 || n > 36 ? 18 : n;
1744
2726
  }
1745
- async function buildApproveSteps(args) {
2727
+ async function buildApproveSteps2(args) {
1746
2728
  const steps = [];
1747
2729
  let spendToken = args.token;
1748
2730
  if (args.isNativeIn && args.nativeWrapped) {
@@ -1750,7 +2732,7 @@ async function buildApproveSteps(args) {
1750
2732
  if (spendToken.toLowerCase() !== weth.toLowerCase()) {
1751
2733
  throw new Error("Native collateral path: token must match wrapped native.");
1752
2734
  }
1753
- const wethData = viem.encodeFunctionData({ abi: wethDepositAbi2, functionName: "deposit" });
2735
+ const wethData = viem.encodeFunctionData({ abi: wethDepositAbi3, functionName: "deposit" });
1754
2736
  steps.push({ kind: "weth_deposit", to: weth, data: wethData, value: args.amountWei });
1755
2737
  spendToken = weth;
1756
2738
  }
@@ -1801,10 +2783,10 @@ async function buildEvmMultisignBodyMorphoBlueSupplyCollateralBatch(args) {
1801
2783
  const onBehalf = viem.getAddress(args.onBehalf);
1802
2784
  const executor = viem.getAddress(args.executorAddress);
1803
2785
  const collateral = viem.getAddress(args.collateralToken);
1804
- const dec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: collateral });
2786
+ const dec = await readTokenDecimals2({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: collateral });
1805
2787
  const amountWei = viem.parseUnits(args.amountHuman, dec);
1806
2788
  if (amountWei === 0n) throw new Error("Collateral amount is zero.");
1807
- const approveSteps = await buildApproveSteps({
2789
+ const approveSteps = await buildApproveSteps2({
1808
2790
  rpcUrl: args.rpcUrl,
1809
2791
  chainId: args.chainId,
1810
2792
  token: collateral,
@@ -1855,7 +2837,7 @@ async function buildEvmMultisignBodyMorphoBlueBorrowBatch(args) {
1855
2837
  const receiver = viem.getAddress(args.receiver);
1856
2838
  const executor = viem.getAddress(args.executorAddress);
1857
2839
  const loan = viem.getAddress(args.loanToken);
1858
- const dec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loan });
2840
+ const dec = await readTokenDecimals2({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loan });
1859
2841
  const amountWei = viem.parseUnits(args.amountHuman, dec);
1860
2842
  if (amountWei === 0n) throw new Error("Borrow amount is zero.");
1861
2843
  const borrowData = viem.encodeFunctionData({
@@ -1895,10 +2877,10 @@ async function buildEvmMultisignBodyMorphoBlueRepayBatch(args) {
1895
2877
  const onBehalf = viem.getAddress(args.onBehalf);
1896
2878
  const executor = viem.getAddress(args.executorAddress);
1897
2879
  const loan = viem.getAddress(args.loanToken);
1898
- const dec = await readTokenDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loan });
2880
+ const dec = await readTokenDecimals2({ rpcUrl: args.rpcUrl, chainId: args.chainId, token: loan });
1899
2881
  const amountWei = viem.parseUnits(args.amountHuman, dec);
1900
2882
  if (amountWei === 0n) throw new Error("Repay amount is zero.");
1901
- const approveSteps = await buildApproveSteps({
2883
+ const approveSteps = await buildApproveSteps2({
1902
2884
  rpcUrl: args.rpcUrl,
1903
2885
  chainId: args.chainId,
1904
2886
  token: loan,
@@ -2034,7 +3016,12 @@ var morphoProtocolModule = {
2034
3016
  { id: "morpho.blue-repay", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Repay Morpho Blue borrow", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
2035
3017
  { id: "morpho.blue-collateral-withdraw", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Withdraw Morpho Blue collateral", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
2036
3018
  { id: "morpho.merkl-claim", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Claim Morpho Merkl rewards", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
2037
- { id: "morpho.midnight-borrow", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Morpho Midnight fixed-rate borrow (coming soon)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3019
+ { id: "morpho.fetch-midnight-books", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "List Morpho Midnight fixed-rate books", commonParams: [], params: {} },
3020
+ { id: "morpho.fetch-midnight-quote", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Quote Morpho Midnight lend/borrow fill", commonParams: [], params: {} },
3021
+ { id: "morpho.fetch-midnight-positions", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "List Morpho Midnight user positions", commonParams: [], params: {} },
3022
+ { id: "morpho.midnight-lend", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Morpho Midnight fixed-rate lend (take asks)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3023
+ { id: "morpho.midnight-borrow", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Morpho Midnight fixed-rate borrow (supply collateral + take bids)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3024
+ { id: "morpho.midnight-repay", protocolId: MORPHO_PROTOCOL_ID, chainCategory: "evm", description: "Morpho Midnight repay debt and withdraw collateral", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
2038
3025
  ]
2039
3026
  };
2040
3027
  registerProtocolModule(morphoProtocolModule);
@@ -2059,6 +3046,9 @@ exports.buildEvmMultisignBodyMorphoBlueRepayBatch = buildEvmMultisignBodyMorphoB
2059
3046
  exports.buildEvmMultisignBodyMorphoBlueSupplyCollateralBatch = buildEvmMultisignBodyMorphoBlueSupplyCollateralBatch;
2060
3047
  exports.buildEvmMultisignBodyMorphoBlueWithdrawCollateralBatch = buildEvmMultisignBodyMorphoBlueWithdrawCollateralBatch;
2061
3048
  exports.buildEvmMultisignBodyMorphoMerklDistributorClaim = buildEvmMultisignBodyMorphoMerklDistributorClaim;
3049
+ exports.buildEvmMultisignBodyMorphoMidnightBorrowBatch = buildEvmMultisignBodyMorphoMidnightBorrowBatch;
3050
+ exports.buildEvmMultisignBodyMorphoMidnightLendBatch = buildEvmMultisignBodyMorphoMidnightLendBatch;
3051
+ exports.buildEvmMultisignBodyMorphoMidnightRepayBatch = buildEvmMultisignBodyMorphoMidnightRepayBatch;
2062
3052
  exports.buildEvmMultisignBodyMorphoVaultDepositBatch = buildEvmMultisignBodyMorphoVaultDepositBatch;
2063
3053
  exports.buildEvmMultisignBodyMorphoVaultWithdraw = buildEvmMultisignBodyMorphoVaultWithdraw;
2064
3054
  exports.emptyMorphoEarnVaultDetailFields = emptyMorphoEarnVaultDetailFields;
@@ -2072,7 +3062,14 @@ exports.fetchMorphoEarnOfferingsForAsset = fetchMorphoEarnOfferingsForAsset;
2072
3062
  exports.fetchMorphoEarnVaultDetails = fetchMorphoEarnVaultDetails;
2073
3063
  exports.fetchMorphoMarketById = fetchMorphoMarketById;
2074
3064
  exports.fetchMorphoMarketsForChain = fetchMorphoMarketsForChain;
3065
+ exports.fetchMorphoMidnightBook = fetchMorphoMidnightBook;
3066
+ exports.fetchMorphoMidnightBookQuote = fetchMorphoMidnightBookQuote;
3067
+ exports.fetchMorphoMidnightBooks = fetchMorphoMidnightBooks;
3068
+ exports.fetchMorphoMidnightBooksForAsset = fetchMorphoMidnightBooksForAsset;
2075
3069
  exports.fetchMorphoMidnightIntents = fetchMorphoMidnightIntents;
3070
+ exports.fetchMorphoMidnightMarketById = fetchMorphoMidnightMarketById;
3071
+ exports.fetchMorphoMidnightUserMarketPosition = fetchMorphoMidnightUserMarketPosition;
3072
+ exports.fetchMorphoMidnightUserPositions = fetchMorphoMidnightUserPositions;
2076
3073
  exports.fetchMorphoUserBluePositions = fetchMorphoUserBluePositions;
2077
3074
  exports.fetchMorphoUserPortfolioUsd = fetchMorphoUserPortfolioUsd;
2078
3075
  exports.fetchMorphoUserVaultPositions = fetchMorphoUserVaultPositions;
@@ -2084,6 +3081,7 @@ exports.fetchMorphoVaultsForChain = fetchMorphoVaultsForChain;
2084
3081
  exports.formatMorphoApyPct = formatMorphoApyPct;
2085
3082
  exports.formatMorphoFeePct = formatMorphoFeePct;
2086
3083
  exports.formatMorphoMarketApySummary = formatMorphoMarketApySummary;
3084
+ exports.formatMorphoMidnightAprPct = formatMorphoMidnightAprPct;
2087
3085
  exports.formatMorphoUsd = formatMorphoUsd;
2088
3086
  exports.isMorphoVaultListed = isMorphoVaultListed;
2089
3087
  exports.isRobinhoodEarnProductFlag = isRobinhoodEarnProductFlag;
@@ -2093,9 +3091,22 @@ exports.marketParamsFromApiRow = marketParamsFromApiRow;
2093
3091
  exports.morphoEarnOfferingToDiscoveryRow = morphoEarnOfferingToDiscoveryRow;
2094
3092
  exports.morphoFetchBlueMarketsSummary = morphoFetchBlueMarketsSummary;
2095
3093
  exports.morphoFetchEarnVaultsSummary = morphoFetchEarnVaultsSummary;
3094
+ exports.morphoFetchMidnightBooksSummary = morphoFetchMidnightBooksSummary;
3095
+ exports.morphoFetchMidnightPositionsSummary = morphoFetchMidnightPositionsSummary;
3096
+ exports.morphoFetchMidnightQuote = morphoFetchMidnightQuote;
3097
+ exports.morphoFetchMidnightQuoteSummary = morphoFetchMidnightQuoteSummary;
2096
3098
  exports.morphoGql = morphoGql;
2097
3099
  exports.morphoKeyForAssetRow = morphoKeyForAssetRow;
2098
3100
  exports.morphoMarketToBorrowRow = morphoMarketToBorrowRow;
3101
+ exports.morphoMidnightAddressesForChain = morphoMidnightAddressesForChain;
3102
+ exports.morphoMidnightApiBaseUrl = morphoMidnightApiBaseUrl;
3103
+ exports.morphoMidnightAprFromPriceWad = morphoMidnightAprFromPriceWad;
3104
+ exports.morphoMidnightBookToDiscoveryRow = morphoMidnightBookToDiscoveryRow;
3105
+ exports.morphoMidnightBookToMarketParams = morphoMidnightBookToMarketParams;
3106
+ exports.morphoMidnightMarketToParams = morphoMidnightMarketToParams;
3107
+ exports.morphoMidnightPositionToDiscoveryRow = morphoMidnightPositionToDiscoveryRow;
3108
+ exports.morphoMidnightTtmSeconds = morphoMidnightTtmSeconds;
3109
+ exports.morphoMidnightUnitsFromAssets = morphoMidnightUnitsFromAssets;
2099
3110
  exports.morphoProtocolModule = morphoProtocolModule;
2100
3111
  exports.morphoResolveListedEarnVaultByAddress = morphoResolveListedEarnVaultByAddress;
2101
3112
  exports.previewMorphoBlueHealthAfterCollateralWithdraw = previewMorphoBlueHealthAfterCollateralWithdraw;