@metamask/earn-controller 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +17 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/EarnController.cjs +230 -0
- package/dist/EarnController.cjs.map +1 -0
- package/dist/EarnController.d.cts +109 -0
- package/dist/EarnController.d.cts.map +1 -0
- package/dist/EarnController.d.mts +109 -0
- package/dist/EarnController.d.mts.map +1 -0
- package/dist/EarnController.mjs +225 -0
- package/dist/EarnController.mjs.map +1 -0
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +78 -0
package/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.1.0]
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Initial release ([#5271](https://github.com/MetaMask/core/pull/5271))
|
15
|
+
|
16
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/earn-controller@0.1.0...HEAD
|
17
|
+
[0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/earn-controller@0.1.0
|
package/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 MetaMask
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# `@metamask/earn-controller`
|
2
|
+
|
3
|
+
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.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
`yarn add @metamask/earn-controller`
|
8
|
+
|
9
|
+
or
|
10
|
+
|
11
|
+
`npm install @metamask/earn-controller`
|
12
|
+
|
13
|
+
## Contributing
|
14
|
+
|
15
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
@@ -0,0 +1,230 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
4
|
+
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");
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
6
|
+
};
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
10
|
+
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");
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
12
|
+
};
|
13
|
+
var _EarnController_instances, _EarnController_stakeSDK, _EarnController_selectedNetworkClientId, _EarnController_stakingApiService, _EarnController_initializeSDK, _EarnController_getCurrentAccount, _EarnController_getCurrentChainId;
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
exports.EarnController = exports.getDefaultEarnControllerState = exports.controllerName = void 0;
|
16
|
+
const providers_1 = require("@ethersproject/providers");
|
17
|
+
const base_controller_1 = require("@metamask/base-controller");
|
18
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
19
|
+
const stake_sdk_1 = require("@metamask/stake-sdk");
|
20
|
+
exports.controllerName = 'EarnController';
|
21
|
+
/**
|
22
|
+
* Metadata for the EarnController.
|
23
|
+
*/
|
24
|
+
const earnControllerMetadata = {
|
25
|
+
pooled_staking: {
|
26
|
+
persist: true,
|
27
|
+
anonymous: false,
|
28
|
+
},
|
29
|
+
stablecoin_lending: {
|
30
|
+
persist: true,
|
31
|
+
anonymous: false,
|
32
|
+
},
|
33
|
+
lastUpdated: {
|
34
|
+
persist: false,
|
35
|
+
anonymous: true,
|
36
|
+
},
|
37
|
+
};
|
38
|
+
// === Default State ===
|
39
|
+
const DEFAULT_STABLECOIN_VAULT = {
|
40
|
+
symbol: '',
|
41
|
+
name: '',
|
42
|
+
chainId: 0,
|
43
|
+
tokenAddress: '',
|
44
|
+
vaultAddress: '',
|
45
|
+
currentAPY: '0',
|
46
|
+
supply: '0',
|
47
|
+
liquidity: '0',
|
48
|
+
};
|
49
|
+
/**
|
50
|
+
* Gets the default state for the EarnController.
|
51
|
+
*
|
52
|
+
* @returns The default EarnController state.
|
53
|
+
*/
|
54
|
+
function getDefaultEarnControllerState() {
|
55
|
+
return {
|
56
|
+
pooled_staking: {
|
57
|
+
pooledStakes: {
|
58
|
+
account: '',
|
59
|
+
lifetimeRewards: '0',
|
60
|
+
assets: '0',
|
61
|
+
exitRequests: [],
|
62
|
+
},
|
63
|
+
exchangeRate: '1',
|
64
|
+
vaultData: {
|
65
|
+
apy: '0',
|
66
|
+
capacity: '0',
|
67
|
+
feePercent: 0,
|
68
|
+
totalAssets: '0',
|
69
|
+
vaultAddress: '0x0000000000000000000000000000000000000000',
|
70
|
+
},
|
71
|
+
isEligible: false,
|
72
|
+
},
|
73
|
+
stablecoin_lending: {
|
74
|
+
vaults: [DEFAULT_STABLECOIN_VAULT],
|
75
|
+
},
|
76
|
+
lastUpdated: 0,
|
77
|
+
};
|
78
|
+
}
|
79
|
+
exports.getDefaultEarnControllerState = getDefaultEarnControllerState;
|
80
|
+
// === CONTROLLER DEFINITION ===
|
81
|
+
/**
|
82
|
+
* EarnController manages DeFi earning opportunities across different protocols and chains.
|
83
|
+
*/
|
84
|
+
class EarnController extends base_controller_1.BaseController {
|
85
|
+
constructor({ messenger, state = {}, }) {
|
86
|
+
super({
|
87
|
+
name: exports.controllerName,
|
88
|
+
metadata: earnControllerMetadata,
|
89
|
+
messenger,
|
90
|
+
state: {
|
91
|
+
...getDefaultEarnControllerState(),
|
92
|
+
...state,
|
93
|
+
},
|
94
|
+
});
|
95
|
+
_EarnController_instances.add(this);
|
96
|
+
_EarnController_stakeSDK.set(this, null);
|
97
|
+
_EarnController_selectedNetworkClientId.set(this, void 0);
|
98
|
+
_EarnController_stakingApiService.set(this, new stake_sdk_1.StakingApiService());
|
99
|
+
__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this);
|
100
|
+
this.refreshPooledStakingData().catch(console.error);
|
101
|
+
const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
|
102
|
+
__classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, selectedNetworkClientId, "f");
|
103
|
+
this.messagingSystem.subscribe('NetworkController:stateChange', (networkControllerState) => {
|
104
|
+
if (networkControllerState.selectedNetworkClientId !==
|
105
|
+
__classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
|
106
|
+
__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this, networkControllerState.selectedNetworkClientId);
|
107
|
+
this.refreshPooledStakingData().catch(console.error);
|
108
|
+
}
|
109
|
+
__classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, networkControllerState.selectedNetworkClientId, "f");
|
110
|
+
});
|
111
|
+
// Listen for account changes
|
112
|
+
this.messagingSystem.subscribe('AccountsController:selectedAccountChange', () => {
|
113
|
+
this.refreshPooledStakingData().catch(console.error);
|
114
|
+
});
|
115
|
+
}
|
116
|
+
/**
|
117
|
+
* Refreshes the pooled stakes data for the current account.
|
118
|
+
* Fetches updated stake information including lifetime rewards, assets, and exit requests
|
119
|
+
* from the staking API service and updates the state.
|
120
|
+
*
|
121
|
+
* @returns A promise that resolves when the stakes data has been updated
|
122
|
+
*/
|
123
|
+
async refreshPooledStakes() {
|
124
|
+
const currentAccount = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this);
|
125
|
+
if (!currentAccount?.address) {
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
|
129
|
+
const { accounts, exchangeRate } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakes([currentAccount.address], chainId);
|
130
|
+
this.update((state) => {
|
131
|
+
state.pooled_staking.pooledStakes = accounts[0];
|
132
|
+
state.pooled_staking.exchangeRate = exchangeRate;
|
133
|
+
});
|
134
|
+
}
|
135
|
+
/**
|
136
|
+
* Refreshes the staking eligibility status for the current account.
|
137
|
+
* Updates the eligibility status in the controller state based on the location and address blocklist for compliance.
|
138
|
+
*
|
139
|
+
* @returns A promise that resolves when the eligibility status has been updated
|
140
|
+
*/
|
141
|
+
async refreshStakingEligibility() {
|
142
|
+
const currentAccount = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this);
|
143
|
+
if (!currentAccount?.address) {
|
144
|
+
return;
|
145
|
+
}
|
146
|
+
const { eligible: isEligible } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakingEligibility([
|
147
|
+
currentAccount.address,
|
148
|
+
]);
|
149
|
+
this.update((state) => {
|
150
|
+
state.pooled_staking.isEligible = isEligible;
|
151
|
+
});
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* Refreshes vault data for the current chain.
|
155
|
+
* Updates the vault data in the controller state including APY, capacity,
|
156
|
+
* fee percentage, total assets, and vault address.
|
157
|
+
*
|
158
|
+
* @returns A promise that resolves when the vault data has been updated
|
159
|
+
*/
|
160
|
+
async refreshVaultData() {
|
161
|
+
const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
|
162
|
+
const vaultData = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getVaultData(chainId);
|
163
|
+
this.update((state) => {
|
164
|
+
state.pooled_staking.vaultData = vaultData;
|
165
|
+
});
|
166
|
+
}
|
167
|
+
/**
|
168
|
+
* Refreshes all pooled staking related data including stakes, eligibility, and vault data.
|
169
|
+
* This method allows partial success, meaning some data may update while other requests fail.
|
170
|
+
* All errors are collected and thrown as a single error message.
|
171
|
+
*
|
172
|
+
* @returns A promise that resolves when all possible data has been updated
|
173
|
+
* @throws {Error} If any of the refresh operations fail, with concatenated error messages
|
174
|
+
*/
|
175
|
+
async refreshPooledStakingData() {
|
176
|
+
const errors = [];
|
177
|
+
await Promise.all([
|
178
|
+
this.refreshPooledStakes().catch((error) => {
|
179
|
+
errors.push(error);
|
180
|
+
}),
|
181
|
+
this.refreshStakingEligibility().catch((error) => {
|
182
|
+
errors.push(error);
|
183
|
+
}),
|
184
|
+
this.refreshVaultData().catch((error) => {
|
185
|
+
errors.push(error);
|
186
|
+
}),
|
187
|
+
]);
|
188
|
+
if (errors.length > 0) {
|
189
|
+
throw new Error(`Failed to refresh some staking data: ${errors
|
190
|
+
.map((e) => e.message)
|
191
|
+
.join(', ')}`);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
exports.EarnController = EarnController;
|
196
|
+
_EarnController_stakeSDK = new WeakMap(), _EarnController_selectedNetworkClientId = new WeakMap(), _EarnController_stakingApiService = new WeakMap(), _EarnController_instances = new WeakSet(), _EarnController_initializeSDK = function _EarnController_initializeSDK(networkClientId) {
|
197
|
+
const { selectedNetworkClientId } = networkClientId
|
198
|
+
? { selectedNetworkClientId: networkClientId }
|
199
|
+
: this.messagingSystem.call('NetworkController:getState');
|
200
|
+
const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
201
|
+
if (!networkClient?.provider) {
|
202
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
|
203
|
+
return;
|
204
|
+
}
|
205
|
+
const provider = new providers_1.Web3Provider(networkClient.provider);
|
206
|
+
const { chainId } = networkClient.configuration;
|
207
|
+
// Initialize appropriate contracts based on chainId
|
208
|
+
const config = {
|
209
|
+
chainId: (0, controller_utils_1.convertHexToDecimal)(chainId),
|
210
|
+
};
|
211
|
+
try {
|
212
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, stake_sdk_1.StakeSdk.create(config), "f");
|
213
|
+
__classPrivateFieldGet(this, _EarnController_stakeSDK, "f").pooledStakingContract.connectSignerOrProvider(provider);
|
214
|
+
}
|
215
|
+
catch (error) {
|
216
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
|
217
|
+
// Only log unexpected errors, not unsupported chain errors
|
218
|
+
if (!(error instanceof Error &&
|
219
|
+
error.message.includes('Unsupported chainId'))) {
|
220
|
+
console.error('Stake SDK initialization failed:', error);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
}, _EarnController_getCurrentAccount = function _EarnController_getCurrentAccount() {
|
224
|
+
return this.messagingSystem.call('AccountsController:getSelectedAccount');
|
225
|
+
}, _EarnController_getCurrentChainId = function _EarnController_getCurrentChainId() {
|
226
|
+
const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
|
227
|
+
const { configuration: { chainId }, } = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
228
|
+
return (0, controller_utils_1.convertHexToDecimal)(chainId);
|
229
|
+
};
|
230
|
+
//# sourceMappingURL=EarnController.cjs.map
|
@@ -0,0 +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 { NetworkControllerStateChangeEvent } from '@metamask/network-controller';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n} from '@metamask/stake-sdk';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultData: VaultData;\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\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 vaultData: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\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.refreshPooledStakingData().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 () => {\n this.refreshPooledStakingData().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 * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes(): Promise<void> {\n const currentAccount = this.#getCurrentAccount();\n if (!currentAccount?.address) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [currentAccount.address],\n chainId,\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 * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility(): Promise<void> {\n const currentAccount = this.#getCurrentAccount();\n if (!currentAccount?.address) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n currentAccount.address,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes vault data for the current chain.\n * Updates the vault data 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 data has been updated\n */\n async refreshVaultData(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultData = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultData = vaultData;\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 * @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(): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes().catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility().catch((error) => {\n errors.push(error);\n }),\n this.refreshVaultData().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"]}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
import type { AccountsControllerGetSelectedAccountAction, AccountsControllerSelectedAccountChangeEvent } from "@metamask/accounts-controller";
|
2
|
+
import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMessenger } from "@metamask/base-controller";
|
3
|
+
import { BaseController } from "@metamask/base-controller";
|
4
|
+
import type { NetworkControllerStateChangeEvent } from "@metamask/network-controller";
|
5
|
+
import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction } from "@metamask/network-controller";
|
6
|
+
import { type PooledStake, type VaultData } from "@metamask/stake-sdk";
|
7
|
+
export declare const controllerName = "EarnController";
|
8
|
+
export type PooledStakingState = {
|
9
|
+
pooledStakes: PooledStake;
|
10
|
+
exchangeRate: string;
|
11
|
+
vaultData: VaultData;
|
12
|
+
isEligible: boolean;
|
13
|
+
};
|
14
|
+
export type StablecoinLendingState = {
|
15
|
+
vaults: StablecoinVault[];
|
16
|
+
};
|
17
|
+
export type StablecoinVault = {
|
18
|
+
symbol: string;
|
19
|
+
name: string;
|
20
|
+
chainId: number;
|
21
|
+
tokenAddress: string;
|
22
|
+
vaultAddress: string;
|
23
|
+
currentAPY: string;
|
24
|
+
supply: string;
|
25
|
+
liquidity: string;
|
26
|
+
};
|
27
|
+
export type EarnControllerState = {
|
28
|
+
pooled_staking: PooledStakingState;
|
29
|
+
stablecoin_lending?: StablecoinLendingState;
|
30
|
+
lastUpdated: number;
|
31
|
+
};
|
32
|
+
/**
|
33
|
+
* Gets the default state for the EarnController.
|
34
|
+
*
|
35
|
+
* @returns The default EarnController state.
|
36
|
+
*/
|
37
|
+
export declare function getDefaultEarnControllerState(): EarnControllerState;
|
38
|
+
/**
|
39
|
+
* The action which can be used to retrieve the state of the EarnController.
|
40
|
+
*/
|
41
|
+
export type EarnControllerGetStateAction = ControllerGetStateAction<typeof controllerName, EarnControllerState>;
|
42
|
+
/**
|
43
|
+
* All actions that EarnController registers, to be called externally.
|
44
|
+
*/
|
45
|
+
export type EarnControllerActions = EarnControllerGetStateAction;
|
46
|
+
/**
|
47
|
+
* All actions that EarnController calls internally.
|
48
|
+
*/
|
49
|
+
export type AllowedActions = NetworkControllerGetNetworkClientByIdAction | NetworkControllerGetStateAction | AccountsControllerGetSelectedAccountAction;
|
50
|
+
/**
|
51
|
+
* The event that EarnController publishes when updating state.
|
52
|
+
*/
|
53
|
+
export type EarnControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, EarnControllerState>;
|
54
|
+
/**
|
55
|
+
* All events that EarnController publishes, to be subscribed to externally.
|
56
|
+
*/
|
57
|
+
export type EarnControllerEvents = EarnControllerStateChangeEvent;
|
58
|
+
/**
|
59
|
+
* All events that EarnController subscribes to internally.
|
60
|
+
*/
|
61
|
+
export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent;
|
62
|
+
/**
|
63
|
+
* The messenger which is restricted to actions and events accessed by
|
64
|
+
* EarnController.
|
65
|
+
*/
|
66
|
+
export type EarnControllerMessenger = RestrictedMessenger<typeof controllerName, EarnControllerActions | AllowedActions, EarnControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
|
67
|
+
/**
|
68
|
+
* EarnController manages DeFi earning opportunities across different protocols and chains.
|
69
|
+
*/
|
70
|
+
export declare class EarnController extends BaseController<typeof controllerName, EarnControllerState, EarnControllerMessenger> {
|
71
|
+
#private;
|
72
|
+
constructor({ messenger, state, }: {
|
73
|
+
messenger: EarnControllerMessenger;
|
74
|
+
state?: Partial<EarnControllerState>;
|
75
|
+
});
|
76
|
+
/**
|
77
|
+
* Refreshes the pooled stakes data for the current account.
|
78
|
+
* Fetches updated stake information including lifetime rewards, assets, and exit requests
|
79
|
+
* from the staking API service and updates the state.
|
80
|
+
*
|
81
|
+
* @returns A promise that resolves when the stakes data has been updated
|
82
|
+
*/
|
83
|
+
refreshPooledStakes(): Promise<void>;
|
84
|
+
/**
|
85
|
+
* Refreshes the staking eligibility status for the current account.
|
86
|
+
* Updates the eligibility status in the controller state based on the location and address blocklist for compliance.
|
87
|
+
*
|
88
|
+
* @returns A promise that resolves when the eligibility status has been updated
|
89
|
+
*/
|
90
|
+
refreshStakingEligibility(): Promise<void>;
|
91
|
+
/**
|
92
|
+
* Refreshes vault data for the current chain.
|
93
|
+
* Updates the vault data in the controller state including APY, capacity,
|
94
|
+
* fee percentage, total assets, and vault address.
|
95
|
+
*
|
96
|
+
* @returns A promise that resolves when the vault data has been updated
|
97
|
+
*/
|
98
|
+
refreshVaultData(): Promise<void>;
|
99
|
+
/**
|
100
|
+
* Refreshes all pooled staking related data including stakes, eligibility, and vault data.
|
101
|
+
* This method allows partial success, meaning some data may update while other requests fail.
|
102
|
+
* All errors are collected and thrown as a single error message.
|
103
|
+
*
|
104
|
+
* @returns A promise that resolves when all possible data has been updated
|
105
|
+
* @throws {Error} If any of the refresh operations fail, with concatenated error messages
|
106
|
+
*/
|
107
|
+
refreshPooledStakingData(): Promise<void>;
|
108
|
+
}
|
109
|
+
//# sourceMappingURL=EarnController.d.cts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"EarnController.d.cts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0CAA0C,EAC1C,4CAA4C,EAC7C,sCAAsC;AACvC,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EAEpB,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,iCAAiC,EAAE,qCAAqC;AACtF,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAChC,qCAAqC;AACtC,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,SAAS,EACf,4BAA4B;AAE7B,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAqBF,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,kBAAkB,CAAC;IACnC,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAcF;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,mBAAmB,CAwBnE;AAID;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,wBAAwB,CACjE,OAAO,cAAc,EACrB,mBAAmB,CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,2CAA2C,GAC3C,+BAA+B,GAC/B,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,0BAA0B,CACrE,OAAO,cAAc,EACrB,mBAAmB,CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,4CAA4C,GAC5C,iCAAiC,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,CACvD,OAAO,cAAc,EACrB,qBAAqB,GAAG,cAAc,EACtC,oBAAoB,GAAG,aAAa,EACpC,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAIF;;GAEG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAChD,OAAO,cAAc,EACrB,mBAAmB,EACnB,uBAAuB,CACxB;;gBAOa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,uBAAuB,CAAC;QACnC,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;KACtC;IAoGD;;;;;;OAMG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB1C;;;;;OAKG;IACG,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBhD;;;;;;OAMG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC;;;;;;;OAOG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBhD"}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
import type { AccountsControllerGetSelectedAccountAction, AccountsControllerSelectedAccountChangeEvent } from "@metamask/accounts-controller";
|
2
|
+
import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMessenger } from "@metamask/base-controller";
|
3
|
+
import { BaseController } from "@metamask/base-controller";
|
4
|
+
import type { NetworkControllerStateChangeEvent } from "@metamask/network-controller";
|
5
|
+
import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction } from "@metamask/network-controller";
|
6
|
+
import { type PooledStake, type VaultData } from "@metamask/stake-sdk";
|
7
|
+
export declare const controllerName = "EarnController";
|
8
|
+
export type PooledStakingState = {
|
9
|
+
pooledStakes: PooledStake;
|
10
|
+
exchangeRate: string;
|
11
|
+
vaultData: VaultData;
|
12
|
+
isEligible: boolean;
|
13
|
+
};
|
14
|
+
export type StablecoinLendingState = {
|
15
|
+
vaults: StablecoinVault[];
|
16
|
+
};
|
17
|
+
export type StablecoinVault = {
|
18
|
+
symbol: string;
|
19
|
+
name: string;
|
20
|
+
chainId: number;
|
21
|
+
tokenAddress: string;
|
22
|
+
vaultAddress: string;
|
23
|
+
currentAPY: string;
|
24
|
+
supply: string;
|
25
|
+
liquidity: string;
|
26
|
+
};
|
27
|
+
export type EarnControllerState = {
|
28
|
+
pooled_staking: PooledStakingState;
|
29
|
+
stablecoin_lending?: StablecoinLendingState;
|
30
|
+
lastUpdated: number;
|
31
|
+
};
|
32
|
+
/**
|
33
|
+
* Gets the default state for the EarnController.
|
34
|
+
*
|
35
|
+
* @returns The default EarnController state.
|
36
|
+
*/
|
37
|
+
export declare function getDefaultEarnControllerState(): EarnControllerState;
|
38
|
+
/**
|
39
|
+
* The action which can be used to retrieve the state of the EarnController.
|
40
|
+
*/
|
41
|
+
export type EarnControllerGetStateAction = ControllerGetStateAction<typeof controllerName, EarnControllerState>;
|
42
|
+
/**
|
43
|
+
* All actions that EarnController registers, to be called externally.
|
44
|
+
*/
|
45
|
+
export type EarnControllerActions = EarnControllerGetStateAction;
|
46
|
+
/**
|
47
|
+
* All actions that EarnController calls internally.
|
48
|
+
*/
|
49
|
+
export type AllowedActions = NetworkControllerGetNetworkClientByIdAction | NetworkControllerGetStateAction | AccountsControllerGetSelectedAccountAction;
|
50
|
+
/**
|
51
|
+
* The event that EarnController publishes when updating state.
|
52
|
+
*/
|
53
|
+
export type EarnControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, EarnControllerState>;
|
54
|
+
/**
|
55
|
+
* All events that EarnController publishes, to be subscribed to externally.
|
56
|
+
*/
|
57
|
+
export type EarnControllerEvents = EarnControllerStateChangeEvent;
|
58
|
+
/**
|
59
|
+
* All events that EarnController subscribes to internally.
|
60
|
+
*/
|
61
|
+
export type AllowedEvents = AccountsControllerSelectedAccountChangeEvent | NetworkControllerStateChangeEvent;
|
62
|
+
/**
|
63
|
+
* The messenger which is restricted to actions and events accessed by
|
64
|
+
* EarnController.
|
65
|
+
*/
|
66
|
+
export type EarnControllerMessenger = RestrictedMessenger<typeof controllerName, EarnControllerActions | AllowedActions, EarnControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
|
67
|
+
/**
|
68
|
+
* EarnController manages DeFi earning opportunities across different protocols and chains.
|
69
|
+
*/
|
70
|
+
export declare class EarnController extends BaseController<typeof controllerName, EarnControllerState, EarnControllerMessenger> {
|
71
|
+
#private;
|
72
|
+
constructor({ messenger, state, }: {
|
73
|
+
messenger: EarnControllerMessenger;
|
74
|
+
state?: Partial<EarnControllerState>;
|
75
|
+
});
|
76
|
+
/**
|
77
|
+
* Refreshes the pooled stakes data for the current account.
|
78
|
+
* Fetches updated stake information including lifetime rewards, assets, and exit requests
|
79
|
+
* from the staking API service and updates the state.
|
80
|
+
*
|
81
|
+
* @returns A promise that resolves when the stakes data has been updated
|
82
|
+
*/
|
83
|
+
refreshPooledStakes(): Promise<void>;
|
84
|
+
/**
|
85
|
+
* Refreshes the staking eligibility status for the current account.
|
86
|
+
* Updates the eligibility status in the controller state based on the location and address blocklist for compliance.
|
87
|
+
*
|
88
|
+
* @returns A promise that resolves when the eligibility status has been updated
|
89
|
+
*/
|
90
|
+
refreshStakingEligibility(): Promise<void>;
|
91
|
+
/**
|
92
|
+
* Refreshes vault data for the current chain.
|
93
|
+
* Updates the vault data in the controller state including APY, capacity,
|
94
|
+
* fee percentage, total assets, and vault address.
|
95
|
+
*
|
96
|
+
* @returns A promise that resolves when the vault data has been updated
|
97
|
+
*/
|
98
|
+
refreshVaultData(): Promise<void>;
|
99
|
+
/**
|
100
|
+
* Refreshes all pooled staking related data including stakes, eligibility, and vault data.
|
101
|
+
* This method allows partial success, meaning some data may update while other requests fail.
|
102
|
+
* All errors are collected and thrown as a single error message.
|
103
|
+
*
|
104
|
+
* @returns A promise that resolves when all possible data has been updated
|
105
|
+
* @throws {Error} If any of the refresh operations fail, with concatenated error messages
|
106
|
+
*/
|
107
|
+
refreshPooledStakingData(): Promise<void>;
|
108
|
+
}
|
109
|
+
//# sourceMappingURL=EarnController.d.mts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"EarnController.d.mts","sourceRoot":"","sources":["../src/EarnController.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0CAA0C,EAC1C,4CAA4C,EAC7C,sCAAsC;AACvC,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EAEpB,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAE3D,OAAO,KAAK,EAAE,iCAAiC,EAAE,qCAAqC;AACtF,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAChC,qCAAqC;AACtC,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,SAAS,EACf,4BAA4B;AAE7B,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAqBF,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,kBAAkB,CAAC;IACnC,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAcF;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,mBAAmB,CAwBnE;AAID;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,wBAAwB,CACjE,OAAO,cAAc,EACrB,mBAAmB,CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,2CAA2C,GAC3C,+BAA+B,GAC/B,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,0BAA0B,CACrE,OAAO,cAAc,EACrB,mBAAmB,CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,4CAA4C,GAC5C,iCAAiC,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,CACvD,OAAO,cAAc,EACrB,qBAAqB,GAAG,cAAc,EACtC,oBAAoB,GAAG,aAAa,EACpC,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAIF;;GAEG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAChD,OAAO,cAAc,EACrB,mBAAmB,EACnB,uBAAuB,CACxB;;gBAOa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,uBAAuB,CAAC;QACnC,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;KACtC;IAoGD;;;;;;OAMG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB1C;;;;;OAKG;IACG,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBhD;;;;;;OAMG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC;;;;;;;OAOG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBhD"}
|
@@ -0,0 +1,225 @@
|
|
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
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
9
|
+
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
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
11
|
+
};
|
12
|
+
var _EarnController_instances, _EarnController_stakeSDK, _EarnController_selectedNetworkClientId, _EarnController_stakingApiService, _EarnController_initializeSDK, _EarnController_getCurrentAccount, _EarnController_getCurrentChainId;
|
13
|
+
import { Web3Provider } from "@ethersproject/providers";
|
14
|
+
import { BaseController } from "@metamask/base-controller";
|
15
|
+
import { convertHexToDecimal } from "@metamask/controller-utils";
|
16
|
+
import { StakeSdk, StakingApiService } from "@metamask/stake-sdk";
|
17
|
+
export const controllerName = 'EarnController';
|
18
|
+
/**
|
19
|
+
* Metadata for the EarnController.
|
20
|
+
*/
|
21
|
+
const earnControllerMetadata = {
|
22
|
+
pooled_staking: {
|
23
|
+
persist: true,
|
24
|
+
anonymous: false,
|
25
|
+
},
|
26
|
+
stablecoin_lending: {
|
27
|
+
persist: true,
|
28
|
+
anonymous: false,
|
29
|
+
},
|
30
|
+
lastUpdated: {
|
31
|
+
persist: false,
|
32
|
+
anonymous: true,
|
33
|
+
},
|
34
|
+
};
|
35
|
+
// === Default State ===
|
36
|
+
const DEFAULT_STABLECOIN_VAULT = {
|
37
|
+
symbol: '',
|
38
|
+
name: '',
|
39
|
+
chainId: 0,
|
40
|
+
tokenAddress: '',
|
41
|
+
vaultAddress: '',
|
42
|
+
currentAPY: '0',
|
43
|
+
supply: '0',
|
44
|
+
liquidity: '0',
|
45
|
+
};
|
46
|
+
/**
|
47
|
+
* Gets the default state for the EarnController.
|
48
|
+
*
|
49
|
+
* @returns The default EarnController state.
|
50
|
+
*/
|
51
|
+
export function getDefaultEarnControllerState() {
|
52
|
+
return {
|
53
|
+
pooled_staking: {
|
54
|
+
pooledStakes: {
|
55
|
+
account: '',
|
56
|
+
lifetimeRewards: '0',
|
57
|
+
assets: '0',
|
58
|
+
exitRequests: [],
|
59
|
+
},
|
60
|
+
exchangeRate: '1',
|
61
|
+
vaultData: {
|
62
|
+
apy: '0',
|
63
|
+
capacity: '0',
|
64
|
+
feePercent: 0,
|
65
|
+
totalAssets: '0',
|
66
|
+
vaultAddress: '0x0000000000000000000000000000000000000000',
|
67
|
+
},
|
68
|
+
isEligible: false,
|
69
|
+
},
|
70
|
+
stablecoin_lending: {
|
71
|
+
vaults: [DEFAULT_STABLECOIN_VAULT],
|
72
|
+
},
|
73
|
+
lastUpdated: 0,
|
74
|
+
};
|
75
|
+
}
|
76
|
+
// === CONTROLLER DEFINITION ===
|
77
|
+
/**
|
78
|
+
* EarnController manages DeFi earning opportunities across different protocols and chains.
|
79
|
+
*/
|
80
|
+
export class EarnController extends BaseController {
|
81
|
+
constructor({ messenger, state = {}, }) {
|
82
|
+
super({
|
83
|
+
name: controllerName,
|
84
|
+
metadata: earnControllerMetadata,
|
85
|
+
messenger,
|
86
|
+
state: {
|
87
|
+
...getDefaultEarnControllerState(),
|
88
|
+
...state,
|
89
|
+
},
|
90
|
+
});
|
91
|
+
_EarnController_instances.add(this);
|
92
|
+
_EarnController_stakeSDK.set(this, null);
|
93
|
+
_EarnController_selectedNetworkClientId.set(this, void 0);
|
94
|
+
_EarnController_stakingApiService.set(this, new StakingApiService());
|
95
|
+
__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this);
|
96
|
+
this.refreshPooledStakingData().catch(console.error);
|
97
|
+
const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
|
98
|
+
__classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, selectedNetworkClientId, "f");
|
99
|
+
this.messagingSystem.subscribe('NetworkController:stateChange', (networkControllerState) => {
|
100
|
+
if (networkControllerState.selectedNetworkClientId !==
|
101
|
+
__classPrivateFieldGet(this, _EarnController_selectedNetworkClientId, "f")) {
|
102
|
+
__classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_initializeSDK).call(this, networkControllerState.selectedNetworkClientId);
|
103
|
+
this.refreshPooledStakingData().catch(console.error);
|
104
|
+
}
|
105
|
+
__classPrivateFieldSet(this, _EarnController_selectedNetworkClientId, networkControllerState.selectedNetworkClientId, "f");
|
106
|
+
});
|
107
|
+
// Listen for account changes
|
108
|
+
this.messagingSystem.subscribe('AccountsController:selectedAccountChange', () => {
|
109
|
+
this.refreshPooledStakingData().catch(console.error);
|
110
|
+
});
|
111
|
+
}
|
112
|
+
/**
|
113
|
+
* Refreshes the pooled stakes data for the current account.
|
114
|
+
* Fetches updated stake information including lifetime rewards, assets, and exit requests
|
115
|
+
* from the staking API service and updates the state.
|
116
|
+
*
|
117
|
+
* @returns A promise that resolves when the stakes data has been updated
|
118
|
+
*/
|
119
|
+
async refreshPooledStakes() {
|
120
|
+
const currentAccount = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this);
|
121
|
+
if (!currentAccount?.address) {
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
|
125
|
+
const { accounts, exchangeRate } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakes([currentAccount.address], chainId);
|
126
|
+
this.update((state) => {
|
127
|
+
state.pooled_staking.pooledStakes = accounts[0];
|
128
|
+
state.pooled_staking.exchangeRate = exchangeRate;
|
129
|
+
});
|
130
|
+
}
|
131
|
+
/**
|
132
|
+
* Refreshes the staking eligibility status for the current account.
|
133
|
+
* Updates the eligibility status in the controller state based on the location and address blocklist for compliance.
|
134
|
+
*
|
135
|
+
* @returns A promise that resolves when the eligibility status has been updated
|
136
|
+
*/
|
137
|
+
async refreshStakingEligibility() {
|
138
|
+
const currentAccount = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentAccount).call(this);
|
139
|
+
if (!currentAccount?.address) {
|
140
|
+
return;
|
141
|
+
}
|
142
|
+
const { eligible: isEligible } = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getPooledStakingEligibility([
|
143
|
+
currentAccount.address,
|
144
|
+
]);
|
145
|
+
this.update((state) => {
|
146
|
+
state.pooled_staking.isEligible = isEligible;
|
147
|
+
});
|
148
|
+
}
|
149
|
+
/**
|
150
|
+
* Refreshes vault data for the current chain.
|
151
|
+
* Updates the vault data in the controller state including APY, capacity,
|
152
|
+
* fee percentage, total assets, and vault address.
|
153
|
+
*
|
154
|
+
* @returns A promise that resolves when the vault data has been updated
|
155
|
+
*/
|
156
|
+
async refreshVaultData() {
|
157
|
+
const chainId = __classPrivateFieldGet(this, _EarnController_instances, "m", _EarnController_getCurrentChainId).call(this);
|
158
|
+
const vaultData = await __classPrivateFieldGet(this, _EarnController_stakingApiService, "f").getVaultData(chainId);
|
159
|
+
this.update((state) => {
|
160
|
+
state.pooled_staking.vaultData = vaultData;
|
161
|
+
});
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* Refreshes all pooled staking related data including stakes, eligibility, and vault data.
|
165
|
+
* This method allows partial success, meaning some data may update while other requests fail.
|
166
|
+
* All errors are collected and thrown as a single error message.
|
167
|
+
*
|
168
|
+
* @returns A promise that resolves when all possible data has been updated
|
169
|
+
* @throws {Error} If any of the refresh operations fail, with concatenated error messages
|
170
|
+
*/
|
171
|
+
async refreshPooledStakingData() {
|
172
|
+
const errors = [];
|
173
|
+
await Promise.all([
|
174
|
+
this.refreshPooledStakes().catch((error) => {
|
175
|
+
errors.push(error);
|
176
|
+
}),
|
177
|
+
this.refreshStakingEligibility().catch((error) => {
|
178
|
+
errors.push(error);
|
179
|
+
}),
|
180
|
+
this.refreshVaultData().catch((error) => {
|
181
|
+
errors.push(error);
|
182
|
+
}),
|
183
|
+
]);
|
184
|
+
if (errors.length > 0) {
|
185
|
+
throw new Error(`Failed to refresh some staking data: ${errors
|
186
|
+
.map((e) => e.message)
|
187
|
+
.join(', ')}`);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
_EarnController_stakeSDK = new WeakMap(), _EarnController_selectedNetworkClientId = new WeakMap(), _EarnController_stakingApiService = new WeakMap(), _EarnController_instances = new WeakSet(), _EarnController_initializeSDK = function _EarnController_initializeSDK(networkClientId) {
|
192
|
+
const { selectedNetworkClientId } = networkClientId
|
193
|
+
? { selectedNetworkClientId: networkClientId }
|
194
|
+
: this.messagingSystem.call('NetworkController:getState');
|
195
|
+
const networkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
196
|
+
if (!networkClient?.provider) {
|
197
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
const provider = new Web3Provider(networkClient.provider);
|
201
|
+
const { chainId } = networkClient.configuration;
|
202
|
+
// Initialize appropriate contracts based on chainId
|
203
|
+
const config = {
|
204
|
+
chainId: convertHexToDecimal(chainId),
|
205
|
+
};
|
206
|
+
try {
|
207
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, StakeSdk.create(config), "f");
|
208
|
+
__classPrivateFieldGet(this, _EarnController_stakeSDK, "f").pooledStakingContract.connectSignerOrProvider(provider);
|
209
|
+
}
|
210
|
+
catch (error) {
|
211
|
+
__classPrivateFieldSet(this, _EarnController_stakeSDK, null, "f");
|
212
|
+
// Only log unexpected errors, not unsupported chain errors
|
213
|
+
if (!(error instanceof Error &&
|
214
|
+
error.message.includes('Unsupported chainId'))) {
|
215
|
+
console.error('Stake SDK initialization failed:', error);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}, _EarnController_getCurrentAccount = function _EarnController_getCurrentAccount() {
|
219
|
+
return this.messagingSystem.call('AccountsController:getSelectedAccount');
|
220
|
+
}, _EarnController_getCurrentChainId = function _EarnController_getCurrentChainId() {
|
221
|
+
const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
|
222
|
+
const { configuration: { chainId }, } = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
223
|
+
return convertHexToDecimal(chainId);
|
224
|
+
};
|
225
|
+
//# sourceMappingURL=EarnController.mjs.map
|
@@ -0,0 +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 { NetworkControllerStateChangeEvent } from '@metamask/network-controller';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n} from '@metamask/network-controller';\nimport {\n StakeSdk,\n StakingApiService,\n type PooledStake,\n type StakeSdkConfig,\n type VaultData,\n} from '@metamask/stake-sdk';\n\nexport const controllerName = 'EarnController';\n\nexport type PooledStakingState = {\n pooledStakes: PooledStake;\n exchangeRate: string;\n vaultData: VaultData;\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\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 vaultData: {\n apy: '0',\n capacity: '0',\n feePercent: 0,\n totalAssets: '0',\n vaultAddress: '0x0000000000000000000000000000000000000000',\n },\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.refreshPooledStakingData().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 () => {\n this.refreshPooledStakingData().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 * @returns A promise that resolves when the stakes data has been updated\n */\n async refreshPooledStakes(): Promise<void> {\n const currentAccount = this.#getCurrentAccount();\n if (!currentAccount?.address) {\n return;\n }\n\n const chainId = this.#getCurrentChainId();\n\n const { accounts, exchangeRate } =\n await this.#stakingApiService.getPooledStakes(\n [currentAccount.address],\n chainId,\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 * @returns A promise that resolves when the eligibility status has been updated\n */\n async refreshStakingEligibility(): Promise<void> {\n const currentAccount = this.#getCurrentAccount();\n if (!currentAccount?.address) {\n return;\n }\n\n const { eligible: isEligible } =\n await this.#stakingApiService.getPooledStakingEligibility([\n currentAccount.address,\n ]);\n\n this.update((state) => {\n state.pooled_staking.isEligible = isEligible;\n });\n }\n\n /**\n * Refreshes vault data for the current chain.\n * Updates the vault data 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 data has been updated\n */\n async refreshVaultData(): Promise<void> {\n const chainId = this.#getCurrentChainId();\n const vaultData = await this.#stakingApiService.getVaultData(chainId);\n\n this.update((state) => {\n state.pooled_staking.vaultData = vaultData;\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 * @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(): Promise<void> {\n const errors: Error[] = [];\n\n await Promise.all([\n this.refreshPooledStakes().catch((error) => {\n errors.push(error);\n }),\n this.refreshStakingEligibility().catch((error) => {\n errors.push(error);\n }),\n this.refreshVaultData().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/dist/index.cjs
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.EarnController = exports.getDefaultEarnControllerState = exports.controllerName = void 0;
|
4
|
+
var EarnController_1 = require("./EarnController.cjs");
|
5
|
+
Object.defineProperty(exports, "controllerName", { enumerable: true, get: function () { return EarnController_1.controllerName; } });
|
6
|
+
Object.defineProperty(exports, "getDefaultEarnControllerState", { enumerable: true, get: function () { return EarnController_1.getDefaultEarnControllerState; } });
|
7
|
+
Object.defineProperty(exports, "EarnController", { enumerable: true, get: function () { return EarnController_1.EarnController; } });
|
8
|
+
//# sourceMappingURL=index.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAYA,uDAI0B;AAHxB,gHAAA,cAAc,OAAA;AACd,+HAAA,6BAA6B,OAAA;AAC7B,gHAAA,cAAc,OAAA","sourcesContent":["export type {\n PooledStakingState,\n StablecoinLendingState,\n StablecoinVault,\n EarnControllerState,\n EarnControllerGetStateAction,\n EarnControllerStateChangeEvent,\n EarnControllerActions,\n EarnControllerEvents,\n EarnControllerMessenger,\n} from './EarnController';\n\nexport {\n controllerName,\n getDefaultEarnControllerState,\n EarnController,\n} from './EarnController';\n"]}
|
package/dist/index.d.cts
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
export type { PooledStakingState, StablecoinLendingState, StablecoinVault, EarnControllerState, EarnControllerGetStateAction, EarnControllerStateChangeEvent, EarnControllerActions, EarnControllerEvents, EarnControllerMessenger, } from "./EarnController.cjs";
|
2
|
+
export { controllerName, getDefaultEarnControllerState, EarnController, } from "./EarnController.cjs";
|
3
|
+
//# sourceMappingURL=index.d.cts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,4BAA4B,EAC5B,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,GACxB,6BAAyB;AAE1B,OAAO,EACL,cAAc,EACd,6BAA6B,EAC7B,cAAc,GACf,6BAAyB"}
|
package/dist/index.d.mts
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
export type { PooledStakingState, StablecoinLendingState, StablecoinVault, EarnControllerState, EarnControllerGetStateAction, EarnControllerStateChangeEvent, EarnControllerActions, EarnControllerEvents, EarnControllerMessenger, } from "./EarnController.mjs";
|
2
|
+
export { controllerName, getDefaultEarnControllerState, EarnController, } from "./EarnController.mjs";
|
3
|
+
//# sourceMappingURL=index.d.mts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,4BAA4B,EAC5B,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,GACxB,6BAAyB;AAE1B,OAAO,EACL,cAAc,EACd,6BAA6B,EAC7B,cAAc,GACf,6BAAyB"}
|
package/dist/index.mjs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,cAAc,EACd,6BAA6B,EAC7B,cAAc,EACf,6BAAyB","sourcesContent":["export type {\n PooledStakingState,\n StablecoinLendingState,\n StablecoinVault,\n EarnControllerState,\n EarnControllerGetStateAction,\n EarnControllerStateChangeEvent,\n EarnControllerActions,\n EarnControllerEvents,\n EarnControllerMessenger,\n} from './EarnController';\n\nexport {\n controllerName,\n getDefaultEarnControllerState,\n EarnController,\n} from './EarnController';\n"]}
|
package/package.json
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
{
|
2
|
+
"name": "@metamask/earn-controller",
|
3
|
+
"version": "0.1.0",
|
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
|
+
"keywords": [
|
6
|
+
"MetaMask",
|
7
|
+
"Ethereum"
|
8
|
+
],
|
9
|
+
"homepage": "https://github.com/MetaMask/core/tree/main/packages/earn-controller#readme",
|
10
|
+
"bugs": {
|
11
|
+
"url": "https://github.com/MetaMask/core/issues"
|
12
|
+
},
|
13
|
+
"repository": {
|
14
|
+
"type": "git",
|
15
|
+
"url": "https://github.com/MetaMask/core.git"
|
16
|
+
},
|
17
|
+
"license": "MIT",
|
18
|
+
"sideEffects": false,
|
19
|
+
"exports": {
|
20
|
+
".": {
|
21
|
+
"import": {
|
22
|
+
"types": "./dist/index.d.mts",
|
23
|
+
"default": "./dist/index.mjs"
|
24
|
+
},
|
25
|
+
"require": {
|
26
|
+
"types": "./dist/index.d.cts",
|
27
|
+
"default": "./dist/index.cjs"
|
28
|
+
}
|
29
|
+
},
|
30
|
+
"./package.json": "./package.json"
|
31
|
+
},
|
32
|
+
"main": "./dist/index.cjs",
|
33
|
+
"types": "./dist/index.d.cts",
|
34
|
+
"files": [
|
35
|
+
"dist/"
|
36
|
+
],
|
37
|
+
"scripts": {
|
38
|
+
"build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references",
|
39
|
+
"build:docs": "typedoc",
|
40
|
+
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/earn-controller",
|
41
|
+
"changelog:update": "../../scripts/update-changelog.sh @metamask/earn-controller",
|
42
|
+
"publish:preview": "yarn npm publish --tag preview",
|
43
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
|
44
|
+
"test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
|
45
|
+
"test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
|
46
|
+
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
|
47
|
+
"since-latest-release": "../../scripts/since-latest-release.sh"
|
48
|
+
},
|
49
|
+
"dependencies": {
|
50
|
+
"@ethersproject/providers": "^5.7.0",
|
51
|
+
"@metamask/base-controller": "^7.1.1",
|
52
|
+
"@metamask/controller-utils": "^11.4.5",
|
53
|
+
"@metamask/stake-sdk": "^1.0.0"
|
54
|
+
},
|
55
|
+
"devDependencies": {
|
56
|
+
"@metamask/accounts-controller": "^22.0.0",
|
57
|
+
"@metamask/auto-changelog": "^3.4.4",
|
58
|
+
"@metamask/network-controller": "^22.1.1",
|
59
|
+
"@types/jest": "^27.4.1",
|
60
|
+
"deepmerge": "^4.2.2",
|
61
|
+
"jest": "^27.5.1",
|
62
|
+
"ts-jest": "^27.1.4",
|
63
|
+
"typedoc": "^0.24.8",
|
64
|
+
"typedoc-plugin-missing-exports": "^2.0.0",
|
65
|
+
"typescript": "~5.2.2"
|
66
|
+
},
|
67
|
+
"peerDependencies": {
|
68
|
+
"@metamask/accounts-controller": "^22.0.0",
|
69
|
+
"@metamask/network-controller": "^22.1.1"
|
70
|
+
},
|
71
|
+
"engines": {
|
72
|
+
"node": "^18.18 || >=20"
|
73
|
+
},
|
74
|
+
"publishConfig": {
|
75
|
+
"access": "public",
|
76
|
+
"registry": "https://registry.npmjs.org/"
|
77
|
+
}
|
78
|
+
}
|