@metamask-previews/earn-controller 0.14.0-preview-2e9de6b → 0.14.0-preview-7bb49dcb

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,19 +1,19 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
1
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
2
  if (kind === "m") throw new TypeError("Private method is not writable");
8
3
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
4
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
5
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
6
  };
12
- var _EarnController_instances, _EarnController_stakeSDK, _EarnController_selectedNetworkClientId, _EarnController_stakingApiService, _EarnController_initializeSDK, _EarnController_getCurrentAccount, _EarnController_getCurrentChainId;
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _EarnController_instances, _EarnController_earnSDK, _EarnController_selectedNetworkClientId, _EarnController_earnApiService, _EarnController_addTransactionFn, _EarnController_supportedPooledStakingChains, _EarnController_initializeSDK, _EarnController_getCurrentAccount, _EarnController_getCurrentChainId;
13
13
  import { Web3Provider } from "@ethersproject/providers";
14
14
  import { BaseController } from "@metamask/base-controller";
15
- import { convertHexToDecimal } from "@metamask/controller-utils";
16
- import { StakeSdk, StakingApiService, ChainId } from "@metamask/stake-sdk";
15
+ import { convertHexToDecimal, toHex } from "@metamask/controller-utils";
16
+ import { EarnSdk, EarnApiService } from "@metamask/stake-sdk";
17
17
  import { TransactionType } from "@metamask/transaction-controller";
18
18
  export const controllerName = 'EarnController';
19
19
  const stakingTransactionTypes = new Set([
@@ -21,6 +21,10 @@ const stakingTransactionTypes = new Set([
21
21
  TransactionType.stakingUnstake,
22
22
  TransactionType.stakingClaim,
23
23
  ]);
24
+ const lendingTransactionTypes = new Set([
25
+ TransactionType.lendingDeposit,
26
+ 'lendingWithdraw',
27
+ ]);
24
28
  /**
25
29
  * Metadata for the EarnController.
26
30
  */
@@ -29,7 +33,7 @@ const earnControllerMetadata = {
29
33
  persist: true,
30
34
  anonymous: false,
31
35
  },
32
- stablecoin_lending: {
36
+ lending: {
33
37
  persist: true,
34
38
  anonymous: false,
35
39
  },
@@ -39,17 +43,42 @@ const earnControllerMetadata = {
39
43
  },
40
44
  };
41
45
  // === Default State ===
42
- const DEFAULT_STABLECOIN_VAULT = {
43
- symbol: '',
46
+ export const DEFAULT_LENDING_MARKET = {
47
+ id: '',
48
+ chainId: 0,
49
+ protocol: '',
44
50
  name: '',
51
+ address: '',
52
+ tvlUnderlying: '0',
53
+ netSupplyRate: 0,
54
+ totalSupplyRate: 0,
55
+ underlying: {
56
+ address: '',
57
+ chainId: 0,
58
+ },
59
+ outputToken: {
60
+ address: '',
61
+ chainId: 0,
62
+ },
63
+ rewards: [
64
+ {
65
+ token: {
66
+ address: '',
67
+ chainId: 0,
68
+ },
69
+ rate: 0,
70
+ },
71
+ ],
72
+ };
73
+ export const DEFAULT_LENDING_POSITION = {
74
+ id: '',
45
75
  chainId: 0,
46
- tokenAddress: '',
47
- vaultAddress: '',
48
- currentAPY: '0',
49
- supply: '0',
50
- liquidity: '0',
76
+ assets: '0',
77
+ marketId: '',
78
+ marketAddress: '',
79
+ protocol: '',
51
80
  };
52
- const DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES = {
81
+ export const DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES = {
53
82
  oneDay: '0',
54
83
  oneWeek: '0',
55
84
  oneMonth: '0',
@@ -57,6 +86,24 @@ const DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES = {
57
86
  sixMonths: '0',
58
87
  oneYear: '0',
59
88
  };
89
+ export const DEFAULT_POOLED_STAKING_CHAIN_STATE = {
90
+ pooledStakes: {
91
+ account: '',
92
+ lifetimeRewards: '0',
93
+ assets: '0',
94
+ exitRequests: [],
95
+ },
96
+ exchangeRate: '1',
97
+ vaultMetadata: {
98
+ apy: '0',
99
+ capacity: '0',
100
+ feePercent: 0,
101
+ totalAssets: '0',
102
+ vaultAddress: '0x0000000000000000000000000000000000000000',
103
+ },
104
+ vaultDailyApys: [],
105
+ vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,
106
+ };
60
107
  /**
61
108
  * Gets the default state for the EarnController.
62
109
  *
@@ -65,26 +112,12 @@ const DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES = {
65
112
  export function getDefaultEarnControllerState() {
66
113
  return {
67
114
  pooled_staking: {
68
- pooledStakes: {
69
- account: '',
70
- lifetimeRewards: '0',
71
- assets: '0',
72
- exitRequests: [],
73
- },
74
- exchangeRate: '1',
75
- vaultMetadata: {
76
- apy: '0',
77
- capacity: '0',
78
- feePercent: 0,
79
- totalAssets: '0',
80
- vaultAddress: '0x0000000000000000000000000000000000000000',
81
- },
82
- vaultDailyApys: [],
83
- vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,
84
115
  isEligible: false,
85
116
  },
86
- stablecoin_lending: {
87
- vaults: [DEFAULT_STABLECOIN_VAULT],
117
+ lending: {
118
+ markets: [DEFAULT_LENDING_MARKET],
119
+ positions: [DEFAULT_LENDING_POSITION],
120
+ isEligible: false,
88
121
  },
89
122
  lastUpdated: 0,
90
123
  };
@@ -94,7 +127,7 @@ export function getDefaultEarnControllerState() {
94
127
  * EarnController manages DeFi earning opportunities across different protocols and chains.
95
128
  */
96
129
  export class EarnController extends BaseController {
97
- constructor({ messenger, state = {}, }) {
130
+ constructor({ messenger, state = {}, addTransactionFn, }) {
98
131
  super({
99
132
  name: controllerName,
100
133
  metadata: earnControllerMetadata,
@@ -105,22 +138,37 @@ export class EarnController extends BaseController {
105
138
  },
106
139
  });
107
140
  _EarnController_instances.add(this);
108
- _EarnController_stakeSDK.set(this, null);
141
+ _EarnController_earnSDK.set(this, null);
109
142
  _EarnController_selectedNetworkClientId.set(this, void 0);
110
- _EarnController_stakingApiService.set(this, new StakingApiService());
111
- __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this);
143
+ _EarnController_earnApiService.set(this, new EarnApiService());
144
+ _EarnController_addTransactionFn.set(this, void 0);
145
+ _EarnController_supportedPooledStakingChains.set(this, void 0);
146
+ // temporary array of supported chains
147
+ // TODO: remove this once we have a more permanent solution
148
+ // from sdk or api to get lending and pooled staking chains
149
+ __classPrivateFieldSet(this, _EarnController_supportedPooledStakingChains, [1, 560048], "f");
150
+ __classPrivateFieldSet(this, _EarnController_addTransactionFn, addTransactionFn, "f");
151
+ __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this).catch(console.error);
112
152
  this.refreshPooledStakingData().catch(console.error);
153
+ this.refreshLendingData().catch(console.error);
113
154
  const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
114
155
  __classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, selectedNetworkClientId, "f");
115
156
  // Listen for network changes
116
157
  this.messagingSystem.subscribe('NetworkController:stateChange', (networkControllerState) => {
117
158
  if (networkControllerState.selectedNetworkClientId !==
118
159
  __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
119
- __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this, networkControllerState.selectedNetworkClientId);
120
- this.refreshPooledStakingVaultMetadata().catch(console.error);
121
- this.refreshPooledStakingVaultDailyApys().catch(console.error);
122
- this.refreshPooledStakingVaultApyAverages().catch(console.error);
123
- this.refreshPooledStakes().catch(console.error);
160
+ const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this, networkControllerState.selectedNetworkClientId);
161
+ __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this, networkControllerState.selectedNetworkClientId).catch(console.error);
162
+ if (__classPrivateFieldGet(this, _EarnController_supportedPooledStakingChains, "f").includes(chainId)) {
163
+ // only refresh pool staking data for the chain we are switching to
164
+ this.refreshPooledStakingVaultMetadata(chainId).catch(console.error);
165
+ this.refreshPooledStakingVaultDailyApys(chainId).catch(console.error);
166
+ this.refreshPooledStakingVaultApyAverages(chainId).catch(console.error);
167
+ this.refreshPooledStakes({ chainId }).catch(console.error);
168
+ }
169
+ // refresh lending data for all chains
170
+ this.refreshLendingMarkets().catch(console.error);
171
+ this.refreshLendingPositions().catch(console.error);
124
172
  }
125
173
  __classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, networkControllerState.selectedNetworkClientId, "f");
126
174
  });
@@ -132,8 +180,11 @@ export class EarnController extends BaseController {
132
180
  * Until this has been fixed, we rely on the event payload for the latest account instead of #getCurrentAccount().
133
181
  * Issue: https://github.com/MetaMask/accounts-planning/issues/887
134
182
  */
183
+ // TODO: temp solution, this will refresh lending eligibility also
184
+ // we could have a more general check, as what is happening is a compliance address check
135
185
  this.refreshStakingEligibility({ address }).catch(console.error);
136
186
  this.refreshPooledStakes({ address }).catch(console.error);
187
+ this.refreshLendingPositions({ address }).catch(console.error);
137
188
  });
138
189
  // Listen for confirmed staking transactions
139
190
  this.messagingSystem.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
@@ -145,10 +196,15 @@ export class EarnController extends BaseController {
145
196
  const { type, originalType } = transactionMeta;
146
197
  const isStakingTransaction = stakingTransactionTypes.has(type) ||
147
198
  stakingTransactionTypes.has(originalType);
199
+ const isLendingTransaction = lendingTransactionTypes.has(type) ||
200
+ lendingTransactionTypes.has(originalType);
201
+ const sender = transactionMeta.txParams.from;
148
202
  if (isStakingTransaction) {
149
- const sender = transactionMeta.txParams.from;
150
203
  this.refreshPooledStakes({ resetCache: true, address: sender }).catch(console.error);
151
204
  }
205
+ if (isLendingTransaction) {
206
+ this.refreshLendingPositions({ address: sender }).catch(console.error);
207
+ }
152
208
  });
153
209
  }
154
210
  /**
@@ -159,18 +215,24 @@ export class EarnController extends BaseController {
159
215
  * @param options - Optional arguments
160
216
  * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).
161
217
  * @param [options.address] - The address to refresh pooled stakes for (optional).
218
+ * @param [options.chainId] - The chain id to refresh pooled stakes for (optional).
162
219
  * @returns A promise that resolves when the stakes data has been updated
163
220
  */
164
- async refreshPooledStakes({ resetCache = false, address, } = {}) {
221
+ async refreshPooledStakes({ resetCache = false, address, chainId, } = {}) {
165
222
  const addressToUse = address ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
166
223
  if (!addressToUse) {
167
224
  return;
168
225
  }
169
- const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
170
- const { accounts, exchangeRate } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakes([addressToUse], chainId, resetCache);
226
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
227
+ const { accounts, exchangeRate } = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getPooledStakes([addressToUse], chainIdToUse, resetCache);
171
228
  this.update((state) => {
172
- state.pooled_staking.pooledStakes = accounts[0];
173
- state.pooled_staking.exchangeRate = exchangeRate;
229
+ const chainState = state.pooled_staking[chainIdToUse] ??
230
+ DEFAULT_POOLED_STAKING_CHAIN_STATE;
231
+ state.pooled_staking[chainIdToUse] = {
232
+ ...chainState,
233
+ pooledStakes: accounts[0],
234
+ exchangeRate,
235
+ };
174
236
  });
175
237
  }
176
238
  /**
@@ -186,11 +248,12 @@ export class EarnController extends BaseController {
186
248
  if (!addressToCheck) {
187
249
  return;
188
250
  }
189
- const { eligible: isEligible } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakingEligibility([
251
+ const { eligible: isEligible } = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getPooledStakingEligibility([
190
252
  addressToCheck,
191
253
  ]);
192
254
  this.update((state) => {
193
255
  state.pooled_staking.isEligible = isEligible;
256
+ state.lending.isEligible = isEligible;
194
257
  });
195
258
  }
196
259
  /**
@@ -198,41 +261,59 @@ export class EarnController extends BaseController {
198
261
  * Updates the vault metadata in the controller state including APY, capacity,
199
262
  * fee percentage, total assets, and vault address.
200
263
  *
264
+ * @param chainId - The chain id to refresh pooled staking vault metadata for (optional).
201
265
  * @returns A promise that resolves when the vault metadata has been updated
202
266
  */
203
- async refreshPooledStakingVaultMetadata() {
204
- const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
205
- const vaultMetadata = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getVaultData(chainId);
267
+ async refreshPooledStakingVaultMetadata(chainId) {
268
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
269
+ const vaultMetadata = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getVaultData(chainIdToUse);
206
270
  this.update((state) => {
207
- state.pooled_staking.vaultMetadata = vaultMetadata;
271
+ const chainState = state.pooled_staking[chainIdToUse] ??
272
+ DEFAULT_POOLED_STAKING_CHAIN_STATE;
273
+ state.pooled_staking[chainIdToUse] = {
274
+ ...chainState,
275
+ vaultMetadata,
276
+ };
208
277
  });
209
278
  }
210
279
  /**
211
280
  * Refreshes pooled staking vault daily apys for the current chain.
212
281
  * Updates the pooled staking vault daily apys controller state.
213
282
  *
283
+ * @param chainId - The chain id to refresh pooled staking vault daily apys for (optional).
214
284
  * @param days - The number of days to fetch pooled staking vault daily apys for (defaults to 365).
215
285
  * @param order - The order in which to fetch pooled staking vault daily apys. Descending order fetches the latest N days (latest working backwards). Ascending order fetches the oldest N days (oldest working forwards) (defaults to 'desc').
216
286
  * @returns A promise that resolves when the pooled staking vault daily apys have been updated.
217
287
  */
218
- async refreshPooledStakingVaultDailyApys(days = 365, order = 'desc') {
219
- const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
220
- const vaultDailyApys = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getVaultDailyApys(chainId, days, order);
288
+ async refreshPooledStakingVaultDailyApys(chainId, days = 365, order = 'desc') {
289
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
290
+ const vaultDailyApys = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getVaultDailyApys(chainIdToUse, days, order);
221
291
  this.update((state) => {
222
- state.pooled_staking.vaultDailyApys = vaultDailyApys;
292
+ const chainState = state.pooled_staking[chainIdToUse] ??
293
+ DEFAULT_POOLED_STAKING_CHAIN_STATE;
294
+ state.pooled_staking[chainIdToUse] = {
295
+ ...chainState,
296
+ vaultDailyApys,
297
+ };
223
298
  });
224
299
  }
225
300
  /**
226
301
  * Refreshes pooled staking vault apy averages for the current chain.
227
302
  * Updates the pooled staking vault apy averages controller state.
228
303
  *
304
+ * @param chainId - The chain id to refresh pooled staking vault apy averages for (optional).
229
305
  * @returns A promise that resolves when the pooled staking vault apy averages have been updated.
230
306
  */
231
- async refreshPooledStakingVaultApyAverages() {
232
- const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
233
- const vaultApyAverages = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getVaultApyAverages(chainId);
307
+ async refreshPooledStakingVaultApyAverages(chainId) {
308
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
309
+ const vaultApyAverages = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getVaultApyAverages(chainIdToUse);
234
310
  this.update((state) => {
235
- state.pooled_staking.vaultApyAverages = vaultApyAverages;
311
+ const chainState = state.pooled_staking[chainIdToUse] ??
312
+ DEFAULT_POOLED_STAKING_CHAIN_STATE;
313
+ state.pooled_staking[chainIdToUse] = {
314
+ ...chainState,
315
+ vaultApyAverages,
316
+ };
236
317
  });
237
318
  }
238
319
  /**
@@ -247,38 +328,305 @@ export class EarnController extends BaseController {
247
328
  * @throws {Error} If any of the refresh operations fail, with concatenated error messages
248
329
  */
249
330
  async refreshPooledStakingData({ resetCache, address, } = {}) {
331
+ const errors = [];
332
+ for (const chainId of __classPrivateFieldGet(this, _EarnController_supportedPooledStakingChains, "f")) {
333
+ await Promise.all([
334
+ this.refreshPooledStakes({ resetCache, address, chainId }).catch((error) => {
335
+ errors.push(error);
336
+ }),
337
+ this.refreshStakingEligibility({ address }).catch((error) => {
338
+ errors.push(error);
339
+ }),
340
+ this.refreshPooledStakingVaultMetadata(chainId).catch((error) => {
341
+ errors.push(error);
342
+ }),
343
+ this.refreshPooledStakingVaultDailyApys(chainId).catch((error) => {
344
+ errors.push(error);
345
+ }),
346
+ this.refreshPooledStakingVaultApyAverages(chainId).catch((error) => {
347
+ errors.push(error);
348
+ }),
349
+ ]);
350
+ }
351
+ if (errors.length > 0) {
352
+ throw new Error(`Failed to refresh some staking data: ${errors
353
+ .map((e) => e.message)
354
+ .join(', ')}`);
355
+ }
356
+ }
357
+ /**
358
+ * Refreshes the lending markets data for all chains.
359
+ * Updates the lending markets in the controller state.
360
+ *
361
+ * @returns A promise that resolves when the lending markets have been updated
362
+ */
363
+ async refreshLendingMarkets() {
364
+ const markets = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").lending.getMarkets();
365
+ this.update((state) => {
366
+ state.lending.markets = markets;
367
+ });
368
+ }
369
+ /**
370
+ * Refreshes the lending positions for the current account.
371
+ * Updates the lending positions in the controller state.
372
+ *
373
+ * @param options - Optional arguments
374
+ * @param [options.address] - The address to refresh lending positions for (optional).
375
+ * @returns A promise that resolves when the lending positions have been updated
376
+ */
377
+ async refreshLendingPositions({ address, } = {}) {
378
+ const addressToUse = address ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
379
+ if (!addressToUse) {
380
+ return;
381
+ }
382
+ // linter complaining about this not being a promise, but it is
383
+ // TODO: figure out why this is not seen as a promise
384
+ const positions = await Promise.resolve(__classPrivateFieldGet(this, _EarnController_earnApiService, "f").lending.getPositions(addressToUse));
385
+ this.update((state) => {
386
+ state.lending.positions = positions.map((position) => ({
387
+ ...position,
388
+ marketId: position.market.id,
389
+ marketAddress: position.market.address,
390
+ protocol: position.market.protocol,
391
+ }));
392
+ });
393
+ }
394
+ /**
395
+ * Refreshes the lending eligibility status for the current account.
396
+ * Updates the eligibility status in the controller state based on the location and address blocklist for compliance.
397
+ *
398
+ * @param options - Optional arguments
399
+ * @param [options.address] - The address to refresh lending eligibility for (optional).
400
+ * @returns A promise that resolves when the eligibility status has been updated
401
+ */
402
+ async refreshLendingEligibility({ address, } = {}) {
403
+ const addressToUse = address ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
404
+ // TODO: this is a temporary solution to refresh lending eligibility as
405
+ // the eligibility check is not yet implemented for lending
406
+ // this check will check the address against the same blocklist as the
407
+ // staking eligibility check
408
+ if (!addressToUse) {
409
+ return;
410
+ }
411
+ const { eligible: isEligible } = await __classPrivateFieldGet(this, _EarnController_earnApiService, "f").pooledStaking.getPooledStakingEligibility([
412
+ addressToUse,
413
+ ]);
414
+ this.update((state) => {
415
+ state.lending.isEligible = isEligible;
416
+ state.pooled_staking.isEligible = isEligible;
417
+ });
418
+ }
419
+ /**
420
+ * Refreshes all lending related data including markets, positions, and eligibility.
421
+ * This method allows partial success, meaning some data may update while other requests fail.
422
+ * All errors are collected and thrown as a single error message.
423
+ *
424
+ * @returns A promise that resolves when all possible data has been updated
425
+ * @throws {Error} If any of the refresh operations fail, with concatenated error messages
426
+ */
427
+ async refreshLendingData() {
250
428
  const errors = [];
251
429
  await Promise.all([
252
- this.refreshPooledStakes({ resetCache, address }).catch((error) => {
430
+ this.refreshLendingMarkets().catch((error) => {
253
431
  errors.push(error);
254
432
  }),
255
- this.refreshStakingEligibility({ address }).catch((error) => {
433
+ this.refreshLendingPositions().catch((error) => {
256
434
  errors.push(error);
257
435
  }),
258
- this.refreshPooledStakingVaultMetadata().catch((error) => {
259
- errors.push(error);
260
- }),
261
- this.refreshPooledStakingVaultDailyApys().catch((error) => {
262
- errors.push(error);
263
- }),
264
- this.refreshPooledStakingVaultApyAverages().catch((error) => {
436
+ this.refreshLendingEligibility().catch((error) => {
265
437
  errors.push(error);
266
438
  }),
267
439
  ]);
268
440
  if (errors.length > 0) {
269
- throw new Error(`Failed to refresh some staking data: ${errors
441
+ throw new Error(`Failed to refresh some lending data: ${errors
270
442
  .map((e) => e.message)
271
443
  .join(', ')}`);
272
444
  }
273
445
  }
446
+ /**
447
+ * Gets the lending position history for the current account.
448
+ *
449
+ * @param options - Optional arguments
450
+ * @param [options.address] - The address to get lending position history for (optional).
451
+ * @param [options.chainId] - The chain id to get lending position history for (optional).
452
+ * @param [options.positionId] - The position id to get lending position history for.
453
+ * @param [options.marketId] - The market id to get lending position history for.
454
+ * @param [options.marketAddress] - The market address to get lending position history for.
455
+ * @param [options.protocol] - The protocol to get lending position history for.
456
+ * @param [options.days] - The number of days to get lending position history for (optional).
457
+ * @returns A promise that resolves when the lending position history has been updated
458
+ */
459
+ getLendingPositionHistory({ address, chainId, positionId, marketId, marketAddress, protocol, days = 730, }) {
460
+ const addressToUse = address ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
461
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
462
+ if (!addressToUse) {
463
+ return [];
464
+ }
465
+ return __classPrivateFieldGet(this, _EarnController_earnApiService, "f").lending.getPositionHistory(addressToUse, chainIdToUse, protocol, marketId, marketAddress, positionId, days);
466
+ }
467
+ /**
468
+ * Gets the lending market daily apys and averages for the current chain.
469
+ *
470
+ * @param options - Optional arguments
471
+ * @param [options.chainId] - The chain id to get lending market daily apys and averages for (optional).
472
+ * @param [options.protocol] - The protocol to get lending market daily apys and averages for.
473
+ * @param [options.marketId] - The market id to get lending market daily apys and averages for.
474
+ * @param [options.days] - The number of days to get lending market daily apys and averages for (optional).
475
+ * @returns A promise that resolves when the lending market daily apys and averages have been updated
476
+ */
477
+ getLendingMarketDailyApysAndAverages({ chainId, protocol, marketId, days = 365, }) {
478
+ const chainIdToUse = chainId ?? __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
479
+ return __classPrivateFieldGet(this, _EarnController_earnApiService, "f").lending.getHistoricMarketApys(chainIdToUse, protocol, marketId, days);
480
+ }
481
+ /**
482
+ * Executes a lending deposit transaction.
483
+ *
484
+ * @param options - The options for the lending deposit transaction.
485
+ * @param options.amount - The amount to deposit.
486
+ * @param options.protocol - The protocol of the lending market.
487
+ * @param options.underlyingTokenAddress - The address of the underlying token.
488
+ * @param options.gasOptions - The gas options for the transaction.
489
+ * @param options.gasOptions.gasLimit - The gas limit for the transaction.
490
+ * @param options.gasOptions.gasBufferPct - The gas buffer percentage for the transaction.
491
+ * @param options.txOptions - The transaction options for the transaction.
492
+ * @returns A promise that resolves to the transaction hash.
493
+ */
494
+ async executeLendingDeposit({ amount, protocol, underlyingTokenAddress, gasOptions, txOptions, }) {
495
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
496
+ const transactionData = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.encodeDepositTransactionData(amount, address, gasOptions);
497
+ if (!transactionData) {
498
+ throw new Error('Transaction data not found');
499
+ }
500
+ if (!__classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
501
+ throw new Error('Selected network client id not found');
502
+ }
503
+ const txHash = await __classPrivateFieldGet(this, _EarnController_addTransactionFn, "f").call(this, {
504
+ ...transactionData,
505
+ value: transactionData.value.toString(),
506
+ chainId: toHex(__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this)),
507
+ gasLimit: String(transactionData.gasLimit),
508
+ }, {
509
+ ...txOptions,
510
+ networkClientId: __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f"),
511
+ });
512
+ return txHash;
513
+ }
514
+ /**
515
+ * Executes a lending withdraw transaction.
516
+ *
517
+ * @param options - The options for the lending withdraw transaction.
518
+ * @param options.amount - The amount to withdraw.
519
+ * @param options.protocol - The protocol of the lending market.
520
+ * @param options.underlyingTokenAddress - The address of the underlying token.
521
+ * @param options.gasOptions - The gas options for the transaction.
522
+ * @param options.gasOptions.gasLimit - The gas limit for the transaction.
523
+ * @param options.gasOptions.gasBufferPct - The gas buffer percentage for the transaction.
524
+ * @param options.txOptions - The transaction options for the transaction.
525
+ * @returns A promise that resolves to the transaction hash.
526
+ */
527
+ async executeLendingWithdraw({ amount, protocol, underlyingTokenAddress, gasOptions, txOptions, }) {
528
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
529
+ const transactionData = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.encodeWithdrawTransactionData(amount, address, gasOptions);
530
+ if (!transactionData) {
531
+ throw new Error('Transaction data not found');
532
+ }
533
+ if (!__classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
534
+ throw new Error('Selected network client id not found');
535
+ }
536
+ const txHash = await __classPrivateFieldGet(this, _EarnController_addTransactionFn, "f").call(this, {
537
+ ...transactionData,
538
+ value: transactionData.value.toString(),
539
+ chainId: toHex(__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this)),
540
+ gasLimit: String(transactionData.gasLimit),
541
+ }, {
542
+ ...txOptions,
543
+ networkClientId: __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f"),
544
+ });
545
+ return txHash;
546
+ }
547
+ /**
548
+ * Executes a lending token approve transaction.
549
+ *
550
+ * @param options - The options for the lending token approve transaction.
551
+ * @param options.amount - The amount to approve.
552
+ * @param options.protocol - The protocol of the lending market.
553
+ * @param options.underlyingTokenAddress - The address of the underlying token.
554
+ * @param options.gasOptions - The gas options for the transaction.
555
+ * @param options.gasOptions.gasLimit - The gas limit for the transaction.
556
+ * @param options.gasOptions.gasBufferPct - The gas buffer percentage for the transaction.
557
+ * @param options.txOptions - The transaction options for the transaction.
558
+ * @returns A promise that resolves to the transaction hash.
559
+ */
560
+ async executeLendingTokenApprove({ protocol, amount, underlyingTokenAddress, gasOptions, txOptions, }) {
561
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
562
+ const transactionData = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.encodeUnderlyingTokenApproveTransactionData(amount, address, gasOptions);
563
+ if (!transactionData) {
564
+ throw new Error('Transaction data not found');
565
+ }
566
+ if (!__classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
567
+ throw new Error('Selected network client id not found');
568
+ }
569
+ const txHash = await __classPrivateFieldGet(this, _EarnController_addTransactionFn, "f").call(this, {
570
+ ...transactionData,
571
+ value: transactionData.value.toString(),
572
+ chainId: toHex(__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this)),
573
+ gasLimit: String(transactionData.gasLimit),
574
+ }, {
575
+ ...txOptions,
576
+ networkClientId: __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f"),
577
+ });
578
+ return txHash;
579
+ }
580
+ /**
581
+ * Gets the allowance for a lending token.
582
+ *
583
+ * @param protocol - The protocol of the lending market.
584
+ * @param underlyingTokenAddress - The address of the underlying token.
585
+ * @returns A promise that resolves to the allowance.
586
+ */
587
+ async getLendingTokenAllowance(protocol, underlyingTokenAddress) {
588
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
589
+ const allowance = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.underlyingTokenAllowance(address);
590
+ return allowance;
591
+ }
592
+ /**
593
+ * Gets the maximum withdraw amount for a lending token's output token or shares if no output token.
594
+ *
595
+ * @param protocol - The protocol of the lending market.
596
+ * @param underlyingTokenAddress - The address of the underlying token.
597
+ * @returns A promise that resolves to the maximum withdraw amount.
598
+ */
599
+ async getLendingTokenMaxWithdraw(protocol, underlyingTokenAddress) {
600
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
601
+ const maxWithdraw = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.maxWithdraw(address);
602
+ return maxWithdraw;
603
+ }
604
+ /**
605
+ * Gets the maximum deposit amount for a lending token.
606
+ *
607
+ * @param protocol - The protocol of the lending market.
608
+ * @param underlyingTokenAddress - The address of the underlying token.
609
+ * @returns A promise that resolves to the maximum deposit amount.
610
+ */
611
+ async getLendingTokenMaxDeposit(protocol, underlyingTokenAddress) {
612
+ const address = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this)?.address;
613
+ const maxDeposit = await __classPrivateFieldGet(this, _EarnController_earnSDK, "f")?.contracts?.lending?.[protocol]?.[underlyingTokenAddress]?.maxDeposit(address);
614
+ return maxDeposit;
615
+ }
274
616
  }
275
- _EarnController_stakeSDK = new WeakMap(), _EarnController_selectedNetworkClientId = new WeakMap(), _EarnController_stakingApiService = new WeakMap(), _EarnController_instances = new WeakSet(), _EarnController_initializeSDK = function _EarnController_initializeSDK(networkClientId) {
617
+ _EarnController_earnSDK = new WeakMap(), _EarnController_selectedNetworkClientId = new WeakMap(), _EarnController_earnApiService = new WeakMap(), _EarnController_addTransactionFn = new WeakMap(), _EarnController_supportedPooledStakingChains = new WeakMap(), _EarnController_instances = new WeakSet(), _EarnController_initializeSDK =
618
+ /**
619
+ * Initializes the Earn SDK.
620
+ *
621
+ * @param networkClientId - The network client id to initialize the Earn SDK for (optional).
622
+ */
623
+ async function _EarnController_initializeSDK(networkClientId) {
276
624
  const { selectedNetworkClientId } = networkClientId
277
625
  ? { selectedNetworkClientId: networkClientId }
278
626
  : this.messagingSystem.call('NetworkController:getState');
279
627
  const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
280
628
  if (!networkClient?.provider) {
281
- __classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
629
+ __classPrivateFieldSet(this, _EarnController_earnSDK, null, "f");
282
630
  return;
283
631
  }
284
632
  const provider = new Web3Provider(networkClient.provider);
@@ -288,31 +636,23 @@ _EarnController_stakeSDK = new WeakMap(), _EarnController_selectedNetworkClientI
288
636
  chainId: convertHexToDecimal(chainId),
289
637
  };
290
638
  try {
291
- __classPrivateFieldSet(this, _EarnController_stakeSDK, StakeSdk.create(config), "f");
292
- __classPrivateFieldGet(this, _EarnController_stakeSDK, "f").pooledStakingContract.connectSignerOrProvider(provider);
639
+ __classPrivateFieldSet(this, _EarnController_earnSDK, await EarnSdk.create(provider, config), "f");
293
640
  }
294
641
  catch (error) {
295
- __classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
642
+ __classPrivateFieldSet(this, _EarnController_earnSDK, null, "f");
296
643
  // Only log unexpected errors, not unsupported chain errors
297
644
  if (!(error instanceof Error &&
298
645
  error.message.includes('Unsupported chainId'))) {
299
- console.error('Stake SDK initialization failed:', error);
646
+ console.error('Earn SDK initialization failed:', error);
300
647
  }
301
648
  }
302
649
  }, _EarnController_getCurrentAccount = function _EarnController_getCurrentAccount() {
303
650
  return this.messagingSystem.call('AccountsController:getSelectedAccount');
304
- }, _EarnController_getCurrentChainId = function _EarnController_getCurrentChainId() {
305
- // const { selectedNetworkClientId } = this.messagingSystem.call(
306
- // 'NetworkController:getState',
307
- // );
308
- // const {
309
- // configuration: { chainId },
310
- // } = this.messagingSystem.call(
311
- // 'NetworkController:getNetworkClientById',
312
- // selectedNetworkClientId,
313
- // );
314
- // return convertHexToDecimal(chainId);
315
- // TEMP: Until we update our data-fetching and storage solution to not depend on single selected network.
316
- return ChainId.ETHEREUM;
651
+ }, _EarnController_getCurrentChainId = function _EarnController_getCurrentChainId(networkClientId) {
652
+ const networkClientIdToUse = networkClientId ??
653
+ this.messagingSystem.call('NetworkController:getState')
654
+ .selectedNetworkClientId;
655
+ const { configuration: { chainId }, } = this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientIdToUse);
656
+ return convertHexToDecimal(chainId);
317
657
  };
318
658
  //# sourceMappingURL=EarnController.mjs.map