Skip to content

Commit 4e5e84a

Browse files
committed
improve migration
1 parent 80d15a2 commit 4e5e84a

File tree

2 files changed

+76
-31
lines changed

2 files changed

+76
-31
lines changed

app/store/migrations/066.test.ts

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import {
55
EthMethod,
66
} from '@metamask/keyring-api';
77
import { AccountsControllerState } from '@metamask/accounts-controller';
8+
import { captureException } from '@sentry/react-native';
89
import migration from './066';
910

1011
jest.mock('../../util/Logger');
1112
jest.mock('@sentry/react-native', () => ({
1213
captureException: jest.fn(),
1314
}));
1415

16+
const mockedCaptureException = jest.mocked(captureException);
17+
1518
interface StateType {
1619
engine: {
1720
backgroundState: {
@@ -143,25 +146,25 @@ describe('migration #66', () => {
143146
},
144147
};
145148

146-
it('should return state if not valid', () => {
149+
it('returns state if not valid', () => {
147150
const result = migration(MOCK_INVALID_STATE);
148151
expect(result).toEqual(MOCK_INVALID_STATE);
149152
});
150153

151-
it('should return state if empty accounts', () => {
154+
it('returns state if empty accounts', () => {
152155
const result = migration(MOCK_EMPTY_STATE);
153156
expect(result).toEqual(MOCK_EMPTY_STATE);
154157
});
155158

156-
it('should not modify accounts that already have valid scopes', () => {
159+
it('preserves accounts that have valid scopes', () => {
157160
const stateCopy = JSON.parse(
158161
JSON.stringify(MOCK_STATE_WITH_EXISTING_SCOPES),
159162
);
160163
const result = migration(stateCopy) as StateType;
161164
expect(result).toEqual(MOCK_STATE_WITH_EXISTING_SCOPES);
162165
});
163166

164-
it('should add correct scopes for all account types', () => {
167+
it('adds correct scopes for all account types', () => {
165168
const stateCopy = JSON.parse(JSON.stringify(MOCK_STATE_WITH_ACCOUNTS));
166169
const result = migration(stateCopy) as StateType;
167170
const accounts =
@@ -185,7 +188,7 @@ describe('migration #66', () => {
185188
]);
186189
});
187190

188-
it('should handle malformed account objects gracefully', () => {
191+
it('handles malformed account objects gracefully', () => {
189192
const malformedState: StateType = {
190193
engine: {
191194
backgroundState: {
@@ -226,7 +229,7 @@ describe('migration #66', () => {
226229
expect(accounts['valid-1']?.scopes).toEqual([EthScopes.Namespace]);
227230
});
228231

229-
it('should handle invalid scopes property gracefully', () => {
232+
it('handles invalid scopes property gracefully', () => {
230233
const stateWithInvalidScopes: StateType = {
231234
engine: {
232235
backgroundState: {
@@ -304,4 +307,49 @@ describe('migration #66', () => {
304307
expect(accounts['invalid-2']?.scopes).toEqual([EthScopes.Namespace]);
305308
expect(accounts['invalid-3']?.scopes).toEqual([EthScopes.Namespace]);
306309
});
310+
311+
it('logs unknown account types to Sentry', () => {
312+
const stateWithUnknownType: StateType = {
313+
engine: {
314+
backgroundState: {
315+
AccountsController: {
316+
internalAccounts: {
317+
selectedAccount: 'unknown-1',
318+
accounts: {
319+
'unknown-1': {
320+
id: 'unknown-1',
321+
// @ts-expect-error Testing unknown account type
322+
type: 'unknown-type',
323+
address: '0x123',
324+
options: {},
325+
metadata: {
326+
name: 'Unknown Account',
327+
keyring: { type: 'HD Key Tree' },
328+
importTime: Date.now(),
329+
},
330+
methods: [],
331+
scopes: [],
332+
},
333+
},
334+
},
335+
},
336+
},
337+
},
338+
};
339+
340+
const result = migration(stateWithUnknownType) as StateType;
341+
const accounts =
342+
result.engine.backgroundState.AccountsController.internalAccounts
343+
.accounts;
344+
345+
// Verify scopes are set to default EVM namespace
346+
expect(accounts['unknown-1']?.scopes).toEqual([EthScopes.Namespace]);
347+
348+
// Verify Sentry exception was captured
349+
expect(mockedCaptureException).toHaveBeenCalledWith(
350+
new Error(
351+
'Migration 66: Unknown account type unknown-type, defaulting to EVM namespace',
352+
),
353+
);
354+
});
307355
});

app/store/migrations/066.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@ import { captureException } from '@sentry/react-native';
1313

1414
const migrationVersion = 66;
1515

16+
function getScopesForAccountType(accountType: string): string[] {
17+
switch (accountType) {
18+
case EthAccountType.Eoa:
19+
case EthAccountType.Erc4337:
20+
return [EthScopes.Namespace];
21+
case BtcAccountType.P2wpkh:
22+
// Default to mainnet scope if address is missing or invalid
23+
return [BtcScopes.Mainnet];
24+
case SolAccountType.DataAccount:
25+
return [SolScopes.Mainnet, SolScopes.Testnet, SolScopes.Devnet];
26+
default:
27+
// Default to EVM namespace for unknown account types
28+
captureException(
29+
new Error(
30+
`Migration ${migrationVersion}: Unknown account type ${accountType}, defaulting to EVM namespace`,
31+
),
32+
);
33+
return [EthScopes.Namespace];
34+
}
35+
}
36+
1637
/**
1738
* Migration for adding scopes to accounts in the AccountsController.
1839
* Each account type gets its appropriate scopes:
@@ -72,31 +93,7 @@ export default function migrate(state: unknown) {
7293
`Migration ${migrationVersion}: Adding scopes for account type ${account.type}`,
7394
);
7495

75-
switch (account.type) {
76-
case EthAccountType.Eoa:
77-
case EthAccountType.Erc4337:
78-
account.scopes = [EthScopes.Namespace];
79-
break;
80-
case BtcAccountType.P2wpkh:
81-
// Default to mainnet scope if address is missing or invalid
82-
account.scopes = [BtcScopes.Mainnet];
83-
break;
84-
case SolAccountType.DataAccount:
85-
account.scopes = [
86-
SolScopes.Mainnet,
87-
SolScopes.Testnet,
88-
SolScopes.Devnet,
89-
];
90-
break;
91-
default:
92-
// Default to EVM namespace for unknown account types
93-
account.scopes = [EthScopes.Namespace];
94-
captureException(
95-
new Error(
96-
`Migration ${migrationVersion}: : Unknown account type ${account.type}, defaulting to EVM namespace`,
97-
),
98-
);
99-
}
96+
account.scopes = getScopesForAccountType(account.type as string);
10097
}
10198

10299
return state;

0 commit comments

Comments
 (0)