@lit-protocol/vincent-ability-morpho 0.1.18-mma → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,30 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.morphoVaultClient = exports.MorphoVaultClient = exports.VAULT_FILTER_PRESETS = exports.BUNDLER_ADDRESSES = exports.BUNDLER_ABI = exports.ERC20_ABI = exports.ERC4626_VAULT_ABI = exports.WELL_KNOWN_TOKENS = exports.SUPPORTED_CHAINS = exports.CHAIN_IDS = void 0;
4
- exports.getTokenAddresses = getTokenAddresses;
5
- exports.getTokenAddress = getTokenAddress;
6
- exports.isSupportedChain = isSupportedChain;
7
- exports.getSupportedChainIds = getSupportedChainIds;
8
- exports.getChainName = getChainName;
9
- exports.isValidAddress = isValidAddress;
10
- exports.parseAmount = parseAmount;
11
- exports.formatAmount = formatAmount;
3
+ exports.ERC4626_VAULT_ABI = exports.ERC20_ABI = exports.CHAIN_IDS = exports.SUPPORTED_CHAINS = void 0;
12
4
  exports.validateOperationRequirements = validateOperationRequirements;
13
- exports.getBestVaultsForAsset = getBestVaultsForAsset;
14
- exports.getTopVaultsByNetApy = getTopVaultsByNetApy;
15
- exports.getTopVaultsByTvl = getTopVaultsByTvl;
16
- exports.searchVaults = searchVaults;
17
- exports.getVaultsByPreset = getVaultsByPreset;
18
- exports.getVaults = getVaults;
19
- exports.getSupportedChainsWithVaults = getSupportedChainsWithVaults;
20
- exports.getVaultDiscoverySummary = getVaultDiscoverySummary;
21
- exports.normalizeLitSig = normalizeLitSig;
22
- exports.buildDepositTxData = buildDepositTxData;
23
- exports.buildRedeemTxData = buildRedeemTxData;
24
- exports.executeChainOperation = executeChainOperation;
5
+ exports.getMorphoVaultByAddress = getMorphoVaultByAddress;
6
+ exports.executeMorphoOperation = executeMorphoOperation;
25
7
  const vincent_scaffold_sdk_1 = require("@lit-protocol/vincent-scaffold-sdk");
26
- const bundler_sdk_ethers_1 = require("@morpho-org/bundler-sdk-ethers");
27
- const ethers_1 = require("ethers");
8
+ const schemas_1 = require("../schemas");
9
+ /**
10
+ * Supported chain IDs and their names
11
+ */
12
+ exports.SUPPORTED_CHAINS = {
13
+ 1: 'ethereum',
14
+ 8453: 'base',
15
+ 42161: 'arbitrum',
16
+ 10: 'optimism',
17
+ 137: 'polygon',
18
+ };
28
19
  /**
29
20
  * Chain names to IDs mapping for backwards compatibility
30
21
  */
@@ -36,51 +27,50 @@ exports.CHAIN_IDS = {
36
27
  polygon: 137,
37
28
  };
38
29
  /**
39
- * Supported chain IDs and their names
40
- */
41
- exports.SUPPORTED_CHAINS = {
42
- [exports.CHAIN_IDS.ethereum]: 'ethereum',
43
- [exports.CHAIN_IDS.base]: 'base',
44
- [exports.CHAIN_IDS.arbitrum]: 'arbitrum',
45
- [exports.CHAIN_IDS.optimism]: 'optimism',
46
- [exports.CHAIN_IDS.polygon]: 'polygon',
47
- };
48
- /**
49
- * Well-known token addresses across different chains
50
- * Using official Circle USDC and canonical WETH addresses
30
+ * ERC20 Token ABI - Essential methods only
51
31
  */
52
- exports.WELL_KNOWN_TOKENS = {
53
- [exports.CHAIN_IDS.ethereum]: {
54
- USDC: '0xA0b86991c6218A36c1D19D4a2e9Eb0cE3606eB48', // Circle USDC
55
- WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // Canonical WETH
56
- USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // Tether USDT
57
- },
58
- [exports.CHAIN_IDS.base]: {
59
- USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Native USDC on Base
60
- WETH: '0x4200000000000000000000000000000000000006', // WETH on Base
61
- USDT: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', // USDT on Base
32
+ exports.ERC20_ABI = [
33
+ {
34
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
35
+ name: 'balanceOf',
36
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
37
+ stateMutability: 'view',
38
+ type: 'function',
62
39
  },
63
- [exports.CHAIN_IDS.arbitrum]: {
64
- USDC: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // Native USDC on Arbitrum
65
- WETH: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', // WETH on Arbitrum
66
- USDT: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // USDT on Arbitrum
40
+ {
41
+ inputs: [
42
+ { internalType: 'address', name: 'owner', type: 'address' },
43
+ { internalType: 'address', name: 'spender', type: 'address' },
44
+ ],
45
+ name: 'allowance',
46
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
47
+ stateMutability: 'view',
48
+ type: 'function',
67
49
  },
68
- [exports.CHAIN_IDS.optimism]: {
69
- USDC: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', // Native USDC on Optimism
70
- WETH: '0x4200000000000000000000000000000000000006', // WETH on Optimism
71
- USDT: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', // USDT on Optimism
50
+ {
51
+ inputs: [
52
+ { internalType: 'address', name: 'spender', type: 'address' },
53
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
54
+ ],
55
+ name: 'approve',
56
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
57
+ stateMutability: 'nonpayable',
58
+ type: 'function',
72
59
  },
73
- [exports.CHAIN_IDS.polygon]: {
74
- USDC: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // Native USDC on Polygon
75
- WETH: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', // WETH on Polygon
76
- USDT: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', // USDT on Polygon
60
+ {
61
+ inputs: [],
62
+ name: 'decimals',
63
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
64
+ stateMutability: 'view',
65
+ type: 'function',
77
66
  },
78
- };
67
+ ];
79
68
  /**
80
69
  * ERC4626 Vault ABI - Essential methods for Morpho vaults
81
70
  */
82
71
  exports.ERC4626_VAULT_ABI = [
83
- // Deposit
72
+ // ERC4626 is an extension of ERC20, the token represents vault shares
73
+ ...exports.ERC20_ABI,
84
74
  {
85
75
  inputs: [
86
76
  { internalType: 'uint256', name: 'assets', type: 'uint256' },
@@ -91,7 +81,6 @@ exports.ERC4626_VAULT_ABI = [
91
81
  stateMutability: 'nonpayable',
92
82
  type: 'function',
93
83
  },
94
- // Redeem
95
84
  {
96
85
  inputs: [
97
86
  { internalType: 'uint256', name: 'shares', type: 'uint256' },
@@ -103,7 +92,6 @@ exports.ERC4626_VAULT_ABI = [
103
92
  stateMutability: 'nonpayable',
104
93
  type: 'function',
105
94
  },
106
- // Asset (underlying token address)
107
95
  {
108
96
  inputs: [],
109
97
  name: 'asset',
@@ -111,15 +99,6 @@ exports.ERC4626_VAULT_ABI = [
111
99
  stateMutability: 'view',
112
100
  type: 'function',
113
101
  },
114
- // Balance of shares
115
- {
116
- inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
117
- name: 'balanceOf',
118
- outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
119
- stateMutability: 'view',
120
- type: 'function',
121
- },
122
- // Convert assets to shares
123
102
  {
124
103
  inputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }],
125
104
  name: 'convertToShares',
@@ -127,7 +106,6 @@ exports.ERC4626_VAULT_ABI = [
127
106
  stateMutability: 'view',
128
107
  type: 'function',
129
108
  },
130
- // Convert shares to assets
131
109
  {
132
110
  inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }],
133
111
  name: 'convertToAssets',
@@ -135,7 +113,6 @@ exports.ERC4626_VAULT_ABI = [
135
113
  stateMutability: 'view',
136
114
  type: 'function',
137
115
  },
138
- // Total assets managed by the vault
139
116
  {
140
117
  inputs: [],
141
118
  name: 'totalAssets',
@@ -143,219 +120,44 @@ exports.ERC4626_VAULT_ABI = [
143
120
  stateMutability: 'view',
144
121
  type: 'function',
145
122
  },
146
- {
147
- inputs: [],
148
- name: 'decimals',
149
- outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
150
- stateMutability: 'view',
151
- type: 'function',
152
- },
153
- ];
154
- /**
155
- * ERC20 Token ABI - Essential methods only
156
- */
157
- exports.ERC20_ABI = [
158
- {
159
- inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
160
- name: 'balanceOf',
161
- outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
162
- stateMutability: 'view',
163
- type: 'function',
164
- },
165
- {
166
- inputs: [
167
- { internalType: 'address', name: 'owner', type: 'address' },
168
- { internalType: 'address', name: 'spender', type: 'address' },
169
- ],
170
- name: 'allowance',
171
- outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
172
- stateMutability: 'view',
173
- type: 'function',
174
- },
175
- {
176
- inputs: [
177
- { internalType: 'address', name: 'spender', type: 'address' },
178
- { internalType: 'uint256', name: 'amount', type: 'uint256' },
179
- ],
180
- name: 'approve',
181
- outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
182
- stateMutability: 'nonpayable',
183
- type: 'function',
184
- },
185
- {
186
- inputs: [],
187
- name: 'decimals',
188
- outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
189
- stateMutability: 'view',
190
- type: 'function',
191
- },
192
- // EIP-2612 ERC20Permit extension
193
- {
194
- inputs: [],
195
- name: 'name',
196
- outputs: [{ internalType: 'string', name: '', type: 'string' }],
197
- stateMutability: 'view',
198
- type: 'function',
199
- },
200
- {
201
- inputs: [],
202
- name: 'version',
203
- outputs: [{ internalType: 'string', name: '', type: 'string' }],
204
- stateMutability: 'view',
205
- type: 'function',
206
- },
207
- {
208
- inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],
209
- name: 'nonces',
210
- outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
211
- stateMutability: 'view',
212
- type: 'function',
213
- },
214
- ];
215
- exports.BUNDLER_ABI = [
216
- {
217
- inputs: [
218
- {
219
- components: [
220
- { internalType: 'address', name: 'to', type: 'address' },
221
- { internalType: 'bytes', name: 'data', type: 'bytes' },
222
- { internalType: 'uint256', name: 'value', type: 'uint256' },
223
- { internalType: 'bool', name: 'skipRevert', type: 'bool' },
224
- { internalType: 'bytes32', name: 'callbackHash', type: 'bytes32' },
225
- ],
226
- internalType: 'struct Call[]',
227
- name: 'bundle',
228
- type: 'tuple[]',
229
- },
230
- ],
231
- name: 'multicall',
232
- outputs: [],
233
- stateMutability: 'payable',
234
- type: 'function',
235
- },
236
123
  ];
237
- exports.BUNDLER_ADDRESSES = {
238
- [exports.CHAIN_IDS.ethereum]: '0x6566194141eefa99Af43Bb5Aa71460Ca2Dc90245',
239
- [exports.CHAIN_IDS.base]: '0x6BFd8137e702540E7A42B74178A4a49Ba43920C4',
240
- [exports.CHAIN_IDS.arbitrum]: '0x1FA4431bC113D308beE1d46B0e98Cb805FB48C13',
241
- [exports.CHAIN_IDS.optimism]: '0xFBCd3C258feB131D8E038F2A3a670A7bE0507C05',
242
- [exports.CHAIN_IDS.polygon]: '0x2d9C3A9E67c966C711208cc78b34fB9E9f8db589',
243
- };
244
- /**
245
- * Pre-configured filter presets for common use cases
246
- */
247
- exports.VAULT_FILTER_PRESETS = {
248
- highYield: {
249
- minNetApy: 0.08,
250
- minTvl: 1000000,
251
- sortBy: 'netApy',
252
- sortOrder: 'desc',
253
- excludeIdle: true,
254
- limit: 10,
255
- },
256
- stable: {
257
- minTvl: 5000000,
258
- maxNetApy: 0.15,
259
- whitelistedOnly: true,
260
- sortBy: 'totalAssetsUsd',
261
- sortOrder: 'desc',
262
- excludeIdle: true,
263
- limit: 10,
264
- },
265
- highTvl: {
266
- minTvl: 10000000,
267
- sortBy: 'totalAssetsUsd',
268
- sortOrder: 'desc',
269
- excludeIdle: true,
270
- limit: 20,
271
- },
272
- };
273
- /**
274
- * Get well-known token addresses for a specific chain
275
- */
276
- function getTokenAddresses(chainId) {
277
- if (!(chainId in exports.WELL_KNOWN_TOKENS)) {
278
- throw new Error(`Unsupported chain ID: ${chainId}. Supported chains: ${Object.keys(exports.WELL_KNOWN_TOKENS).join(', ')}`);
279
- }
280
- return exports.WELL_KNOWN_TOKENS[chainId];
281
- }
282
- /**
283
- * Get token address for a specific token symbol and chain
284
- */
285
- function getTokenAddress(symbol, chainId) {
286
- const tokens = getTokenAddresses(chainId);
287
- const upperSymbol = symbol.toUpperCase();
288
- if (!(upperSymbol in tokens)) {
289
- throw new Error(`Token ${symbol} not found on chain ${chainId}. Available tokens: ${Object.keys(tokens).join(', ')}`);
290
- }
291
- return tokens[upperSymbol];
292
- }
293
- /**
294
- * Check if a chain is supported by Morpho
295
- */
296
- function isSupportedChain(chainId) {
297
- return chainId in exports.WELL_KNOWN_TOKENS;
298
- }
299
- /**
300
- * Get all supported chain IDs
301
- */
302
- function getSupportedChainIds() {
303
- return Object.keys(exports.WELL_KNOWN_TOKENS).map(Number);
304
- }
305
- /**
306
- * Get chain name from chain ID
307
- */
308
- function getChainName(chainId) {
309
- return exports.SUPPORTED_CHAINS[chainId] || `chain-${chainId}`;
310
- }
311
- /**
312
- * Utility function to validate Ethereum address
313
- */
314
- function isValidAddress(address) {
315
- return /^0x[a-fA-F0-9]{40}$/.test(address);
316
- }
317
- /**
318
- * Utility function to parse amount with decimals
319
- */
320
- function parseAmount(amount, decimals = 18) {
321
- return ethers_1.ethers.utils.parseUnits(amount, decimals).toString();
322
- }
323
- /**
324
- * Utility function to format amount from wei
325
- */
326
- function formatAmount(amount, decimals = 18) {
327
- return ethers_1.ethers.utils.formatUnits(amount, decimals);
328
- }
329
124
  /**
330
125
  * Validate operation-specific requirements for Morpho vaults
331
126
  */
332
- async function validateOperationRequirements(operation, userBalance, vaultShares, convertedAmount) {
333
- const userBalanceBN = BigInt(userBalance);
334
- const vaultSharesBN = BigInt(vaultShares);
335
- const convertedAmountBN = BigInt(convertedAmount);
127
+ async function validateOperationRequirements(operation, userBalance, allowance, vaultShares, amount) {
128
+ const debugParams = {
129
+ operation,
130
+ userBalance: userBalance.toString(),
131
+ allowance: allowance.toString(),
132
+ vaultShares: vaultShares.toString(),
133
+ amount: amount.toString(),
134
+ };
336
135
  switch (operation) {
337
- case 'deposit':
338
- // Check if user has enough balance
339
- if (userBalanceBN < convertedAmountBN) {
136
+ case schemas_1.MorphoOperation.APPROVE:
137
+ // No need to check anything, the user can always approve token spending even when not having enough of them
138
+ break;
139
+ case schemas_1.MorphoOperation.DEPOSIT:
140
+ // Check if the user has enough tokens to deposit
141
+ if (userBalance.lt(amount)) {
340
142
  return {
341
143
  valid: false,
342
- error: `Insufficient balance for deposit operation. You have ${userBalance} and need ${convertedAmount}`,
144
+ error: `Insufficient balance for deposit operation. ${debugParams}`,
343
145
  };
344
146
  }
345
- break;
346
- case 'redeem':
347
- // For redeem, we need to check if user has enough vault shares
348
- if (vaultSharesBN === 0n) {
147
+ // Check if the user has approved vault to take his tokens
148
+ if (allowance.lt(amount)) {
349
149
  return {
350
150
  valid: false,
351
- error: 'No vault shares available for redeem',
151
+ error: `Insufficient allowance for deposit operation. Please approve vault to take your tokens first. ${debugParams}`,
352
152
  };
353
153
  }
354
- // For redeem, the amount is in shares, so check directly
355
- if (vaultSharesBN < convertedAmountBN) {
154
+ break;
155
+ case schemas_1.MorphoOperation.REDEEM:
156
+ // Check if the user can take enough vault shares
157
+ if (vaultShares.lt(amount)) {
356
158
  return {
357
159
  valid: false,
358
- error: `Insufficient vault shares for redeem operation. You have ${vaultShares} shares and need ${convertedAmount} shares`,
160
+ error: `Insufficient vault shares for redeem operation. ${debugParams}`,
359
161
  };
360
162
  }
361
163
  break;
@@ -364,179 +166,69 @@ async function validateOperationRequirements(operation, userBalance, vaultShares
364
166
  }
365
167
  return { valid: true };
366
168
  }
367
- /**
368
- * Morpho GraphQL API Client
369
- */
370
- class MorphoVaultClient {
371
- apiUrl = 'https://blue-api.morpho.org/graphql';
372
- /**
373
- * Fetch vault data from Morpho GraphQL API
374
- */
375
- async fetchVaultData(query, variables) {
376
- try {
377
- // console.log("fetchVaultData", query, variables);
378
- const response = await fetch(this.apiUrl, {
379
- method: 'POST',
380
- headers: {
381
- 'Content-Type': 'application/json',
382
- },
383
- body: JSON.stringify({
384
- query,
385
- variables,
386
- }),
387
- });
388
- if (!response.ok) {
389
- const body = await response.text();
390
- throw new Error(`HTTP error! status: ${response.status} and body: ${body}`);
391
- }
392
- const data = await response.json();
393
- if (data.errors) {
394
- throw new Error(`GraphQL error: ${data.errors.map((e) => e.message).join(', ')}`);
395
- }
396
- return data.data;
397
- }
398
- catch (error) {
399
- console.error('Failed to fetch vault data:', error);
400
- throw error;
401
- }
402
- }
403
- /**
404
- * Get all vaults with comprehensive information
405
- * Now uses proper server-side filtering via GraphQL VaultFilters
406
- */
407
- async getAllVaults(options = {}) {
408
- // Build GraphQL where clause from options
409
- const whereClause = this.buildVaultFilters(options);
410
- const query = `
411
- query GetAllVaults($first: Int, $orderBy: VaultOrderBy, $orderDirection: OrderDirection, $where: VaultFilters) {
412
- vaults(first: $first, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
413
- items {
414
- address
415
- name
416
- symbol
417
- whitelisted
418
- creationTimestamp
419
- asset {
420
- address
421
- symbol
422
- name
423
- decimals
424
- }
425
- chain {
426
- id
427
- network
428
- }
429
- state {
430
- apy
431
- netApy
432
- totalAssets
433
- totalAssetsUsd
434
- fee
435
- rewards {
436
- asset {
437
- address
438
- symbol
439
- }
440
- supplyApr
441
- yearlySupplyTokens
442
- }
443
- }
444
- }
445
- }
446
- }
447
- `;
448
- // Fetch more results than requested to account for client-side filtering
449
- // If excludeIdle is true, we might need to filter some out, so fetch extra
450
- // But never exceed 1000 (GraphQL API limit)
451
- const calculateFetchLimit = (requestedLimit) => {
452
- if (!requestedLimit)
453
- return 100; // Default limit
454
- // Always cap at 1000 to respect GraphQL API limits
455
- const cappedLimit = Math.min(requestedLimit, 1000);
456
- if (options.excludeIdle) {
457
- // For excludeIdle filtering, fetch extra but never exceed 1000
458
- return Math.max(cappedLimit, 1000);
459
- }
460
- // No client-side filtering, use requested limit (capped at 1000)
461
- return cappedLimit;
462
- };
463
- const fetchLimit = calculateFetchLimit(options.limit);
464
- const variables = {
465
- first: fetchLimit,
466
- orderBy: this.mapSortBy(options.sortBy || 'totalAssetsUsd'),
467
- orderDirection: options.sortOrder === 'asc' ? 'Asc' : 'Desc',
468
- where: whereClause,
469
- };
470
- const data = await this.fetchVaultData(query, variables);
471
- const vaults = data.vaults.items.map((vault) => this.mapVaultData(vault));
472
- // console.log("vaults after server-side filtering", vaults.length);
473
- // Apply only remaining client-side filters not supported by GraphQL
474
- const filtered = this.applyRemainingClientFilters(vaults, options);
475
- // console.log("vaults after additional client filtering", filtered.length);
476
- // Apply the limit AFTER client-side filtering to ensure we get the expected number of results
477
- const finalResults = options.limit ? filtered.slice(0, options.limit) : filtered;
478
- // Log a warning if we couldn't fetch enough results due to API limits
479
- if (options.limit && options.limit > 1000 && finalResults.length < options.limit) {
480
- console.warn(`Warning: Requested ${options.limit} vaults but GraphQL API limit is 1000. Got ${finalResults.length} results.`);
169
+ async function fetchVaultData(query, variables) {
170
+ try {
171
+ const response = await fetch('https://blue-api.morpho.org/graphql', {
172
+ method: 'POST',
173
+ headers: {
174
+ 'Content-Type': 'application/json',
175
+ },
176
+ body: JSON.stringify({
177
+ query,
178
+ variables,
179
+ }),
180
+ });
181
+ if (!response.ok) {
182
+ const body = await response.text();
183
+ throw new Error(`HTTP error! status: ${response.status} and body: ${body}`);
481
184
  }
482
- return finalResults;
483
- }
484
- /**
485
- * Unified function to get vaults with flexible filtering
486
- * Supports filtering by asset, chain, and all other options
487
- */
488
- async getVaults(options = {}) {
489
- // If specific asset or chain filters are provided, enhance the options
490
- const enhancedOptions = { ...options };
491
- // Handle chain filtering - support both chainId and chain name/ID
492
- if (options.chainId) {
493
- enhancedOptions.chain = options.chainId;
185
+ const data = await response.json();
186
+ if (data.errors) {
187
+ throw new Error(`GraphQL error: ${data.errors.map((e) => e.message).join(', ')}`);
494
188
  }
495
- return this.getAllVaults(enhancedOptions);
496
- }
497
- /**
498
- * Get top vaults by APY
499
- */
500
- async getTopVaultsByNetApy(limit = 10, minTvl = 0) {
501
- return this.getAllVaults({
502
- sortBy: 'netApy',
503
- sortOrder: 'desc',
504
- limit,
505
- minTvl,
506
- excludeIdle: true,
507
- });
508
- }
509
- /**
510
- * Get top vaults by TVL
511
- */
512
- async getTopVaultsByTvl(limit = 10) {
513
- return this.getAllVaults({
514
- sortBy: 'totalAssetsUsd',
515
- sortOrder: 'desc',
516
- limit,
517
- excludeIdle: true,
518
- });
189
+ return data.data;
519
190
  }
520
- /**
521
- * Search vaults by name, symbol, or asset
522
- */
523
- async searchVaults(searchOptions) {
524
- const allVaults = await this.getAllVaults({ limit: 500 }); // Reduced to avoid GraphQL limit issues
525
- if (!searchOptions.query) {
526
- return allVaults.slice(0, searchOptions.limit || 50);
527
- }
528
- const query = searchOptions.query.toLowerCase();
529
- const filtered = allVaults.filter((vault) => vault.name.toLowerCase().includes(query) ||
530
- vault.symbol.toLowerCase().includes(query) ||
531
- vault.asset.symbol.toLowerCase().includes(query) ||
532
- vault.asset.name.toLowerCase().includes(query));
533
- return filtered.slice(0, searchOptions.limit || 50);
191
+ catch (error) {
192
+ console.error('Failed to fetch vault data:', error);
193
+ throw error;
534
194
  }
535
- /**
536
- * Get vault details by address
537
- */
538
- async getVaultByAddress(address, chainId) {
539
- const query = `
195
+ }
196
+ function mapVaultData(vault) {
197
+ return {
198
+ address: vault.address,
199
+ name: vault.name,
200
+ symbol: vault.symbol,
201
+ asset: {
202
+ address: vault.asset.address,
203
+ symbol: vault.asset.symbol,
204
+ name: vault.asset.name,
205
+ decimals: vault.asset.decimals,
206
+ },
207
+ chain: {
208
+ id: vault.chain.id,
209
+ network: vault.chain.network,
210
+ },
211
+ metrics: {
212
+ apy: vault.state.apy || 0,
213
+ netApy: vault.state.netApy || 0,
214
+ totalAssets: vault.state.totalAssets || '0',
215
+ totalAssetsUsd: vault.state.totalAssetsUsd || 0,
216
+ fee: vault.state.fee || 0,
217
+ rewards: vault.state.rewards?.map((reward) => ({
218
+ asset: reward.asset.address,
219
+ supplyApr: reward.supplyApr,
220
+ yearlySupplyTokens: reward.yearlySupplyTokens,
221
+ })) || [],
222
+ },
223
+ whitelisted: vault.whitelisted,
224
+ creationTimestamp: vault.creationTimestamp,
225
+ };
226
+ }
227
+ /**
228
+ * Get Morpho vault details using their graphql api
229
+ */
230
+ async function getMorphoVaultByAddress(address, chainId) {
231
+ const query = `
540
232
  query GetVaultByAddress($address: String!, $chainId: Int!) {
541
233
  vaultByAddress(address: $address, chainId: $chainId) {
542
234
  address
@@ -572,542 +264,28 @@ class MorphoVaultClient {
572
264
  }
573
265
  }
574
266
  `;
575
- const variables = { address, chainId };
576
- try {
577
- const data = await this.fetchVaultData(query, variables);
578
- return data.vaultByAddress ? this.mapVaultData(data.vaultByAddress) : null;
579
- }
580
- catch (error) {
581
- console.error(`Failed to fetch vault ${address}:`, error);
582
- return null;
583
- }
584
- }
585
- /**
586
- * Get best vaults for a specific asset
587
- */
588
- async getBestVaultsForAsset(assetSymbol, limit = 5) {
589
- const vaults = await this.getAllVaults({
590
- sortBy: 'netApy',
591
- sortOrder: 'desc',
592
- limit: 100,
593
- minTvl: 10000, // Minimum $10k TVL
594
- excludeIdle: true,
595
- });
596
- return vaults
597
- .filter((vault) => vault.asset.symbol.toLowerCase() === assetSymbol.toLowerCase())
598
- .slice(0, limit);
599
- }
600
- /**
601
- * Map vault data from GraphQL response
602
- */
603
- mapVaultData(vault) {
604
- return {
605
- address: vault.address,
606
- name: vault.name,
607
- symbol: vault.symbol,
608
- asset: {
609
- address: vault.asset.address,
610
- symbol: vault.asset.symbol,
611
- name: vault.asset.name,
612
- decimals: vault.asset.decimals,
613
- },
614
- chain: {
615
- id: vault.chain.id,
616
- network: vault.chain.network,
617
- },
618
- metrics: {
619
- apy: vault.state.apy || 0,
620
- netApy: vault.state.netApy || 0,
621
- totalAssets: vault.state.totalAssets || '0',
622
- totalAssetsUsd: vault.state.totalAssetsUsd || 0,
623
- fee: vault.state.fee || 0,
624
- rewards: vault.state.rewards?.map((reward) => ({
625
- asset: reward.asset.address,
626
- supplyApr: reward.supplyApr,
627
- yearlySupplyTokens: reward.yearlySupplyTokens,
628
- })) || [],
629
- },
630
- whitelisted: vault.whitelisted,
631
- creationTimestamp: vault.creationTimestamp,
632
- isIdle: vault.state.totalAssetsUsd < 100, // Consider vaults with < $100 TVL as idle
633
- };
634
- }
635
- /**
636
- * Build GraphQL VaultFilters from filter options
637
- * Uses proper server-side filtering for better performance
638
- */
639
- buildVaultFilters(options) {
640
- const filters = {};
641
- // Chain filtering - server-side supported
642
- if (options.chain !== undefined || options.chainId !== undefined) {
643
- let targetChainId;
644
- if (options.chainId !== undefined) {
645
- targetChainId = options.chainId;
646
- }
647
- else if (options.chain !== undefined) {
648
- targetChainId =
649
- typeof options.chain === 'string'
650
- ? exports.CHAIN_IDS[options.chain]
651
- : options.chain;
652
- }
653
- if (targetChainId !== undefined) {
654
- filters.chainId_in = [targetChainId];
655
- }
656
- }
657
- // Asset filtering - server-side supported
658
- if (options.assetAddress) {
659
- filters.assetAddress_in = [options.assetAddress.toLowerCase()];
660
- }
661
- if (options.assetSymbol) {
662
- filters.assetSymbol_in = [options.assetSymbol.toUpperCase()];
663
- }
664
- // Whitelisted status filtering - server-side supported
665
- if (options.whitelistedOnly) {
666
- filters.whitelisted = true;
667
- }
668
- // Net APY filtering - server-side supported
669
- if (options.minNetApy !== undefined) {
670
- filters.netApy_gte = options.minNetApy;
671
- }
672
- if (options.maxNetApy !== undefined) {
673
- filters.netApy_lte = options.maxNetApy;
674
- }
675
- // TVL filtering - server-side supported
676
- if (options.minTvl !== undefined) {
677
- filters.totalAssetsUsd_gte = options.minTvl;
678
- }
679
- if (options.maxTvl !== undefined) {
680
- filters.totalAssetsUsd_lte = options.maxTvl;
681
- }
682
- // Total assets filtering - server-side supported
683
- if (options.minTotalAssets !== undefined) {
684
- filters.totalAssets_gte = options.minTotalAssets.toString();
685
- }
686
- if (options.maxTotalAssets !== undefined) {
687
- filters.totalAssets_lte = options.maxTotalAssets.toString();
688
- }
689
- // Return null if no filters to avoid empty where clause
690
- return Object.keys(filters).length > 0 ? filters : null;
691
- }
692
- /**
693
- * Apply remaining client-side filters not supported by GraphQL
694
- * Only handles computed properties like isIdle
695
- */
696
- applyRemainingClientFilters(vaults, options) {
697
- let filtered = vaults;
698
- // Idle vault filtering (computed client-side)
699
- if (options.excludeIdle) {
700
- filtered = filtered.filter((vault) => !vault.isIdle);
701
- }
702
- return filtered;
703
- }
704
- /**
705
- * Map sortBy option to GraphQL enum
706
- */
707
- mapSortBy(sortBy) {
708
- switch (sortBy) {
709
- case 'netApy':
710
- return 'NetApy';
711
- case 'totalAssets':
712
- return 'TotalAssets';
713
- case 'totalAssetsUsd':
714
- return 'TotalAssetsUsd';
715
- case 'creationTimestamp':
716
- return 'CreationTimestamp';
717
- default:
718
- return 'TotalAssetsUsd';
719
- }
720
- }
721
- }
722
- exports.MorphoVaultClient = MorphoVaultClient;
723
- /**
724
- * Create a singleton instance of MorphoVaultClient
725
- */
726
- exports.morphoVaultClient = new MorphoVaultClient();
727
- /**
728
- * Helper function to get best vaults for a specific asset
729
- */
730
- async function getBestVaultsForAsset(assetSymbol, limit = 5) {
731
- return exports.morphoVaultClient.getBestVaultsForAsset(assetSymbol, limit);
732
- }
733
- /**
734
- * Helper function to get top vaults by APY
735
- */
736
- async function getTopVaultsByNetApy(limit = 10, minTvl = 10000) {
737
- return exports.morphoVaultClient.getTopVaultsByNetApy(limit, minTvl);
738
- }
739
- /**
740
- * Helper function to get top vaults by TVL
741
- */
742
- async function getTopVaultsByTvl(limit = 10) {
743
- return exports.morphoVaultClient.getTopVaultsByTvl(limit);
744
- }
745
- /**
746
- * Helper function to search vaults
747
- */
748
- async function searchVaults(query, limit = 20) {
749
- return exports.morphoVaultClient.searchVaults({ query, limit });
750
- }
751
- /**
752
- * 🚀 **Quick Vault Search with Presets**
753
- *
754
- * Get vaults using pre-configured filter presets for common use cases.
755
- *
756
- * @param preset - Pre-configured filter preset
757
- * @param overrides - Additional options to override preset defaults
758
- * @returns Promise resolving to array of vault information
759
- *
760
- * @example
761
- * ```typescript
762
- * // Find high-yield vaults
763
- * const highYieldVaults = await getVaultsByPreset("highYield");
764
- *
765
- * // Find high-yield USDC vaults specifically
766
- * const usdcHighYield = await getVaultsByPreset("highYield", {
767
- * assetSymbol: "USDC"
768
- * });
769
- *
770
- * // Find stable vaults on Base chain
771
- * const stableBaseVaults = await getVaultsByPreset("stable", {
772
- * chainId: 8453
773
- * });
774
- * ```
775
- */
776
- async function getVaultsByPreset(preset, overrides = {}) {
777
- const presetOptions = exports.VAULT_FILTER_PRESETS[preset];
778
- const mergedOptions = { ...presetOptions, ...overrides };
779
- return getVaults(mergedOptions);
780
- }
781
- /**
782
- * 🔍 **Primary Vault Discovery Function**
783
- *
784
- * Get Morpho vaults with comprehensive filtering and sorting options.
785
- * Uses server-side GraphQL queries for optimal performance.
786
- *
787
- * @param options - Vault filtering and sorting options
788
- * @returns Promise resolving to array of vault information
789
- *
790
- * @example
791
- * ```typescript
792
- * // Find best USDC vaults across all chains
793
- * const topVaults = await getVaults({
794
- * assetSymbol: "USDC",
795
- * minNetApy: 0.05,
796
- * minTvl: 1000000,
797
- * sortBy: "netApy",
798
- * sortOrder: "desc",
799
- * limit: 5
800
- * });
801
- *
802
- * // Filter by specific chain
803
- * const baseVaults = await getVaults({
804
- * chainId: 8453, // Base
805
- * excludeIdle: true,
806
- * sortBy: "totalAssetsUsd"
807
- * });
808
- *
809
- * // Search with multiple criteria
810
- * const premiumVaults = await getVaults({
811
- * minNetApy: 10.0,
812
- * minTvl: 5000000,
813
- * whitelistedOnly: true,
814
- * sortBy: "netApy",
815
- * limit: 3
816
- * });
817
- * ```
818
- */
819
- async function getVaults(options = {}) {
820
- return exports.morphoVaultClient.getVaults(options);
821
- }
822
- /**
823
- * Get supported chains with active vaults
824
- */
825
- async function getSupportedChainsWithVaults() {
826
- const supportedChains = getSupportedChainIds();
827
- const results = [];
828
- for (const chainId of supportedChains) {
829
- try {
830
- const vaults = await exports.morphoVaultClient.getVaults({
831
- chainId,
832
- limit: 1,
833
- excludeIdle: true,
834
- });
835
- if (vaults.length > 0) {
836
- // Get total count - reduced limit to avoid GraphQL errors
837
- const allVaults = await exports.morphoVaultClient.getVaults({
838
- chainId,
839
- limit: 500, // Reduced to avoid GraphQL limit issues
840
- excludeIdle: true,
841
- });
842
- results.push({
843
- chainId,
844
- name: getChainName(chainId),
845
- vaultCount: allVaults.length,
846
- });
847
- }
848
- }
849
- catch (error) {
850
- console.warn(`Could not fetch vaults for chain ${chainId}:`, error instanceof Error ? error.message : String(error));
851
- }
852
- }
853
- return results.sort((a, b) => b.vaultCount - a.vaultCount);
854
- }
855
- /**
856
- * Get vault discovery summary for a chain
857
- */
858
- async function getVaultDiscoverySummary(chainId) {
859
- try {
860
- const [topByTvl, topByNetApy, assetBreakdown] = await Promise.all([
861
- exports.morphoVaultClient.getVaults({
862
- chainId,
863
- sortBy: 'totalAssetsUsd',
864
- sortOrder: 'desc',
865
- limit: 5,
866
- excludeIdle: true,
867
- }),
868
- exports.morphoVaultClient.getVaults({
869
- chainId,
870
- sortBy: 'netApy',
871
- sortOrder: 'desc',
872
- limit: 5,
873
- excludeIdle: true,
874
- }),
875
- exports.morphoVaultClient.getVaults({
876
- chainId,
877
- limit: 500, // Reduced to avoid GraphQL limit issues
878
- excludeIdle: true,
879
- }),
880
- ]);
881
- // Group by asset
882
- const assetGroups = assetBreakdown.reduce((acc, vault) => {
883
- const symbol = vault.asset.symbol;
884
- if (!acc[symbol]) {
885
- acc[symbol] = { count: 0, totalTvl: 0, maxNetApy: 0 };
886
- }
887
- acc[symbol].count++;
888
- acc[symbol].totalTvl += vault.metrics.totalAssetsUsd;
889
- acc[symbol].maxNetApy = Math.max(acc[symbol].maxNetApy, vault.metrics.netApy);
890
- return acc;
891
- }, {});
892
- return {
893
- chainId,
894
- chainName: getChainName(chainId),
895
- totalVaults: assetBreakdown.length,
896
- totalTvl: assetBreakdown.reduce((sum, v) => sum + v.metrics.totalAssetsUsd, 0),
897
- topVaultsByTvl: topByTvl,
898
- topVaultsByNetApy: topByNetApy,
899
- assetBreakdown: Object.entries(assetGroups)
900
- .map(([symbol, data]) => ({ symbol, ...data }))
901
- .sort((a, b) => b.totalTvl - a.totalTvl),
902
- };
903
- }
904
- catch (error) {
905
- console.error(`Error getting vault summary for chain ${chainId}:`, error);
906
- throw error;
907
- }
908
- }
909
- const N = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
910
- const N2 = N >> 1n;
911
- function add0x(h) {
912
- return h.startsWith('0x') ? h : '0x' + h;
913
- }
914
- function to32Bytes(h) {
915
- const bytes = ethers_1.ethers.utils.arrayify(add0x(h));
916
- if (bytes.length === 32) {
917
- return ethers_1.ethers.utils.hexlify(bytes);
918
- }
919
- // Lit sometimes prefixes a single "tag" byte. If so, drop it.
920
- if (bytes.length === 33 && (bytes[0] === 0x00 || bytes[0] === 0x02 || bytes[0] === 0x03)) {
921
- return ethers_1.ethers.utils.hexlify(bytes.slice(1));
922
- }
923
- // Left-pad if < 32
924
- if (bytes.length < 32) {
925
- const out = new Uint8Array(32);
926
- out.set(bytes, 32 - bytes.length);
927
- return ethers_1.ethers.utils.hexlify(out);
928
- }
929
- throw new Error(`Invalid 32-byte value length=${bytes.length} for ${h}`);
930
- }
931
- function normalizeLitSig(parsed) {
932
- const r = to32Bytes(parsed.r);
933
- let s = to32Bytes(parsed.s);
934
- let v = parsed.v;
935
- // map 0/1 -> 27/28 (ethers v5 wants that for many contracts)
936
- if (v === 0 || v === 1)
937
- v += 27;
938
- // low-s normalization (OpenZeppelin ECDSA-compatible)
939
- let sBN = BigInt(s);
940
- if (sBN > N2) {
941
- sBN = N - sBN;
942
- s = '0x' + sBN.toString(16).padStart(64, '0');
943
- v = v === 27 ? 28 : 27; // flip parity
944
- }
945
- return { r, s, v };
946
- }
947
- async function buildDepositTxData({ bundlerStepsLimit, skipRevertOnPermit, amount, pkpAddress, pkpPublicKey, provider, tokenAddress, vaultAddress, }) {
948
- const { chainId } = await provider.getNetwork();
949
- const bundlerAddress = exports.BUNDLER_ADDRESSES[chainId];
950
- if (!bundlerAddress) {
951
- throw new Error(`No bundler address found for chain ${chainId}`);
952
- }
953
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Building EIP-2612 permit data in runOnce');
954
- const permitDataResponse = await Lit.Actions.runOnce({ waitForResponse: true, name: 'permitData' }, async () => {
955
- const tokenContract = new ethers_1.ethers.Contract(tokenAddress, exports.ERC20_ABI, provider);
956
- const [name, nonce, version] = await Promise.all([
957
- tokenContract.name(),
958
- tokenContract.nonces(pkpAddress),
959
- tokenContract.version(),
960
- ]);
961
- const deadline = Math.floor(Date.now() / 1000) + 60 * 30; // 30 min
962
- // EIP-2612 permit signature
963
- const domain = {
964
- name,
965
- version,
966
- chainId,
967
- verifyingContract: tokenAddress,
968
- };
969
- const message = {
970
- owner: pkpAddress,
971
- spender: bundlerAddress,
972
- value: amount,
973
- nonce: nonce.toString(),
974
- deadline,
975
- };
976
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built EIP-2612 permit properties', {
977
- domain,
978
- message,
979
- });
980
- return JSON.stringify({
981
- deadline,
982
- domain,
983
- message,
984
- });
985
- });
986
- if (!permitDataResponse ||
987
- permitDataResponse[0] !== '{' ||
988
- permitDataResponse.includes('error')) {
989
- throw new Error(`permitData runOnce failed: ${permitDataResponse}`);
990
- }
991
- const { deadline, domain, message } = JSON.parse(permitDataResponse);
992
- const types = {
993
- Permit: [
994
- { name: 'owner', type: 'address' },
995
- { name: 'spender', type: 'address' },
996
- { name: 'value', type: 'uint256' },
997
- { name: 'nonce', type: 'uint256' },
998
- { name: 'deadline', type: 'uint256' },
999
- ],
1000
- };
1001
- const digest = ethers_1.ethers.utils._TypedDataEncoder.hash(domain, types, message);
1002
- const toSign = ethers_1.ethers.utils.arrayify(digest);
1003
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built EIP-2612 permit msg', {
1004
- toSign,
1005
- });
1006
- const publicKey = pkpPublicKey.replace(/^0x/, '');
1007
- const permitSignatureString = await Lit.Actions.signAndCombineEcdsa({
1008
- publicKey,
1009
- toSign,
1010
- sigName: 'tokenPermit',
1011
- });
1012
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Permit signature', {
1013
- permitSignatureString,
1014
- });
1015
- const permitSignatureParsed = JSON.parse(permitSignatureString);
1016
- const { r, s, v } = normalizeLitSig(permitSignatureParsed);
1017
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Parsed permit signature', {
1018
- r,
1019
- s,
1020
- v,
1021
- });
1022
- // Signature sanity check
1023
- const recovered = ethers_1.ethers.utils.recoverAddress(digest, { r, s, v });
1024
- if (recovered.toLowerCase() !== pkpAddress.toLowerCase()) {
1025
- throw new Error(`Permit sig does not recover to owner: ${recovered} != ${pkpAddress}`);
1026
- }
1027
- // Permit sanity check
1028
- try {
1029
- const tokenContract = new ethers_1.ethers.Contract(tokenAddress, [
1030
- 'function nonces(address) view returns (uint256)',
1031
- 'function permit(address owner,address spender,uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s)',
1032
- ], provider);
1033
- await tokenContract.callStatic.permit(pkpAddress, bundlerAddress, amount, deadline, v, r, s);
1034
- }
1035
- catch (error) {
1036
- console.error(`[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Permit sanity check failed:`, error);
1037
- throw new Error(`Permit sanity check failed: ${error}`);
1038
- }
1039
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Building bundler calls');
1040
- const calls = [
1041
- // @ts-expect-error permit expects a full Signature but having v ∈ {27, 28} which is not what ethers gives us
1042
- bundler_sdk_ethers_1.BundlerAction.permit(tokenAddress, amount, deadline, { r, s, v }, skipRevertOnPermit),
1043
- bundler_sdk_ethers_1.BundlerAction.erc20TransferFrom(tokenAddress, amount),
1044
- // Deposit into the ERC4626 vault (minShares = 0; set if you want protection)
1045
- bundler_sdk_ethers_1.BundlerAction.erc4626Deposit(vaultAddress, amount, 0, pkpAddress),
1046
- ].slice(0, bundlerStepsLimit);
1047
- console.log(`[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built calls:`, calls);
1048
- const iface = new ethers_1.ethers.utils.Interface(exports.BUNDLER_ABI);
1049
- const data = iface.encodeFunctionData('multicall', [calls]);
1050
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built bundler encoded tx data', {
1051
- data,
1052
- });
1053
- return {
1054
- data,
1055
- abi: exports.BUNDLER_ABI,
1056
- functionName: 'multicall',
1057
- args: [calls],
1058
- to: bundlerAddress,
1059
- value: '0x0',
1060
- };
1061
- }
1062
- async function buildRedeemTxData({ bundlerStepsLimit, amount, pkpAddress, provider, vaultAddress, }) {
1063
- const { chainId } = await provider.getNetwork();
1064
- const bundlerAddress = exports.BUNDLER_ADDRESSES[chainId];
1065
- if (!bundlerAddress) {
1066
- throw new Error(`No bundler address found for chain ${chainId}`);
1067
- }
1068
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Building bundler calls');
1069
- const calls = [
1070
- bundler_sdk_ethers_1.BundlerAction.erc4626Redeem(vaultAddress, amount, amount, pkpAddress, pkpAddress),
1071
- ].slice(0, bundlerStepsLimit);
1072
- console.log(`[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built calls:`, calls);
1073
- const iface = new ethers_1.ethers.utils.Interface(exports.BUNDLER_ABI);
1074
- const data = iface.encodeFunctionData('multicall', [calls]);
1075
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built bundler encoded tx data', {
1076
- data,
1077
- });
1078
- return {
1079
- data,
1080
- abi: exports.BUNDLER_ABI,
1081
- functionName: 'multicall',
1082
- args: [calls],
1083
- to: bundlerAddress,
1084
- value: '0x0',
1085
- };
267
+ const variables = { address, chainId };
268
+ const data = await fetchVaultData(query, variables);
269
+ return data.vaultByAddress ? mapVaultData(data.vaultByAddress) : null;
1086
270
  }
1087
271
  /**
1088
272
  * Generic function to execute any Morpho operation, with optional gas sponsorship
1089
273
  */
1090
- async function executeChainOperation({ abi, provider, pkpEthAddress, pkpPublicKey, contractAddress, functionName, args, chainId, alchemyGasSponsor, alchemyGasSponsorApiKey, alchemyGasSponsorPolicyId, }) {
274
+ async function executeMorphoOperation({ abi, args, alchemyGasSponsor = false, alchemyGasSponsorApiKey, alchemyGasSponsorPolicyId, contractAddress, chainId, functionName, provider, pkpInfo, }) {
1091
275
  console.log(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Starting ${functionName} operation`, { sponsored: !!alchemyGasSponsor });
1092
276
  // Use gas sponsorship if enabled and all required parameters are provided
1093
277
  if (alchemyGasSponsor && alchemyGasSponsorApiKey && alchemyGasSponsorPolicyId) {
1094
278
  console.log(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Using EIP-7702 gas sponsorship`, { contractAddress, functionName, args, policyId: alchemyGasSponsorPolicyId });
1095
- try {
1096
- return await vincent_scaffold_sdk_1.laUtils.transaction.handler.sponsoredGasContractCall({
1097
- abi,
1098
- pkpPublicKey,
1099
- contractAddress,
1100
- functionName,
1101
- args,
1102
- chainId,
1103
- eip7702AlchemyApiKey: alchemyGasSponsorApiKey,
1104
- eip7702AlchemyPolicyId: alchemyGasSponsorPolicyId,
1105
- });
1106
- }
1107
- catch (error) {
1108
- console.error(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] EIP-7702 operation failed:`, error);
1109
- throw error;
1110
- }
279
+ return await vincent_scaffold_sdk_1.laUtils.transaction.handler.sponsoredGasContractCall({
280
+ abi,
281
+ args,
282
+ contractAddress,
283
+ chainId,
284
+ functionName,
285
+ eip7702AlchemyApiKey: alchemyGasSponsorApiKey,
286
+ eip7702AlchemyPolicyId: alchemyGasSponsorPolicyId,
287
+ pkpPublicKey: pkpInfo.publicKey,
288
+ });
1111
289
  }
1112
290
  else {
1113
291
  // Use regular transaction without gas sponsorship
@@ -1115,22 +293,16 @@ async function executeChainOperation({ abi, provider, pkpEthAddress, pkpPublicKe
1115
293
  if (!provider) {
1116
294
  throw new Error('Provider is required for non-sponsored transactions');
1117
295
  }
1118
- try {
1119
- return await vincent_scaffold_sdk_1.laUtils.transaction.handler.contractCall({
1120
- abi,
1121
- provider,
1122
- pkpPublicKey,
1123
- contractAddress,
1124
- functionName,
1125
- args,
1126
- chainId,
1127
- callerAddress: pkpEthAddress,
1128
- });
1129
- }
1130
- catch (error) {
1131
- console.error(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Regular transaction failed:`, error);
1132
- throw error;
1133
- }
296
+ return await vincent_scaffold_sdk_1.laUtils.transaction.handler.contractCall({
297
+ abi,
298
+ args,
299
+ chainId,
300
+ contractAddress,
301
+ functionName,
302
+ provider,
303
+ callerAddress: pkpInfo.ethAddress,
304
+ pkpPublicKey: pkpInfo.publicKey,
305
+ });
1134
306
  }
1135
307
  }
1136
308
  //# sourceMappingURL=index.js.map