@metamask-previews/earn-controller 0.10.0-preview-7f6d1f4 → 0.11.0-preview-c7dcfd5a

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.0]
11
+
12
+ ### Added
13
+
14
+ - Refresh staking data when staking txs are confirmed ([#5607](https://github.com/MetaMask/core/pull/5607))
15
+
10
16
  ### Changed
11
17
 
12
18
  - Bump `@metamask/controller-utils` to `^11.7.0` ([#5583](https://github.com/MetaMask/core/pull/5583))
@@ -79,7 +85,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
79
85
 
80
86
  - Initial release ([#5271](https://github.com/MetaMask/core/pull/5271))
81
87
 
82
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.10.0...HEAD
88
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.11.0...HEAD
89
+ [0.11.0]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.10.0...@metamask/earn-controller@0.11.0
83
90
  [0.10.0]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.9.0...@metamask/earn-controller@0.10.0
84
91
  [0.9.0]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.8.0...@metamask/earn-controller@0.9.0
85
92
  [0.8.0]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.7.0...@metamask/earn-controller@0.8.0
@@ -17,7 +17,13 @@ const providers_1 = require("@ethersproject/providers");
17
17
  const base_controller_1 = require("@metamask/base-controller");
18
18
  const controller_utils_1 = require("@metamask/controller-utils");
19
19
  const stake_sdk_1 = require("@metamask/stake-sdk");
20
+ const transaction_controller_1 = require("@metamask/transaction-controller");
20
21
  exports.controllerName = 'EarnController';
22
+ const stakingTransactionTypes = new Set([
23
+ transaction_controller_1.TransactionType.stakingDeposit,
24
+ transaction_controller_1.TransactionType.stakingUnstake,
25
+ transaction_controller_1.TransactionType.stakingClaim,
26
+ ]);
21
27
  /**
22
28
  * Metadata for the EarnController.
23
29
  */
@@ -110,6 +116,7 @@ class EarnController extends base_controller_1.BaseController {
110
116
  this.refreshPooledStakingData().catch(console.error);
111
117
  const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
112
118
  __classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, selectedNetworkClientId, "f");
119
+ // Listen for network changes
113
120
  this.messagingSystem.subscribe('NetworkController:stateChange', (networkControllerState) => {
114
121
  if (networkControllerState.selectedNetworkClientId !==
115
122
  __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
@@ -132,6 +139,21 @@ class EarnController extends base_controller_1.BaseController {
132
139
  this.refreshStakingEligibility({ address }).catch(console.error);
133
140
  this.refreshPooledStakes({ address }).catch(console.error);
134
141
  });
142
+ // Listen for confirmed staking transactions
143
+ this.messagingSystem.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
144
+ /**
145
+ * When we speed up a transaction, we set the type as Retry and we lose
146
+ * information about type of transaction that is being set up, so we use
147
+ * original type to track that information.
148
+ */
149
+ const { type, originalType } = transactionMeta;
150
+ const isStakingTransaction = stakingTransactionTypes.has(type) ||
151
+ stakingTransactionTypes.has(originalType);
152
+ if (isStakingTransaction) {
153
+ const sender = transactionMeta.txParams.from;
154
+ this.refreshPooledStakes({ resetCache: true, address: sender }).catch(console.error);
155
+ }
156
+ });
135
157
  }
136
158
  /**
137
159
  * Refreshes the pooled stakes data for the current account.
@@ -1 +1 @@
1
- {"version":3,"file":"EarnController.cjs","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n type VaultDailyApy,\n type VaultApyAverages,\n} from '@metamask/stake-sdk';\n\nimport type {\n RefreshPooledStakesOptions,\n RefreshPooledStakingDataOptions,\n RefreshStakingEligibilityOptions,\n} from './types';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultMetadata: VaultData;\n vaultDailyApys: VaultDailyApy[];\n vaultApyAverages: VaultApyAverages;\n isEligible: boolean;\n};\n\nexport type StablecoinLendingState = {\n vaults: StablecoinVault[];\n};\n\nexport type StablecoinVault = {\n symbol: string;\n name: string;\n chainId: number;\n tokenAddress: string;\n vaultAddress: string;\n currentAPY: string;\n supply: string;\n liquidity: string;\n};\n\n/**\n * Metadata for the EarnController.\n */\nconst earnControllerMetadata: StateMetadata<EarnControllerState> = {\n pooled_staking: {\n persist: true,\n anonymous: false,\n },\n stablecoin_lending: {\n persist: true,\n anonymous: false,\n },\n lastUpdated: {\n persist: false,\n anonymous: true,\n },\n};\n\n// === State Types ===\nexport type EarnControllerState = {\n pooled_staking: PooledStakingState;\n stablecoin_lending?: StablecoinLendingState;\n lastUpdated: number;\n};\n\n// === Default State ===\nconst DEFAULT_STABLECOIN_VAULT: StablecoinVault = {\n symbol: '',\n name: '',\n chainId: 0,\n tokenAddress: '',\n vaultAddress: '',\n currentAPY: '0',\n supply: '0',\n liquidity: '0',\n};\n\nconst DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES: VaultApyAverages = {\n oneDay: '0',\n oneWeek: '0',\n oneMonth: '0',\n threeMonths: '0',\n sixMonths: '0',\n oneYear: '0',\n};\n\n/**\n * Gets the default state for the EarnController.\n *\n * @returns The default EarnController state.\n */\nexport function getDefaultEarnControllerState(): EarnControllerState {\n return {\n pooled_staking: {\n pooledStakes: {\n account: '',\n lifetimeRewards: '0',\n assets: '0',\n exitRequests: [],\n },\n exchangeRate: '1',\n vaultMetadata: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\n vaultDailyApys: [],\n vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,\n isEligible: false,\n },\n stablecoin_lending: {\n vaults: [DEFAULT_STABLECOIN_VAULT],\n },\n lastUpdated: 0,\n };\n}\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the EarnController.\n */\nexport type EarnControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All actions that EarnController registers, to be called externally.\n */\nexport type EarnControllerActions = EarnControllerGetStateAction;\n\n/**\n * All actions that EarnController calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The event that EarnController publishes when updating state.\n */\nexport type EarnControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All events that EarnController publishes, to be subscribed to externally.\n */\nexport type EarnControllerEvents = EarnControllerStateChangeEvent;\n\n/**\n * All events that EarnController subscribes to internally.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedAccountChangeEvent\n | NetworkControllerStateChangeEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * EarnController.\n */\nexport type EarnControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n EarnControllerActions | AllowedActions,\n EarnControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * EarnController manages DeFi earning opportunities across different protocols and chains.\n */\nexport class EarnController extends BaseController<\n typeof controllerName,\n EarnControllerState,\n EarnControllerMessenger\n> {\n #stakeSDK: StakeSdk | null = null;\n\n #selectedNetworkClientId?: string;\n\n readonly #stakingApiService: StakingApiService = new StakingApiService();\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: EarnControllerMessenger;\n state?: Partial<EarnControllerState>;\n }) {\n super({\n name: controllerName,\n metadata: earnControllerMetadata,\n messenger,\n state: {\n ...getDefaultEarnControllerState(),\n ...state,\n },\n });\n\n this.#initializeSDK();\n this.refreshPooledStakingData().catch(console.error);\n\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n this.#selectedNetworkClientId = selectedNetworkClientId;\n\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) => {\n if (\n networkControllerState.selectedNetworkClientId !==\n this.#selectedNetworkClientId\n ) {\n this.#initializeSDK(networkControllerState.selectedNetworkClientId);\n this.refreshPooledStakingVaultMetadata().catch(console.error);\n this.refreshPooledStakingVaultDailyApys().catch(console.error);\n this.refreshPooledStakingVaultApyAverages().catch(console.error);\n this.refreshPooledStakes().catch(console.error);\n }\n this.#selectedNetworkClientId =\n networkControllerState.selectedNetworkClientId;\n },\n );\n\n // Listen for account changes\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => {\n const address = account?.address;\n /**\n * TEMP: There's a race condition where the account state isn't updated immediately.\n * Until this has been fixed, we rely on the event payload for the latest account instead of #getCurrentAccount().\n * Issue: https://github.com/MetaMask/accounts-planning/issues/887\n */\n this.refreshStakingEligibility({ address }).catch(console.error);\n this.refreshPooledStakes({ address }).catch(console.error);\n },\n );\n }\n\n #initializeSDK(networkClientId?: string) {\n const { selectedNetworkClientId } = networkClientId\n ? { selectedNetworkClientId: networkClientId }\n : this.messagingSystem.call('NetworkController:getState');\n\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (!networkClient?.provider) {\n this.#stakeSDK = null;\n return;\n }\n\n const provider = new Web3Provider(networkClient.provider);\n const { chainId } = networkClient.configuration;\n\n // Initialize appropriate contracts based on chainId\n const config: StakeSdkConfig = {\n chainId: convertHexToDecimal(chainId),\n };\n\n try {\n this.#stakeSDK = StakeSdk.create(config);\n this.#stakeSDK.pooledStakingContract.connectSignerOrProvider(provider);\n } catch (error) {\n this.#stakeSDK = null;\n // Only log unexpected errors, not unsupported chain errors\n if (\n !(\n error instanceof Error &&\n error.message.includes('Unsupported chainId')\n )\n ) {\n console.error('Stake SDK initialization failed:', error);\n }\n }\n }\n\n #getCurrentAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getCurrentChainId(): number {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return convertHexToDecimal(chainId);\n }\n\n /**\n * Refreshes the pooled stakes data for the current account.\n * Fetches updated stake information including lifetime rewards, assets, and exit requests\n * from the staking API service and updates the state.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes({\n resetCache = false,\n address,\n }: RefreshPooledStakesOptions = {}): Promise<void> {\n const addressToUse = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToUse) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [addressToUse],\n chainId,\n resetCache,\n );\n\n this.update((state) => {\n state.pooled_staking.pooledStakes = accounts[0];\n state.pooled_staking.exchangeRate = exchangeRate;\n });\n }\n\n /**\n * Refreshes the staking eligibility status for the current account.\n * Updates the eligibility status in the controller state based on the location and address blocklist for compliance.\n *\n * @param options - Optional arguments\n * @param [options.address] - Address to refresh staking eligibility for (optional).\n * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility({\n address,\n }: RefreshStakingEligibilityOptions = {}): Promise<void> {\n const addressToCheck = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToCheck) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n addressToCheck,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes pooled staking vault metadata for the current chain.\n * Updates the vault metadata in the controller state including APY, capacity,\n * fee percentage, total assets, and vault address.\n *\n * @returns A promise that resolves when the vault metadata has been updated\n */\n async refreshPooledStakingVaultMetadata(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultMetadata = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultMetadata = vaultMetadata;\n });\n }\n\n /**\n * Refreshes pooled staking vault daily apys for the current chain.\n * Updates the pooled staking vault daily apys controller state.\n *\n * @param days - The number of days to fetch pooled staking vault daily apys for (defaults to 365).\n * @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').\n * @returns A promise that resolves when the pooled staking vault daily apys have been updated.\n */\n async refreshPooledStakingVaultDailyApys(\n days = 365,\n order: 'asc' | 'desc' = 'desc',\n ): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultDailyApys = await this.#stakingApiService.getVaultDailyApys(\n chainId,\n days,\n order,\n );\n\n this.update((state) => {\n state.pooled_staking.vaultDailyApys = vaultDailyApys;\n });\n }\n\n /**\n * Refreshes pooled staking vault apy averages for the current chain.\n * Updates the pooled staking vault apy averages controller state.\n *\n * @returns A promise that resolves when the pooled staking vault apy averages have been updated.\n */\n async refreshPooledStakingVaultApyAverages() {\n const chainId = this.#getCurrentChainId();\n const vaultApyAverages =\n await this.#stakingApiService.getVaultApyAverages(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultApyAverages = vaultApyAverages;\n });\n }\n\n /**\n * Refreshes all pooled staking related data including stakes, eligibility, and vault data.\n * This method allows partial success, meaning some data may update while other requests fail.\n * All errors are collected and thrown as a single error message.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when all possible data has been updated\n * @throws {Error} If any of the refresh operations fail, with concatenated error messages\n */\n async refreshPooledStakingData({\n resetCache,\n address,\n }: RefreshPooledStakingDataOptions = {}): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes({ resetCache, address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility({ address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultMetadata().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultDailyApys().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultApyAverages().catch((error) => {\n errors.push(error);\n }),\n ]);\n\n if (errors.length > 0) {\n throw new Error(\n `Failed to refresh some staking data: ${errors\n .map((e) => e.message)\n .join(', ')}`,\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"EarnController.cjs","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n type VaultDailyApy,\n type VaultApyAverages,\n} from '@metamask/stake-sdk';\nimport {\n TransactionType,\n type TransactionControllerTransactionConfirmedEvent,\n} from '@metamask/transaction-controller';\n\nimport type {\n RefreshPooledStakesOptions,\n RefreshPooledStakingDataOptions,\n RefreshStakingEligibilityOptions,\n} from './types';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultMetadata: VaultData;\n vaultDailyApys: VaultDailyApy[];\n vaultApyAverages: VaultApyAverages;\n isEligible: boolean;\n};\n\nexport type StablecoinLendingState = {\n vaults: StablecoinVault[];\n};\n\nexport type StablecoinVault = {\n symbol: string;\n name: string;\n chainId: number;\n tokenAddress: string;\n vaultAddress: string;\n currentAPY: string;\n supply: string;\n liquidity: string;\n};\n\ntype StakingTransactionTypes =\n | TransactionType.stakingDeposit\n | TransactionType.stakingUnstake\n | TransactionType.stakingClaim;\n\nconst stakingTransactionTypes = new Set<StakingTransactionTypes>([\n TransactionType.stakingDeposit,\n TransactionType.stakingUnstake,\n TransactionType.stakingClaim,\n]);\n\n/**\n * Metadata for the EarnController.\n */\nconst earnControllerMetadata: StateMetadata<EarnControllerState> = {\n pooled_staking: {\n persist: true,\n anonymous: false,\n },\n stablecoin_lending: {\n persist: true,\n anonymous: false,\n },\n lastUpdated: {\n persist: false,\n anonymous: true,\n },\n};\n\n// === State Types ===\nexport type EarnControllerState = {\n pooled_staking: PooledStakingState;\n stablecoin_lending?: StablecoinLendingState;\n lastUpdated: number;\n};\n\n// === Default State ===\nconst DEFAULT_STABLECOIN_VAULT: StablecoinVault = {\n symbol: '',\n name: '',\n chainId: 0,\n tokenAddress: '',\n vaultAddress: '',\n currentAPY: '0',\n supply: '0',\n liquidity: '0',\n};\n\nconst DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES: VaultApyAverages = {\n oneDay: '0',\n oneWeek: '0',\n oneMonth: '0',\n threeMonths: '0',\n sixMonths: '0',\n oneYear: '0',\n};\n\n/**\n * Gets the default state for the EarnController.\n *\n * @returns The default EarnController state.\n */\nexport function getDefaultEarnControllerState(): EarnControllerState {\n return {\n pooled_staking: {\n pooledStakes: {\n account: '',\n lifetimeRewards: '0',\n assets: '0',\n exitRequests: [],\n },\n exchangeRate: '1',\n vaultMetadata: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\n vaultDailyApys: [],\n vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,\n isEligible: false,\n },\n stablecoin_lending: {\n vaults: [DEFAULT_STABLECOIN_VAULT],\n },\n lastUpdated: 0,\n };\n}\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the EarnController.\n */\nexport type EarnControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All actions that EarnController registers, to be called externally.\n */\nexport type EarnControllerActions = EarnControllerGetStateAction;\n\n/**\n * All actions that EarnController calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The event that EarnController publishes when updating state.\n */\nexport type EarnControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All events that EarnController publishes, to be subscribed to externally.\n */\nexport type EarnControllerEvents = EarnControllerStateChangeEvent;\n\n/**\n * All events that EarnController subscribes to internally.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedAccountChangeEvent\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * EarnController.\n */\nexport type EarnControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n EarnControllerActions | AllowedActions,\n EarnControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * EarnController manages DeFi earning opportunities across different protocols and chains.\n */\nexport class EarnController extends BaseController<\n typeof controllerName,\n EarnControllerState,\n EarnControllerMessenger\n> {\n #stakeSDK: StakeSdk | null = null;\n\n #selectedNetworkClientId?: string;\n\n readonly #stakingApiService: StakingApiService = new StakingApiService();\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: EarnControllerMessenger;\n state?: Partial<EarnControllerState>;\n }) {\n super({\n name: controllerName,\n metadata: earnControllerMetadata,\n messenger,\n state: {\n ...getDefaultEarnControllerState(),\n ...state,\n },\n });\n\n this.#initializeSDK();\n this.refreshPooledStakingData().catch(console.error);\n\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n this.#selectedNetworkClientId = selectedNetworkClientId;\n\n // Listen for network changes\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) => {\n if (\n networkControllerState.selectedNetworkClientId !==\n this.#selectedNetworkClientId\n ) {\n this.#initializeSDK(networkControllerState.selectedNetworkClientId);\n this.refreshPooledStakingVaultMetadata().catch(console.error);\n this.refreshPooledStakingVaultDailyApys().catch(console.error);\n this.refreshPooledStakingVaultApyAverages().catch(console.error);\n this.refreshPooledStakes().catch(console.error);\n }\n this.#selectedNetworkClientId =\n networkControllerState.selectedNetworkClientId;\n },\n );\n\n // Listen for account changes\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => {\n const address = account?.address;\n /**\n * TEMP: There's a race condition where the account state isn't updated immediately.\n * Until this has been fixed, we rely on the event payload for the latest account instead of #getCurrentAccount().\n * Issue: https://github.com/MetaMask/accounts-planning/issues/887\n */\n this.refreshStakingEligibility({ address }).catch(console.error);\n this.refreshPooledStakes({ address }).catch(console.error);\n },\n );\n\n // Listen for confirmed staking transactions\n this.messagingSystem.subscribe(\n 'TransactionController:transactionConfirmed',\n (transactionMeta) => {\n /**\n * When we speed up a transaction, we set the type as Retry and we lose\n * information about type of transaction that is being set up, so we use\n * original type to track that information.\n */\n const { type, originalType } = transactionMeta;\n\n const isStakingTransaction =\n stakingTransactionTypes.has(type as StakingTransactionTypes) ||\n stakingTransactionTypes.has(originalType as StakingTransactionTypes);\n\n if (isStakingTransaction) {\n const sender = transactionMeta.txParams.from;\n this.refreshPooledStakes({ resetCache: true, address: sender }).catch(\n console.error,\n );\n }\n },\n );\n }\n\n #initializeSDK(networkClientId?: string) {\n const { selectedNetworkClientId } = networkClientId\n ? { selectedNetworkClientId: networkClientId }\n : this.messagingSystem.call('NetworkController:getState');\n\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (!networkClient?.provider) {\n this.#stakeSDK = null;\n return;\n }\n\n const provider = new Web3Provider(networkClient.provider);\n const { chainId } = networkClient.configuration;\n\n // Initialize appropriate contracts based on chainId\n const config: StakeSdkConfig = {\n chainId: convertHexToDecimal(chainId),\n };\n\n try {\n this.#stakeSDK = StakeSdk.create(config);\n this.#stakeSDK.pooledStakingContract.connectSignerOrProvider(provider);\n } catch (error) {\n this.#stakeSDK = null;\n // Only log unexpected errors, not unsupported chain errors\n if (\n !(\n error instanceof Error &&\n error.message.includes('Unsupported chainId')\n )\n ) {\n console.error('Stake SDK initialization failed:', error);\n }\n }\n }\n\n #getCurrentAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getCurrentChainId(): number {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return convertHexToDecimal(chainId);\n }\n\n /**\n * Refreshes the pooled stakes data for the current account.\n * Fetches updated stake information including lifetime rewards, assets, and exit requests\n * from the staking API service and updates the state.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes({\n resetCache = false,\n address,\n }: RefreshPooledStakesOptions = {}): Promise<void> {\n const addressToUse = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToUse) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [addressToUse],\n chainId,\n resetCache,\n );\n\n this.update((state) => {\n state.pooled_staking.pooledStakes = accounts[0];\n state.pooled_staking.exchangeRate = exchangeRate;\n });\n }\n\n /**\n * Refreshes the staking eligibility status for the current account.\n * Updates the eligibility status in the controller state based on the location and address blocklist for compliance.\n *\n * @param options - Optional arguments\n * @param [options.address] - Address to refresh staking eligibility for (optional).\n * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility({\n address,\n }: RefreshStakingEligibilityOptions = {}): Promise<void> {\n const addressToCheck = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToCheck) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n addressToCheck,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes pooled staking vault metadata for the current chain.\n * Updates the vault metadata in the controller state including APY, capacity,\n * fee percentage, total assets, and vault address.\n *\n * @returns A promise that resolves when the vault metadata has been updated\n */\n async refreshPooledStakingVaultMetadata(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultMetadata = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultMetadata = vaultMetadata;\n });\n }\n\n /**\n * Refreshes pooled staking vault daily apys for the current chain.\n * Updates the pooled staking vault daily apys controller state.\n *\n * @param days - The number of days to fetch pooled staking vault daily apys for (defaults to 365).\n * @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').\n * @returns A promise that resolves when the pooled staking vault daily apys have been updated.\n */\n async refreshPooledStakingVaultDailyApys(\n days = 365,\n order: 'asc' | 'desc' = 'desc',\n ): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultDailyApys = await this.#stakingApiService.getVaultDailyApys(\n chainId,\n days,\n order,\n );\n\n this.update((state) => {\n state.pooled_staking.vaultDailyApys = vaultDailyApys;\n });\n }\n\n /**\n * Refreshes pooled staking vault apy averages for the current chain.\n * Updates the pooled staking vault apy averages controller state.\n *\n * @returns A promise that resolves when the pooled staking vault apy averages have been updated.\n */\n async refreshPooledStakingVaultApyAverages() {\n const chainId = this.#getCurrentChainId();\n const vaultApyAverages =\n await this.#stakingApiService.getVaultApyAverages(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultApyAverages = vaultApyAverages;\n });\n }\n\n /**\n * Refreshes all pooled staking related data including stakes, eligibility, and vault data.\n * This method allows partial success, meaning some data may update while other requests fail.\n * All errors are collected and thrown as a single error message.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when all possible data has been updated\n * @throws {Error} If any of the refresh operations fail, with concatenated error messages\n */\n async refreshPooledStakingData({\n resetCache,\n address,\n }: RefreshPooledStakingDataOptions = {}): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes({ resetCache, address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility({ address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultMetadata().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultDailyApys().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultApyAverages().catch((error) => {\n errors.push(error);\n }),\n ]);\n\n if (errors.length > 0) {\n throw new Error(\n `Failed to refresh some staking data: ${errors\n .map((e) => e.message)\n .join(', ')}`,\n );\n }\n }\n}\n"]}
@@ -3,6 +3,7 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMe
3
3
  import { BaseController } from "@metamask/base-controller";
4
4
  import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, NetworkControllerStateChangeEvent } from "@metamask/network-controller";
5
5
  import { type PooledStake, type VaultData, type VaultDailyApy, type VaultApyAverages } from "@metamask/stake-sdk";
6
+ import { type TransactionControllerTransactionConfirmedEvent } from "@metamask/transaction-controller";
6
7
  import type { RefreshPooledStakesOptions, RefreshPooledStakingDataOptions, RefreshStakingEligibilityOptions } from "./types.cjs";
7
8
  export declare const controllerName = "EarnController";
8
9
  export type PooledStakingState = {
@@ -60,7 +61,7 @@ export type EarnControllerEvents = EarnControllerStateChangeEvent;
60
61
  /**
61
62
  * All events that EarnController subscribes to internally.
62
63
  */
63
- export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent;
64
+ export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent | TransactionControllerTransactionConfirmedEvent;
64
65
  /**
65
66
  * The messenger which is restricted to actions and events accessed by
66
67
  * EarnController.
@@ -1 +1 @@
1
- {"version":3,"file":"EarnController.d.cts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EarnController.d.cts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMe
3
3
  import { BaseController } from "@metamask/base-controller";
4
4
  import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, NetworkControllerStateChangeEvent } from "@metamask/network-controller";
5
5
  import { type PooledStake, type VaultData, type VaultDailyApy, type VaultApyAverages } from "@metamask/stake-sdk";
6
+ import { type TransactionControllerTransactionConfirmedEvent } from "@metamask/transaction-controller";
6
7
  import type { RefreshPooledStakesOptions, RefreshPooledStakingDataOptions, RefreshStakingEligibilityOptions } from "./types.mjs";
7
8
  export declare const controllerName = "EarnController";
8
9
  export type PooledStakingState = {
@@ -60,7 +61,7 @@ export type EarnControllerEvents = EarnControllerStateChangeEvent;
60
61
  /**
61
62
  * All events that EarnController subscribes to internally.
62
63
  */
63
- export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent;
64
+ export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent | TransactionControllerTransactionConfirmedEvent;
64
65
  /**
65
66
  * The messenger which is restricted to actions and events accessed by
66
67
  * EarnController.
@@ -1 +1 @@
1
- {"version":3,"file":"EarnController.d.mts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EarnController.d.mts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,13 @@ import { Web3Provider } from "@ethersproject/providers";
14
14
  import { BaseController } from "@metamask/base-controller";
15
15
  import { convertHexToDecimal } from "@metamask/controller-utils";
16
16
  import { StakeSdk, StakingApiService } from "@metamask/stake-sdk";
17
+ import { TransactionType } from "@metamask/transaction-controller";
17
18
  export const controllerName = 'EarnController';
19
+ const stakingTransactionTypes = new Set([
20
+ TransactionType.stakingDeposit,
21
+ TransactionType.stakingUnstake,
22
+ TransactionType.stakingClaim,
23
+ ]);
18
24
  /**
19
25
  * Metadata for the EarnController.
20
26
  */
@@ -106,6 +112,7 @@ export class EarnController extends BaseController {
106
112
  this.refreshPooledStakingData().catch(console.error);
107
113
  const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
108
114
  __classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, selectedNetworkClientId, "f");
115
+ // Listen for network changes
109
116
  this.messagingSystem.subscribe('NetworkController:stateChange', (networkControllerState) => {
110
117
  if (networkControllerState.selectedNetworkClientId !==
111
118
  __classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
@@ -128,6 +135,21 @@ export class EarnController extends BaseController {
128
135
  this.refreshStakingEligibility({ address }).catch(console.error);
129
136
  this.refreshPooledStakes({ address }).catch(console.error);
130
137
  });
138
+ // Listen for confirmed staking transactions
139
+ this.messagingSystem.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
140
+ /**
141
+ * When we speed up a transaction, we set the type as Retry and we lose
142
+ * information about type of transaction that is being set up, so we use
143
+ * original type to track that information.
144
+ */
145
+ const { type, originalType } = transactionMeta;
146
+ const isStakingTransaction = stakingTransactionTypes.has(type) ||
147
+ stakingTransactionTypes.has(originalType);
148
+ if (isStakingTransaction) {
149
+ const sender = transactionMeta.txParams.from;
150
+ this.refreshPooledStakes({ resetCache: true, address: sender }).catch(console.error);
151
+ }
152
+ });
131
153
  }
132
154
  /**
133
155
  * Refreshes the pooled stakes data for the current account.
@@ -1 +1 @@
1
- {"version":3,"file":"EarnController.mjs","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n type VaultDailyApy,\n type VaultApyAverages,\n} from '@metamask/stake-sdk';\n\nimport type {\n RefreshPooledStakesOptions,\n RefreshPooledStakingDataOptions,\n RefreshStakingEligibilityOptions,\n} from './types';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultMetadata: VaultData;\n vaultDailyApys: VaultDailyApy[];\n vaultApyAverages: VaultApyAverages;\n isEligible: boolean;\n};\n\nexport type StablecoinLendingState = {\n vaults: StablecoinVault[];\n};\n\nexport type StablecoinVault = {\n symbol: string;\n name: string;\n chainId: number;\n tokenAddress: string;\n vaultAddress: string;\n currentAPY: string;\n supply: string;\n liquidity: string;\n};\n\n/**\n * Metadata for the EarnController.\n */\nconst earnControllerMetadata: StateMetadata<EarnControllerState> = {\n pooled_staking: {\n persist: true,\n anonymous: false,\n },\n stablecoin_lending: {\n persist: true,\n anonymous: false,\n },\n lastUpdated: {\n persist: false,\n anonymous: true,\n },\n};\n\n// === State Types ===\nexport type EarnControllerState = {\n pooled_staking: PooledStakingState;\n stablecoin_lending?: StablecoinLendingState;\n lastUpdated: number;\n};\n\n// === Default State ===\nconst DEFAULT_STABLECOIN_VAULT: StablecoinVault = {\n symbol: '',\n name: '',\n chainId: 0,\n tokenAddress: '',\n vaultAddress: '',\n currentAPY: '0',\n supply: '0',\n liquidity: '0',\n};\n\nconst DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES: VaultApyAverages = {\n oneDay: '0',\n oneWeek: '0',\n oneMonth: '0',\n threeMonths: '0',\n sixMonths: '0',\n oneYear: '0',\n};\n\n/**\n * Gets the default state for the EarnController.\n *\n * @returns The default EarnController state.\n */\nexport function getDefaultEarnControllerState(): EarnControllerState {\n return {\n pooled_staking: {\n pooledStakes: {\n account: '',\n lifetimeRewards: '0',\n assets: '0',\n exitRequests: [],\n },\n exchangeRate: '1',\n vaultMetadata: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\n vaultDailyApys: [],\n vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,\n isEligible: false,\n },\n stablecoin_lending: {\n vaults: [DEFAULT_STABLECOIN_VAULT],\n },\n lastUpdated: 0,\n };\n}\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the EarnController.\n */\nexport type EarnControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All actions that EarnController registers, to be called externally.\n */\nexport type EarnControllerActions = EarnControllerGetStateAction;\n\n/**\n * All actions that EarnController calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The event that EarnController publishes when updating state.\n */\nexport type EarnControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All events that EarnController publishes, to be subscribed to externally.\n */\nexport type EarnControllerEvents = EarnControllerStateChangeEvent;\n\n/**\n * All events that EarnController subscribes to internally.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedAccountChangeEvent\n | NetworkControllerStateChangeEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * EarnController.\n */\nexport type EarnControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n EarnControllerActions | AllowedActions,\n EarnControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * EarnController manages DeFi earning opportunities across different protocols and chains.\n */\nexport class EarnController extends BaseController<\n typeof controllerName,\n EarnControllerState,\n EarnControllerMessenger\n> {\n #stakeSDK: StakeSdk | null = null;\n\n #selectedNetworkClientId?: string;\n\n readonly #stakingApiService: StakingApiService = new StakingApiService();\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: EarnControllerMessenger;\n state?: Partial<EarnControllerState>;\n }) {\n super({\n name: controllerName,\n metadata: earnControllerMetadata,\n messenger,\n state: {\n ...getDefaultEarnControllerState(),\n ...state,\n },\n });\n\n this.#initializeSDK();\n this.refreshPooledStakingData().catch(console.error);\n\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n this.#selectedNetworkClientId = selectedNetworkClientId;\n\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) => {\n if (\n networkControllerState.selectedNetworkClientId !==\n this.#selectedNetworkClientId\n ) {\n this.#initializeSDK(networkControllerState.selectedNetworkClientId);\n this.refreshPooledStakingVaultMetadata().catch(console.error);\n this.refreshPooledStakingVaultDailyApys().catch(console.error);\n this.refreshPooledStakingVaultApyAverages().catch(console.error);\n this.refreshPooledStakes().catch(console.error);\n }\n this.#selectedNetworkClientId =\n networkControllerState.selectedNetworkClientId;\n },\n );\n\n // Listen for account changes\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => {\n const address = account?.address;\n /**\n * TEMP: There's a race condition where the account state isn't updated immediately.\n * Until this has been fixed, we rely on the event payload for the latest account instead of #getCurrentAccount().\n * Issue: https://github.com/MetaMask/accounts-planning/issues/887\n */\n this.refreshStakingEligibility({ address }).catch(console.error);\n this.refreshPooledStakes({ address }).catch(console.error);\n },\n );\n }\n\n #initializeSDK(networkClientId?: string) {\n const { selectedNetworkClientId } = networkClientId\n ? { selectedNetworkClientId: networkClientId }\n : this.messagingSystem.call('NetworkController:getState');\n\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (!networkClient?.provider) {\n this.#stakeSDK = null;\n return;\n }\n\n const provider = new Web3Provider(networkClient.provider);\n const { chainId } = networkClient.configuration;\n\n // Initialize appropriate contracts based on chainId\n const config: StakeSdkConfig = {\n chainId: convertHexToDecimal(chainId),\n };\n\n try {\n this.#stakeSDK = StakeSdk.create(config);\n this.#stakeSDK.pooledStakingContract.connectSignerOrProvider(provider);\n } catch (error) {\n this.#stakeSDK = null;\n // Only log unexpected errors, not unsupported chain errors\n if (\n !(\n error instanceof Error &&\n error.message.includes('Unsupported chainId')\n )\n ) {\n console.error('Stake SDK initialization failed:', error);\n }\n }\n }\n\n #getCurrentAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getCurrentChainId(): number {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return convertHexToDecimal(chainId);\n }\n\n /**\n * Refreshes the pooled stakes data for the current account.\n * Fetches updated stake information including lifetime rewards, assets, and exit requests\n * from the staking API service and updates the state.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes({\n resetCache = false,\n address,\n }: RefreshPooledStakesOptions = {}): Promise<void> {\n const addressToUse = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToUse) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [addressToUse],\n chainId,\n resetCache,\n );\n\n this.update((state) => {\n state.pooled_staking.pooledStakes = accounts[0];\n state.pooled_staking.exchangeRate = exchangeRate;\n });\n }\n\n /**\n * Refreshes the staking eligibility status for the current account.\n * Updates the eligibility status in the controller state based on the location and address blocklist for compliance.\n *\n * @param options - Optional arguments\n * @param [options.address] - Address to refresh staking eligibility for (optional).\n * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility({\n address,\n }: RefreshStakingEligibilityOptions = {}): Promise<void> {\n const addressToCheck = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToCheck) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n addressToCheck,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes pooled staking vault metadata for the current chain.\n * Updates the vault metadata in the controller state including APY, capacity,\n * fee percentage, total assets, and vault address.\n *\n * @returns A promise that resolves when the vault metadata has been updated\n */\n async refreshPooledStakingVaultMetadata(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultMetadata = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultMetadata = vaultMetadata;\n });\n }\n\n /**\n * Refreshes pooled staking vault daily apys for the current chain.\n * Updates the pooled staking vault daily apys controller state.\n *\n * @param days - The number of days to fetch pooled staking vault daily apys for (defaults to 365).\n * @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').\n * @returns A promise that resolves when the pooled staking vault daily apys have been updated.\n */\n async refreshPooledStakingVaultDailyApys(\n days = 365,\n order: 'asc' | 'desc' = 'desc',\n ): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultDailyApys = await this.#stakingApiService.getVaultDailyApys(\n chainId,\n days,\n order,\n );\n\n this.update((state) => {\n state.pooled_staking.vaultDailyApys = vaultDailyApys;\n });\n }\n\n /**\n * Refreshes pooled staking vault apy averages for the current chain.\n * Updates the pooled staking vault apy averages controller state.\n *\n * @returns A promise that resolves when the pooled staking vault apy averages have been updated.\n */\n async refreshPooledStakingVaultApyAverages() {\n const chainId = this.#getCurrentChainId();\n const vaultApyAverages =\n await this.#stakingApiService.getVaultApyAverages(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultApyAverages = vaultApyAverages;\n });\n }\n\n /**\n * Refreshes all pooled staking related data including stakes, eligibility, and vault data.\n * This method allows partial success, meaning some data may update while other requests fail.\n * All errors are collected and thrown as a single error message.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when all possible data has been updated\n * @throws {Error} If any of the refresh operations fail, with concatenated error messages\n */\n async refreshPooledStakingData({\n resetCache,\n address,\n }: RefreshPooledStakingDataOptions = {}): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes({ resetCache, address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility({ address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultMetadata().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultDailyApys().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultApyAverages().catch((error) => {\n errors.push(error);\n }),\n ]);\n\n if (errors.length > 0) {\n throw new Error(\n `Failed to refresh some staking data: ${errors\n .map((e) => e.message)\n .join(', ')}`,\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"EarnController.mjs","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n type VaultDailyApy,\n type VaultApyAverages,\n} from '@metamask/stake-sdk';\nimport {\n TransactionType,\n type TransactionControllerTransactionConfirmedEvent,\n} from '@metamask/transaction-controller';\n\nimport type {\n RefreshPooledStakesOptions,\n RefreshPooledStakingDataOptions,\n RefreshStakingEligibilityOptions,\n} from './types';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultMetadata: VaultData;\n vaultDailyApys: VaultDailyApy[];\n vaultApyAverages: VaultApyAverages;\n isEligible: boolean;\n};\n\nexport type StablecoinLendingState = {\n vaults: StablecoinVault[];\n};\n\nexport type StablecoinVault = {\n symbol: string;\n name: string;\n chainId: number;\n tokenAddress: string;\n vaultAddress: string;\n currentAPY: string;\n supply: string;\n liquidity: string;\n};\n\ntype StakingTransactionTypes =\n | TransactionType.stakingDeposit\n | TransactionType.stakingUnstake\n | TransactionType.stakingClaim;\n\nconst stakingTransactionTypes = new Set<StakingTransactionTypes>([\n TransactionType.stakingDeposit,\n TransactionType.stakingUnstake,\n TransactionType.stakingClaim,\n]);\n\n/**\n * Metadata for the EarnController.\n */\nconst earnControllerMetadata: StateMetadata<EarnControllerState> = {\n pooled_staking: {\n persist: true,\n anonymous: false,\n },\n stablecoin_lending: {\n persist: true,\n anonymous: false,\n },\n lastUpdated: {\n persist: false,\n anonymous: true,\n },\n};\n\n// === State Types ===\nexport type EarnControllerState = {\n pooled_staking: PooledStakingState;\n stablecoin_lending?: StablecoinLendingState;\n lastUpdated: number;\n};\n\n// === Default State ===\nconst DEFAULT_STABLECOIN_VAULT: StablecoinVault = {\n symbol: '',\n name: '',\n chainId: 0,\n tokenAddress: '',\n vaultAddress: '',\n currentAPY: '0',\n supply: '0',\n liquidity: '0',\n};\n\nconst DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES: VaultApyAverages = {\n oneDay: '0',\n oneWeek: '0',\n oneMonth: '0',\n threeMonths: '0',\n sixMonths: '0',\n oneYear: '0',\n};\n\n/**\n * Gets the default state for the EarnController.\n *\n * @returns The default EarnController state.\n */\nexport function getDefaultEarnControllerState(): EarnControllerState {\n return {\n pooled_staking: {\n pooledStakes: {\n account: '',\n lifetimeRewards: '0',\n assets: '0',\n exitRequests: [],\n },\n exchangeRate: '1',\n vaultMetadata: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\n vaultDailyApys: [],\n vaultApyAverages: DEFAULT_POOLED_STAKING_VAULT_APY_AVERAGES,\n isEligible: false,\n },\n stablecoin_lending: {\n vaults: [DEFAULT_STABLECOIN_VAULT],\n },\n lastUpdated: 0,\n };\n}\n\n// === MESSENGER ===\n\n/**\n * The action which can be used to retrieve the state of the EarnController.\n */\nexport type EarnControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All actions that EarnController registers, to be called externally.\n */\nexport type EarnControllerActions = EarnControllerGetStateAction;\n\n/**\n * All actions that EarnController calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The event that EarnController publishes when updating state.\n */\nexport type EarnControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n EarnControllerState\n>;\n\n/**\n * All events that EarnController publishes, to be subscribed to externally.\n */\nexport type EarnControllerEvents = EarnControllerStateChangeEvent;\n\n/**\n * All events that EarnController subscribes to internally.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedAccountChangeEvent\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * EarnController.\n */\nexport type EarnControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n EarnControllerActions | AllowedActions,\n EarnControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * EarnController manages DeFi earning opportunities across different protocols and chains.\n */\nexport class EarnController extends BaseController<\n typeof controllerName,\n EarnControllerState,\n EarnControllerMessenger\n> {\n #stakeSDK: StakeSdk | null = null;\n\n #selectedNetworkClientId?: string;\n\n readonly #stakingApiService: StakingApiService = new StakingApiService();\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: EarnControllerMessenger;\n state?: Partial<EarnControllerState>;\n }) {\n super({\n name: controllerName,\n metadata: earnControllerMetadata,\n messenger,\n state: {\n ...getDefaultEarnControllerState(),\n ...state,\n },\n });\n\n this.#initializeSDK();\n this.refreshPooledStakingData().catch(console.error);\n\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n this.#selectedNetworkClientId = selectedNetworkClientId;\n\n // Listen for network changes\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n (networkControllerState) => {\n if (\n networkControllerState.selectedNetworkClientId !==\n this.#selectedNetworkClientId\n ) {\n this.#initializeSDK(networkControllerState.selectedNetworkClientId);\n this.refreshPooledStakingVaultMetadata().catch(console.error);\n this.refreshPooledStakingVaultDailyApys().catch(console.error);\n this.refreshPooledStakingVaultApyAverages().catch(console.error);\n this.refreshPooledStakes().catch(console.error);\n }\n this.#selectedNetworkClientId =\n networkControllerState.selectedNetworkClientId;\n },\n );\n\n // Listen for account changes\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => {\n const address = account?.address;\n /**\n * TEMP: There's a race condition where the account state isn't updated immediately.\n * Until this has been fixed, we rely on the event payload for the latest account instead of #getCurrentAccount().\n * Issue: https://github.com/MetaMask/accounts-planning/issues/887\n */\n this.refreshStakingEligibility({ address }).catch(console.error);\n this.refreshPooledStakes({ address }).catch(console.error);\n },\n );\n\n // Listen for confirmed staking transactions\n this.messagingSystem.subscribe(\n 'TransactionController:transactionConfirmed',\n (transactionMeta) => {\n /**\n * When we speed up a transaction, we set the type as Retry and we lose\n * information about type of transaction that is being set up, so we use\n * original type to track that information.\n */\n const { type, originalType } = transactionMeta;\n\n const isStakingTransaction =\n stakingTransactionTypes.has(type as StakingTransactionTypes) ||\n stakingTransactionTypes.has(originalType as StakingTransactionTypes);\n\n if (isStakingTransaction) {\n const sender = transactionMeta.txParams.from;\n this.refreshPooledStakes({ resetCache: true, address: sender }).catch(\n console.error,\n );\n }\n },\n );\n }\n\n #initializeSDK(networkClientId?: string) {\n const { selectedNetworkClientId } = networkClientId\n ? { selectedNetworkClientId: networkClientId }\n : this.messagingSystem.call('NetworkController:getState');\n\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (!networkClient?.provider) {\n this.#stakeSDK = null;\n return;\n }\n\n const provider = new Web3Provider(networkClient.provider);\n const { chainId } = networkClient.configuration;\n\n // Initialize appropriate contracts based on chainId\n const config: StakeSdkConfig = {\n chainId: convertHexToDecimal(chainId),\n };\n\n try {\n this.#stakeSDK = StakeSdk.create(config);\n this.#stakeSDK.pooledStakingContract.connectSignerOrProvider(provider);\n } catch (error) {\n this.#stakeSDK = null;\n // Only log unexpected errors, not unsupported chain errors\n if (\n !(\n error instanceof Error &&\n error.message.includes('Unsupported chainId')\n )\n ) {\n console.error('Stake SDK initialization failed:', error);\n }\n }\n }\n\n #getCurrentAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getCurrentChainId(): number {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return convertHexToDecimal(chainId);\n }\n\n /**\n * Refreshes the pooled stakes data for the current account.\n * Fetches updated stake information including lifetime rewards, assets, and exit requests\n * from the staking API service and updates the state.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes({\n resetCache = false,\n address,\n }: RefreshPooledStakesOptions = {}): Promise<void> {\n const addressToUse = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToUse) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [addressToUse],\n chainId,\n resetCache,\n );\n\n this.update((state) => {\n state.pooled_staking.pooledStakes = accounts[0];\n state.pooled_staking.exchangeRate = exchangeRate;\n });\n }\n\n /**\n * Refreshes the staking eligibility status for the current account.\n * Updates the eligibility status in the controller state based on the location and address blocklist for compliance.\n *\n * @param options - Optional arguments\n * @param [options.address] - Address to refresh staking eligibility for (optional).\n * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility({\n address,\n }: RefreshStakingEligibilityOptions = {}): Promise<void> {\n const addressToCheck = address ?? this.#getCurrentAccount()?.address;\n\n if (!addressToCheck) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n addressToCheck,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes pooled staking vault metadata for the current chain.\n * Updates the vault metadata in the controller state including APY, capacity,\n * fee percentage, total assets, and vault address.\n *\n * @returns A promise that resolves when the vault metadata has been updated\n */\n async refreshPooledStakingVaultMetadata(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultMetadata = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultMetadata = vaultMetadata;\n });\n }\n\n /**\n * Refreshes pooled staking vault daily apys for the current chain.\n * Updates the pooled staking vault daily apys controller state.\n *\n * @param days - The number of days to fetch pooled staking vault daily apys for (defaults to 365).\n * @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').\n * @returns A promise that resolves when the pooled staking vault daily apys have been updated.\n */\n async refreshPooledStakingVaultDailyApys(\n days = 365,\n order: 'asc' | 'desc' = 'desc',\n ): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultDailyApys = await this.#stakingApiService.getVaultDailyApys(\n chainId,\n days,\n order,\n );\n\n this.update((state) => {\n state.pooled_staking.vaultDailyApys = vaultDailyApys;\n });\n }\n\n /**\n * Refreshes pooled staking vault apy averages for the current chain.\n * Updates the pooled staking vault apy averages controller state.\n *\n * @returns A promise that resolves when the pooled staking vault apy averages have been updated.\n */\n async refreshPooledStakingVaultApyAverages() {\n const chainId = this.#getCurrentChainId();\n const vaultApyAverages =\n await this.#stakingApiService.getVaultApyAverages(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultApyAverages = vaultApyAverages;\n });\n }\n\n /**\n * Refreshes all pooled staking related data including stakes, eligibility, and vault data.\n * This method allows partial success, meaning some data may update while other requests fail.\n * All errors are collected and thrown as a single error message.\n *\n * @param options - Optional arguments\n * @param [options.resetCache] - Control whether the BE cache should be invalidated (optional).\n * @param [options.address] - The address to refresh pooled stakes for (optional).\n * @returns A promise that resolves when all possible data has been updated\n * @throws {Error} If any of the refresh operations fail, with concatenated error messages\n */\n async refreshPooledStakingData({\n resetCache,\n address,\n }: RefreshPooledStakingDataOptions = {}): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes({ resetCache, address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility({ address }).catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultMetadata().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultDailyApys().catch((error) => {\n errors.push(error);\n }),\n this.refreshPooledStakingVaultApyAverages().catch((error) => {\n errors.push(error);\n }),\n ]);\n\n if (errors.length > 0) {\n throw new Error(\n `Failed to refresh some staking data: ${errors\n .map((e) => e.message)\n .join(', ')}`,\n );\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/earn-controller",
3
- "version": "0.10.0-preview-7f6d1f4",
3
+ "version": "0.11.0-preview-c7dcfd5a",
4
4
  "description": "Manages state for earning features and coordinates interactions between staking services, SDK integrations, and other controllers to enable users to participate in various earning opportunities",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -56,6 +56,7 @@
56
56
  "@metamask/accounts-controller": "^27.0.0",
57
57
  "@metamask/auto-changelog": "^3.4.4",
58
58
  "@metamask/network-controller": "^23.2.0",
59
+ "@metamask/transaction-controller": "^53.0.0",
59
60
  "@types/jest": "^27.4.1",
60
61
  "deepmerge": "^4.2.2",
61
62
  "jest": "^27.5.1",