Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import {
UpdateRequestState,
} from '@metamask/approval-controller';
import {
KeyringControllerGetKeyringsByTypeAction,
KeyringControllerLockEvent,
KeyringControllerUnlockEvent,
KeyringControllerWithKeyringAction,
} from '@metamask/keyring-controller';
import { SelectedNetworkControllerGetNetworkClientIdForDomainAction } from '@metamask/selected-network-controller';
import { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller';
Expand Down Expand Up @@ -166,7 +166,7 @@ export function getSnapControllerMessenger(
}

type InitActions =
| KeyringControllerGetKeyringsByTypeAction
| KeyringControllerWithKeyringAction
| PreferencesControllerGetStateAction
| MetaMetricsControllerTrackEventAction
| SetClientActive
Expand Down Expand Up @@ -203,7 +203,7 @@ export function getSnapControllerInitMessenger(
messenger.delegate({
messenger: controllerInitMessenger,
actions: [
'KeyringController:getKeyringsByType',
'KeyringController:withKeyring',
'PreferencesController:getState',
'MetaMetricsController:trackEvent',
'SnapController:setClientActive',
Expand Down
23 changes: 3 additions & 20 deletions app/scripts/controller-init/snaps/snap-controller-init.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { SnapController } from '@metamask/snaps-controllers';
import { createDeferredPromise, hasProperty, Json } from '@metamask/utils';
import { createDeferredPromise, Json } from '@metamask/utils';
import { ControllerInitFunction } from '../types';
import {
EndowmentPermissions,
ExcludedSnapEndowments,
ExcludedSnapPermissions,
} from '../../../../shared/constants/snaps/permissions';
import { encryptorFactory } from '../../lib/encryptor-factory';
import { KeyringType } from '../../../../shared/constants/keyring';
import {
SnapControllerInitMessenger,
SnapControllerMessenger,
} from '../messengers/snaps';
import { getBooleanFlag } from '../../lib/util';
import { OnboardingControllerState } from '../../controllers/onboarding';
import { getMnemonicSeed } from '../../controllers/permissions/snaps/utils';

// Copied from `@metamask/snaps-controllers`, since it is not exported.
type TrackingEventPayload = {
Expand Down Expand Up @@ -61,23 +61,6 @@ export const SnapControllerInit: ControllerInitFunction<
);
///: END:ONLY_INCLUDE_IF

async function getMnemonicSeed() {
const keyrings = initMessenger.call(
'KeyringController:getKeyringsByType',
KeyringType.hdKeyTree,
);

if (
!keyrings[0] ||
!hasProperty(keyrings[0], 'seed') ||
!(keyrings[0].seed instanceof Uint8Array)
) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return keyrings[0].seed;
}

/**
* Get the feature flags for the `SnapController.
*
Expand Down Expand Up @@ -150,7 +133,7 @@ export const SnapControllerInit: ControllerInitFunction<
// TODO: Look into the type mismatch.
encryptor: encryptorFactory(600_000),

getMnemonicSeed,
getMnemonicSeed: getMnemonicSeed.bind(null, initMessenger, undefined),
Comment thread
cursor[bot] marked this conversation as resolved.

preinstalledSnaps,
getFeatureFlags,
Expand Down
97 changes: 3 additions & 94 deletions app/scripts/controllers/permissions/snaps/specifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
KeyringTypes,
KeyringMetadata,
} from '@metamask/keyring-controller';
import { hasProperty } from '@metamask/utils';
import {
RateLimitControllerCallApiAction,
RateLimitedApiMap,
Expand All @@ -33,6 +32,7 @@ import { PreferencesControllerGetStateAction } from '../../preferences-controlle
import { KeyringType } from '../../../../../shared/constants/keyring';
import { AppStateControllerGetUnlockPromiseAction } from '../../app-state-controller';
import { RootMessenger } from '../../../lib/messenger';
import { getMnemonic, getMnemonicSeed } from './utils';

export type SnapPermissionSpecificationsActions =
| AppStateControllerGetUnlockPromiseAction
Expand Down Expand Up @@ -122,99 +122,8 @@ export function getSnapPermissionSpecifications(
'SnapController:clearSnapState',
),

/**
* Get the mnemonic for a given entropy source. If no source is
* provided, the primary HD keyring's mnemonic will be returned.
*
* @param source - The ID of the entropy source keyring.
* @returns The mnemonic.
*/
getMnemonic: async (source: string) => {
if (!source) {
const [keyring] = messenger.call(
'KeyringController:getKeyringsByType',
KeyringType.hdKeyTree,
) as { mnemonic?: string }[];

if (!keyring.mnemonic) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return keyring.mnemonic;
}

try {
const { type, mnemonic } = (await messenger.call(
'KeyringController:withKeyring',
{
id: source,
},
async ({ keyring }) => ({
type: keyring.type,
mnemonic: hasProperty(keyring, 'mnemonic')
? keyring.mnemonic
: undefined,
}),
)) as { type: string; mnemonic?: string };

if (type !== KeyringTypes.hd || !mnemonic) {
// The keyring isn't guaranteed to have a mnemonic (e.g.,
// hardware wallets, which can't be used as entropy sources),
// so we throw an error if it doesn't.
throw new Error(`Entropy source with ID "${source}" not found.`);
}

return mnemonic;
} catch {
throw new Error(`Entropy source with ID "${source}" not found.`);
}
},

/**
* Get the mnemonic seed for a given entropy source. If no source is
* provided, the primary HD keyring's mnemonic seed will be returned.
*
* @param source - The ID of the entropy source keyring.
* @returns The mnemonic seed.
*/
getMnemonicSeed: async (source: string) => {
if (!source) {
const [keyring] = messenger.call(
'KeyringController:getKeyringsByType',
KeyringType.hdKeyTree,
) as { seed?: Uint8Array }[];

if (!keyring.seed) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return keyring.seed;
}

try {
const { type, seed } = (await messenger.call(
'KeyringController:withKeyring',
{
id: source,
},
async ({ keyring }) => ({
type: keyring.type,
seed: hasProperty(keyring, 'seed') ? keyring.seed : undefined,
}),
)) as { type: string; seed?: Uint8Array };

if (type !== KeyringTypes.hd || !seed) {
// The keyring isn't guaranteed to have a mnemonic (e.g.,
// hardware wallets, which can't be used as entropy sources),
// so we throw an error if it doesn't.
throw new Error(`Entropy source with ID "${source}" not found.`);
}

return seed;
} catch {
throw new Error(`Entropy source with ID "${source}" not found.`);
}
},
getMnemonic: getMnemonic.bind(null, messenger),
getMnemonicSeed: getMnemonicSeed.bind(null, messenger),

getUnlockPromise: messenger.call.bind(
messenger,
Expand Down
121 changes: 121 additions & 0 deletions app/scripts/controllers/permissions/snaps/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {
KeyringControllerWithKeyringAction,
KeyringTypes,
} from '@metamask/keyring-controller';
import type { HdKeyring } from '@metamask/eth-hd-keyring';
import { RootMessenger } from '../../../lib/messenger';

/**
* Get the mnemonic for a given entropy source. If no source is
* provided, the primary HD keyring's mnemonic will be returned.
*
* @param messenger - The messenger.
* @param source - The ID of the entropy source keyring.
* @returns The mnemonic.
*/
export async function getMnemonic(
messenger: RootMessenger<KeyringControllerWithKeyringAction, never>,
source?: string | undefined,
): Promise<Uint8Array> {
if (!source) {
const mnemonic = (await messenger.call(
'KeyringController:withKeyring',
{
type: KeyringTypes.hd,
index: 0,
},
async ({ keyring }) => (keyring as HdKeyring).mnemonic,
)) as Uint8Array | null;

if (!mnemonic) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return mnemonic;
}

try {
const keyringData = await messenger.call(
'KeyringController:withKeyring',
{
id: source,
},
async ({ keyring }) => ({
type: keyring.type,
mnemonic: (keyring as HdKeyring).mnemonic,
}),
);

const { type, mnemonic } = keyringData as {
type: string;
mnemonic?: Uint8Array;
};

if (type !== KeyringTypes.hd || !mnemonic) {
// The keyring isn't guaranteed to have a mnemonic (e.g.,
// hardware wallets, which can't be used as entropy sources),
// so we throw an error if it doesn't.
throw new Error(`Entropy source with ID "${source}" not found.`);
}

return mnemonic;
} catch {
throw new Error(`Entropy source with ID "${source}" not found.`);
}
}
Comment thread
FrederikBolding marked this conversation as resolved.

/**
* Get the mnemonic seed for a given entropy source. If no source is
* provided, the primary HD keyring's mnemonic seed will be returned.
*
* @param messenger - The messenger.
* @param source - The ID of the entropy source keyring.
* @returns The mnemonic seed.
*/
export async function getMnemonicSeed(
messenger: RootMessenger<KeyringControllerWithKeyringAction, never>,
source?: string | undefined,
): Promise<Uint8Array> {
if (!source) {
const seed = (await messenger.call(
'KeyringController:withKeyring',
{
type: KeyringTypes.hd,
index: 0,
},
async ({ keyring }) => (keyring as HdKeyring).seed,
)) as Uint8Array | null;

if (!seed) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return seed;
}

try {
const keyringData = await messenger.call(
'KeyringController:withKeyring',
{
id: source,
},
async ({ keyring }) => ({
type: keyring.type,
seed: (keyring as HdKeyring).seed,
}),
);

const { type, seed } = keyringData as { type: string; seed?: Uint8Array };

if (type !== KeyringTypes.hd || !seed) {
// The keyring isn't guaranteed to have a mnemonic (e.g.,
// hardware wallets, which can't be used as entropy sources),
// so we throw an error if it doesn't.
throw new Error(`Entropy source with ID "${source}" not found.`);
}

return seed;
} catch {
throw new Error(`Entropy source with ID "${source}" not found.`);
}
}
35 changes: 0 additions & 35 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5494,41 +5494,6 @@ export default class MetamaskController extends EventEmitter {
await this.keyringController.verifyPassword(password);
}

/**
* @type Identity
* @property {string} name - The account nickname.
* @property {string} address - The account's ethereum address, in lower case.
* receiving funds from our automatic Ropsten faucet.
*/
Comment thread
FrederikBolding marked this conversation as resolved.

/**
* Gets the mnemonic of the user's primary keyring.
*/
getPrimaryKeyringMnemonic() {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code

const [keyring] = this.keyringController.getKeyringsByType(
KeyringType.hdKeyTree,
);
if (!keyring.mnemonic) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return keyring.mnemonic;
}

/**
* Gets the mnemonic seed of the user's primary keyring.
*/
getPrimaryKeyringMnemonicSeed() {
const [keyring] = this.keyringController.getKeyringsByType(
KeyringType.hdKeyTree,
);
if (!keyring.seed) {
throw new Error('Primary keyring mnemonic unavailable.');
}

return keyring.seed;
}

//
// Hardware
//
Expand Down
Loading
Loading