@lit-protocol/vincent-ability-morpho 0.1.17-mma → 0.1.19-mma

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,218 +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
123
  ];
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
- internalType: 'bytes[]',
220
- name: 'data',
221
- type: 'bytes[]',
222
- },
223
- ],
224
- name: 'multicall',
225
- outputs: [
226
- {
227
- internalType: 'bytes[]',
228
- name: 'results',
229
- type: 'bytes[]',
230
- },
231
- ],
232
- stateMutability: 'payable',
233
- type: 'function',
234
- },
235
- ];
236
- exports.BUNDLER_ADDRESSES = {
237
- [exports.CHAIN_IDS.ethereum]: '0x6566194141eefa99Af43Bb5Aa71460Ca2Dc90245',
238
- [exports.CHAIN_IDS.base]: '0x6BFd8137e702540E7A42B74178A4a49Ba43920C4',
239
- [exports.CHAIN_IDS.arbitrum]: '0x1FA4431bC113D308beE1d46B0e98Cb805FB48C13',
240
- [exports.CHAIN_IDS.optimism]: '0xFBCd3C258feB131D8E038F2A3a670A7bE0507C05',
241
- [exports.CHAIN_IDS.polygon]: '0x2d9C3A9E67c966C711208cc78b34fB9E9f8db589',
242
- };
243
- /**
244
- * Pre-configured filter presets for common use cases
245
- */
246
- exports.VAULT_FILTER_PRESETS = {
247
- highYield: {
248
- minNetApy: 0.08,
249
- minTvl: 1000000,
250
- sortBy: 'netApy',
251
- sortOrder: 'desc',
252
- excludeIdle: true,
253
- limit: 10,
254
- },
255
- stable: {
256
- minTvl: 5000000,
257
- maxNetApy: 0.15,
258
- whitelistedOnly: true,
259
- sortBy: 'totalAssetsUsd',
260
- sortOrder: 'desc',
261
- excludeIdle: true,
262
- limit: 10,
263
- },
264
- highTvl: {
265
- minTvl: 10000000,
266
- sortBy: 'totalAssetsUsd',
267
- sortOrder: 'desc',
268
- excludeIdle: true,
269
- limit: 20,
270
- },
271
- };
272
- /**
273
- * Get well-known token addresses for a specific chain
274
- */
275
- function getTokenAddresses(chainId) {
276
- if (!(chainId in exports.WELL_KNOWN_TOKENS)) {
277
- throw new Error(`Unsupported chain ID: ${chainId}. Supported chains: ${Object.keys(exports.WELL_KNOWN_TOKENS).join(', ')}`);
278
- }
279
- return exports.WELL_KNOWN_TOKENS[chainId];
280
- }
281
- /**
282
- * Get token address for a specific token symbol and chain
283
- */
284
- function getTokenAddress(symbol, chainId) {
285
- const tokens = getTokenAddresses(chainId);
286
- const upperSymbol = symbol.toUpperCase();
287
- if (!(upperSymbol in tokens)) {
288
- throw new Error(`Token ${symbol} not found on chain ${chainId}. Available tokens: ${Object.keys(tokens).join(', ')}`);
289
- }
290
- return tokens[upperSymbol];
291
- }
292
- /**
293
- * Check if a chain is supported by Morpho
294
- */
295
- function isSupportedChain(chainId) {
296
- return chainId in exports.WELL_KNOWN_TOKENS;
297
- }
298
- /**
299
- * Get all supported chain IDs
300
- */
301
- function getSupportedChainIds() {
302
- return Object.keys(exports.WELL_KNOWN_TOKENS).map(Number);
303
- }
304
- /**
305
- * Get chain name from chain ID
306
- */
307
- function getChainName(chainId) {
308
- return exports.SUPPORTED_CHAINS[chainId] || `chain-${chainId}`;
309
- }
310
- /**
311
- * Utility function to validate Ethereum address
312
- */
313
- function isValidAddress(address) {
314
- return /^0x[a-fA-F0-9]{40}$/.test(address);
315
- }
316
- /**
317
- * Utility function to parse amount with decimals
318
- */
319
- function parseAmount(amount, decimals = 18) {
320
- return ethers_1.ethers.utils.parseUnits(amount, decimals).toString();
321
- }
322
- /**
323
- * Utility function to format amount from wei
324
- */
325
- function formatAmount(amount, decimals = 18) {
326
- return ethers_1.ethers.utils.formatUnits(amount, decimals);
327
- }
328
124
  /**
329
125
  * Validate operation-specific requirements for Morpho vaults
330
126
  */
331
- async function validateOperationRequirements(operation, userBalance, vaultShares, convertedAmount) {
332
- const userBalanceBN = BigInt(userBalance);
333
- const vaultSharesBN = BigInt(vaultShares);
334
- 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
+ };
335
135
  switch (operation) {
336
- case 'deposit':
337
- // Check if user has enough balance
338
- 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)) {
339
142
  return {
340
143
  valid: false,
341
- error: `Insufficient balance for deposit operation. You have ${userBalance} and need ${convertedAmount}`,
144
+ error: `Insufficient balance for deposit operation. ${debugParams}`,
342
145
  };
343
146
  }
344
- break;
345
- case 'redeem':
346
- // For redeem, we need to check if user has enough vault shares
347
- if (vaultSharesBN === 0n) {
147
+ // Check if the user has approved vault to take his tokens
148
+ if (allowance.lt(amount)) {
348
149
  return {
349
150
  valid: false,
350
- error: 'No vault shares available for redeem',
151
+ error: `Insufficient allowance for deposit operation. Please approve vault to take your tokens first. ${debugParams}`,
351
152
  };
352
153
  }
353
- // For redeem, the amount is in shares, so check directly
354
- 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)) {
355
158
  return {
356
159
  valid: false,
357
- error: `Insufficient vault shares for redeem operation. You have ${vaultShares} shares and need ${convertedAmount} shares`,
160
+ error: `Insufficient vault shares for redeem operation. ${debugParams}`,
358
161
  };
359
162
  }
360
163
  break;
@@ -363,179 +166,69 @@ async function validateOperationRequirements(operation, userBalance, vaultShares
363
166
  }
364
167
  return { valid: true };
365
168
  }
366
- /**
367
- * Morpho GraphQL API Client
368
- */
369
- class MorphoVaultClient {
370
- apiUrl = 'https://blue-api.morpho.org/graphql';
371
- /**
372
- * Fetch vault data from Morpho GraphQL API
373
- */
374
- async fetchVaultData(query, variables) {
375
- try {
376
- // console.log("fetchVaultData", query, variables);
377
- const response = await fetch(this.apiUrl, {
378
- method: 'POST',
379
- headers: {
380
- 'Content-Type': 'application/json',
381
- },
382
- body: JSON.stringify({
383
- query,
384
- variables,
385
- }),
386
- });
387
- if (!response.ok) {
388
- const body = await response.text();
389
- throw new Error(`HTTP error! status: ${response.status} and body: ${body}`);
390
- }
391
- const data = await response.json();
392
- if (data.errors) {
393
- throw new Error(`GraphQL error: ${data.errors.map((e) => e.message).join(', ')}`);
394
- }
395
- return data.data;
396
- }
397
- catch (error) {
398
- console.error('Failed to fetch vault data:', error);
399
- throw error;
400
- }
401
- }
402
- /**
403
- * Get all vaults with comprehensive information
404
- * Now uses proper server-side filtering via GraphQL VaultFilters
405
- */
406
- async getAllVaults(options = {}) {
407
- // Build GraphQL where clause from options
408
- const whereClause = this.buildVaultFilters(options);
409
- const query = `
410
- query GetAllVaults($first: Int, $orderBy: VaultOrderBy, $orderDirection: OrderDirection, $where: VaultFilters) {
411
- vaults(first: $first, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) {
412
- items {
413
- address
414
- name
415
- symbol
416
- whitelisted
417
- creationTimestamp
418
- asset {
419
- address
420
- symbol
421
- name
422
- decimals
423
- }
424
- chain {
425
- id
426
- network
427
- }
428
- state {
429
- apy
430
- netApy
431
- totalAssets
432
- totalAssetsUsd
433
- fee
434
- rewards {
435
- asset {
436
- address
437
- symbol
438
- }
439
- supplyApr
440
- yearlySupplyTokens
441
- }
442
- }
443
- }
444
- }
445
- }
446
- `;
447
- // Fetch more results than requested to account for client-side filtering
448
- // If excludeIdle is true, we might need to filter some out, so fetch extra
449
- // But never exceed 1000 (GraphQL API limit)
450
- const calculateFetchLimit = (requestedLimit) => {
451
- if (!requestedLimit)
452
- return 100; // Default limit
453
- // Always cap at 1000 to respect GraphQL API limits
454
- const cappedLimit = Math.min(requestedLimit, 1000);
455
- if (options.excludeIdle) {
456
- // For excludeIdle filtering, fetch extra but never exceed 1000
457
- return Math.max(cappedLimit, 1000);
458
- }
459
- // No client-side filtering, use requested limit (capped at 1000)
460
- return cappedLimit;
461
- };
462
- const fetchLimit = calculateFetchLimit(options.limit);
463
- const variables = {
464
- first: fetchLimit,
465
- orderBy: this.mapSortBy(options.sortBy || 'totalAssetsUsd'),
466
- orderDirection: options.sortOrder === 'asc' ? 'Asc' : 'Desc',
467
- where: whereClause,
468
- };
469
- const data = await this.fetchVaultData(query, variables);
470
- const vaults = data.vaults.items.map((vault) => this.mapVaultData(vault));
471
- // console.log("vaults after server-side filtering", vaults.length);
472
- // Apply only remaining client-side filters not supported by GraphQL
473
- const filtered = this.applyRemainingClientFilters(vaults, options);
474
- // console.log("vaults after additional client filtering", filtered.length);
475
- // Apply the limit AFTER client-side filtering to ensure we get the expected number of results
476
- const finalResults = options.limit ? filtered.slice(0, options.limit) : filtered;
477
- // Log a warning if we couldn't fetch enough results due to API limits
478
- if (options.limit && options.limit > 1000 && finalResults.length < options.limit) {
479
- 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}`);
480
184
  }
481
- return finalResults;
482
- }
483
- /**
484
- * Unified function to get vaults with flexible filtering
485
- * Supports filtering by asset, chain, and all other options
486
- */
487
- async getVaults(options = {}) {
488
- // If specific asset or chain filters are provided, enhance the options
489
- const enhancedOptions = { ...options };
490
- // Handle chain filtering - support both chainId and chain name/ID
491
- if (options.chainId) {
492
- 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(', ')}`);
493
188
  }
494
- return this.getAllVaults(enhancedOptions);
495
- }
496
- /**
497
- * Get top vaults by APY
498
- */
499
- async getTopVaultsByNetApy(limit = 10, minTvl = 0) {
500
- return this.getAllVaults({
501
- sortBy: 'netApy',
502
- sortOrder: 'desc',
503
- limit,
504
- minTvl,
505
- excludeIdle: true,
506
- });
507
- }
508
- /**
509
- * Get top vaults by TVL
510
- */
511
- async getTopVaultsByTvl(limit = 10) {
512
- return this.getAllVaults({
513
- sortBy: 'totalAssetsUsd',
514
- sortOrder: 'desc',
515
- limit,
516
- excludeIdle: true,
517
- });
189
+ return data.data;
518
190
  }
519
- /**
520
- * Search vaults by name, symbol, or asset
521
- */
522
- async searchVaults(searchOptions) {
523
- const allVaults = await this.getAllVaults({ limit: 500 }); // Reduced to avoid GraphQL limit issues
524
- if (!searchOptions.query) {
525
- return allVaults.slice(0, searchOptions.limit || 50);
526
- }
527
- const query = searchOptions.query.toLowerCase();
528
- const filtered = allVaults.filter((vault) => vault.name.toLowerCase().includes(query) ||
529
- vault.symbol.toLowerCase().includes(query) ||
530
- vault.asset.symbol.toLowerCase().includes(query) ||
531
- vault.asset.name.toLowerCase().includes(query));
532
- return filtered.slice(0, searchOptions.limit || 50);
191
+ catch (error) {
192
+ console.error('Failed to fetch vault data:', error);
193
+ throw error;
533
194
  }
534
- /**
535
- * Get vault details by address
536
- */
537
- async getVaultByAddress(address, chainId) {
538
- 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 = `
539
232
  query GetVaultByAddress($address: String!, $chainId: Int!) {
540
233
  vaultByAddress(address: $address, chainId: $chainId) {
541
234
  address
@@ -571,541 +264,28 @@ class MorphoVaultClient {
571
264
  }
572
265
  }
573
266
  `;
574
- const variables = { address, chainId };
575
- try {
576
- const data = await this.fetchVaultData(query, variables);
577
- return data.vaultByAddress ? this.mapVaultData(data.vaultByAddress) : null;
578
- }
579
- catch (error) {
580
- console.error(`Failed to fetch vault ${address}:`, error);
581
- return null;
582
- }
583
- }
584
- /**
585
- * Get best vaults for a specific asset
586
- */
587
- async getBestVaultsForAsset(assetSymbol, limit = 5) {
588
- const vaults = await this.getAllVaults({
589
- sortBy: 'netApy',
590
- sortOrder: 'desc',
591
- limit: 100,
592
- minTvl: 10000, // Minimum $10k TVL
593
- excludeIdle: true,
594
- });
595
- return vaults
596
- .filter((vault) => vault.asset.symbol.toLowerCase() === assetSymbol.toLowerCase())
597
- .slice(0, limit);
598
- }
599
- /**
600
- * Map vault data from GraphQL response
601
- */
602
- mapVaultData(vault) {
603
- return {
604
- address: vault.address,
605
- name: vault.name,
606
- symbol: vault.symbol,
607
- asset: {
608
- address: vault.asset.address,
609
- symbol: vault.asset.symbol,
610
- name: vault.asset.name,
611
- decimals: vault.asset.decimals,
612
- },
613
- chain: {
614
- id: vault.chain.id,
615
- network: vault.chain.network,
616
- },
617
- metrics: {
618
- apy: vault.state.apy || 0,
619
- netApy: vault.state.netApy || 0,
620
- totalAssets: vault.state.totalAssets || '0',
621
- totalAssetsUsd: vault.state.totalAssetsUsd || 0,
622
- fee: vault.state.fee || 0,
623
- rewards: vault.state.rewards?.map((reward) => ({
624
- asset: reward.asset.address,
625
- supplyApr: reward.supplyApr,
626
- yearlySupplyTokens: reward.yearlySupplyTokens,
627
- })) || [],
628
- },
629
- whitelisted: vault.whitelisted,
630
- creationTimestamp: vault.creationTimestamp,
631
- isIdle: vault.state.totalAssetsUsd < 100, // Consider vaults with < $100 TVL as idle
632
- };
633
- }
634
- /**
635
- * Build GraphQL VaultFilters from filter options
636
- * Uses proper server-side filtering for better performance
637
- */
638
- buildVaultFilters(options) {
639
- const filters = {};
640
- // Chain filtering - server-side supported
641
- if (options.chain !== undefined || options.chainId !== undefined) {
642
- let targetChainId;
643
- if (options.chainId !== undefined) {
644
- targetChainId = options.chainId;
645
- }
646
- else if (options.chain !== undefined) {
647
- targetChainId =
648
- typeof options.chain === 'string'
649
- ? exports.CHAIN_IDS[options.chain]
650
- : options.chain;
651
- }
652
- if (targetChainId !== undefined) {
653
- filters.chainId_in = [targetChainId];
654
- }
655
- }
656
- // Asset filtering - server-side supported
657
- if (options.assetAddress) {
658
- filters.assetAddress_in = [options.assetAddress.toLowerCase()];
659
- }
660
- if (options.assetSymbol) {
661
- filters.assetSymbol_in = [options.assetSymbol.toUpperCase()];
662
- }
663
- // Whitelisted status filtering - server-side supported
664
- if (options.whitelistedOnly) {
665
- filters.whitelisted = true;
666
- }
667
- // Net APY filtering - server-side supported
668
- if (options.minNetApy !== undefined) {
669
- filters.netApy_gte = options.minNetApy;
670
- }
671
- if (options.maxNetApy !== undefined) {
672
- filters.netApy_lte = options.maxNetApy;
673
- }
674
- // TVL filtering - server-side supported
675
- if (options.minTvl !== undefined) {
676
- filters.totalAssetsUsd_gte = options.minTvl;
677
- }
678
- if (options.maxTvl !== undefined) {
679
- filters.totalAssetsUsd_lte = options.maxTvl;
680
- }
681
- // Total assets filtering - server-side supported
682
- if (options.minTotalAssets !== undefined) {
683
- filters.totalAssets_gte = options.minTotalAssets.toString();
684
- }
685
- if (options.maxTotalAssets !== undefined) {
686
- filters.totalAssets_lte = options.maxTotalAssets.toString();
687
- }
688
- // Return null if no filters to avoid empty where clause
689
- return Object.keys(filters).length > 0 ? filters : null;
690
- }
691
- /**
692
- * Apply remaining client-side filters not supported by GraphQL
693
- * Only handles computed properties like isIdle
694
- */
695
- applyRemainingClientFilters(vaults, options) {
696
- let filtered = vaults;
697
- // Idle vault filtering (computed client-side)
698
- if (options.excludeIdle) {
699
- filtered = filtered.filter((vault) => !vault.isIdle);
700
- }
701
- return filtered;
702
- }
703
- /**
704
- * Map sortBy option to GraphQL enum
705
- */
706
- mapSortBy(sortBy) {
707
- switch (sortBy) {
708
- case 'netApy':
709
- return 'NetApy';
710
- case 'totalAssets':
711
- return 'TotalAssets';
712
- case 'totalAssetsUsd':
713
- return 'TotalAssetsUsd';
714
- case 'creationTimestamp':
715
- return 'CreationTimestamp';
716
- default:
717
- return 'TotalAssetsUsd';
718
- }
719
- }
720
- }
721
- exports.MorphoVaultClient = MorphoVaultClient;
722
- /**
723
- * Create a singleton instance of MorphoVaultClient
724
- */
725
- exports.morphoVaultClient = new MorphoVaultClient();
726
- /**
727
- * Helper function to get best vaults for a specific asset
728
- */
729
- async function getBestVaultsForAsset(assetSymbol, limit = 5) {
730
- return exports.morphoVaultClient.getBestVaultsForAsset(assetSymbol, limit);
731
- }
732
- /**
733
- * Helper function to get top vaults by APY
734
- */
735
- async function getTopVaultsByNetApy(limit = 10, minTvl = 10000) {
736
- return exports.morphoVaultClient.getTopVaultsByNetApy(limit, minTvl);
737
- }
738
- /**
739
- * Helper function to get top vaults by TVL
740
- */
741
- async function getTopVaultsByTvl(limit = 10) {
742
- return exports.morphoVaultClient.getTopVaultsByTvl(limit);
743
- }
744
- /**
745
- * Helper function to search vaults
746
- */
747
- async function searchVaults(query, limit = 20) {
748
- return exports.morphoVaultClient.searchVaults({ query, limit });
749
- }
750
- /**
751
- * 🚀 **Quick Vault Search with Presets**
752
- *
753
- * Get vaults using pre-configured filter presets for common use cases.
754
- *
755
- * @param preset - Pre-configured filter preset
756
- * @param overrides - Additional options to override preset defaults
757
- * @returns Promise resolving to array of vault information
758
- *
759
- * @example
760
- * ```typescript
761
- * // Find high-yield vaults
762
- * const highYieldVaults = await getVaultsByPreset("highYield");
763
- *
764
- * // Find high-yield USDC vaults specifically
765
- * const usdcHighYield = await getVaultsByPreset("highYield", {
766
- * assetSymbol: "USDC"
767
- * });
768
- *
769
- * // Find stable vaults on Base chain
770
- * const stableBaseVaults = await getVaultsByPreset("stable", {
771
- * chainId: 8453
772
- * });
773
- * ```
774
- */
775
- async function getVaultsByPreset(preset, overrides = {}) {
776
- const presetOptions = exports.VAULT_FILTER_PRESETS[preset];
777
- const mergedOptions = { ...presetOptions, ...overrides };
778
- return getVaults(mergedOptions);
779
- }
780
- /**
781
- * 🔍 **Primary Vault Discovery Function**
782
- *
783
- * Get Morpho vaults with comprehensive filtering and sorting options.
784
- * Uses server-side GraphQL queries for optimal performance.
785
- *
786
- * @param options - Vault filtering and sorting options
787
- * @returns Promise resolving to array of vault information
788
- *
789
- * @example
790
- * ```typescript
791
- * // Find best USDC vaults across all chains
792
- * const topVaults = await getVaults({
793
- * assetSymbol: "USDC",
794
- * minNetApy: 0.05,
795
- * minTvl: 1000000,
796
- * sortBy: "netApy",
797
- * sortOrder: "desc",
798
- * limit: 5
799
- * });
800
- *
801
- * // Filter by specific chain
802
- * const baseVaults = await getVaults({
803
- * chainId: 8453, // Base
804
- * excludeIdle: true,
805
- * sortBy: "totalAssetsUsd"
806
- * });
807
- *
808
- * // Search with multiple criteria
809
- * const premiumVaults = await getVaults({
810
- * minNetApy: 10.0,
811
- * minTvl: 5000000,
812
- * whitelistedOnly: true,
813
- * sortBy: "netApy",
814
- * limit: 3
815
- * });
816
- * ```
817
- */
818
- async function getVaults(options = {}) {
819
- return exports.morphoVaultClient.getVaults(options);
820
- }
821
- /**
822
- * Get supported chains with active vaults
823
- */
824
- async function getSupportedChainsWithVaults() {
825
- const supportedChains = getSupportedChainIds();
826
- const results = [];
827
- for (const chainId of supportedChains) {
828
- try {
829
- const vaults = await exports.morphoVaultClient.getVaults({
830
- chainId,
831
- limit: 1,
832
- excludeIdle: true,
833
- });
834
- if (vaults.length > 0) {
835
- // Get total count - reduced limit to avoid GraphQL errors
836
- const allVaults = await exports.morphoVaultClient.getVaults({
837
- chainId,
838
- limit: 500, // Reduced to avoid GraphQL limit issues
839
- excludeIdle: true,
840
- });
841
- results.push({
842
- chainId,
843
- name: getChainName(chainId),
844
- vaultCount: allVaults.length,
845
- });
846
- }
847
- }
848
- catch (error) {
849
- console.warn(`Could not fetch vaults for chain ${chainId}:`, error instanceof Error ? error.message : String(error));
850
- }
851
- }
852
- return results.sort((a, b) => b.vaultCount - a.vaultCount);
853
- }
854
- /**
855
- * Get vault discovery summary for a chain
856
- */
857
- async function getVaultDiscoverySummary(chainId) {
858
- try {
859
- const [topByTvl, topByNetApy, assetBreakdown] = await Promise.all([
860
- exports.morphoVaultClient.getVaults({
861
- chainId,
862
- sortBy: 'totalAssetsUsd',
863
- sortOrder: 'desc',
864
- limit: 5,
865
- excludeIdle: true,
866
- }),
867
- exports.morphoVaultClient.getVaults({
868
- chainId,
869
- sortBy: 'netApy',
870
- sortOrder: 'desc',
871
- limit: 5,
872
- excludeIdle: true,
873
- }),
874
- exports.morphoVaultClient.getVaults({
875
- chainId,
876
- limit: 500, // Reduced to avoid GraphQL limit issues
877
- excludeIdle: true,
878
- }),
879
- ]);
880
- // Group by asset
881
- const assetGroups = assetBreakdown.reduce((acc, vault) => {
882
- const symbol = vault.asset.symbol;
883
- if (!acc[symbol]) {
884
- acc[symbol] = { count: 0, totalTvl: 0, maxNetApy: 0 };
885
- }
886
- acc[symbol].count++;
887
- acc[symbol].totalTvl += vault.metrics.totalAssetsUsd;
888
- acc[symbol].maxNetApy = Math.max(acc[symbol].maxNetApy, vault.metrics.netApy);
889
- return acc;
890
- }, {});
891
- return {
892
- chainId,
893
- chainName: getChainName(chainId),
894
- totalVaults: assetBreakdown.length,
895
- totalTvl: assetBreakdown.reduce((sum, v) => sum + v.metrics.totalAssetsUsd, 0),
896
- topVaultsByTvl: topByTvl,
897
- topVaultsByNetApy: topByNetApy,
898
- assetBreakdown: Object.entries(assetGroups)
899
- .map(([symbol, data]) => ({ symbol, ...data }))
900
- .sort((a, b) => b.totalTvl - a.totalTvl),
901
- };
902
- }
903
- catch (error) {
904
- console.error(`Error getting vault summary for chain ${chainId}:`, error);
905
- throw error;
906
- }
907
- }
908
- const N = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
909
- const N2 = N >> 1n;
910
- function add0x(h) {
911
- return h.startsWith("0x") ? h : ("0x" + h);
912
- }
913
- function to32Bytes(h) {
914
- const bytes = ethers_1.ethers.utils.arrayify(add0x(h));
915
- if (bytes.length === 32) {
916
- return ethers_1.ethers.utils.hexlify(bytes);
917
- }
918
- // Lit sometimes prefixes a single "tag" byte. If so, drop it.
919
- if (bytes.length === 33 &&
920
- (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
- const iface = new ethers_1.ethers.utils.Interface(exports.BUNDLER_ABI);
1048
- const data = iface.encodeFunctionData('multicall', [calls]);
1049
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built bundler encoded tx data', {
1050
- data,
1051
- });
1052
- return {
1053
- data,
1054
- abi: exports.BUNDLER_ABI,
1055
- functionName: 'multicall',
1056
- args: [calls],
1057
- to: bundlerAddress,
1058
- value: '0x0',
1059
- };
1060
- }
1061
- async function buildRedeemTxData({ bundlerStepsLimit, amount, pkpAddress, provider, vaultAddress, }) {
1062
- const { chainId } = await provider.getNetwork();
1063
- const bundlerAddress = exports.BUNDLER_ADDRESSES[chainId];
1064
- if (!bundlerAddress) {
1065
- throw new Error(`No bundler address found for chain ${chainId}`);
1066
- }
1067
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Building bundler calls');
1068
- const calls = [
1069
- bundler_sdk_ethers_1.BundlerAction.erc4626Redeem(vaultAddress, amount, amount, pkpAddress, pkpAddress),
1070
- ].slice(0, bundlerStepsLimit);
1071
- const iface = new ethers_1.ethers.utils.Interface(exports.BUNDLER_ABI);
1072
- const data = iface.encodeFunctionData('multicall', [calls]);
1073
- console.log('[@lit-protocol/vincent-ability-morpho/buildDepositTxData] Built bundler encoded tx data', {
1074
- data,
1075
- });
1076
- return {
1077
- data,
1078
- abi: exports.BUNDLER_ABI,
1079
- functionName: 'multicall',
1080
- args: [calls],
1081
- to: bundlerAddress,
1082
- value: '0x0',
1083
- };
267
+ const variables = { address, chainId };
268
+ const data = await fetchVaultData(query, variables);
269
+ return data.vaultByAddress ? mapVaultData(data.vaultByAddress) : null;
1084
270
  }
1085
271
  /**
1086
272
  * Generic function to execute any Morpho operation, with optional gas sponsorship
1087
273
  */
1088
- 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, }) {
1089
275
  console.log(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Starting ${functionName} operation`, { sponsored: !!alchemyGasSponsor });
1090
276
  // Use gas sponsorship if enabled and all required parameters are provided
1091
277
  if (alchemyGasSponsor && alchemyGasSponsorApiKey && alchemyGasSponsorPolicyId) {
1092
278
  console.log(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Using EIP-7702 gas sponsorship`, { contractAddress, functionName, args, policyId: alchemyGasSponsorPolicyId });
1093
- try {
1094
- return await vincent_scaffold_sdk_1.laUtils.transaction.handler.sponsoredGasContractCall({
1095
- abi,
1096
- pkpPublicKey,
1097
- contractAddress,
1098
- functionName,
1099
- args,
1100
- chainId,
1101
- eip7702AlchemyApiKey: alchemyGasSponsorApiKey,
1102
- eip7702AlchemyPolicyId: alchemyGasSponsorPolicyId,
1103
- });
1104
- }
1105
- catch (error) {
1106
- console.error(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] EIP-7702 operation failed:`, error);
1107
- throw error;
1108
- }
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
+ });
1109
289
  }
1110
290
  else {
1111
291
  // Use regular transaction without gas sponsorship
@@ -1113,22 +293,16 @@ async function executeChainOperation({ abi, provider, pkpEthAddress, pkpPublicKe
1113
293
  if (!provider) {
1114
294
  throw new Error('Provider is required for non-sponsored transactions');
1115
295
  }
1116
- try {
1117
- return await vincent_scaffold_sdk_1.laUtils.transaction.handler.contractCall({
1118
- abi,
1119
- provider,
1120
- pkpPublicKey,
1121
- contractAddress,
1122
- functionName,
1123
- args,
1124
- chainId,
1125
- callerAddress: pkpEthAddress,
1126
- });
1127
- }
1128
- catch (error) {
1129
- console.error(`[@lit-protocol/vincent-ability-morpho/executeMorphoOperation] Regular transaction failed:`, error);
1130
- throw error;
1131
- }
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
+ });
1132
306
  }
1133
307
  }
1134
308
  //# sourceMappingURL=index.js.map