@metamask-previews/multichain-account-controller 0.0.0-preview-a3f523c0 → 0.0.0-preview-0e455278
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/dist/providers/EvmAccountProvider.cjs +13 -5
- package/dist/providers/EvmAccountProvider.cjs.map +1 -1
- package/dist/providers/EvmAccountProvider.d.cts.map +1 -1
- package/dist/providers/EvmAccountProvider.d.mts.map +1 -1
- package/dist/providers/EvmAccountProvider.mjs +13 -5
- package/dist/providers/EvmAccountProvider.mjs.map +1 -1
- package/dist/providers/SolAccountProvider.cjs +40 -6
- package/dist/providers/SolAccountProvider.cjs.map +1 -1
- package/dist/providers/SolAccountProvider.d.cts.map +1 -1
- package/dist/providers/SolAccountProvider.d.mts.map +1 -1
- package/dist/providers/SolAccountProvider.mjs +40 -6
- package/dist/providers/SolAccountProvider.mjs.map +1 -1
- package/dist/tests/accounts.cjs +170 -0
- package/dist/tests/accounts.cjs.map +1 -0
- package/dist/tests/accounts.d.cts +74 -0
- package/dist/tests/accounts.d.cts.map +1 -0
- package/dist/tests/accounts.d.mts +74 -0
- package/dist/tests/accounts.d.mts.map +1 -0
- package/dist/tests/accounts.mjs +166 -0
- package/dist/tests/accounts.mjs.map +1 -0
- package/dist/tests/index.cjs +19 -0
- package/dist/tests/index.cjs.map +1 -0
- package/dist/tests/index.d.cts +3 -0
- package/dist/tests/index.d.cts.map +1 -0
- package/dist/tests/index.d.mts +3 -0
- package/dist/tests/index.d.mts.map +1 -0
- package/dist/tests/index.mjs +3 -0
- package/dist/tests/index.mjs.map +1 -0
- package/dist/tests/messenger.cjs +34 -0
- package/dist/tests/messenger.cjs.map +1 -0
- package/dist/tests/messenger.d.cts +16 -0
- package/dist/tests/messenger.d.cts.map +1 -0
- package/dist/tests/messenger.d.mts +16 -0
- package/dist/tests/messenger.d.mts.map +1 -0
- package/dist/tests/messenger.mjs +29 -0
- package/dist/tests/messenger.mjs.map +1 -0
- package/package.json +17 -10
@@ -30,17 +30,25 @@ class EvmAccountProvider {
|
|
30
30
|
__classPrivateFieldSet(this, _EvmAccountProvider_messenger, messenger, "f");
|
31
31
|
}
|
32
32
|
async createAccounts({ entropySource, groupIndex, }) {
|
33
|
-
const
|
33
|
+
const [address] = await __classPrivateFieldGet(this, _EvmAccountProvider_instances, "m", _EvmAccountProvider_withKeyring).call(this, { id: entropySource }, async ({ keyring }) => {
|
34
34
|
const accounts = await keyring.getAccounts();
|
35
|
-
if (groupIndex
|
35
|
+
if (groupIndex < accounts.length) {
|
36
36
|
// Nothing new to create, we just re-use the existing accounts here,
|
37
37
|
return [accounts[groupIndex]];
|
38
38
|
}
|
39
|
+
// For now, we don't allow for gap, so if we need to create a new
|
40
|
+
// account, this has to be the next one.
|
41
|
+
if (groupIndex !== accounts.length) {
|
42
|
+
throw new Error('Trying to create too many accounts');
|
43
|
+
}
|
39
44
|
// Create new accounts (and returns their addresses).
|
40
|
-
|
45
|
+
// NOTE: We need the `+ 1` here since we use the "number of accounts"
|
46
|
+
// in `addAccounts`, so:
|
47
|
+
// - 1 means, 1 account -> index 0
|
48
|
+
// - 2 means, 2 accounts -> index 0 and 1
|
49
|
+
// - etc...
|
50
|
+
return await keyring.addAccounts(groupIndex + 1);
|
41
51
|
});
|
42
|
-
// Only use the account associated for that index.
|
43
|
-
const address = addresses[groupIndex];
|
44
52
|
const account = __classPrivateFieldGet(this, _EvmAccountProvider_messenger, "f").call('AccountsController:getAccountByAddress', address);
|
45
53
|
// We MUST have the associated internal account.
|
46
54
|
assertInternalAccountExists(account);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EvmAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,uDAA6E;AAC7E,qEAIsC;
|
1
|
+
{"version":3,"file":"EvmAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { EthAccountType, type EntropySourceId } from '@metamask/keyring-api';\nimport {\n KeyringTypes,\n type KeyringMetadata,\n type KeyringSelector,\n} from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\n\nimport type { MultichainAccountControllerMessenger } from '../types';\n\n// Max index used by discovery (until we move the proper discovery here).\nconst MAX_GROUP_INDEX = 1;\n\ntype EoaInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport class EvmAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n }\n\n async #withKeyring<\n SelectedKeyring extends EthKeyring = EthKeyring,\n CallbackResult = void,\n >(\n selector: KeyringSelector,\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SelectedKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n const result = await this.#messenger.call(\n 'KeyringController:withKeyring',\n selector,\n ({ keyring, metadata }) =>\n operation({\n keyring: keyring as SelectedKeyring,\n metadata,\n }),\n );\n\n return result as CallbackResult;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const [address] = await this.#withKeyring(\n { id: entropySource },\n async ({ keyring }) => {\n const accounts = await keyring.getAccounts();\n if (groupIndex < accounts.length) {\n // Nothing new to create, we just re-use the existing accounts here,\n return [accounts[groupIndex]];\n }\n\n // For now, we don't allow for gap, so if we need to create a new\n // account, this has to be the next one.\n if (groupIndex !== accounts.length) {\n throw new Error('Trying to create too many accounts');\n }\n\n // Create new accounts (and returns their addresses).\n // NOTE: We need the `+ 1` here since we use the \"number of accounts\"\n // in `addAccounts`, so:\n // - 1 means, 1 account -> index 0\n // - 2 means, 2 accounts -> index 0 and 1\n // - etc...\n return await keyring.addAccounts(groupIndex + 1);\n },\n );\n\n const account = this.#messenger.call(\n 'AccountsController:getAccountByAddress',\n address,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n // TODO: Move account discovery here (for EVM).\n\n if (groupIndex < MAX_GROUP_INDEX) {\n return await this.createAccounts({ entropySource, groupIndex });\n }\n return [];\n }\n\n #getAccounts(): EoaInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== EthAccountType.Eoa ||\n account.metadata.keyring.type !== (KeyringTypes.hd as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found an HD account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found an HD account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as EoaInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EvmAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,8BAA8B;AAM7E,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;
|
1
|
+
{"version":3,"file":"EvmAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,8BAA8B;AAM7E,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAExE,OAAO,KAAK,EAAE,oCAAoC,EAAE,qBAAiB;AAqBrE,qBAAa,kBAAmB,YAAW,eAAe;;gBAG5C,SAAS,EAAE,oCAAoC;IA8BrD,cAAc,CAAC,EACnB,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IAqCK,yBAAyB,CAAC,EAC9B,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IAyCD,WAAW,CAAC,EACV,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,eAAe,EAAE;IASrB,iBAAiB,IAAI,eAAe,EAAE;CASvC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EvmAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,8BAA8B;AAM7E,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;
|
1
|
+
{"version":3,"file":"EvmAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,8BAA8B;AAM7E,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAExE,OAAO,KAAK,EAAE,oCAAoC,EAAE,qBAAiB;AAqBrE,qBAAa,kBAAmB,YAAW,eAAe;;gBAG5C,SAAS,EAAE,oCAAoC;IA8BrD,cAAc,CAAC,EACnB,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IAqCK,yBAAyB,CAAC,EAC9B,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IAyCD,WAAW,CAAC,EACV,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,eAAe,EAAE;IASrB,iBAAiB,IAAI,eAAe,EAAE;CASvC"}
|
@@ -27,17 +27,25 @@ export class EvmAccountProvider {
|
|
27
27
|
__classPrivateFieldSet(this, _EvmAccountProvider_messenger, messenger, "f");
|
28
28
|
}
|
29
29
|
async createAccounts({ entropySource, groupIndex, }) {
|
30
|
-
const
|
30
|
+
const [address] = await __classPrivateFieldGet(this, _EvmAccountProvider_instances, "m", _EvmAccountProvider_withKeyring).call(this, { id: entropySource }, async ({ keyring }) => {
|
31
31
|
const accounts = await keyring.getAccounts();
|
32
|
-
if (groupIndex
|
32
|
+
if (groupIndex < accounts.length) {
|
33
33
|
// Nothing new to create, we just re-use the existing accounts here,
|
34
34
|
return [accounts[groupIndex]];
|
35
35
|
}
|
36
|
+
// For now, we don't allow for gap, so if we need to create a new
|
37
|
+
// account, this has to be the next one.
|
38
|
+
if (groupIndex !== accounts.length) {
|
39
|
+
throw new Error('Trying to create too many accounts');
|
40
|
+
}
|
36
41
|
// Create new accounts (and returns their addresses).
|
37
|
-
|
42
|
+
// NOTE: We need the `+ 1` here since we use the "number of accounts"
|
43
|
+
// in `addAccounts`, so:
|
44
|
+
// - 1 means, 1 account -> index 0
|
45
|
+
// - 2 means, 2 accounts -> index 0 and 1
|
46
|
+
// - etc...
|
47
|
+
return await keyring.addAccounts(groupIndex + 1);
|
38
48
|
});
|
39
|
-
// Only use the account associated for that index.
|
40
|
-
const address = addresses[groupIndex];
|
41
49
|
const account = __classPrivateFieldGet(this, _EvmAccountProvider_messenger, "f").call('AccountsController:getAccountByAddress', address);
|
42
50
|
// We MUST have the associated internal account.
|
43
51
|
assertInternalAccountExists(account);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EvmAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,cAAc,EAAwB,8BAA8B;AAC7E,OAAO,EACL,YAAY,EAGb,qCAAqC;
|
1
|
+
{"version":3,"file":"EvmAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { EthAccountType, type EntropySourceId } from '@metamask/keyring-api';\nimport {\n KeyringTypes,\n type KeyringMetadata,\n type KeyringSelector,\n} from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\n\nimport type { MultichainAccountControllerMessenger } from '../types';\n\n// Max index used by discovery (until we move the proper discovery here).\nconst MAX_GROUP_INDEX = 1;\n\ntype EoaInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport class EvmAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n }\n\n async #withKeyring<\n SelectedKeyring extends EthKeyring = EthKeyring,\n CallbackResult = void,\n >(\n selector: KeyringSelector,\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SelectedKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n const result = await this.#messenger.call(\n 'KeyringController:withKeyring',\n selector,\n ({ keyring, metadata }) =>\n operation({\n keyring: keyring as SelectedKeyring,\n metadata,\n }),\n );\n\n return result as CallbackResult;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const [address] = await this.#withKeyring(\n { id: entropySource },\n async ({ keyring }) => {\n const accounts = await keyring.getAccounts();\n if (groupIndex < accounts.length) {\n // Nothing new to create, we just re-use the existing accounts here,\n return [accounts[groupIndex]];\n }\n\n // For now, we don't allow for gap, so if we need to create a new\n // account, this has to be the next one.\n if (groupIndex !== accounts.length) {\n throw new Error('Trying to create too many accounts');\n }\n\n // Create new accounts (and returns their addresses).\n // NOTE: We need the `+ 1` here since we use the \"number of accounts\"\n // in `addAccounts`, so:\n // - 1 means, 1 account -> index 0\n // - 2 means, 2 accounts -> index 0 and 1\n // - etc...\n return await keyring.addAccounts(groupIndex + 1);\n },\n );\n\n const account = this.#messenger.call(\n 'AccountsController:getAccountByAddress',\n address,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n // TODO: Move account discovery here (for EVM).\n\n if (groupIndex < MAX_GROUP_INDEX) {\n return await this.createAccounts({ entropySource, groupIndex });\n }\n return [];\n }\n\n #getAccounts(): EoaInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== EthAccountType.Eoa ||\n account.metadata.keyring.type !== (KeyringTypes.hd as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found an HD account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found an HD account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as EoaInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
10
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
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
12
12
|
};
|
13
|
-
var _SolAccountProvider_instances, _SolAccountProvider_messenger, _SolAccountProvider_client, _SolAccountProvider_getKeyringClientFromSnapId, _SolAccountProvider_createAccount, _SolAccountProvider_getAccounts;
|
13
|
+
var _SolAccountProvider_instances, _SolAccountProvider_messenger, _SolAccountProvider_client, _SolAccountProvider_withKeyring, _SolAccountProvider_getKeyringClientFromSnapId, _SolAccountProvider_createAccount, _SolAccountProvider_getAccounts;
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
15
15
|
exports.SolAccountProvider = void 0;
|
16
16
|
const keyring_api_1 = require("@metamask/keyring-api");
|
@@ -23,14 +23,15 @@ function assertInternalAccountExists(account) {
|
|
23
23
|
throw new Error('Internal account does not exist');
|
24
24
|
}
|
25
25
|
}
|
26
|
+
const SOLANA_SNAP_ID = 'npm:@metamask/solana-wallet-snap';
|
26
27
|
class SolAccountProvider {
|
27
28
|
constructor(messenger) {
|
28
29
|
_SolAccountProvider_instances.add(this);
|
29
30
|
_SolAccountProvider_messenger.set(this, void 0);
|
30
31
|
_SolAccountProvider_client.set(this, void 0);
|
31
32
|
__classPrivateFieldSet(this, _SolAccountProvider_messenger, messenger, "f");
|
32
|
-
// TODO: Change this once we introduce 1 Snap keyring per Snaps
|
33
|
-
__classPrivateFieldSet(this, _SolAccountProvider_client, __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_getKeyringClientFromSnapId).call(this,
|
33
|
+
// TODO: Change this once we introduce 1 Snap keyring per Snaps.
|
34
|
+
__classPrivateFieldSet(this, _SolAccountProvider_client, __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_getKeyringClientFromSnapId).call(this, SOLANA_SNAP_ID), "f");
|
34
35
|
}
|
35
36
|
async createAccounts({ entropySource, groupIndex, }) {
|
36
37
|
const account = await __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_createAccount).call(this, {
|
@@ -58,7 +59,13 @@ class SolAccountProvider {
|
|
58
59
|
}
|
59
60
|
}
|
60
61
|
exports.SolAccountProvider = SolAccountProvider;
|
61
|
-
_SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new WeakMap(), _SolAccountProvider_instances = new WeakSet(),
|
62
|
+
_SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new WeakMap(), _SolAccountProvider_instances = new WeakSet(), _SolAccountProvider_withKeyring = async function _SolAccountProvider_withKeyring(selector, operation) {
|
63
|
+
const result = await __classPrivateFieldGet(this, _SolAccountProvider_messenger, "f").call('KeyringController:withKeyring', selector, ({ keyring, metadata }) => operation({
|
64
|
+
keyring: keyring,
|
65
|
+
metadata,
|
66
|
+
}));
|
67
|
+
return result;
|
68
|
+
}, _SolAccountProvider_getKeyringClientFromSnapId = function _SolAccountProvider_getKeyringClientFromSnapId(snapId) {
|
62
69
|
return new keyring_snap_client_1.KeyringClient({
|
63
70
|
send: async (request) => {
|
64
71
|
const response = await __classPrivateFieldGet(this, _SolAccountProvider_messenger, "f").call('SnapController:handleRequest', {
|
@@ -71,9 +78,36 @@ _SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new
|
|
71
78
|
},
|
72
79
|
});
|
73
80
|
}, _SolAccountProvider_createAccount = async function _SolAccountProvider_createAccount(opts) {
|
74
|
-
|
81
|
+
// NOTE: We're not supposed to make the keyring instance escape `withKeyring` but
|
82
|
+
// we have to use the `SnapKeyring` instance to be able to create Solana account
|
83
|
+
// without triggering UI confirmation.
|
84
|
+
// Also, creating account that way won't invalidate the snap keyring state. The
|
85
|
+
// account will get created and persisted properly with the Snap account creation
|
86
|
+
// flow "asynchronously" (with `notify:accountCreated`).
|
87
|
+
const createAccount = await __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_withKeyring).call(this, { type: keyring_controller_1.KeyringTypes.snap }, async ({ keyring }) => keyring.createAccount.bind(keyring));
|
88
|
+
const keyringAccount = await createAccount(SOLANA_SNAP_ID, opts, {
|
89
|
+
displayAccountNameSuggestion: false,
|
90
|
+
displayConfirmation: false,
|
91
|
+
});
|
92
|
+
// FIXME: This part of the flow is truly async, so when the `KeyringClient`
|
93
|
+
// returns the `KeyringAccount`, its `InternalAccount` won't be "ready"
|
94
|
+
// right away. For now we just re-create a fake `InternalAccount` and
|
95
|
+
// we might have to rely solely on `account.id`.
|
75
96
|
// Actually get the associated `InternalAccount`.
|
76
|
-
const account =
|
97
|
+
// const account = this.#messenger.call(
|
98
|
+
// 'AccountsController:getAccount',
|
99
|
+
// keyringAccount.id,
|
100
|
+
// );
|
101
|
+
const account = {
|
102
|
+
...keyringAccount,
|
103
|
+
metadata: {
|
104
|
+
name: `Solana account -- ${keyringAccount.options.index}`,
|
105
|
+
importTime: 0,
|
106
|
+
keyring: {
|
107
|
+
type: keyring_controller_1.KeyringTypes.snap,
|
108
|
+
},
|
109
|
+
},
|
110
|
+
};
|
77
111
|
// We MUST have the associated internal account.
|
78
112
|
assertInternalAccountExists(account);
|
79
113
|
return account;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SolAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SolAccountType,\n SolScope,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MultichainAccountControllerMessenger } from '../types';\n\ntype SolInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport class SolAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n \n readonly #client: KeyringClient;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n\n // TODO: Change this once we introduce 1 Snap keyring per Snaps\n this.#client = this.#getKeyringClientFromSnapId(\n 'npm:@metamask/solana-wallet-snap',\n );\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) => {\n const response = await this.#messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Promise<Json>;\n },\n });\n }\n\n async #createAccount(opts: {\n entropySource: EntropySourceId;\n derivationPath: `m/${string}`;\n }) {\n const keyringAccount = await this.#client.createAccount(opts);\n\n // Actually get the associated `InternalAccount`.\n const account = this.#messenger.call(\n 'AccountsController:getAccount',\n keyringAccount.id,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return account;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const account = await this.#createAccount({\n entropySource,\n derivationPath: `m/44'/501'/${groupIndex}'/0'`,\n });\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const discoveredAccounts = await this.#client.discoverAccounts(\n [SolScope.Mainnet, SolScope.Testnet],\n entropySource,\n groupIndex,\n );\n\n return await Promise.all(\n discoveredAccounts.map(\n async ({ derivationPath }) =>\n await this.#createAccount({ entropySource, derivationPath }),\n ),\n );\n }\n\n #getAccounts(): SolInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== SolAccountType.DataAccount ||\n account.metadata.keyring.type !== (KeyringTypes.snap as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found a Solana account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found a Solana account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as SolInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
1
|
+
{"version":3,"file":"SolAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapKeyring } from '@metamask/eth-snap-keyring';\nimport {\n SolAccountType,\n SolScope,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringMetadata,\n KeyringSelector,\n} from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { MultichainAccountControllerMessenger } from '../types';\n\ntype SolInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nconst SOLANA_SNAP_ID = 'npm:@metamask/solana-wallet-snap' as SnapId;\nexport class SolAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n\n readonly #client: KeyringClient;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n\n // TODO: Change this once we introduce 1 Snap keyring per Snaps.\n this.#client = this.#getKeyringClientFromSnapId(SOLANA_SNAP_ID);\n }\n\n async #withKeyring<SelectedKeyring, CallbackResult = void>(\n selector: KeyringSelector,\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SelectedKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n const result = await this.#messenger.call(\n 'KeyringController:withKeyring',\n selector,\n ({ keyring, metadata }) =>\n operation({\n keyring: keyring as SelectedKeyring,\n metadata,\n }),\n );\n\n return result as CallbackResult;\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) => {\n const response = await this.#messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Promise<Json>;\n },\n });\n }\n\n async #createAccount(opts: {\n entropySource: EntropySourceId;\n derivationPath: `m/${string}`;\n }) {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyring` but\n // we have to use the `SnapKeyring` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const createAccount = await this.#withKeyring<\n SnapKeyring,\n SnapKeyring['createAccount']\n >({ type: KeyringTypes.snap }, async ({ keyring }) =>\n keyring.createAccount.bind(keyring),\n );\n\n const keyringAccount = await createAccount(SOLANA_SNAP_ID, opts, {\n displayAccountNameSuggestion: false,\n displayConfirmation: false,\n });\n\n // FIXME: This part of the flow is truly async, so when the `KeyringClient`\n // returns the `KeyringAccount`, its `InternalAccount` won't be \"ready\"\n // right away. For now we just re-create a fake `InternalAccount` and\n // we might have to rely solely on `account.id`.\n\n // Actually get the associated `InternalAccount`.\n // const account = this.#messenger.call(\n // 'AccountsController:getAccount',\n // keyringAccount.id,\n // );\n\n const account: InternalAccount = {\n ...keyringAccount,\n metadata: {\n name: `Solana account -- ${keyringAccount.options.index}`,\n importTime: 0,\n keyring: {\n type: KeyringTypes.snap,\n },\n },\n };\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return account;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const account = await this.#createAccount({\n entropySource,\n derivationPath: `m/44'/501'/${groupIndex}'/0'`,\n });\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const discoveredAccounts = await this.#client.discoverAccounts(\n [SolScope.Mainnet, SolScope.Testnet],\n entropySource,\n groupIndex,\n );\n\n return await Promise.all(\n discoveredAccounts.map(\n async ({ derivationPath }) =>\n await this.#createAccount({ entropySource, derivationPath }),\n ),\n );\n }\n\n #getAccounts(): SolInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== SolAccountType.DataAccount ||\n account.metadata.keyring.type !== (KeyringTypes.snap as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found a Solana account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found a Solana account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as SolInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SolAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"SolAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,eAAe,EACrB,8BAA8B;AAM/B,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAGxE,OAAO,KAAK,EAAE,IAAI,EAAkB,wBAAwB;AAE5D,OAAO,KAAK,EAAE,oCAAoC,EAAE,qBAAiB;AAmBrE,qBAAa,kBAAmB,YAAW,eAAe;;gBAK5C,SAAS,EAAE,oCAAoC;IAiGrD,cAAc,CAAC,EACnB,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IASK,yBAAyB,CAAC,EAC9B,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IA+CD,WAAW,CAAC,EACV,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,eAAe,EAAE;IASrB,iBAAiB,IAAI,eAAe,EAAE;CASvC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SolAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"SolAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,eAAe,EACrB,8BAA8B;AAM/B,OAAO,KAAK,EAEV,eAAe,EAChB,uCAAuC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAGxE,OAAO,KAAK,EAAE,IAAI,EAAkB,wBAAwB;AAE5D,OAAO,KAAK,EAAE,oCAAoC,EAAE,qBAAiB;AAmBrE,qBAAa,kBAAmB,YAAW,eAAe;;gBAK5C,SAAS,EAAE,oCAAoC;IAiGrD,cAAc,CAAC,EACnB,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IASK,yBAAyB,CAAC,EAC9B,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;;;;;;;;;;;;IA+CD,WAAW,CAAC,EACV,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,eAAe,EAAE;IASrB,iBAAiB,IAAI,eAAe,EAAE;CASvC"}
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
9
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
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
11
|
};
|
12
|
-
var _SolAccountProvider_instances, _SolAccountProvider_messenger, _SolAccountProvider_client, _SolAccountProvider_getKeyringClientFromSnapId, _SolAccountProvider_createAccount, _SolAccountProvider_getAccounts;
|
12
|
+
var _SolAccountProvider_instances, _SolAccountProvider_messenger, _SolAccountProvider_client, _SolAccountProvider_withKeyring, _SolAccountProvider_getKeyringClientFromSnapId, _SolAccountProvider_createAccount, _SolAccountProvider_getAccounts;
|
13
13
|
import { SolAccountType, SolScope } from "@metamask/keyring-api";
|
14
14
|
import { KeyringTypes } from "@metamask/keyring-controller";
|
15
15
|
import { KeyringClient } from "@metamask/keyring-snap-client";
|
@@ -20,14 +20,15 @@ function assertInternalAccountExists(account) {
|
|
20
20
|
throw new Error('Internal account does not exist');
|
21
21
|
}
|
22
22
|
}
|
23
|
+
const SOLANA_SNAP_ID = 'npm:@metamask/solana-wallet-snap';
|
23
24
|
export class SolAccountProvider {
|
24
25
|
constructor(messenger) {
|
25
26
|
_SolAccountProvider_instances.add(this);
|
26
27
|
_SolAccountProvider_messenger.set(this, void 0);
|
27
28
|
_SolAccountProvider_client.set(this, void 0);
|
28
29
|
__classPrivateFieldSet(this, _SolAccountProvider_messenger, messenger, "f");
|
29
|
-
// TODO: Change this once we introduce 1 Snap keyring per Snaps
|
30
|
-
__classPrivateFieldSet(this, _SolAccountProvider_client, __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_getKeyringClientFromSnapId).call(this,
|
30
|
+
// TODO: Change this once we introduce 1 Snap keyring per Snaps.
|
31
|
+
__classPrivateFieldSet(this, _SolAccountProvider_client, __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_getKeyringClientFromSnapId).call(this, SOLANA_SNAP_ID), "f");
|
31
32
|
}
|
32
33
|
async createAccounts({ entropySource, groupIndex, }) {
|
33
34
|
const account = await __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_createAccount).call(this, {
|
@@ -54,7 +55,13 @@ export class SolAccountProvider {
|
|
54
55
|
return Array.from(entropySources);
|
55
56
|
}
|
56
57
|
}
|
57
|
-
_SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new WeakMap(), _SolAccountProvider_instances = new WeakSet(),
|
58
|
+
_SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new WeakMap(), _SolAccountProvider_instances = new WeakSet(), _SolAccountProvider_withKeyring = async function _SolAccountProvider_withKeyring(selector, operation) {
|
59
|
+
const result = await __classPrivateFieldGet(this, _SolAccountProvider_messenger, "f").call('KeyringController:withKeyring', selector, ({ keyring, metadata }) => operation({
|
60
|
+
keyring: keyring,
|
61
|
+
metadata,
|
62
|
+
}));
|
63
|
+
return result;
|
64
|
+
}, _SolAccountProvider_getKeyringClientFromSnapId = function _SolAccountProvider_getKeyringClientFromSnapId(snapId) {
|
58
65
|
return new KeyringClient({
|
59
66
|
send: async (request) => {
|
60
67
|
const response = await __classPrivateFieldGet(this, _SolAccountProvider_messenger, "f").call('SnapController:handleRequest', {
|
@@ -67,9 +74,36 @@ _SolAccountProvider_messenger = new WeakMap(), _SolAccountProvider_client = new
|
|
67
74
|
},
|
68
75
|
});
|
69
76
|
}, _SolAccountProvider_createAccount = async function _SolAccountProvider_createAccount(opts) {
|
70
|
-
|
77
|
+
// NOTE: We're not supposed to make the keyring instance escape `withKeyring` but
|
78
|
+
// we have to use the `SnapKeyring` instance to be able to create Solana account
|
79
|
+
// without triggering UI confirmation.
|
80
|
+
// Also, creating account that way won't invalidate the snap keyring state. The
|
81
|
+
// account will get created and persisted properly with the Snap account creation
|
82
|
+
// flow "asynchronously" (with `notify:accountCreated`).
|
83
|
+
const createAccount = await __classPrivateFieldGet(this, _SolAccountProvider_instances, "m", _SolAccountProvider_withKeyring).call(this, { type: KeyringTypes.snap }, async ({ keyring }) => keyring.createAccount.bind(keyring));
|
84
|
+
const keyringAccount = await createAccount(SOLANA_SNAP_ID, opts, {
|
85
|
+
displayAccountNameSuggestion: false,
|
86
|
+
displayConfirmation: false,
|
87
|
+
});
|
88
|
+
// FIXME: This part of the flow is truly async, so when the `KeyringClient`
|
89
|
+
// returns the `KeyringAccount`, its `InternalAccount` won't be "ready"
|
90
|
+
// right away. For now we just re-create a fake `InternalAccount` and
|
91
|
+
// we might have to rely solely on `account.id`.
|
71
92
|
// Actually get the associated `InternalAccount`.
|
72
|
-
const account =
|
93
|
+
// const account = this.#messenger.call(
|
94
|
+
// 'AccountsController:getAccount',
|
95
|
+
// keyringAccount.id,
|
96
|
+
// );
|
97
|
+
const account = {
|
98
|
+
...keyringAccount,
|
99
|
+
metadata: {
|
100
|
+
name: `Solana account -- ${keyringAccount.options.index}`,
|
101
|
+
importTime: 0,
|
102
|
+
keyring: {
|
103
|
+
type: KeyringTypes.snap,
|
104
|
+
},
|
105
|
+
},
|
106
|
+
};
|
73
107
|
// We MUST have the associated internal account.
|
74
108
|
assertInternalAccountExists(account);
|
75
109
|
return account;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SolAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SolAccountType,\n SolScope,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MultichainAccountControllerMessenger } from '../types';\n\ntype SolInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport class SolAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n \n readonly #client: KeyringClient;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n\n // TODO: Change this once we introduce 1 Snap keyring per Snaps\n this.#client = this.#getKeyringClientFromSnapId(\n 'npm:@metamask/solana-wallet-snap',\n );\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) => {\n const response = await this.#messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Promise<Json>;\n },\n });\n }\n\n async #createAccount(opts: {\n entropySource: EntropySourceId;\n derivationPath: `m/${string}`;\n }) {\n const keyringAccount = await this.#client.createAccount(opts);\n\n // Actually get the associated `InternalAccount`.\n const account = this.#messenger.call(\n 'AccountsController:getAccount',\n keyringAccount.id,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return account;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const account = await this.#createAccount({\n entropySource,\n derivationPath: `m/44'/501'/${groupIndex}'/0'`,\n });\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const discoveredAccounts = await this.#client.discoverAccounts(\n [SolScope.Mainnet, SolScope.Testnet],\n entropySource,\n groupIndex,\n );\n\n return await Promise.all(\n discoveredAccounts.map(\n async ({ derivationPath }) =>\n await this.#createAccount({ entropySource, derivationPath }),\n ),\n );\n }\n\n #getAccounts(): SolInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== SolAccountType.DataAccount ||\n account.metadata.keyring.type !== (KeyringTypes.snap as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found a Solana account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found a Solana account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as SolInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
1
|
+
{"version":3,"file":"SolAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/SolAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapKeyring } from '@metamask/eth-snap-keyring';\nimport {\n SolAccountType,\n SolScope,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringMetadata,\n KeyringSelector,\n} from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { AccountProvider } from '@metamask/multichain-account-api';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { MultichainAccountControllerMessenger } from '../types';\n\ntype SolInternalAccount = InternalAccount & {\n options: {\n index: number;\n entropySource: EntropySourceId;\n };\n};\n\n// eslint-disable-next-line jsdoc/require-jsdoc\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nconst SOLANA_SNAP_ID = 'npm:@metamask/solana-wallet-snap' as SnapId;\nexport class SolAccountProvider implements AccountProvider {\n readonly #messenger: MultichainAccountControllerMessenger;\n\n readonly #client: KeyringClient;\n\n constructor(messenger: MultichainAccountControllerMessenger) {\n this.#messenger = messenger;\n\n // TODO: Change this once we introduce 1 Snap keyring per Snaps.\n this.#client = this.#getKeyringClientFromSnapId(SOLANA_SNAP_ID);\n }\n\n async #withKeyring<SelectedKeyring, CallbackResult = void>(\n selector: KeyringSelector,\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SelectedKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n const result = await this.#messenger.call(\n 'KeyringController:withKeyring',\n selector,\n ({ keyring, metadata }) =>\n operation({\n keyring: keyring as SelectedKeyring,\n metadata,\n }),\n );\n\n return result as CallbackResult;\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) => {\n const response = await this.#messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Promise<Json>;\n },\n });\n }\n\n async #createAccount(opts: {\n entropySource: EntropySourceId;\n derivationPath: `m/${string}`;\n }) {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyring` but\n // we have to use the `SnapKeyring` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const createAccount = await this.#withKeyring<\n SnapKeyring,\n SnapKeyring['createAccount']\n >({ type: KeyringTypes.snap }, async ({ keyring }) =>\n keyring.createAccount.bind(keyring),\n );\n\n const keyringAccount = await createAccount(SOLANA_SNAP_ID, opts, {\n displayAccountNameSuggestion: false,\n displayConfirmation: false,\n });\n\n // FIXME: This part of the flow is truly async, so when the `KeyringClient`\n // returns the `KeyringAccount`, its `InternalAccount` won't be \"ready\"\n // right away. For now we just re-create a fake `InternalAccount` and\n // we might have to rely solely on `account.id`.\n\n // Actually get the associated `InternalAccount`.\n // const account = this.#messenger.call(\n // 'AccountsController:getAccount',\n // keyringAccount.id,\n // );\n\n const account: InternalAccount = {\n ...keyringAccount,\n metadata: {\n name: `Solana account -- ${keyringAccount.options.index}`,\n importTime: 0,\n keyring: {\n type: KeyringTypes.snap,\n },\n },\n };\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n return account;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const account = await this.#createAccount({\n entropySource,\n derivationPath: `m/44'/501'/${groupIndex}'/0'`,\n });\n\n return [account];\n }\n\n async discoverAndCreateAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }) {\n const discoveredAccounts = await this.#client.discoverAccounts(\n [SolScope.Mainnet, SolScope.Testnet],\n entropySource,\n groupIndex,\n );\n\n return await Promise.all(\n discoveredAccounts.map(\n async ({ derivationPath }) =>\n await this.#createAccount({ entropySource, derivationPath }),\n ),\n );\n }\n\n #getAccounts(): SolInternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts')\n .filter((account) => {\n // We only check for EOA accounts for multichain accounts.\n if (\n account.type !== SolAccountType.DataAccount ||\n account.metadata.keyring.type !== (KeyringTypes.snap as string)\n ) {\n return false;\n }\n\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found a Solana account with no entropy source: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n // TODO: We need to add this index for native accounts too!\n if (account.options.index === undefined) {\n console.warn(\n \"! Found a Solana account with no index: account won't be associated to its wallet.\",\n );\n return false;\n }\n\n return true;\n }) as SolInternalAccount[]; // Safe, we did check for options fields during filtering.\n }\n\n getAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): InternalAccount[] {\n return this.#getAccounts().filter((account) => {\n return (\n account.options.entropySource === entropySource &&\n account.options.index === groupIndex\n );\n });\n }\n\n getEntropySources(): EntropySourceId[] {\n const entropySources = new Set<EntropySourceId>();\n\n for (const account of this.#getAccounts()) {\n entropySources.add(account.options.entropySource);\n }\n\n return Array.from(entropySources);\n }\n}\n"]}
|
@@ -0,0 +1,170 @@
|
|
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 _MockAccountBuilder_account;
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
exports.MockAccountBuilder = exports.MOCK_HARDWARE_ACCOUNT_1 = exports.MOCK_SNAP_ACCOUNT_2 = exports.MOCK_SNAP_ACCOUNT_1 = exports.MOCK_HD_ACCOUNT_2 = exports.MOCK_HD_ACCOUNT_1 = exports.MOCK_HD_KEYRING_2 = exports.MOCK_HD_KEYRING_1 = exports.MOCK_ENTROPY_SOURCE_2 = exports.MOCK_ENTROPY_SOURCE_1 = exports.MOCK_SNAP_2 = exports.MOCK_SNAP_1 = void 0;
|
16
|
+
const keyring_api_1 = require("@metamask/keyring-api");
|
17
|
+
const keyring_controller_1 = require("@metamask/keyring-controller");
|
18
|
+
const uuid_1 = require("uuid");
|
19
|
+
const ETH_EOA_METHODS = [
|
20
|
+
keyring_api_1.EthMethod.PersonalSign,
|
21
|
+
keyring_api_1.EthMethod.Sign,
|
22
|
+
keyring_api_1.EthMethod.SignTransaction,
|
23
|
+
keyring_api_1.EthMethod.SignTypedDataV1,
|
24
|
+
keyring_api_1.EthMethod.SignTypedDataV3,
|
25
|
+
keyring_api_1.EthMethod.SignTypedDataV4,
|
26
|
+
];
|
27
|
+
const SOL_METHODS = Object.values(keyring_api_1.SolMethod);
|
28
|
+
exports.MOCK_SNAP_1 = {
|
29
|
+
id: 'local:mock-snap-id-1',
|
30
|
+
name: 'Mock Snap 1',
|
31
|
+
enabled: true,
|
32
|
+
manifest: {
|
33
|
+
proposedName: 'Mock Snap 1',
|
34
|
+
},
|
35
|
+
};
|
36
|
+
exports.MOCK_SNAP_2 = {
|
37
|
+
id: 'local:mock-snap-id-2',
|
38
|
+
name: 'Mock Snap 2',
|
39
|
+
enabled: true,
|
40
|
+
manifest: {
|
41
|
+
proposedName: 'Mock Snap 2',
|
42
|
+
},
|
43
|
+
};
|
44
|
+
exports.MOCK_ENTROPY_SOURCE_1 = 'mock-keyring-id-1';
|
45
|
+
exports.MOCK_ENTROPY_SOURCE_2 = 'mock-keyring-id-2';
|
46
|
+
exports.MOCK_HD_KEYRING_1 = {
|
47
|
+
type: keyring_controller_1.KeyringTypes.hd,
|
48
|
+
metadata: { id: exports.MOCK_ENTROPY_SOURCE_1, name: 'HD Keyring 1' },
|
49
|
+
accounts: ['0x123'],
|
50
|
+
};
|
51
|
+
exports.MOCK_HD_KEYRING_2 = {
|
52
|
+
type: keyring_controller_1.KeyringTypes.hd,
|
53
|
+
metadata: { id: exports.MOCK_ENTROPY_SOURCE_2, name: 'HD Keyring 2' },
|
54
|
+
accounts: ['0x456'],
|
55
|
+
};
|
56
|
+
exports.MOCK_HD_ACCOUNT_1 = {
|
57
|
+
id: 'mock-id-1',
|
58
|
+
address: '0x123',
|
59
|
+
options: {
|
60
|
+
entropySource: exports.MOCK_HD_KEYRING_1.metadata.id,
|
61
|
+
index: 0,
|
62
|
+
},
|
63
|
+
methods: [...ETH_EOA_METHODS],
|
64
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
65
|
+
scopes: [keyring_api_1.EthScope.Eoa],
|
66
|
+
metadata: {
|
67
|
+
name: 'Account 1',
|
68
|
+
keyring: { type: keyring_controller_1.KeyringTypes.hd },
|
69
|
+
importTime: 0,
|
70
|
+
lastSelected: 0,
|
71
|
+
nameLastUpdatedAt: 0,
|
72
|
+
},
|
73
|
+
};
|
74
|
+
exports.MOCK_HD_ACCOUNT_2 = {
|
75
|
+
id: 'mock-id-2',
|
76
|
+
address: '0x456',
|
77
|
+
options: {
|
78
|
+
entropySource: exports.MOCK_HD_KEYRING_2.metadata.id,
|
79
|
+
index: 0,
|
80
|
+
},
|
81
|
+
methods: [...ETH_EOA_METHODS],
|
82
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
83
|
+
scopes: [keyring_api_1.EthScope.Eoa],
|
84
|
+
metadata: {
|
85
|
+
name: 'Account 2',
|
86
|
+
keyring: { type: keyring_controller_1.KeyringTypes.hd },
|
87
|
+
importTime: 0,
|
88
|
+
lastSelected: 0,
|
89
|
+
nameLastUpdatedAt: 0,
|
90
|
+
},
|
91
|
+
};
|
92
|
+
exports.MOCK_SNAP_ACCOUNT_1 = {
|
93
|
+
id: 'mock-snap-id-1',
|
94
|
+
address: 'aabbccdd',
|
95
|
+
options: {
|
96
|
+
entropySource: exports.MOCK_HD_KEYRING_2.metadata.id,
|
97
|
+
index: 0,
|
98
|
+
},
|
99
|
+
methods: SOL_METHODS,
|
100
|
+
type: keyring_api_1.SolAccountType.DataAccount,
|
101
|
+
scopes: [keyring_api_1.SolScope.Mainnet],
|
102
|
+
metadata: {
|
103
|
+
name: 'Snap Account 1',
|
104
|
+
keyring: { type: keyring_controller_1.KeyringTypes.snap },
|
105
|
+
snap: exports.MOCK_SNAP_1,
|
106
|
+
importTime: 0,
|
107
|
+
lastSelected: 0,
|
108
|
+
},
|
109
|
+
};
|
110
|
+
exports.MOCK_SNAP_ACCOUNT_2 = {
|
111
|
+
id: 'mock-snap-id-2',
|
112
|
+
address: '0x789',
|
113
|
+
options: {},
|
114
|
+
methods: [...ETH_EOA_METHODS],
|
115
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
116
|
+
scopes: [keyring_api_1.EthScope.Eoa],
|
117
|
+
metadata: {
|
118
|
+
name: 'Snap Acc 2',
|
119
|
+
keyring: { type: keyring_controller_1.KeyringTypes.snap },
|
120
|
+
snap: exports.MOCK_SNAP_2,
|
121
|
+
importTime: 0,
|
122
|
+
lastSelected: 0,
|
123
|
+
},
|
124
|
+
};
|
125
|
+
exports.MOCK_HARDWARE_ACCOUNT_1 = {
|
126
|
+
id: 'mock-hardware-id-1',
|
127
|
+
address: '0xABC',
|
128
|
+
options: {},
|
129
|
+
methods: [...ETH_EOA_METHODS],
|
130
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
131
|
+
scopes: [keyring_api_1.EthScope.Eoa],
|
132
|
+
metadata: {
|
133
|
+
name: 'Hardware Acc 1',
|
134
|
+
keyring: { type: keyring_controller_1.KeyringTypes.ledger },
|
135
|
+
importTime: 0,
|
136
|
+
lastSelected: 0,
|
137
|
+
},
|
138
|
+
};
|
139
|
+
class MockAccountBuilder {
|
140
|
+
constructor(account) {
|
141
|
+
_MockAccountBuilder_account.set(this, void 0);
|
142
|
+
// Make a deep-copy to avoid mutating the same ref.
|
143
|
+
__classPrivateFieldSet(this, _MockAccountBuilder_account, JSON.parse(JSON.stringify(account)), "f");
|
144
|
+
}
|
145
|
+
static from(account) {
|
146
|
+
return new MockAccountBuilder(account);
|
147
|
+
}
|
148
|
+
static toKeyringAccount(account) {
|
149
|
+
const { metadata, ...keyringAccount } = account;
|
150
|
+
return keyringAccount;
|
151
|
+
}
|
152
|
+
withUuuid() {
|
153
|
+
__classPrivateFieldGet(this, _MockAccountBuilder_account, "f").id = (0, uuid_1.v4)();
|
154
|
+
return this;
|
155
|
+
}
|
156
|
+
withEntropySource(entropySource) {
|
157
|
+
__classPrivateFieldGet(this, _MockAccountBuilder_account, "f").options.entropySource = entropySource;
|
158
|
+
return this;
|
159
|
+
}
|
160
|
+
withGroupIndex(groupIndex) {
|
161
|
+
__classPrivateFieldGet(this, _MockAccountBuilder_account, "f").options.index = groupIndex;
|
162
|
+
return this;
|
163
|
+
}
|
164
|
+
get() {
|
165
|
+
return __classPrivateFieldGet(this, _MockAccountBuilder_account, "f");
|
166
|
+
}
|
167
|
+
}
|
168
|
+
exports.MockAccountBuilder = MockAccountBuilder;
|
169
|
+
_MockAccountBuilder_account = new WeakMap();
|
170
|
+
//# sourceMappingURL=accounts.cjs.map
|