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
84 changes: 74 additions & 10 deletions app/scripts/lib/snap-keyring/metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ describe('getSnapAndHardwareInfoForMetrics', () => {
});

describe('when the wallet is unlocked', () => {
it('resolves keyring and device info for a HD account', async () => {
it('resolves keyring info for a HD account', async () => {
getAccountType.mockResolvedValue('accountType');
getDeviceModel.mockResolvedValue('deviceModel');
getHardwareTypeForMetric.mockResolvedValue('hardwareType');
messenger.call
.mockReturnValueOnce({
address: '0x123',
Expand Down Expand Up @@ -69,7 +68,6 @@ describe('getSnapAndHardwareInfoForMetrics', () => {

expect(getAccountType).toHaveBeenCalledWith('0x123');
expect(getDeviceModel).toHaveBeenCalledWith('0x123');
expect(getHardwareTypeForMetric).toHaveBeenCalledWith('0x123');
expect(messenger.call).toHaveBeenNthCalledWith(
1,
'AccountsController:getSelectedAccount',
Expand All @@ -87,20 +85,16 @@ describe('getSnapAndHardwareInfoForMetrics', () => {
device_model: 'deviceModel',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_hardware_type: 'hardwareType',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_snap_type: undefined,
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_snap_version: undefined,
});
});

it('resolves keyring, device, and snap info for a snap account', async () => {
it('resolves keyring and snap info for a snap account', async () => {
getAccountType.mockResolvedValue('accountType');
getDeviceModel.mockResolvedValue('deviceModel');
getHardwareTypeForMetric.mockResolvedValue('hardwareType');
messenger.call
.mockReturnValueOnce({
address: '0x123',
Expand Down Expand Up @@ -138,7 +132,6 @@ describe('getSnapAndHardwareInfoForMetrics', () => {

expect(getAccountType).toHaveBeenCalledWith('0x123');
expect(getDeviceModel).toHaveBeenCalledWith('0x123');
expect(getHardwareTypeForMetric).toHaveBeenCalledWith('0x123');
expect(messenger.call).toHaveBeenNthCalledWith(
1,
'AccountsController:getSelectedAccount',
Expand All @@ -161,13 +154,84 @@ describe('getSnapAndHardwareInfoForMetrics', () => {
device_model: 'deviceModel',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_hardware_type: 'hardwareType',
account_snap_type: 'snapId',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_snap_version: 'snapVersion',
});
});

it('resolves device and account type info for a hardware wallet account', async () => {
getAccountType.mockResolvedValue('accountType');
getDeviceModel.mockResolvedValue('deviceModel');
getHardwareTypeForMetric.mockResolvedValue('hardwareType');
messenger.call
.mockReturnValueOnce({
address: '0x123',
id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3',
metadata: {
name: 'Account 1',
keyring: {
type: 'Snap Keyring',
},
snap: {
id: 'snapId',
name: 'mock-name',
enabled: true,
},
},
options: {},
methods: [
'personal_sign',
'eth_signTransaction',
'eth_signTypedData_v1',
'eth_signTypedData_v3',
'eth_signTypedData_v4',
],
type: 'eip155:eoa',
})
.mockReturnValueOnce({ id: 'snapId', version: 'snapVersion' })
.mockReturnValueOnce({ isUnlocked: true });

const result = await getSnapAndHardwareInfoForMetrics(
getAccountType,
getDeviceModel,
getHardwareTypeForMetric,
messenger,
);

expect(getAccountType).toHaveBeenCalledWith('0x123');
expect(getDeviceModel).toHaveBeenCalledWith('0x123');
expect(getHardwareTypeForMetric).toHaveBeenCalledWith('0x123');
expect(messenger.call).toHaveBeenNthCalledWith(
1,
'AccountsController:getSelectedAccount',
);
expect(messenger.call).toHaveBeenNthCalledWith(
2,
'SnapController:get',
'snapId',
);
expect(messenger.call).toHaveBeenNthCalledWith(
3,
'KeyringController:getState',
);
expect(result).toEqual({
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_type: 'accountType',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
device_model: 'deviceModel',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_snap_type: 'snapId',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_snap_version: 'snapVersion',
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_hardware_type: 'hardwareType',
});
});
});
Expand Down
14 changes: 11 additions & 3 deletions app/scripts/lib/snap-keyring/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,18 @@ export async function getSnapAndHardwareInfoForMetrics(
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
device_model: await getDeviceModel(selectedAddress),
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_hardware_type: await getHardwareTypeForMetric(selectedAddress),
};

const hardwareType = await getHardwareTypeForMetric(selectedAddress);

if (hardwareType) {
keyringAccountInfo = {
...keyringAccountInfo,
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
// eslint-disable-next-line @typescript-eslint/naming-convention
account_hardware_type: hardwareType,
};
}
}

return {
Expand Down
6 changes: 3 additions & 3 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ import {

import {
HardwareDeviceNames,
HardwareKeyringType,
LedgerTransportTypes,
KEYRING_DEVICE_PROPERTY_MAP,
} from '../../shared/constants/hardware-wallets';
import { KeyringType } from '../../shared/constants/keyring';
import { RestrictedMethods } from '../../shared/constants/permissions';
Expand Down Expand Up @@ -5448,7 +5448,7 @@ export default class MetamaskController extends EventEmitter {
async getHardwareTypeForMetric(address) {
return await this.keyringController.withKeyring(
{ address },
({ keyring }) => HardwareKeyringType[keyring.type],
({ keyring }) => KEYRING_DEVICE_PROPERTY_MAP[keyring.type],
);
}

Expand Down Expand Up @@ -5486,7 +5486,7 @@ export default class MetamaskController extends EventEmitter {
case KeyringType.lattice:
case KeyringType.qr:
case KeyringType.ledger:
return 'hardware';
return KEYRING_DEVICE_PROPERTY_MAP[keyringType];
Copy link

Choose a reason for hiding this comment

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

Bug: Map key mismatch causes undefined return for hardware wallets

The getAccountType function uses KEYRING_DEVICE_PROPERTY_MAP[keyringType] to look up the hardware wallet display name. However, KEYRING_DEVICE_PROPERTY_MAP is keyed by KeyringTypes.xxx values from @metamask/keyring-controller, while keyringType comes from the switch case which matches against KeyringType.xxx values (like 'Ledger Hardware'). If these values differ (e.g., KeyringTypes.ledger = 'ledger' vs KeyringType.ledger = 'Ledger Hardware'), the map lookup will return undefined instead of the expected display name like 'Ledger'. The PR discussion mentions missing account_hardware_type properties, which aligns with this lookup returning falsy values.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's ok, the keyringType should always be valid, so as long as KEYRING_DEVICE_PROPERTY_MAP uses KeyringTypes (and is exhaustive and complete) that should be fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: But the jsdoc is now wrong, since we're not returning 'hardware' anymore!

case KeyringType.imported:
return 'imported';
case KeyringType.snap:
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/metamask-controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import { KeyringTypes } from '@metamask/keyring-controller';
import { createTestProviderTools } from '../../test/stub/provider';
import {
HardwareDeviceNames,
HardwareKeyringType,
KEYRING_DEVICE_PROPERTY_MAP,
} from '../../shared/constants/hardware-wallets';
import { KeyringType } from '../../shared/constants/keyring';
import { LOG_EVENT } from '../../shared/constants/logs';
Expand Down Expand Up @@ -1630,7 +1630,7 @@ describe('MetaMaskController', () => {
const result =
await metamaskController.getHardwareTypeForMetric('0x123');

expect(result).toBe(HardwareKeyringType[type]);
expect(result).toBe(KEYRING_DEVICE_PROPERTY_MAP[type]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: We could have used Object.keys(KEYRING_DEVICE_PROPERTY_MAP) for this test (in it.each, instead of enumerating each hardware keyring types now that we have a proper mapping for it!

},
);
});
Expand Down
8 changes: 8 additions & 0 deletions shared/constants/hardware-wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ export const DEVICE_KEYRING_MAP = {
[HardwareDeviceNames.qr]: KeyringTypes.qr,
};

export const KEYRING_DEVICE_PROPERTY_MAP = {
Copy link
Contributor

Choose a reason for hiding this comment

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

I see a lot of duplication in here. It might be too complex to refactor now but maybe something we can aim to do later on.

[KeyringTypes.ledger]: 'Ledger',
[KeyringTypes.trezor]: 'Trezor',
[KeyringTypes.oneKey]: 'OneKey',
[KeyringTypes.lattice]: 'Lattice',
[KeyringTypes.qr]: 'QR Hardware',
};

export const U2F_ERROR = 'U2F';

export const LEDGER_ERRORS_CODES = {
Expand Down
Loading