@metamask/snaps-controllers 9.17.0 → 9.19.0

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/dist/index.cjs +1 -0
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1 -0
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +1 -0
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.mjs +1 -0
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/multichain/MultichainRouter.cjs +199 -0
  11. package/dist/multichain/MultichainRouter.cjs.map +1 -0
  12. package/dist/multichain/MultichainRouter.d.cts +107 -0
  13. package/dist/multichain/MultichainRouter.d.cts.map +1 -0
  14. package/dist/multichain/MultichainRouter.d.mts +107 -0
  15. package/dist/multichain/MultichainRouter.d.mts.map +1 -0
  16. package/dist/multichain/MultichainRouter.mjs +195 -0
  17. package/dist/multichain/MultichainRouter.mjs.map +1 -0
  18. package/dist/multichain/index.cjs +18 -0
  19. package/dist/multichain/index.cjs.map +1 -0
  20. package/dist/multichain/index.d.cts +2 -0
  21. package/dist/multichain/index.d.cts.map +1 -0
  22. package/dist/multichain/index.d.mts +2 -0
  23. package/dist/multichain/index.d.mts.map +1 -0
  24. package/dist/multichain/index.mjs +2 -0
  25. package/dist/multichain/index.mjs.map +1 -0
  26. package/dist/snaps/SnapController.cjs +59 -5
  27. package/dist/snaps/SnapController.cjs.map +1 -1
  28. package/dist/snaps/SnapController.d.cts +12 -2
  29. package/dist/snaps/SnapController.d.cts.map +1 -1
  30. package/dist/snaps/SnapController.d.mts +12 -2
  31. package/dist/snaps/SnapController.d.mts.map +1 -1
  32. package/dist/snaps/SnapController.mjs +61 -7
  33. package/dist/snaps/SnapController.mjs.map +1 -1
  34. package/package.json +5 -5
@@ -0,0 +1,195 @@
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 _MultichainRouter_instances, _MultichainRouter_messenger, _MultichainRouter_withSnapKeyring, _MultichainRouter_resolveRequestAddress, _MultichainRouter_getSnapAccountId, _MultichainRouter_getProtocolSnaps, _MultichainRouter_getSupportedAccountsMetadata;
13
+ import { rpcErrors } from "@metamask/rpc-errors";
14
+ import { getProtocolCaveatScopes, SnapEndowments } from "@metamask/snaps-rpc-methods";
15
+ import { HandlerType } from "@metamask/snaps-utils";
16
+ import { assert, hasProperty, KnownCaipNamespace, parseCaipAccountId } from "@metamask/utils";
17
+ import { getRunnableSnaps } from "../snaps/index.mjs";
18
+ const name = 'MultichainRouter';
19
+ export class MultichainRouter {
20
+ constructor({ messenger, withSnapKeyring }) {
21
+ _MultichainRouter_instances.add(this);
22
+ _MultichainRouter_messenger.set(this, void 0);
23
+ _MultichainRouter_withSnapKeyring.set(this, void 0);
24
+ __classPrivateFieldSet(this, _MultichainRouter_messenger, messenger, "f");
25
+ __classPrivateFieldSet(this, _MultichainRouter_withSnapKeyring, withSnapKeyring, "f");
26
+ __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").registerActionHandler(`${name}:handleRequest`, async (...args) => this.handleRequest(...args));
27
+ __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").registerActionHandler(`${name}:getSupportedMethods`, (...args) => this.getSupportedMethods(...args));
28
+ __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").registerActionHandler(`${name}:getSupportedAccounts`, (...args) => this.getSupportedAccounts(...args));
29
+ __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").registerActionHandler(`${name}:isSupportedScope`, (...args) => this.isSupportedScope(...args));
30
+ }
31
+ /**
32
+ * Handle an incoming JSON-RPC request tied to a specific scope by routing
33
+ * to either a procotol Snap or an account Snap.
34
+ *
35
+ * @param options - An options bag.
36
+ * @param options.connectedAddresses - Addresses currently connected to the origin.
37
+ * @param options.origin - The origin of the RPC request.
38
+ * @param options.request - The JSON-RPC request.
39
+ * @param options.scope - The CAIP-2 scope for the request.
40
+ * @returns The response from the chosen Snap.
41
+ * @throws If no handler was found.
42
+ */
43
+ async handleRequest({ connectedAddresses, origin, scope, request, }) {
44
+ // Explicitly block EVM scopes, just in case.
45
+ assert(!scope.startsWith(KnownCaipNamespace.Eip155) &&
46
+ !scope.startsWith('wallet:eip155'));
47
+ const { method, params } = request;
48
+ // If the RPC request can be serviced by an account Snap, route it there.
49
+ const accountId = await __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_getSnapAccountId).call(this, connectedAddresses, scope, request);
50
+ if (accountId) {
51
+ return __classPrivateFieldGet(this, _MultichainRouter_withSnapKeyring, "f").call(this, async (keyring) => keyring.submitRequest({
52
+ account: accountId,
53
+ scope,
54
+ method,
55
+ params: params,
56
+ }));
57
+ }
58
+ // If the RPC request cannot be serviced by an account Snap,
59
+ // but has a protocol Snap available, route it there.
60
+ const protocolSnaps = __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_getProtocolSnaps).call(this, scope);
61
+ const protocolSnap = protocolSnaps.find((snap) => snap.methods.includes(method));
62
+ if (protocolSnap) {
63
+ return __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").call('SnapController:handleRequest', {
64
+ snapId: protocolSnap.snapId,
65
+ origin,
66
+ request: {
67
+ method: '',
68
+ params: {
69
+ request,
70
+ scope,
71
+ },
72
+ },
73
+ handler: HandlerType.OnProtocolRequest,
74
+ });
75
+ }
76
+ // If no compatible account or protocol Snaps were found, throw.
77
+ throw rpcErrors.methodNotFound();
78
+ }
79
+ /**
80
+ * Get a list of supported methods for a given scope.
81
+ * This combines both protocol and account Snaps supported methods.
82
+ *
83
+ * @param scope - The CAIP-2 scope.
84
+ * @returns A list of supported methods.
85
+ */
86
+ getSupportedMethods(scope) {
87
+ const accountMethods = __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_getSupportedAccountsMetadata).call(this, scope).flatMap((account) => account.methods);
88
+ const protocolMethods = __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_getProtocolSnaps).call(this, scope).flatMap((snap) => snap.methods);
89
+ return Array.from(new Set([...accountMethods, ...protocolMethods]));
90
+ }
91
+ /**
92
+ * Get a list of supported accounts for a given scope.
93
+ *
94
+ * @param scope - The CAIP-2 scope.
95
+ * @returns A list of CAIP-10 addresses.
96
+ */
97
+ getSupportedAccounts(scope) {
98
+ return __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_getSupportedAccountsMetadata).call(this, scope).map((account) => `${scope}:${account.address}`);
99
+ }
100
+ /**
101
+ * Determine whether a given CAIP-2 scope is supported by the router.
102
+ *
103
+ * @param scope - The CAIP-2 scope.
104
+ * @returns True if the router can service the scope, otherwise false.
105
+ */
106
+ isSupportedScope(scope) {
107
+ // We currently assume here that if one Snap exists that service the scope, we can service the scope generally.
108
+ return __classPrivateFieldGet(this, _MultichainRouter_messenger, "f")
109
+ .call('AccountsController:listMultichainAccounts', scope)
110
+ .some((account) => account.metadata.snap?.enabled);
111
+ }
112
+ }
113
+ _MultichainRouter_messenger = new WeakMap(), _MultichainRouter_withSnapKeyring = new WeakMap(), _MultichainRouter_instances = new WeakSet(), _MultichainRouter_resolveRequestAddress =
114
+ /**
115
+ * Attempts to resolve the account address to use for a given request by inspecting the request itself.
116
+ *
117
+ * The request is sent to to an account Snap via the SnapKeyring that will attempt this resolution.
118
+ *
119
+ * @param snapId - The ID of the Snap to send the request to.
120
+ * @param scope - The CAIP-2 scope for the request.
121
+ * @param request - The JSON-RPC request.
122
+ * @returns The resolved address if found, otherwise null.
123
+ * @throws If the invocation of the SnapKeyring fails.
124
+ */
125
+ async function _MultichainRouter_resolveRequestAddress(snapId, scope, request) {
126
+ try {
127
+ const result = await __classPrivateFieldGet(this, _MultichainRouter_withSnapKeyring, "f").call(this, async (keyring) => keyring.resolveAccountAddress(snapId, scope, request));
128
+ const address = result?.address;
129
+ return address ? parseCaipAccountId(address).address : null;
130
+ }
131
+ catch {
132
+ throw rpcErrors.internal();
133
+ }
134
+ }, _MultichainRouter_getSnapAccountId =
135
+ /**
136
+ * Get the account ID of the account that should service the RPC request via an account Snap.
137
+ *
138
+ * This function checks whether any accounts exist that can service a given request by
139
+ * using a combination of the resolveAccountAddress functionality and the connected accounts.
140
+ *
141
+ * If an account is expected to service this request but none is found, the function will throw.
142
+ *
143
+ * @param connectedAddresses - The CAIP-10 addresses connected to the requesting origin.
144
+ * @param scope - The CAIP-2 scope for the request.
145
+ * @param request - The JSON-RPC request.
146
+ * @returns An account ID if found, otherwise null.
147
+ * @throws If no account is found, but the accounts exist that could service the request.
148
+ */
149
+ async function _MultichainRouter_getSnapAccountId(connectedAddresses, scope, request) {
150
+ const accounts = __classPrivateFieldGet(this, _MultichainRouter_messenger, "f")
151
+ .call('AccountsController:listMultichainAccounts', scope)
152
+ .filter((account) => Boolean(account.metadata.snap?.enabled) &&
153
+ account.methods.includes(request.method));
154
+ // If no accounts can service the request, return null.
155
+ if (accounts.length === 0) {
156
+ return null;
157
+ }
158
+ const resolutionSnapId = accounts[0].metadata.snap.id;
159
+ // Attempt to resolve the address that should be used for signing.
160
+ const address = await __classPrivateFieldGet(this, _MultichainRouter_instances, "m", _MultichainRouter_resolveRequestAddress).call(this, resolutionSnapId, scope, request);
161
+ const parsedConnectedAddresses = connectedAddresses.map((connectedAddress) => parseCaipAccountId(connectedAddress).address);
162
+ // If we have a resolved address, try to find the selected account based on that
163
+ // otherwise, default to one of the connected accounts.
164
+ // TODO: Eventually let the user choose if we have more than one option for the account.
165
+ const selectedAccount = accounts.find((account) => parsedConnectedAddresses.includes(account.address) &&
166
+ (!address || account.address.toLowerCase() === address.toLowerCase()));
167
+ if (!selectedAccount) {
168
+ throw rpcErrors.invalidParams({
169
+ message: 'No available account found for request.',
170
+ });
171
+ }
172
+ return selectedAccount.id;
173
+ }, _MultichainRouter_getProtocolSnaps = function _MultichainRouter_getProtocolSnaps(scope) {
174
+ const allSnaps = __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").call('SnapController:getAll');
175
+ const filteredSnaps = getRunnableSnaps(allSnaps);
176
+ return filteredSnaps.reduce((accumulator, snap) => {
177
+ const permissions = __classPrivateFieldGet(this, _MultichainRouter_messenger, "f").call('PermissionController:getPermissions', snap.id);
178
+ if (permissions && hasProperty(permissions, SnapEndowments.Protocol)) {
179
+ const permission = permissions[SnapEndowments.Protocol];
180
+ const scopes = getProtocolCaveatScopes(permission);
181
+ if (scopes && hasProperty(scopes, scope)) {
182
+ accumulator.push({
183
+ snapId: snap.id,
184
+ methods: scopes[scope].methods,
185
+ });
186
+ }
187
+ }
188
+ return accumulator;
189
+ }, []);
190
+ }, _MultichainRouter_getSupportedAccountsMetadata = function _MultichainRouter_getSupportedAccountsMetadata(scope) {
191
+ return __classPrivateFieldGet(this, _MultichainRouter_messenger, "f")
192
+ .call('AccountsController:listMultichainAccounts', scope)
193
+ .filter((account) => account.metadata.snap?.enabled);
194
+ };
195
+ //# sourceMappingURL=MultichainRouter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultichainRouter.mjs","sourceRoot":"","sources":["../../src/multichain/MultichainRouter.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,OAAO,EAAE,SAAS,EAAE,6BAA6B;AACjD,OAAO,EACL,uBAAuB,EACvB,cAAc,EACf,oCAAoC;AAErC,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAMpD,OAAO,EACL,MAAM,EACN,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EACnB,wBAAwB;AAEzB,OAAO,EAAE,gBAAgB,EAAE,2BAAiB;AA4F5C,MAAM,IAAI,GAAG,kBAAkB,CAAC;AAEhC,MAAM,OAAO,gBAAgB;IAK3B,YAAY,EAAE,SAAS,EAAE,eAAe,EAAwB;;QAJhE,8CAAsC;QAEtC,oDAA0C;QAGxC,uBAAA,IAAI,+BAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,qCAAoB,eAAe,MAAA,CAAC;QAExC,uBAAA,IAAI,mCAAW,CAAC,qBAAqB,CACnC,GAAG,IAAI,gBAAgB,EACvB,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAC/C,CAAC;QAEF,uBAAA,IAAI,mCAAW,CAAC,qBAAqB,CACnC,GAAG,IAAI,sBAAsB,EAC7B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,CAC/C,CAAC;QAEF,uBAAA,IAAI,mCAAW,CAAC,qBAAqB,CACnC,GAAG,IAAI,uBAAuB,EAC9B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAChD,CAAC;QAEF,uBAAA,IAAI,mCAAW,CAAC,qBAAqB,CACnC,GAAG,IAAI,mBAAmB,EAC1B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,CAC5C,CAAC;IACJ,CAAC;IAkID;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,aAAa,CAAC,EAClB,kBAAkB,EAClB,MAAM,EACN,KAAK,EACL,OAAO,GAMR;QACC,6CAA6C;QAC7C,MAAM,CACJ,CAAC,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC;YAC1C,CAAC,KAAK,CAAC,UAAU,CAAC,eAAe,CAAC,CACrC,CAAC;QAEF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAEnC,yEAAyE;QACzE,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,uEAAkB,MAAtB,IAAI,EAC1B,kBAAkB,EAClB,KAAK,EACL,OAAO,CACR,CAAC;QAEF,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,uBAAA,IAAI,yCAAiB,MAArB,IAAI,EAAkB,KAAK,EAAE,OAAO,EAAE,EAAE,CAC7C,OAAO,CAAC,aAAa,CAAC;gBACpB,OAAO,EAAE,SAAS;gBAClB,KAAK;gBACL,MAAM;gBACN,MAAM,EAAE,MAAuB;aAChC,CAAC,CACH,CAAC;QACJ,CAAC;QAED,4DAA4D;QAC5D,qDAAqD;QACrD,MAAM,aAAa,GAAG,uBAAA,IAAI,uEAAkB,MAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC9B,CAAC;QAEF,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,uBAAA,IAAI,mCAAW,CAAC,IAAI,CAAC,8BAA8B,EAAE;gBAC1D,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,MAAM;gBACN,OAAO,EAAE;oBACP,MAAM,EAAE,EAAE;oBACV,MAAM,EAAE;wBACN,OAAO;wBACP,KAAK;qBACN;iBACF;gBACD,OAAO,EAAE,WAAW,CAAC,iBAAiB;aACvC,CAAkB,CAAC;QACtB,CAAC;QAED,gEAAgE;QAChE,MAAM,SAAS,CAAC,cAAc,EAAE,CAAC;IACnC,CAAC;IAcD;;;;;;OAMG;IACH,mBAAmB,CAAC,KAAkB;QACpC,MAAM,cAAc,GAAG,uBAAA,IAAI,mFAA8B,MAAlC,IAAI,EAA+B,KAAK,CAAC,CAAC,OAAO,CACtE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAC7B,CAAC;QAEF,MAAM,eAAe,GAAG,uBAAA,IAAI,uEAAkB,MAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC,OAAO,CAC3D,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CACvB,CAAC;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED;;;;;OAKG;IACH,oBAAoB,CAAC,KAAkB;QACrC,OAAO,uBAAA,IAAI,mFAA8B,MAAlC,IAAI,EAA+B,KAAK,CAAC,CAAC,GAAG,CAClD,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAC3C,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,KAAkB;QACjC,+GAA+G;QAC/G,OAAO,uBAAA,IAAI,mCAAW;aACnB,IAAI,CAAC,2CAA2C,EAAE,KAAK,CAAC;aACxD,IAAI,CAAC,CAAC,OAAwB,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC;CACF;;AAlQC;;;;;;;;;;GAUG;AACH,KAAK,kDACH,MAAc,EACd,KAAkB,EAClB,OAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,yCAAiB,MAArB,IAAI,EAAkB,KAAK,EAAE,OAAO,EAAE,EAAE,CAC3D,OAAO,CAAC,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CACtD,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,CAAC;QAChC,OAAO,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,6CACH,kBAAmC,EACnC,KAAkB,EAClB,OAAuB;IAEvB,MAAM,QAAQ,GAAG,uBAAA,IAAI,mCAAW;SAC7B,IAAI,CAAC,2CAA2C,EAAE,KAAK,CAAC;SACxD,MAAM,CACL,CACE,OAAwB,EAGxB,EAAE,CACF,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;QACvC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAC3C,CAAC;IAEJ,uDAAuD;IACvD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IAEtD,kEAAkE;IAClE,MAAM,OAAO,GAAG,MAAM,uBAAA,IAAI,4EAAuB,MAA3B,IAAI,EACxB,gBAAgB,EAChB,KAAK,EACL,OAAO,CACR,CAAC;IAEF,MAAM,wBAAwB,GAAG,kBAAkB,CAAC,GAAG,CACrD,CAAC,gBAAgB,EAAE,EAAE,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC,OAAO,CACnE,CAAC;IAEF,gFAAgF;IAChF,uDAAuD;IACvD,wFAAwF;IACxF,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CACnC,CAAC,OAAO,EAAE,EAAE,CACV,wBAAwB,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC;QAClD,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CACxE,CAAC;IAEF,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,SAAS,CAAC,aAAa,CAAC;YAC5B,OAAO,EAAE,yCAAyC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,eAAe,CAAC,EAAE,CAAC;AAC5B,CAAC,mFAWiB,KAAkB;IAClC,MAAM,QAAQ,GAAG,uBAAA,IAAI,mCAAW,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO,aAAa,CAAC,MAAM,CAAiB,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE;QAChE,MAAM,WAAW,GAAG,uBAAA,IAAI,mCAAW,CAAC,IAAI,CACtC,qCAAqC,EACrC,IAAI,CAAC,EAAE,CACR,CAAC;QAEF,IAAI,WAAW,IAAI,WAAW,CAAC,WAAW,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,UAAU,GAAG,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;YACnD,IAAI,MAAM,IAAI,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;gBACzC,WAAW,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,IAAI,CAAC,EAAE;oBACf,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC,2GAmF6B,KAAkB;IAC9C,OAAO,uBAAA,IAAI,mCAAW;SACnB,IAAI,CAAC,2CAA2C,EAAE,KAAK,CAAC;SACxD,MAAM,CAAC,CAAC,OAAwB,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n getProtocolCaveatScopes,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type {\n CaipAccountId,\n CaipChainId,\n JsonRpcParams,\n} from '@metamask/utils';\nimport {\n assert,\n hasProperty,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\n\nimport { getRunnableSnaps } from '../snaps';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\n\nexport type MultichainRouterHandleRequestAction = {\n type: `${typeof name}:handleRequest`;\n handler: MultichainRouter['handleRequest'];\n};\n\nexport type MultichainRouterGetSupportedMethodsAction = {\n type: `${typeof name}:getSupportedMethods`;\n handler: MultichainRouter['getSupportedMethods'];\n};\n\nexport type MultichainRouterGetSupportedAccountsAction = {\n type: `${typeof name}:getSupportedAccounts`;\n handler: MultichainRouter['getSupportedAccounts'];\n};\n\nexport type MultichainRouterIsSupportedScopeAction = {\n type: `${typeof name}:isSupportedScope`;\n handler: MultichainRouter['isSupportedScope'];\n};\n\n// Since the AccountsController depends on snaps-controllers we manually type this\ntype InternalAccount = {\n id: string;\n type: string;\n address: string;\n options: Record<string, Json>;\n methods: string[];\n metadata: {\n name: string;\n snap?: { id: SnapId; enabled: boolean; name: string };\n };\n};\n\ntype SnapKeyring = {\n submitRequest: (request: {\n account: string;\n method: string;\n params?: Json[] | Record<string, Json>;\n scope: CaipChainId;\n }) => Promise<Json>;\n resolveAccountAddress: (\n snapId: SnapId,\n scope: CaipChainId,\n request: Json,\n ) => Promise<{ address: CaipAccountId } | null>;\n};\n\n// Expecting a bound function that calls KeyringController.withKeyring selecting the Snap keyring\ntype WithSnapKeyringFunction = <ReturnType>(\n operation: (keyring: SnapKeyring) => Promise<ReturnType>,\n) => Promise<ReturnType>;\n\nexport type AccountsControllerListMultichainAccountsAction = {\n type: `AccountsController:listMultichainAccounts`;\n handler: (chainId?: CaipChainId) => InternalAccount[];\n};\n\nexport type MultichainRouterActions =\n | MultichainRouterHandleRequestAction\n | MultichainRouterGetSupportedMethodsAction\n | MultichainRouterGetSupportedAccountsAction\n | MultichainRouterIsSupportedScopeAction;\n\nexport type MultichainRouterAllowedActions =\n | GetAllSnaps\n | HandleSnapRequest\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction;\n\nexport type MultichainRouterEvents = never;\n\nexport type MultichainRouterMessenger = RestrictedControllerMessenger<\n typeof name,\n MultichainRouterActions | MultichainRouterAllowedActions,\n never,\n MultichainRouterAllowedActions['type'],\n MultichainRouterEvents['type']\n>;\n\nexport type MultichainRouterArgs = {\n messenger: MultichainRouterMessenger;\n withSnapKeyring: WithSnapKeyringFunction;\n};\n\ntype ProtocolSnap = {\n snapId: SnapId;\n methods: string[];\n};\n\nconst name = 'MultichainRouter';\n\nexport class MultichainRouter {\n #messenger: MultichainRouterMessenger;\n\n #withSnapKeyring: WithSnapKeyringFunction;\n\n constructor({ messenger, withSnapKeyring }: MultichainRouterArgs) {\n this.#messenger = messenger;\n this.#withSnapKeyring = withSnapKeyring;\n\n this.#messenger.registerActionHandler(\n `${name}:handleRequest`,\n async (...args) => this.handleRequest(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedMethods`,\n (...args) => this.getSupportedMethods(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedAccounts`,\n (...args) => this.getSupportedAccounts(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:isSupportedScope`,\n (...args) => this.isSupportedScope(...args),\n );\n }\n\n /**\n * Attempts to resolve the account address to use for a given request by inspecting the request itself.\n *\n * The request is sent to to an account Snap via the SnapKeyring that will attempt this resolution.\n *\n * @param snapId - The ID of the Snap to send the request to.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns The resolved address if found, otherwise null.\n * @throws If the invocation of the SnapKeyring fails.\n */\n async #resolveRequestAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n try {\n const result = await this.#withSnapKeyring(async (keyring) =>\n keyring.resolveAccountAddress(snapId, scope, request),\n );\n const address = result?.address;\n return address ? parseCaipAccountId(address).address : null;\n } catch {\n throw rpcErrors.internal();\n }\n }\n\n /**\n * Get the account ID of the account that should service the RPC request via an account Snap.\n *\n * This function checks whether any accounts exist that can service a given request by\n * using a combination of the resolveAccountAddress functionality and the connected accounts.\n *\n * If an account is expected to service this request but none is found, the function will throw.\n *\n * @param connectedAddresses - The CAIP-10 addresses connected to the requesting origin.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns An account ID if found, otherwise null.\n * @throws If no account is found, but the accounts exist that could service the request.\n */\n async #getSnapAccountId(\n connectedAddresses: CaipAccountId[],\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n const accounts = this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter(\n (\n account: InternalAccount,\n ): account is InternalAccount & {\n metadata: Required<InternalAccount['metadata']>;\n } =>\n Boolean(account.metadata.snap?.enabled) &&\n account.methods.includes(request.method),\n );\n\n // If no accounts can service the request, return null.\n if (accounts.length === 0) {\n return null;\n }\n\n const resolutionSnapId = accounts[0].metadata.snap.id;\n\n // Attempt to resolve the address that should be used for signing.\n const address = await this.#resolveRequestAddress(\n resolutionSnapId,\n scope,\n request,\n );\n\n const parsedConnectedAddresses = connectedAddresses.map(\n (connectedAddress) => parseCaipAccountId(connectedAddress).address,\n );\n\n // If we have a resolved address, try to find the selected account based on that\n // otherwise, default to one of the connected accounts.\n // TODO: Eventually let the user choose if we have more than one option for the account.\n const selectedAccount = accounts.find(\n (account) =>\n parsedConnectedAddresses.includes(account.address) &&\n (!address || account.address.toLowerCase() === address.toLowerCase()),\n );\n\n if (!selectedAccount) {\n throw rpcErrors.invalidParams({\n message: 'No available account found for request.',\n });\n }\n\n return selectedAccount.id;\n }\n\n /**\n * Get all protocol Snaps that can service a given CAIP-2 scope.\n *\n * Protocol Snaps are deemed fit to service a scope if they are runnable\n * and have the proper permissions set for the scope.\n *\n * @param scope - A CAIP-2 scope.\n * @returns A list of all the protocol Snaps available and their RPC methods.\n */\n #getProtocolSnaps(scope: CaipChainId) {\n const allSnaps = this.#messenger.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<ProtocolSnap[]>((accumulator, snap) => {\n const permissions = this.#messenger.call(\n 'PermissionController:getPermissions',\n snap.id,\n );\n\n if (permissions && hasProperty(permissions, SnapEndowments.Protocol)) {\n const permission = permissions[SnapEndowments.Protocol];\n const scopes = getProtocolCaveatScopes(permission);\n if (scopes && hasProperty(scopes, scope)) {\n accumulator.push({\n snapId: snap.id,\n methods: scopes[scope].methods,\n });\n }\n }\n\n return accumulator;\n }, []);\n }\n\n /**\n * Handle an incoming JSON-RPC request tied to a specific scope by routing\n * to either a procotol Snap or an account Snap.\n *\n * @param options - An options bag.\n * @param options.connectedAddresses - Addresses currently connected to the origin.\n * @param options.origin - The origin of the RPC request.\n * @param options.request - The JSON-RPC request.\n * @param options.scope - The CAIP-2 scope for the request.\n * @returns The response from the chosen Snap.\n * @throws If no handler was found.\n */\n async handleRequest({\n connectedAddresses,\n origin,\n scope,\n request,\n }: {\n connectedAddresses: CaipAccountId[];\n origin: string;\n scope: CaipChainId;\n request: JsonRpcRequest;\n }): Promise<Json> {\n // Explicitly block EVM scopes, just in case.\n assert(\n !scope.startsWith(KnownCaipNamespace.Eip155) &&\n !scope.startsWith('wallet:eip155'),\n );\n\n const { method, params } = request;\n\n // If the RPC request can be serviced by an account Snap, route it there.\n const accountId = await this.#getSnapAccountId(\n connectedAddresses,\n scope,\n request,\n );\n\n if (accountId) {\n return this.#withSnapKeyring(async (keyring) =>\n keyring.submitRequest({\n account: accountId,\n scope,\n method,\n params: params as JsonRpcParams,\n }),\n );\n }\n\n // If the RPC request cannot be serviced by an account Snap,\n // but has a protocol Snap available, route it there.\n const protocolSnaps = this.#getProtocolSnaps(scope);\n const protocolSnap = protocolSnaps.find((snap) =>\n snap.methods.includes(method),\n );\n\n if (protocolSnap) {\n return this.#messenger.call('SnapController:handleRequest', {\n snapId: protocolSnap.snapId,\n origin,\n request: {\n method: '',\n params: {\n request,\n scope,\n },\n },\n handler: HandlerType.OnProtocolRequest,\n }) as Promise<Json>;\n }\n\n // If no compatible account or protocol Snaps were found, throw.\n throw rpcErrors.methodNotFound();\n }\n\n /**\n * Get a list of metadata for supported accounts for a given scope from the client.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of metadata for the supported accounts.\n */\n #getSupportedAccountsMetadata(scope: CaipChainId): InternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter((account: InternalAccount) => account.metadata.snap?.enabled);\n }\n\n /**\n * Get a list of supported methods for a given scope.\n * This combines both protocol and account Snaps supported methods.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of supported methods.\n */\n getSupportedMethods(scope: CaipChainId): string[] {\n const accountMethods = this.#getSupportedAccountsMetadata(scope).flatMap(\n (account) => account.methods,\n );\n\n const protocolMethods = this.#getProtocolSnaps(scope).flatMap(\n (snap) => snap.methods,\n );\n\n return Array.from(new Set([...accountMethods, ...protocolMethods]));\n }\n\n /**\n * Get a list of supported accounts for a given scope.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of CAIP-10 addresses.\n */\n getSupportedAccounts(scope: CaipChainId): string[] {\n return this.#getSupportedAccountsMetadata(scope).map(\n (account) => `${scope}:${account.address}`,\n );\n }\n\n /**\n * Determine whether a given CAIP-2 scope is supported by the router.\n *\n * @param scope - The CAIP-2 scope.\n * @returns True if the router can service the scope, otherwise false.\n */\n isSupportedScope(scope: CaipChainId): boolean {\n // We currently assume here that if one Snap exists that service the scope, we can service the scope generally.\n return this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .some((account: InternalAccount) => account.metadata.snap?.enabled);\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./MultichainRouter.cjs"), exports);
18
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/multichain/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAmC","sourcesContent":["export * from './MultichainRouter';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from "./MultichainRouter.cjs";
2
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/multichain/index.ts"],"names":[],"mappings":"AAAA,uCAAmC"}
@@ -0,0 +1,2 @@
1
+ export * from "./MultichainRouter.mjs";
2
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/multichain/index.ts"],"names":[],"mappings":"AAAA,uCAAmC"}
@@ -0,0 +1,2 @@
1
+ export * from "./MultichainRouter.mjs";
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/multichain/index.ts"],"names":[],"mappings":"AAAA,uCAAmC","sourcesContent":["export * from './MultichainRouter';\n"]}
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_dynamicPermissions, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_maxIdleTime, _SnapController_encryptor, _SnapController_getMnemonic, _SnapController_getFeatureFlags, _SnapController_clientCryptography, _SnapController_detectSnapLocation, _SnapController_snapsRuntimeData, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_preinstalledSnaps, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_handlePreinstalledSnaps, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_assertCanInstallSnaps, _SnapController_assertCanUsePlatform, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_getSnapEncryptionKey, _SnapController_hasCachedEncryptionKey, _SnapController_decryptSnapState, _SnapController_encryptSnapState, _SnapController_getStateToPersist, _SnapController_persistSnapState, _SnapController_handleInitialConnections, _SnapController_addSnapToSubject, _SnapController_removeSnapFromSubjects, _SnapController_revokeAllSnapPermissions, _SnapController_createApproval, _SnapController_updateApproval, _SnapController_resolveAllowlistVersion, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_validateSnapPermissions, _SnapController_validatePlatformVersion, _SnapController_getExecutionTimeout, _SnapController_getRpcRequestHandler, _SnapController_createInterface, _SnapController_assertInterfaceExists, _SnapController_transformSnapRpcRequestResult, _SnapController_assertSnapRpcRequestResult, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isSubjectConnectedToSnap, _SnapController_calculateConnectionsChange, _SnapController_updatePermissions, _SnapController_isValidUpdate, _SnapController_callLifecycleHook, _SnapController_handleLock;
16
+ var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_dynamicPermissions, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_maxIdleTime, _SnapController_encryptor, _SnapController_getMnemonic, _SnapController_getFeatureFlags, _SnapController_clientCryptography, _SnapController_detectSnapLocation, _SnapController_snapsRuntimeData, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_preinstalledSnaps, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_handlePreinstalledSnaps, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_assertCanInstallSnaps, _SnapController_assertCanUsePlatform, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_getSnapEncryptionKey, _SnapController_hasCachedEncryptionKey, _SnapController_decryptSnapState, _SnapController_encryptSnapState, _SnapController_getStateToPersist, _SnapController_persistSnapState, _SnapController_handleInitialConnections, _SnapController_addSnapToSubject, _SnapController_removeSnapFromSubjects, _SnapController_revokeAllSnapPermissions, _SnapController_createApproval, _SnapController_updateApproval, _SnapController_resolveAllowlistVersion, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_validateSnapPermissions, _SnapController_validatePlatformVersion, _SnapController_getExecutionTimeout, _SnapController_getRpcRequestHandler, _SnapController_createInterface, _SnapController_assertInterfaceExists, _SnapController_transformSnapRpcRequestResult, _SnapController_transformOnAssetsLookupResult, _SnapController_transformOnAssetsConversionResult, _SnapController_assertSnapRpcRequestResult, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isSubjectConnectedToSnap, _SnapController_calculateConnectionsChange, _SnapController_updatePermissions, _SnapController_isValidUpdate, _SnapController_callLifecycleHook, _SnapController_handleLock;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SnapController = exports.SNAP_APPROVAL_RESULT = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
19
19
  const base_controller_1 = require("@metamask/base-controller");
@@ -34,6 +34,7 @@ const constants_1 = require("./constants.cjs");
34
34
  const location_1 = require("./location/index.cjs");
35
35
  const registry_1 = require("./registry/index.cjs");
36
36
  const RequestQueue_1 = require("./RequestQueue.cjs");
37
+ const selectors_1 = require("./selectors.cjs");
37
38
  const Timer_1 = require("./Timer.cjs");
38
39
  exports.controllerName = 'SnapController';
39
40
  // TODO: Figure out how to name these
@@ -68,7 +69,6 @@ function truncateSnap(snap) {
68
69
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
69
70
  return truncatedSnap;
70
71
  }
71
- const name = 'SnapController';
72
72
  /*
73
73
  * A snap is initialized in three phases:
74
74
  * - Add: Loads the snap from a remote source and parses it.
@@ -109,7 +109,7 @@ class SnapController extends base_controller_1.BaseController {
109
109
  anonymous: false,
110
110
  },
111
111
  },
112
- name,
112
+ name: exports.controllerName,
113
113
  state: {
114
114
  ...defaultState,
115
115
  ...state,
@@ -621,6 +621,14 @@ class SnapController extends base_controller_1.BaseController {
621
621
  getAllSnaps() {
622
622
  return Object.values(this.state.snaps).map(truncateSnap);
623
623
  }
624
+ /**
625
+ * Gets all runnable snaps.
626
+ *
627
+ * @returns All runnable snaps.
628
+ */
629
+ getRunnableSnaps() {
630
+ return (0, selectors_1.getRunnableSnaps)(this.getAllSnaps());
631
+ }
624
632
  /**
625
633
  * Gets the serialized permitted snaps of the given origin, if any.
626
634
  *
@@ -1090,6 +1098,7 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_dynamicPerm
1090
1098
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:getPermitted`, (...args) => this.getPermittedSnaps(...args));
1091
1099
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:install`, async (...args) => this.installSnaps(...args));
1092
1100
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:getAll`, (...args) => this.getAllSnaps(...args));
1101
+ this.messagingSystem.registerActionHandler(`${exports.controllerName}:getRunnableSnaps`, (...args) => this.getRunnableSnaps(...args));
1093
1102
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:incrementActiveReferences`, (...args) => this.incrementActiveReferences(...args));
1094
1103
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:decrementActiveReferences`, (...args) => this.decrementActiveReferences(...args));
1095
1104
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:getRegistryMetadata`, async (...args) => this.getRegistryMetadata(...args));
@@ -1723,7 +1732,7 @@ async function _SnapController_getEndowments(snapId) {
1723
1732
  throw new Error(`${snapId} failed to respond to the request in time.`);
1724
1733
  }
1725
1734
  await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertSnapRpcRequestResult).call(this, snapId, handlerType, result);
1726
- const transformedResult = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transformSnapRpcRequestResult).call(this, snapId, handlerType, result);
1735
+ const transformedResult = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transformSnapRpcRequestResult).call(this, snapId, handlerType, request, result);
1727
1736
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_recordSnapRpcRequestFinish).call(this, snapId, request.id);
1728
1737
  return transformedResult;
1729
1738
  }
@@ -1759,10 +1768,11 @@ async function _SnapController_createInterface(snapId, content, contentType) {
1759
1768
  *
1760
1769
  * @param snapId - The snap ID of the snap that produced the result.
1761
1770
  * @param handlerType - The handler type that produced the result.
1771
+ * @param request - The request that returned the result.
1762
1772
  * @param result - The result.
1763
1773
  * @returns The transformed result if applicable, otherwise the original result.
1764
1774
  */
1765
- async function _SnapController_transformSnapRpcRequestResult(snapId, handlerType, result) {
1775
+ async function _SnapController_transformSnapRpcRequestResult(snapId, handlerType, request, result) {
1766
1776
  switch (handlerType) {
1767
1777
  case snaps_utils_1.HandlerType.OnTransaction:
1768
1778
  case snaps_utils_1.HandlerType.OnSignature:
@@ -1778,9 +1788,47 @@ async function _SnapController_transformSnapRpcRequestResult(snapId, handlerType
1778
1788
  }
1779
1789
  return result;
1780
1790
  }
1791
+ case snaps_utils_1.HandlerType.OnAssetsLookup:
1792
+ // We can cast since the request and result have already been validated.
1793
+ return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transformOnAssetsLookupResult).call(this, snapId, request, result);
1794
+ case snaps_utils_1.HandlerType.OnAssetsConversion:
1795
+ // We can cast since the request and result have already been validated.
1796
+ return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transformOnAssetsConversionResult).call(this, request, result);
1781
1797
  default:
1782
1798
  return result;
1783
1799
  }
1800
+ }, _SnapController_transformOnAssetsLookupResult = function _SnapController_transformOnAssetsLookupResult(snapId, { params: requestedParams }, { assets }) {
1801
+ const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
1802
+ // We know the permissions are guaranteed to be set here.
1803
+ (0, utils_1.assert)(permissions);
1804
+ const permission = permissions[snaps_rpc_methods_1.SnapEndowments.Assets];
1805
+ const scopes = (0, snaps_rpc_methods_1.getChainIdsCaveat)(permission);
1806
+ (0, utils_1.assert)(scopes);
1807
+ const { assets: requestedAssets } = requestedParams;
1808
+ const filteredAssets = Object.keys(assets).reduce((accumulator, assetType) => {
1809
+ const castAssetType = assetType;
1810
+ const isValid = scopes.some((scope) => castAssetType.startsWith(scope)) &&
1811
+ requestedAssets.includes(castAssetType);
1812
+ // Filter out unrequested assets and assets for scopes the Snap hasn't registered for.
1813
+ if (isValid) {
1814
+ accumulator[castAssetType] = assets[castAssetType];
1815
+ }
1816
+ return accumulator;
1817
+ }, {});
1818
+ return { assets: filteredAssets };
1819
+ }, _SnapController_transformOnAssetsConversionResult = function _SnapController_transformOnAssetsConversionResult({ params: requestedParams }, { conversionRates }) {
1820
+ const { conversions: requestedConversions } = requestedParams;
1821
+ const filteredConversionRates = requestedConversions.reduce((accumulator, conversion) => {
1822
+ var _a;
1823
+ const rate = conversionRates[conversion.from]?.[conversion.to];
1824
+ // Only include rates that were actually requested.
1825
+ if (rate) {
1826
+ accumulator[_a = conversion.from] ?? (accumulator[_a] = {});
1827
+ accumulator[conversion.from][conversion.to] = rate;
1828
+ }
1829
+ return accumulator;
1830
+ }, {});
1831
+ return { conversionRates: filteredConversionRates };
1784
1832
  }, _SnapController_assertSnapRpcRequestResult =
1785
1833
  /**
1786
1834
  * Assert that the returned result of a Snap RPC call is the expected shape.
@@ -1822,6 +1870,12 @@ async function _SnapController_assertSnapRpcRequestResult(snapId, handlerType, r
1822
1870
  case snaps_utils_1.HandlerType.OnNameLookup:
1823
1871
  (0, utils_1.assertStruct)(result, snaps_utils_1.OnNameLookupResponseStruct);
1824
1872
  break;
1873
+ case snaps_utils_1.HandlerType.OnAssetsLookup:
1874
+ (0, utils_1.assertStruct)(result, snaps_sdk_1.OnAssetsLookupResponseStruct);
1875
+ break;
1876
+ case snaps_utils_1.HandlerType.OnAssetsConversion:
1877
+ (0, utils_1.assertStruct)(result, snaps_sdk_1.OnAssetsConversionResponseStruct);
1878
+ break;
1825
1879
  default:
1826
1880
  break;
1827
1881
  }