@metamask-previews/assets-controllers 109.4.1-preview-30b493585 → 109.4.1-preview-8abc30aca
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 +2 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.cjs +7 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.cjs.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.d.cts +28 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.d.cts.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.d.mts +28 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.d.mts.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.mjs +6 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.mjs.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.cjs +128 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.cjs.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.d.cts +89 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.d.cts.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.d.mts +89 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.d.mts.map +1 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.mjs +123 -0
- package/dist/DeFiPositionsController/DeFiPositionsControllerV2.mjs.map +1 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.cjs +73 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.cjs.map +1 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.d.cts +34 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.d.cts.map +1 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.d.mts +34 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.d.mts.map +1 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.mjs +69 -0
- package/dist/DeFiPositionsController/build-defi-balances-query.mjs.map +1 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.cjs +235 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.cjs.map +1 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.d.cts +117 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.d.cts.map +1 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.d.mts +117 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.d.mts.map +1 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.mjs +231 -0
- package/dist/DeFiPositionsController/group-defi-positions-v6.mjs.map +1 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.cjs +71 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.cjs.map +1 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.d.cts +16 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.d.cts.map +1 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.d.mts +16 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.d.mts.map +1 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.mjs +67 -0
- package/dist/DeFiPositionsController/merge-positions-for-accounts.mjs.map +1 -0
- package/dist/index.cjs +9 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +6 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- Add `DeFiPositionsControllerV2`, which fetches DeFi positions from the Accounts API v6 multiaccount balances endpoint and stores them in a client-ready shape under `allDeFiPositionsV2` ([#9503](https://github.com/MetaMask/core/pull/9503))
|
|
13
|
+
- Export `DeFiPositionsControllerV2` and supporting types
|
|
12
14
|
- Add `isDeprecated` option to `TokenDetectionController` constructor ([#9362](https://github.com/MetaMask/core/pull/9362))
|
|
13
15
|
- When `isDeprecated()` returns `true`, no network requests are sent and entry points bail early at `start`, `detectTokens`, `_executePoll`, `addDetectedTokensViaWs`, and `addDetectedTokensViaPolling`, so no token detection work runs while the controller is disabled.
|
|
14
16
|
- The function is re-evaluated on each entry point so it can be toggled at runtime without reconstructing the controller.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2-method-action-types.cjs","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { DeFiPositionsControllerV2 } from './DeFiPositionsControllerV2';\n\n/**\n * Fetches DeFi positions for the selected account group. Each account key in\n * a ready response replaces that account's state (other accounts stay).\n * Accounts still indexing (`processingDefiPositions`) are skipped so prior\n * state is kept for them. No-ops when disabled or when the group has no\n * supported accounts. Caching / spam prevention is handled by the apiClient\n * TanStack Query cache (keyed by accounts + query options including\n * `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.\n * pull-to-refresh).\n *\n * @param options - Optional fetch modifiers.\n * @param options.forceRefresh - When true, bypass the apiClient cache and\n * fetch immediately.\n */\nexport type DeFiPositionsControllerV2FetchDeFiPositionsAction = {\n type: `DeFiPositionsControllerV2:fetchDeFiPositions`;\n handler: DeFiPositionsControllerV2['fetchDeFiPositions'];\n};\n\n/**\n * Union of all DeFiPositionsControllerV2 action types.\n */\nexport type DeFiPositionsControllerV2MethodActions =\n DeFiPositionsControllerV2FetchDeFiPositionsAction;\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is auto generated.
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
import type { DeFiPositionsControllerV2 } from "./DeFiPositionsControllerV2.cjs";
|
|
6
|
+
/**
|
|
7
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
8
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
9
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
10
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
11
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
12
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
13
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
14
|
+
* pull-to-refresh).
|
|
15
|
+
*
|
|
16
|
+
* @param options - Optional fetch modifiers.
|
|
17
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
18
|
+
* fetch immediately.
|
|
19
|
+
*/
|
|
20
|
+
export type DeFiPositionsControllerV2FetchDeFiPositionsAction = {
|
|
21
|
+
type: `DeFiPositionsControllerV2:fetchDeFiPositions`;
|
|
22
|
+
handler: DeFiPositionsControllerV2['fetchDeFiPositions'];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Union of all DeFiPositionsControllerV2 action types.
|
|
26
|
+
*/
|
|
27
|
+
export type DeFiPositionsControllerV2MethodActions = DeFiPositionsControllerV2FetchDeFiPositionsAction;
|
|
28
|
+
//# sourceMappingURL=DeFiPositionsControllerV2-method-action-types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2-method-action-types.d.cts","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,wCAAoC;AAE7E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iDAAiD,GAAG;IAC9D,IAAI,EAAE,8CAA8C,CAAC;IACrD,OAAO,EAAE,yBAAyB,CAAC,oBAAoB,CAAC,CAAC;CAC1D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAChD,iDAAiD,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is auto generated.
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
import type { DeFiPositionsControllerV2 } from "./DeFiPositionsControllerV2.mjs";
|
|
6
|
+
/**
|
|
7
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
8
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
9
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
10
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
11
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
12
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
13
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
14
|
+
* pull-to-refresh).
|
|
15
|
+
*
|
|
16
|
+
* @param options - Optional fetch modifiers.
|
|
17
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
18
|
+
* fetch immediately.
|
|
19
|
+
*/
|
|
20
|
+
export type DeFiPositionsControllerV2FetchDeFiPositionsAction = {
|
|
21
|
+
type: `DeFiPositionsControllerV2:fetchDeFiPositions`;
|
|
22
|
+
handler: DeFiPositionsControllerV2['fetchDeFiPositions'];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Union of all DeFiPositionsControllerV2 action types.
|
|
26
|
+
*/
|
|
27
|
+
export type DeFiPositionsControllerV2MethodActions = DeFiPositionsControllerV2FetchDeFiPositionsAction;
|
|
28
|
+
//# sourceMappingURL=DeFiPositionsControllerV2-method-action-types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2-method-action-types.d.mts","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,wCAAoC;AAE7E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iDAAiD,GAAG;IAC9D,IAAI,EAAE,8CAA8C,CAAC;IACrD,OAAO,EAAE,yBAAyB,CAAC,oBAAoB,CAAC,CAAC;CAC1D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAChD,iDAAiD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2-method-action-types.mjs","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { DeFiPositionsControllerV2 } from './DeFiPositionsControllerV2';\n\n/**\n * Fetches DeFi positions for the selected account group. Each account key in\n * a ready response replaces that account's state (other accounts stay).\n * Accounts still indexing (`processingDefiPositions`) are skipped so prior\n * state is kept for them. No-ops when disabled or when the group has no\n * supported accounts. Caching / spam prevention is handled by the apiClient\n * TanStack Query cache (keyed by accounts + query options including\n * `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.\n * pull-to-refresh).\n *\n * @param options - Optional fetch modifiers.\n * @param options.forceRefresh - When true, bypass the apiClient cache and\n * fetch immediately.\n */\nexport type DeFiPositionsControllerV2FetchDeFiPositionsAction = {\n type: `DeFiPositionsControllerV2:fetchDeFiPositions`;\n handler: DeFiPositionsControllerV2['fetchDeFiPositions'];\n};\n\n/**\n * Union of all DeFiPositionsControllerV2 action types.\n */\nexport type DeFiPositionsControllerV2MethodActions =\n DeFiPositionsControllerV2FetchDeFiPositionsAction;\n"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
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");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
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");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _DeFiPositionsControllerV2_apiClient, _DeFiPositionsControllerV2_isEnabled, _DeFiPositionsControllerV2_getVsCurrency;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.DeFiPositionsControllerV2 = exports.getDefaultDeFiPositionsControllerV2State = void 0;
|
|
16
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
17
|
+
const build_defi_balances_query_1 = require("./build-defi-balances-query.cjs");
|
|
18
|
+
const group_defi_positions_v6_1 = require("./group-defi-positions-v6.cjs");
|
|
19
|
+
const controllerName = 'DeFiPositionsControllerV2';
|
|
20
|
+
const MESSENGER_EXPOSED_METHODS = ['fetchDeFiPositions'];
|
|
21
|
+
const controllerMetadata = {
|
|
22
|
+
allDeFiPositionsV2: {
|
|
23
|
+
includeInStateLogs: false,
|
|
24
|
+
persist: true,
|
|
25
|
+
includeInDebugSnapshot: false,
|
|
26
|
+
usedInUi: true,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const getDefaultDeFiPositionsControllerV2State = () => {
|
|
30
|
+
return {
|
|
31
|
+
allDeFiPositionsV2: {},
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
exports.getDefaultDeFiPositionsControllerV2State = getDefaultDeFiPositionsControllerV2State;
|
|
35
|
+
/**
|
|
36
|
+
* Controller that fetches DeFi positions for the selected account group from
|
|
37
|
+
* the Accounts API (v6 multiaccount balances) and stores them in the shape the
|
|
38
|
+
* client consumes directly.
|
|
39
|
+
*
|
|
40
|
+
* Deduplication and freshness are handled by the shared TanStack Query cache on
|
|
41
|
+
* {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass
|
|
42
|
+
* `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.
|
|
43
|
+
*/
|
|
44
|
+
class DeFiPositionsControllerV2 extends base_controller_1.BaseController {
|
|
45
|
+
/**
|
|
46
|
+
* @param options - Constructor options.
|
|
47
|
+
* @param options.messenger - The controller messenger.
|
|
48
|
+
* @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.
|
|
49
|
+
* @param options.isEnabled - Returns whether fetching is enabled (default: () => false).
|
|
50
|
+
* @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').
|
|
51
|
+
* @param options.state - Initial controller state.
|
|
52
|
+
*/
|
|
53
|
+
constructor({ messenger, apiClient, isEnabled, getVsCurrency, state, }) {
|
|
54
|
+
super({
|
|
55
|
+
name: controllerName,
|
|
56
|
+
metadata: controllerMetadata,
|
|
57
|
+
messenger,
|
|
58
|
+
state: {
|
|
59
|
+
...(0, exports.getDefaultDeFiPositionsControllerV2State)(),
|
|
60
|
+
...state,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
_DeFiPositionsControllerV2_apiClient.set(this, void 0);
|
|
64
|
+
_DeFiPositionsControllerV2_isEnabled.set(this, void 0);
|
|
65
|
+
_DeFiPositionsControllerV2_getVsCurrency.set(this, void 0);
|
|
66
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_apiClient, apiClient, "f");
|
|
67
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_isEnabled, isEnabled, "f");
|
|
68
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_getVsCurrency, getVsCurrency, "f");
|
|
69
|
+
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
73
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
74
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
75
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
76
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
77
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
78
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
79
|
+
* pull-to-refresh).
|
|
80
|
+
*
|
|
81
|
+
* @param options - Optional fetch modifiers.
|
|
82
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
83
|
+
* fetch immediately.
|
|
84
|
+
*/
|
|
85
|
+
async fetchDeFiPositions(options) {
|
|
86
|
+
if (!__classPrivateFieldGet(this, _DeFiPositionsControllerV2_isEnabled, "f").call(this)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const selectedAccounts = this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
90
|
+
const { networks, internalAccountIdByCaip } = (0, build_defi_balances_query_1.buildDeFiBalancesQuery)(selectedAccounts);
|
|
91
|
+
if (internalAccountIdByCaip.size === 0 || networks.length === 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const accountIds = [...internalAccountIdByCaip.keys()];
|
|
95
|
+
const vsCurrency = __classPrivateFieldGet(this, _DeFiPositionsControllerV2_getVsCurrency, "f").call(this).toLowerCase();
|
|
96
|
+
try {
|
|
97
|
+
const response = await __classPrivateFieldGet(this, _DeFiPositionsControllerV2_apiClient, "f").accounts.fetchV6MultiAccountBalances(accountIds, {
|
|
98
|
+
networks,
|
|
99
|
+
includeDeFiBalances: true,
|
|
100
|
+
forceFetchDeFiPositions: true,
|
|
101
|
+
includePrices: true,
|
|
102
|
+
vsCurrency,
|
|
103
|
+
}, {
|
|
104
|
+
// staleTime: 0 makes TanStack treat the cache as stale for this call.
|
|
105
|
+
...(options?.forceRefresh ? { staleTime: 0 } : {}),
|
|
106
|
+
});
|
|
107
|
+
// Skip accounts still indexing — their balances are not a valid snapshot.
|
|
108
|
+
const readyAccounts = response.accounts.filter((account) => !account.processingDefiPositions);
|
|
109
|
+
if (readyAccounts.length === 0) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const positionsByAccount = (0, group_defi_positions_v6_1.groupDeFiPositionsV6)({ ...response, accounts: readyAccounts }, internalAccountIdByCaip);
|
|
113
|
+
// Last valid response wins per ready account; processing / other accounts
|
|
114
|
+
// stay untouched.
|
|
115
|
+
this.update((state) => {
|
|
116
|
+
for (const [accountId, positions] of Object.entries(positionsByAccount)) {
|
|
117
|
+
state.allDeFiPositionsV2[accountId] = positions;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error('Failed to fetch DeFi positions', error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.DeFiPositionsControllerV2 = DeFiPositionsControllerV2;
|
|
127
|
+
_DeFiPositionsControllerV2_apiClient = new WeakMap(), _DeFiPositionsControllerV2_isEnabled = new WeakMap(), _DeFiPositionsControllerV2_getVsCurrency = new WeakMap();
|
|
128
|
+
//# sourceMappingURL=DeFiPositionsControllerV2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2.cjs","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerGetAccountsFromSelectedAccountGroupAction } from '@metamask/account-tree-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { buildDeFiBalancesQuery } from './build-defi-balances-query';\nimport type { DeFiPositionsControllerV2MethodActions } from './DeFiPositionsControllerV2-method-action-types';\nimport type { DeFiPositionsByAccount } from './group-defi-positions-v6';\nimport { groupDeFiPositionsV6 } from './group-defi-positions-v6';\n\nconst controllerName = 'DeFiPositionsControllerV2';\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchDeFiPositions'] as const;\n\nexport type DeFiPositionsControllerV2State = {\n /**\n * DeFi positions keyed by internal MetaMask account ID (`InternalAccount.id`,\n * the same key AssetsController uses). Each account maps to a flat list of\n * protocol groups shown in the DeFi tab, each carrying its own `chainId` for\n * filtering plus the details-page sections embedded inside it. This is\n * exactly the shape the client consumes, so no further transformation is\n * needed on read.\n *\n * Named `allDeFiPositionsV2` (rather than `allDeFiPositions`) so it can live\n * alongside the legacy `DeFiPositionsController` in clients that flatten every\n * controller's state into a single object (e.g. the extension background),\n * without colliding on the shared `allDeFiPositions` key.\n */\n allDeFiPositionsV2: DeFiPositionsByAccount;\n};\n\nconst controllerMetadata: StateMetadata<DeFiPositionsControllerV2State> = {\n allDeFiPositionsV2: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\nexport const getDefaultDeFiPositionsControllerV2State =\n (): DeFiPositionsControllerV2State => {\n return {\n allDeFiPositionsV2: {},\n };\n };\n\nexport type DeFiPositionsControllerV2GetStateAction = ControllerGetStateAction<\n typeof controllerName,\n DeFiPositionsControllerV2State\n>;\n\nexport type DeFiPositionsControllerV2Actions =\n | DeFiPositionsControllerV2GetStateAction\n | DeFiPositionsControllerV2MethodActions;\n\nexport type DeFiPositionsControllerV2StateChangedEvent =\n ControllerStateChangedEvent<\n typeof controllerName,\n DeFiPositionsControllerV2State\n >;\n\nexport type DeFiPositionsControllerV2Events =\n DeFiPositionsControllerV2StateChangedEvent;\n\n/**\n * The external actions available to the {@link DeFiPositionsControllerV2}.\n */\nexport type AllowedActions =\n AccountTreeControllerGetAccountsFromSelectedAccountGroupAction;\n\n/**\n * The external events available to the {@link DeFiPositionsControllerV2}.\n *\n * None yet — clients must call `fetchDeFiPositions` (and optionally\n * `{ forceRefresh: true }`) on their own triggers. Likely future subscriptions:\n * `AccountTreeController:selectedAccountGroupChange`,\n * `TransactionController:transactionConfirmed`, and `KeyringController:lock`.\n */\nexport type AllowedEvents = never;\n\nexport type DeFiPositionsControllerV2Messenger = Messenger<\n typeof controllerName,\n DeFiPositionsControllerV2Actions | AllowedActions,\n DeFiPositionsControllerV2Events | AllowedEvents\n>;\n\n/**\n * Controller that fetches DeFi positions for the selected account group from\n * the Accounts API (v6 multiaccount balances) and stores them in the shape the\n * client consumes directly.\n *\n * Deduplication and freshness are handled by the shared TanStack Query cache on\n * {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass\n * `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.\n */\nexport class DeFiPositionsControllerV2 extends BaseController<\n typeof controllerName,\n DeFiPositionsControllerV2State,\n DeFiPositionsControllerV2Messenger\n> {\n readonly #apiClient: ApiPlatformClient;\n\n readonly #isEnabled: () => boolean;\n\n readonly #getVsCurrency: () => string;\n\n /**\n * @param options - Constructor options.\n * @param options.messenger - The controller messenger.\n * @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.\n * @param options.isEnabled - Returns whether fetching is enabled (default: () => false).\n * @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n apiClient,\n isEnabled,\n getVsCurrency,\n state,\n }: {\n messenger: DeFiPositionsControllerV2Messenger;\n apiClient: ApiPlatformClient;\n isEnabled: () => boolean;\n getVsCurrency: () => string;\n state?: Partial<DeFiPositionsControllerV2State>;\n }) {\n super({\n name: controllerName,\n metadata: controllerMetadata,\n messenger,\n state: {\n ...getDefaultDeFiPositionsControllerV2State(),\n ...state,\n },\n });\n\n this.#apiClient = apiClient;\n this.#isEnabled = isEnabled;\n this.#getVsCurrency = getVsCurrency;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches DeFi positions for the selected account group. Each account key in\n * a ready response replaces that account's state (other accounts stay).\n * Accounts still indexing (`processingDefiPositions`) are skipped so prior\n * state is kept for them. No-ops when disabled or when the group has no\n * supported accounts. Caching / spam prevention is handled by the apiClient\n * TanStack Query cache (keyed by accounts + query options including\n * `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.\n * pull-to-refresh).\n *\n * @param options - Optional fetch modifiers.\n * @param options.forceRefresh - When true, bypass the apiClient cache and\n * fetch immediately.\n */\n async fetchDeFiPositions(options?: {\n forceRefresh?: boolean;\n }): Promise<void> {\n if (!this.#isEnabled()) {\n return;\n }\n\n const selectedAccounts = this.messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n );\n\n const { networks, internalAccountIdByCaip } =\n buildDeFiBalancesQuery(selectedAccounts);\n\n if (internalAccountIdByCaip.size === 0 || networks.length === 0) {\n return;\n }\n\n const accountIds = [...internalAccountIdByCaip.keys()];\n const vsCurrency = this.#getVsCurrency().toLowerCase();\n\n try {\n const response =\n await this.#apiClient.accounts.fetchV6MultiAccountBalances(\n accountIds,\n {\n networks,\n includeDeFiBalances: true,\n forceFetchDeFiPositions: true,\n includePrices: true,\n vsCurrency,\n },\n {\n // staleTime: 0 makes TanStack treat the cache as stale for this call.\n ...(options?.forceRefresh ? { staleTime: 0 } : {}),\n },\n );\n\n // Skip accounts still indexing — their balances are not a valid snapshot.\n const readyAccounts = response.accounts.filter(\n (account) => !account.processingDefiPositions,\n );\n if (readyAccounts.length === 0) {\n return;\n }\n\n const positionsByAccount = groupDeFiPositionsV6(\n { ...response, accounts: readyAccounts },\n internalAccountIdByCaip,\n );\n\n // Last valid response wins per ready account; processing / other accounts\n // stay untouched.\n this.update((state) => {\n for (const [accountId, positions] of Object.entries(\n positionsByAccount,\n )) {\n state.allDeFiPositionsV2[accountId] = positions;\n }\n });\n } catch (error) {\n console.error('Failed to fetch DeFi positions', error);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AccountTreeControllerGetAccountsFromSelectedAccountGroupAction } from "@metamask/account-tree-controller";
|
|
2
|
+
import { BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { ControllerGetStateAction, ControllerStateChangedEvent } from "@metamask/base-controller";
|
|
4
|
+
import type { ApiPlatformClient } from "@metamask/core-backend";
|
|
5
|
+
import type { Messenger } from "@metamask/messenger";
|
|
6
|
+
import type { DeFiPositionsControllerV2MethodActions } from "./DeFiPositionsControllerV2-method-action-types.cjs";
|
|
7
|
+
import type { DeFiPositionsByAccount } from "./group-defi-positions-v6.cjs";
|
|
8
|
+
declare const controllerName = "DeFiPositionsControllerV2";
|
|
9
|
+
export type DeFiPositionsControllerV2State = {
|
|
10
|
+
/**
|
|
11
|
+
* DeFi positions keyed by internal MetaMask account ID (`InternalAccount.id`,
|
|
12
|
+
* the same key AssetsController uses). Each account maps to a flat list of
|
|
13
|
+
* protocol groups shown in the DeFi tab, each carrying its own `chainId` for
|
|
14
|
+
* filtering plus the details-page sections embedded inside it. This is
|
|
15
|
+
* exactly the shape the client consumes, so no further transformation is
|
|
16
|
+
* needed on read.
|
|
17
|
+
*
|
|
18
|
+
* Named `allDeFiPositionsV2` (rather than `allDeFiPositions`) so it can live
|
|
19
|
+
* alongside the legacy `DeFiPositionsController` in clients that flatten every
|
|
20
|
+
* controller's state into a single object (e.g. the extension background),
|
|
21
|
+
* without colliding on the shared `allDeFiPositions` key.
|
|
22
|
+
*/
|
|
23
|
+
allDeFiPositionsV2: DeFiPositionsByAccount;
|
|
24
|
+
};
|
|
25
|
+
export declare const getDefaultDeFiPositionsControllerV2State: () => DeFiPositionsControllerV2State;
|
|
26
|
+
export type DeFiPositionsControllerV2GetStateAction = ControllerGetStateAction<typeof controllerName, DeFiPositionsControllerV2State>;
|
|
27
|
+
export type DeFiPositionsControllerV2Actions = DeFiPositionsControllerV2GetStateAction | DeFiPositionsControllerV2MethodActions;
|
|
28
|
+
export type DeFiPositionsControllerV2StateChangedEvent = ControllerStateChangedEvent<typeof controllerName, DeFiPositionsControllerV2State>;
|
|
29
|
+
export type DeFiPositionsControllerV2Events = DeFiPositionsControllerV2StateChangedEvent;
|
|
30
|
+
/**
|
|
31
|
+
* The external actions available to the {@link DeFiPositionsControllerV2}.
|
|
32
|
+
*/
|
|
33
|
+
export type AllowedActions = AccountTreeControllerGetAccountsFromSelectedAccountGroupAction;
|
|
34
|
+
/**
|
|
35
|
+
* The external events available to the {@link DeFiPositionsControllerV2}.
|
|
36
|
+
*
|
|
37
|
+
* None yet — clients must call `fetchDeFiPositions` (and optionally
|
|
38
|
+
* `{ forceRefresh: true }`) on their own triggers. Likely future subscriptions:
|
|
39
|
+
* `AccountTreeController:selectedAccountGroupChange`,
|
|
40
|
+
* `TransactionController:transactionConfirmed`, and `KeyringController:lock`.
|
|
41
|
+
*/
|
|
42
|
+
export type AllowedEvents = never;
|
|
43
|
+
export type DeFiPositionsControllerV2Messenger = Messenger<typeof controllerName, DeFiPositionsControllerV2Actions | AllowedActions, DeFiPositionsControllerV2Events | AllowedEvents>;
|
|
44
|
+
/**
|
|
45
|
+
* Controller that fetches DeFi positions for the selected account group from
|
|
46
|
+
* the Accounts API (v6 multiaccount balances) and stores them in the shape the
|
|
47
|
+
* client consumes directly.
|
|
48
|
+
*
|
|
49
|
+
* Deduplication and freshness are handled by the shared TanStack Query cache on
|
|
50
|
+
* {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass
|
|
51
|
+
* `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.
|
|
52
|
+
*/
|
|
53
|
+
export declare class DeFiPositionsControllerV2 extends BaseController<typeof controllerName, DeFiPositionsControllerV2State, DeFiPositionsControllerV2Messenger> {
|
|
54
|
+
#private;
|
|
55
|
+
/**
|
|
56
|
+
* @param options - Constructor options.
|
|
57
|
+
* @param options.messenger - The controller messenger.
|
|
58
|
+
* @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.
|
|
59
|
+
* @param options.isEnabled - Returns whether fetching is enabled (default: () => false).
|
|
60
|
+
* @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').
|
|
61
|
+
* @param options.state - Initial controller state.
|
|
62
|
+
*/
|
|
63
|
+
constructor({ messenger, apiClient, isEnabled, getVsCurrency, state, }: {
|
|
64
|
+
messenger: DeFiPositionsControllerV2Messenger;
|
|
65
|
+
apiClient: ApiPlatformClient;
|
|
66
|
+
isEnabled: () => boolean;
|
|
67
|
+
getVsCurrency: () => string;
|
|
68
|
+
state?: Partial<DeFiPositionsControllerV2State>;
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
72
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
73
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
74
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
75
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
76
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
77
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
78
|
+
* pull-to-refresh).
|
|
79
|
+
*
|
|
80
|
+
* @param options - Optional fetch modifiers.
|
|
81
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
82
|
+
* fetch immediately.
|
|
83
|
+
*/
|
|
84
|
+
fetchDeFiPositions(options?: {
|
|
85
|
+
forceRefresh?: boolean;
|
|
86
|
+
}): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=DeFiPositionsControllerV2.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2.d.cts","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8DAA8D,EAAE,0CAA0C;AACxH,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAE5B,kCAAkC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,sCAAsC,EAAE,4DAAwD;AAC9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,sCAAkC;AAGxE,QAAA,MAAM,cAAc,8BAA8B,CAAC;AAInD,MAAM,MAAM,8BAA8B,GAAG;IAC3C;;;;;;;;;;;;OAYG;IACH,kBAAkB,EAAE,sBAAsB,CAAC;CAC5C,CAAC;AAWF,eAAO,MAAM,wCAAwC,QAC/C,8BAIH,CAAC;AAEJ,MAAM,MAAM,uCAAuC,GAAG,wBAAwB,CAC5E,OAAO,cAAc,EACrB,8BAA8B,CAC/B,CAAC;AAEF,MAAM,MAAM,gCAAgC,GACxC,uCAAuC,GACvC,sCAAsC,CAAC;AAE3C,MAAM,MAAM,0CAA0C,GACpD,2BAA2B,CACzB,OAAO,cAAc,EACrB,8BAA8B,CAC/B,CAAC;AAEJ,MAAM,MAAM,+BAA+B,GACzC,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,cAAc,GACxB,8DAA8D,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC,MAAM,MAAM,kCAAkC,GAAG,SAAS,CACxD,OAAO,cAAc,EACrB,gCAAgC,GAAG,cAAc,EACjD,+BAA+B,GAAG,aAAa,CAChD,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,SAAQ,cAAc,CAC3D,OAAO,cAAc,EACrB,8BAA8B,EAC9B,kCAAkC,CACnC;;IAOC;;;;;;;OAOG;gBACS,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,aAAa,EACb,KAAK,GACN,EAAE;QACD,SAAS,EAAE,kCAAkC,CAAC;QAC9C,SAAS,EAAE,iBAAiB,CAAC;QAC7B,SAAS,EAAE,MAAM,OAAO,CAAC;QACzB,aAAa,EAAE,MAAM,MAAM,CAAC;QAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;KACjD;IAqBD;;;;;;;;;;;;;OAaG;IACG,kBAAkB,CAAC,OAAO,CAAC,EAAE;QACjC,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC;CA8DlB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AccountTreeControllerGetAccountsFromSelectedAccountGroupAction } from "@metamask/account-tree-controller";
|
|
2
|
+
import { BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { ControllerGetStateAction, ControllerStateChangedEvent } from "@metamask/base-controller";
|
|
4
|
+
import type { ApiPlatformClient } from "@metamask/core-backend";
|
|
5
|
+
import type { Messenger } from "@metamask/messenger";
|
|
6
|
+
import type { DeFiPositionsControllerV2MethodActions } from "./DeFiPositionsControllerV2-method-action-types.mjs";
|
|
7
|
+
import type { DeFiPositionsByAccount } from "./group-defi-positions-v6.mjs";
|
|
8
|
+
declare const controllerName = "DeFiPositionsControllerV2";
|
|
9
|
+
export type DeFiPositionsControllerV2State = {
|
|
10
|
+
/**
|
|
11
|
+
* DeFi positions keyed by internal MetaMask account ID (`InternalAccount.id`,
|
|
12
|
+
* the same key AssetsController uses). Each account maps to a flat list of
|
|
13
|
+
* protocol groups shown in the DeFi tab, each carrying its own `chainId` for
|
|
14
|
+
* filtering plus the details-page sections embedded inside it. This is
|
|
15
|
+
* exactly the shape the client consumes, so no further transformation is
|
|
16
|
+
* needed on read.
|
|
17
|
+
*
|
|
18
|
+
* Named `allDeFiPositionsV2` (rather than `allDeFiPositions`) so it can live
|
|
19
|
+
* alongside the legacy `DeFiPositionsController` in clients that flatten every
|
|
20
|
+
* controller's state into a single object (e.g. the extension background),
|
|
21
|
+
* without colliding on the shared `allDeFiPositions` key.
|
|
22
|
+
*/
|
|
23
|
+
allDeFiPositionsV2: DeFiPositionsByAccount;
|
|
24
|
+
};
|
|
25
|
+
export declare const getDefaultDeFiPositionsControllerV2State: () => DeFiPositionsControllerV2State;
|
|
26
|
+
export type DeFiPositionsControllerV2GetStateAction = ControllerGetStateAction<typeof controllerName, DeFiPositionsControllerV2State>;
|
|
27
|
+
export type DeFiPositionsControllerV2Actions = DeFiPositionsControllerV2GetStateAction | DeFiPositionsControllerV2MethodActions;
|
|
28
|
+
export type DeFiPositionsControllerV2StateChangedEvent = ControllerStateChangedEvent<typeof controllerName, DeFiPositionsControllerV2State>;
|
|
29
|
+
export type DeFiPositionsControllerV2Events = DeFiPositionsControllerV2StateChangedEvent;
|
|
30
|
+
/**
|
|
31
|
+
* The external actions available to the {@link DeFiPositionsControllerV2}.
|
|
32
|
+
*/
|
|
33
|
+
export type AllowedActions = AccountTreeControllerGetAccountsFromSelectedAccountGroupAction;
|
|
34
|
+
/**
|
|
35
|
+
* The external events available to the {@link DeFiPositionsControllerV2}.
|
|
36
|
+
*
|
|
37
|
+
* None yet — clients must call `fetchDeFiPositions` (and optionally
|
|
38
|
+
* `{ forceRefresh: true }`) on their own triggers. Likely future subscriptions:
|
|
39
|
+
* `AccountTreeController:selectedAccountGroupChange`,
|
|
40
|
+
* `TransactionController:transactionConfirmed`, and `KeyringController:lock`.
|
|
41
|
+
*/
|
|
42
|
+
export type AllowedEvents = never;
|
|
43
|
+
export type DeFiPositionsControllerV2Messenger = Messenger<typeof controllerName, DeFiPositionsControllerV2Actions | AllowedActions, DeFiPositionsControllerV2Events | AllowedEvents>;
|
|
44
|
+
/**
|
|
45
|
+
* Controller that fetches DeFi positions for the selected account group from
|
|
46
|
+
* the Accounts API (v6 multiaccount balances) and stores them in the shape the
|
|
47
|
+
* client consumes directly.
|
|
48
|
+
*
|
|
49
|
+
* Deduplication and freshness are handled by the shared TanStack Query cache on
|
|
50
|
+
* {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass
|
|
51
|
+
* `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.
|
|
52
|
+
*/
|
|
53
|
+
export declare class DeFiPositionsControllerV2 extends BaseController<typeof controllerName, DeFiPositionsControllerV2State, DeFiPositionsControllerV2Messenger> {
|
|
54
|
+
#private;
|
|
55
|
+
/**
|
|
56
|
+
* @param options - Constructor options.
|
|
57
|
+
* @param options.messenger - The controller messenger.
|
|
58
|
+
* @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.
|
|
59
|
+
* @param options.isEnabled - Returns whether fetching is enabled (default: () => false).
|
|
60
|
+
* @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').
|
|
61
|
+
* @param options.state - Initial controller state.
|
|
62
|
+
*/
|
|
63
|
+
constructor({ messenger, apiClient, isEnabled, getVsCurrency, state, }: {
|
|
64
|
+
messenger: DeFiPositionsControllerV2Messenger;
|
|
65
|
+
apiClient: ApiPlatformClient;
|
|
66
|
+
isEnabled: () => boolean;
|
|
67
|
+
getVsCurrency: () => string;
|
|
68
|
+
state?: Partial<DeFiPositionsControllerV2State>;
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
72
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
73
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
74
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
75
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
76
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
77
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
78
|
+
* pull-to-refresh).
|
|
79
|
+
*
|
|
80
|
+
* @param options - Optional fetch modifiers.
|
|
81
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
82
|
+
* fetch immediately.
|
|
83
|
+
*/
|
|
84
|
+
fetchDeFiPositions(options?: {
|
|
85
|
+
forceRefresh?: boolean;
|
|
86
|
+
}): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=DeFiPositionsControllerV2.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2.d.mts","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8DAA8D,EAAE,0CAA0C;AACxH,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAE5B,kCAAkC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,sCAAsC,EAAE,4DAAwD;AAC9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,sCAAkC;AAGxE,QAAA,MAAM,cAAc,8BAA8B,CAAC;AAInD,MAAM,MAAM,8BAA8B,GAAG;IAC3C;;;;;;;;;;;;OAYG;IACH,kBAAkB,EAAE,sBAAsB,CAAC;CAC5C,CAAC;AAWF,eAAO,MAAM,wCAAwC,QAC/C,8BAIH,CAAC;AAEJ,MAAM,MAAM,uCAAuC,GAAG,wBAAwB,CAC5E,OAAO,cAAc,EACrB,8BAA8B,CAC/B,CAAC;AAEF,MAAM,MAAM,gCAAgC,GACxC,uCAAuC,GACvC,sCAAsC,CAAC;AAE3C,MAAM,MAAM,0CAA0C,GACpD,2BAA2B,CACzB,OAAO,cAAc,EACrB,8BAA8B,CAC/B,CAAC;AAEJ,MAAM,MAAM,+BAA+B,GACzC,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,cAAc,GACxB,8DAA8D,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC,MAAM,MAAM,kCAAkC,GAAG,SAAS,CACxD,OAAO,cAAc,EACrB,gCAAgC,GAAG,cAAc,EACjD,+BAA+B,GAAG,aAAa,CAChD,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,SAAQ,cAAc,CAC3D,OAAO,cAAc,EACrB,8BAA8B,EAC9B,kCAAkC,CACnC;;IAOC;;;;;;;OAOG;gBACS,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,aAAa,EACb,KAAK,GACN,EAAE;QACD,SAAS,EAAE,kCAAkC,CAAC;QAC9C,SAAS,EAAE,iBAAiB,CAAC;QAC7B,SAAS,EAAE,MAAM,OAAO,CAAC;QACzB,aAAa,EAAE,MAAM,MAAM,CAAC;QAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAC;KACjD;IAqBD;;;;;;;;;;;;;OAaG;IACG,kBAAkB,CAAC,OAAO,CAAC,EAAE;QACjC,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC;CA8DlB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _DeFiPositionsControllerV2_apiClient, _DeFiPositionsControllerV2_isEnabled, _DeFiPositionsControllerV2_getVsCurrency;
|
|
13
|
+
import { BaseController } from "@metamask/base-controller";
|
|
14
|
+
import { buildDeFiBalancesQuery } from "./build-defi-balances-query.mjs";
|
|
15
|
+
import { groupDeFiPositionsV6 } from "./group-defi-positions-v6.mjs";
|
|
16
|
+
const controllerName = 'DeFiPositionsControllerV2';
|
|
17
|
+
const MESSENGER_EXPOSED_METHODS = ['fetchDeFiPositions'];
|
|
18
|
+
const controllerMetadata = {
|
|
19
|
+
allDeFiPositionsV2: {
|
|
20
|
+
includeInStateLogs: false,
|
|
21
|
+
persist: true,
|
|
22
|
+
includeInDebugSnapshot: false,
|
|
23
|
+
usedInUi: true,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export const getDefaultDeFiPositionsControllerV2State = () => {
|
|
27
|
+
return {
|
|
28
|
+
allDeFiPositionsV2: {},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Controller that fetches DeFi positions for the selected account group from
|
|
33
|
+
* the Accounts API (v6 multiaccount balances) and stores them in the shape the
|
|
34
|
+
* client consumes directly.
|
|
35
|
+
*
|
|
36
|
+
* Deduplication and freshness are handled by the shared TanStack Query cache on
|
|
37
|
+
* {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass
|
|
38
|
+
* `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.
|
|
39
|
+
*/
|
|
40
|
+
export class DeFiPositionsControllerV2 extends BaseController {
|
|
41
|
+
/**
|
|
42
|
+
* @param options - Constructor options.
|
|
43
|
+
* @param options.messenger - The controller messenger.
|
|
44
|
+
* @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.
|
|
45
|
+
* @param options.isEnabled - Returns whether fetching is enabled (default: () => false).
|
|
46
|
+
* @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').
|
|
47
|
+
* @param options.state - Initial controller state.
|
|
48
|
+
*/
|
|
49
|
+
constructor({ messenger, apiClient, isEnabled, getVsCurrency, state, }) {
|
|
50
|
+
super({
|
|
51
|
+
name: controllerName,
|
|
52
|
+
metadata: controllerMetadata,
|
|
53
|
+
messenger,
|
|
54
|
+
state: {
|
|
55
|
+
...getDefaultDeFiPositionsControllerV2State(),
|
|
56
|
+
...state,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
_DeFiPositionsControllerV2_apiClient.set(this, void 0);
|
|
60
|
+
_DeFiPositionsControllerV2_isEnabled.set(this, void 0);
|
|
61
|
+
_DeFiPositionsControllerV2_getVsCurrency.set(this, void 0);
|
|
62
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_apiClient, apiClient, "f");
|
|
63
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_isEnabled, isEnabled, "f");
|
|
64
|
+
__classPrivateFieldSet(this, _DeFiPositionsControllerV2_getVsCurrency, getVsCurrency, "f");
|
|
65
|
+
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fetches DeFi positions for the selected account group. Each account key in
|
|
69
|
+
* a ready response replaces that account's state (other accounts stay).
|
|
70
|
+
* Accounts still indexing (`processingDefiPositions`) are skipped so prior
|
|
71
|
+
* state is kept for them. No-ops when disabled or when the group has no
|
|
72
|
+
* supported accounts. Caching / spam prevention is handled by the apiClient
|
|
73
|
+
* TanStack Query cache (keyed by accounts + query options including
|
|
74
|
+
* `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.
|
|
75
|
+
* pull-to-refresh).
|
|
76
|
+
*
|
|
77
|
+
* @param options - Optional fetch modifiers.
|
|
78
|
+
* @param options.forceRefresh - When true, bypass the apiClient cache and
|
|
79
|
+
* fetch immediately.
|
|
80
|
+
*/
|
|
81
|
+
async fetchDeFiPositions(options) {
|
|
82
|
+
if (!__classPrivateFieldGet(this, _DeFiPositionsControllerV2_isEnabled, "f").call(this)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const selectedAccounts = this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
86
|
+
const { networks, internalAccountIdByCaip } = buildDeFiBalancesQuery(selectedAccounts);
|
|
87
|
+
if (internalAccountIdByCaip.size === 0 || networks.length === 0) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const accountIds = [...internalAccountIdByCaip.keys()];
|
|
91
|
+
const vsCurrency = __classPrivateFieldGet(this, _DeFiPositionsControllerV2_getVsCurrency, "f").call(this).toLowerCase();
|
|
92
|
+
try {
|
|
93
|
+
const response = await __classPrivateFieldGet(this, _DeFiPositionsControllerV2_apiClient, "f").accounts.fetchV6MultiAccountBalances(accountIds, {
|
|
94
|
+
networks,
|
|
95
|
+
includeDeFiBalances: true,
|
|
96
|
+
forceFetchDeFiPositions: true,
|
|
97
|
+
includePrices: true,
|
|
98
|
+
vsCurrency,
|
|
99
|
+
}, {
|
|
100
|
+
// staleTime: 0 makes TanStack treat the cache as stale for this call.
|
|
101
|
+
...(options?.forceRefresh ? { staleTime: 0 } : {}),
|
|
102
|
+
});
|
|
103
|
+
// Skip accounts still indexing — their balances are not a valid snapshot.
|
|
104
|
+
const readyAccounts = response.accounts.filter((account) => !account.processingDefiPositions);
|
|
105
|
+
if (readyAccounts.length === 0) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const positionsByAccount = groupDeFiPositionsV6({ ...response, accounts: readyAccounts }, internalAccountIdByCaip);
|
|
109
|
+
// Last valid response wins per ready account; processing / other accounts
|
|
110
|
+
// stay untouched.
|
|
111
|
+
this.update((state) => {
|
|
112
|
+
for (const [accountId, positions] of Object.entries(positionsByAccount)) {
|
|
113
|
+
state.allDeFiPositionsV2[accountId] = positions;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error('Failed to fetch DeFi positions', error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
_DeFiPositionsControllerV2_apiClient = new WeakMap(), _DeFiPositionsControllerV2_isEnabled = new WeakMap(), _DeFiPositionsControllerV2_getVsCurrency = new WeakMap();
|
|
123
|
+
//# sourceMappingURL=DeFiPositionsControllerV2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeFiPositionsControllerV2.mjs","sourceRoot":"","sources":["../../src/DeFiPositionsController/DeFiPositionsControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerGetAccountsFromSelectedAccountGroupAction } from '@metamask/account-tree-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { buildDeFiBalancesQuery } from './build-defi-balances-query';\nimport type { DeFiPositionsControllerV2MethodActions } from './DeFiPositionsControllerV2-method-action-types';\nimport type { DeFiPositionsByAccount } from './group-defi-positions-v6';\nimport { groupDeFiPositionsV6 } from './group-defi-positions-v6';\n\nconst controllerName = 'DeFiPositionsControllerV2';\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchDeFiPositions'] as const;\n\nexport type DeFiPositionsControllerV2State = {\n /**\n * DeFi positions keyed by internal MetaMask account ID (`InternalAccount.id`,\n * the same key AssetsController uses). Each account maps to a flat list of\n * protocol groups shown in the DeFi tab, each carrying its own `chainId` for\n * filtering plus the details-page sections embedded inside it. This is\n * exactly the shape the client consumes, so no further transformation is\n * needed on read.\n *\n * Named `allDeFiPositionsV2` (rather than `allDeFiPositions`) so it can live\n * alongside the legacy `DeFiPositionsController` in clients that flatten every\n * controller's state into a single object (e.g. the extension background),\n * without colliding on the shared `allDeFiPositions` key.\n */\n allDeFiPositionsV2: DeFiPositionsByAccount;\n};\n\nconst controllerMetadata: StateMetadata<DeFiPositionsControllerV2State> = {\n allDeFiPositionsV2: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\nexport const getDefaultDeFiPositionsControllerV2State =\n (): DeFiPositionsControllerV2State => {\n return {\n allDeFiPositionsV2: {},\n };\n };\n\nexport type DeFiPositionsControllerV2GetStateAction = ControllerGetStateAction<\n typeof controllerName,\n DeFiPositionsControllerV2State\n>;\n\nexport type DeFiPositionsControllerV2Actions =\n | DeFiPositionsControllerV2GetStateAction\n | DeFiPositionsControllerV2MethodActions;\n\nexport type DeFiPositionsControllerV2StateChangedEvent =\n ControllerStateChangedEvent<\n typeof controllerName,\n DeFiPositionsControllerV2State\n >;\n\nexport type DeFiPositionsControllerV2Events =\n DeFiPositionsControllerV2StateChangedEvent;\n\n/**\n * The external actions available to the {@link DeFiPositionsControllerV2}.\n */\nexport type AllowedActions =\n AccountTreeControllerGetAccountsFromSelectedAccountGroupAction;\n\n/**\n * The external events available to the {@link DeFiPositionsControllerV2}.\n *\n * None yet — clients must call `fetchDeFiPositions` (and optionally\n * `{ forceRefresh: true }`) on their own triggers. Likely future subscriptions:\n * `AccountTreeController:selectedAccountGroupChange`,\n * `TransactionController:transactionConfirmed`, and `KeyringController:lock`.\n */\nexport type AllowedEvents = never;\n\nexport type DeFiPositionsControllerV2Messenger = Messenger<\n typeof controllerName,\n DeFiPositionsControllerV2Actions | AllowedActions,\n DeFiPositionsControllerV2Events | AllowedEvents\n>;\n\n/**\n * Controller that fetches DeFi positions for the selected account group from\n * the Accounts API (v6 multiaccount balances) and stores them in the shape the\n * client consumes directly.\n *\n * Deduplication and freshness are handled by the shared TanStack Query cache on\n * {@link ApiPlatformClient} (balances default `staleTime` is 1 minute). Pass\n * `{ forceRefresh: true }` to bypass that cache for pull-to-refresh.\n */\nexport class DeFiPositionsControllerV2 extends BaseController<\n typeof controllerName,\n DeFiPositionsControllerV2State,\n DeFiPositionsControllerV2Messenger\n> {\n readonly #apiClient: ApiPlatformClient;\n\n readonly #isEnabled: () => boolean;\n\n readonly #getVsCurrency: () => string;\n\n /**\n * @param options - Constructor options.\n * @param options.messenger - The controller messenger.\n * @param options.apiClient - Accounts API client used to fetch balances/positions. Auth is handled by the client.\n * @param options.isEnabled - Returns whether fetching is enabled (default: () => false).\n * @param options.getVsCurrency - Returns the fiat currency for prices (default: () => 'usd').\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n apiClient,\n isEnabled,\n getVsCurrency,\n state,\n }: {\n messenger: DeFiPositionsControllerV2Messenger;\n apiClient: ApiPlatformClient;\n isEnabled: () => boolean;\n getVsCurrency: () => string;\n state?: Partial<DeFiPositionsControllerV2State>;\n }) {\n super({\n name: controllerName,\n metadata: controllerMetadata,\n messenger,\n state: {\n ...getDefaultDeFiPositionsControllerV2State(),\n ...state,\n },\n });\n\n this.#apiClient = apiClient;\n this.#isEnabled = isEnabled;\n this.#getVsCurrency = getVsCurrency;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches DeFi positions for the selected account group. Each account key in\n * a ready response replaces that account's state (other accounts stay).\n * Accounts still indexing (`processingDefiPositions`) are skipped so prior\n * state is kept for them. No-ops when disabled or when the group has no\n * supported accounts. Caching / spam prevention is handled by the apiClient\n * TanStack Query cache (keyed by accounts + query options including\n * `vsCurrency`). Pass `{ forceRefresh: true }` to bypass the cache (e.g.\n * pull-to-refresh).\n *\n * @param options - Optional fetch modifiers.\n * @param options.forceRefresh - When true, bypass the apiClient cache and\n * fetch immediately.\n */\n async fetchDeFiPositions(options?: {\n forceRefresh?: boolean;\n }): Promise<void> {\n if (!this.#isEnabled()) {\n return;\n }\n\n const selectedAccounts = this.messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n );\n\n const { networks, internalAccountIdByCaip } =\n buildDeFiBalancesQuery(selectedAccounts);\n\n if (internalAccountIdByCaip.size === 0 || networks.length === 0) {\n return;\n }\n\n const accountIds = [...internalAccountIdByCaip.keys()];\n const vsCurrency = this.#getVsCurrency().toLowerCase();\n\n try {\n const response =\n await this.#apiClient.accounts.fetchV6MultiAccountBalances(\n accountIds,\n {\n networks,\n includeDeFiBalances: true,\n forceFetchDeFiPositions: true,\n includePrices: true,\n vsCurrency,\n },\n {\n // staleTime: 0 makes TanStack treat the cache as stale for this call.\n ...(options?.forceRefresh ? { staleTime: 0 } : {}),\n },\n );\n\n // Skip accounts still indexing — their balances are not a valid snapshot.\n const readyAccounts = response.accounts.filter(\n (account) => !account.processingDefiPositions,\n );\n if (readyAccounts.length === 0) {\n return;\n }\n\n const positionsByAccount = groupDeFiPositionsV6(\n { ...response, accounts: readyAccounts },\n internalAccountIdByCaip,\n );\n\n // Last valid response wins per ready account; processing / other accounts\n // stay untouched.\n this.update((state) => {\n for (const [accountId, positions] of Object.entries(\n positionsByAccount,\n )) {\n state.allDeFiPositionsV2[accountId] = positions;\n }\n });\n } catch (error) {\n console.error('Failed to fetch DeFi positions', error);\n }\n }\n}\n"]}
|