Skip to content

Commit 9bd819b

Browse files
sethkfmantommasiniCal-Lgithub-actions[bot]Gudahtt
authored
chore: merge 7.24.1 into 7.24.2 (#10013)
## **Description** Merge into release 7.24.2 ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: tommasini <[email protected]> Co-authored-by: Cal Leung <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Cal Leung <[email protected]> Co-authored-by: Mark Stacey <[email protected]>
1 parent e32f46f commit 9bd819b

File tree

12 files changed

+677
-55
lines changed

12 files changed

+677
-55
lines changed

Diff for: CHANGELOG.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
### Fixed
1010
- [#9905](https://github.com/MetaMask/metamask-mobile/pull/9905): fix: remove metametrics redundant calls and improve compliance
1111

12-
1312
## 7.24.1 - Jun 13, 2024
1413
### Fixed
15-
- [#9943](https://github.com/MetaMask/metamask-mobile/pull/9943): fix: duplicate accounts
16-
- [#9974](https://github.com/MetaMask/metamask-mobile/pull/9974): fix: fix(ramp): memoize asset before passing it to balance hook (#9968)
17-
- [#9978](https://github.com/MetaMask/metamask-mobile/pull/9978): fix: Engine does not exist, network controller is missing ids
18-
- [#9946](https://github.com/MetaMask/metamask-mobile/pull/9946): fix: Update help center URLs
14+
- [#9943](https://github.com/MetaMask/metamask-mobile/pull/9943): fix: Remove duplicate accounts (#9943)
15+
- [#10006](https://github.com/MetaMask/metamask-mobile/pull/10006): fix: Fix order of accounts (#10006)
16+
- [#10004](https://github.com/MetaMask/metamask-mobile/pull/10004): fix: Synchronize account names (#10004)
17+
- [#9974](https://github.com/MetaMask/metamask-mobile/pull/9974): fix: Fix freeze on buy and sell flow (#9974)
18+
- [#9980](https://github.com/MetaMask/metamask-mobile/pull/9980): fix: Fix initialization crash / login error "Engine does not exist (#9980)
1919

2020
## 7.24.0 - Jun 11, 2024
2121
### Added

Diff for: android/app/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ android {
181181
applicationId "io.metamask"
182182
minSdkVersion rootProject.ext.minSdkVersion
183183
targetSdkVersion rootProject.ext.targetSdkVersion
184-
versionCode 1347
184+
versionCode 1348
185185
versionName "7.24.2"
186186
testBuildType System.getProperty('testBuildType', 'debug')
187187
missingDimensionStrategy 'react-native-camera', 'general'

Diff for: app/selectors/accountsController.test.ts

+67-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AccountsControllerState } from '@metamask/accounts-controller';
22
import { captureException } from '@sentry/react-native';
33
import { Hex, isValidChecksumAddress } from '@metamask/utils';
4+
import { InternalAccount } from '@metamask/keyring-api';
45
import DefaultPreference from 'react-native-default-preference';
56
import {
67
selectSelectedInternalAccount,
@@ -13,9 +14,48 @@ import {
1314
expectedUuid2,
1415
internalAccount1,
1516
MOCK_ADDRESS_2,
17+
createMockInternalAccount,
18+
createMockUuidFromAddress,
1619
} from '../util/test/accountsControllerTestUtils';
1720
import { RootState } from '../reducers';
1821
import { AGREED } from '../constants/storage';
22+
import {
23+
MOCK_KEYRINGS,
24+
MOCK_KEYRING_CONTROLLER,
25+
} from './keyringController/testUtils';
26+
27+
/**
28+
* Generates a mocked AccountsController state
29+
* The internal accounts are generated in reverse order relative to the mock keyrings that are used for generation
30+
*
31+
* @returns - A mocked state of AccountsController
32+
*/
33+
const MOCK_GENERATED_ACCOUNTS_CONTROLLER_REVERSED =
34+
(): AccountsControllerState => {
35+
const reversedKeyringAccounts = [...MOCK_KEYRINGS]
36+
.reverse()
37+
.flatMap((keyring) => [...keyring.accounts].reverse());
38+
const accountsForInternalAccounts = reversedKeyringAccounts.reduce(
39+
(record, keyringAccount, index) => {
40+
const lowercasedKeyringAccount = keyringAccount.toLowerCase();
41+
const accountName = `Account ${index}`;
42+
const uuid = createMockUuidFromAddress(lowercasedKeyringAccount);
43+
const internalAccount = createMockInternalAccount(
44+
lowercasedKeyringAccount,
45+
accountName,
46+
);
47+
record[uuid] = internalAccount;
48+
return record;
49+
},
50+
{} as Record<string, InternalAccount>,
51+
);
52+
return {
53+
internalAccounts: {
54+
accounts: accountsForInternalAccounts,
55+
selectedAccount: Object.values(accountsForInternalAccounts)[0].id,
56+
},
57+
};
58+
};
1959

2060
jest.mock('@sentry/react-native', () => ({
2161
captureException: jest.fn(),
@@ -84,47 +124,35 @@ describe('Accounts Controller Selectors', () => {
84124
});
85125
});
86126
describe('selectInternalAccounts', () => {
87-
it('returns all internal accounts in the accounts controller state', () => {
88-
expect(
89-
selectInternalAccounts({
90-
engine: {
91-
backgroundState: {
92-
AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE,
93-
},
127+
it(`returns internal accounts of the accounts controller sorted by the keyring controller's accounts`, () => {
128+
const mockAccountsControllerReversed =
129+
MOCK_GENERATED_ACCOUNTS_CONTROLLER_REVERSED();
130+
const internalAccountsResult = selectInternalAccounts({
131+
engine: {
132+
backgroundState: {
133+
KeyringController: MOCK_KEYRING_CONTROLLER,
134+
AccountsController: mockAccountsControllerReversed,
94135
},
95-
} as RootState),
96-
).toEqual([
97-
{
98-
address: '0xc4955c0d639d99699bfd7ec54d9fafee40e4d272',
99-
id: expectedUuid,
100-
metadata: { name: 'Account 1', keyring: { type: 'HD Key Tree' } },
101-
options: {},
102-
methods: [
103-
'personal_sign',
104-
'eth_sign',
105-
'eth_signTransaction',
106-
'eth_signTypedData_v1',
107-
'eth_signTypedData_v3',
108-
'eth_signTypedData_v4',
109-
],
110-
type: 'eip155:eoa',
111-
},
112-
{
113-
address: '0xc4966c0d659d99699bfd7eb54d8fafee40e4a756',
114-
id: expectedUuid2,
115-
metadata: { name: 'Account 2', keyring: { type: 'HD Key Tree' } },
116-
options: {},
117-
methods: [
118-
'personal_sign',
119-
'eth_sign',
120-
'eth_signTransaction',
121-
'eth_signTypedData_v1',
122-
'eth_signTypedData_v3',
123-
'eth_signTypedData_v4',
124-
],
125-
type: 'eip155:eoa',
126136
},
127-
]);
137+
} as RootState);
138+
const expectedInteralAccountsResult = Object.values(
139+
mockAccountsControllerReversed.internalAccounts.accounts,
140+
).reverse();
141+
142+
const internalAccountAddressesResult = internalAccountsResult.map(
143+
(account) => account.address,
144+
);
145+
const expectedAccountAddressesResult = [...MOCK_KEYRINGS].flatMap(
146+
(keyring) => keyring.accounts,
147+
);
148+
149+
// Ensure accounts are correct
150+
expect(internalAccountsResult).toEqual(expectedInteralAccountsResult);
151+
152+
// Ensure that order of internal accounts match order of keyring accounts
153+
expect(internalAccountAddressesResult).toEqual(
154+
expectedAccountAddressesResult,
155+
);
128156
});
129157
});
130158
describe('selectSelectedInternalAccountChecksummedAddress', () => {

Diff for: app/selectors/accountsController.ts

+32-2
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,43 @@ import { captureException } from '@sentry/react-native';
44
import { createSelector } from 'reselect';
55
import { RootState } from '../reducers';
66
import { createDeepEqualSelector } from './util';
7+
import { selectFlattenedKeyringAccounts } from './keyringController';
78

9+
/**
10+
*
11+
* @param state - Root redux state
12+
* @returns - AccountsController state
13+
*/
814
const selectAccountsControllerState = (state: RootState) =>
915
state.engine.backgroundState.AccountsController;
1016

17+
/**
18+
* A memoized selector that returns internal accounts from the AccountsController, sorted by the order of KeyringController's keyring accounts
19+
*/
1120
export const selectInternalAccounts = createDeepEqualSelector(
1221
selectAccountsControllerState,
13-
(accountControllerState) =>
14-
Object.values(accountControllerState.internalAccounts.accounts),
22+
selectFlattenedKeyringAccounts,
23+
(accountControllerState, orderedKeyringAccounts) => {
24+
const keyringAccountsMap = new Map(
25+
orderedKeyringAccounts.map((account, index) => [
26+
account.toLowerCase(),
27+
index,
28+
]),
29+
);
30+
const sortedAccounts = Object.values(
31+
accountControllerState.internalAccounts.accounts,
32+
).sort(
33+
(a, b) =>
34+
(keyringAccountsMap.get(a.address.toLowerCase()) || 0) -
35+
(keyringAccountsMap.get(b.address.toLowerCase()) || 0),
36+
);
37+
return sortedAccounts;
38+
},
1539
);
1640

41+
/**
42+
* A memoized selector that returns the selected internal account from the AccountsController
43+
*/
1744
export const selectSelectedInternalAccount = createDeepEqualSelector(
1845
selectAccountsControllerState,
1946
(accountsControllerState: AccountsControllerState) => {
@@ -31,6 +58,9 @@ export const selectSelectedInternalAccount = createDeepEqualSelector(
3158
},
3259
);
3360

61+
/**
62+
* A memoized selector that returns the selected internal account address in checksum format
63+
*/
3464
export const selectSelectedInternalAccountChecksummedAddress = createSelector(
3565
selectSelectedInternalAccount,
3666
(account) => {

Diff for: app/selectors/keyringController/index.test.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { selectKeyrings, selectFlattenedKeyringAccounts } from './index';
2+
import { RootState } from '../../reducers';
3+
import {
4+
MOCK_SIMPLE_ACCOUNTS,
5+
MOCK_QR_ACCOUNTS,
6+
MOCK_HD_ACCOUNTS,
7+
MOCK_KEYRINGS,
8+
MOCK_KEYRING_CONTROLLER,
9+
} from './testUtils';
10+
11+
describe('KeyringController Selectors', () => {
12+
describe('selectKeyrings', () => {
13+
it('returns keyrings', () => {
14+
expect(
15+
selectKeyrings({
16+
engine: {
17+
backgroundState: {
18+
KeyringController: MOCK_KEYRING_CONTROLLER,
19+
},
20+
},
21+
} as RootState),
22+
).toEqual(MOCK_KEYRINGS);
23+
});
24+
});
25+
describe('selectFlattenedKeyringAccounts', () => {
26+
it('returns flattened keyring accounts', () => {
27+
const expectedOrderedKeyringAccounts = [
28+
...MOCK_SIMPLE_ACCOUNTS,
29+
...MOCK_QR_ACCOUNTS,
30+
...MOCK_HD_ACCOUNTS,
31+
];
32+
expect(
33+
selectFlattenedKeyringAccounts({
34+
engine: {
35+
backgroundState: {
36+
KeyringController: MOCK_KEYRING_CONTROLLER,
37+
},
38+
},
39+
} as RootState),
40+
).toEqual(expectedOrderedKeyringAccounts);
41+
});
42+
});
43+
});

Diff for: app/selectors/keyringController/index.ts

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { RootState } from '../../reducers';
2+
import { createDeepEqualSelector } from '../util';
3+
4+
/**
5+
*
6+
* @param state - Root Redux state
7+
* @returns - KeyringController state
8+
*/
9+
const selectKeyringControllerState = (state: RootState) =>
10+
state.engine.backgroundState.KeyringController;
11+
12+
/**
13+
* A memoized selector that retrieves keyrings from the KeyringController
14+
*/
15+
export const selectKeyrings = createDeepEqualSelector(
16+
selectKeyringControllerState,
17+
(keyringControllerState) => keyringControllerState.keyrings,
18+
);
19+
20+
/**
21+
* A memoized selector that returns the list of accounts from all keyrings in the form of a flattened array of strings.
22+
*/
23+
export const selectFlattenedKeyringAccounts = createDeepEqualSelector(
24+
selectKeyrings,
25+
(keyrings) => {
26+
const flattenedKeyringAccounts = keyrings.flatMap(
27+
(keyring) => keyring.accounts,
28+
);
29+
return flattenedKeyringAccounts;
30+
},
31+
);

Diff for: app/selectors/keyringController/testUtils.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {
2+
KeyringControllerState,
3+
KeyringObject,
4+
KeyringTypes,
5+
} from '@metamask/keyring-controller';
6+
7+
export const MOCK_SIMPLE_ACCOUNTS = ['0x1', '0x2'];
8+
export const MOCK_QR_ACCOUNTS = ['0x3', '0x4'];
9+
export const MOCK_HD_ACCOUNTS = ['0x5', '0x6'];
10+
export const MOCK_KEYRINGS: KeyringObject[] = [
11+
{ accounts: MOCK_SIMPLE_ACCOUNTS, type: KeyringTypes.simple },
12+
{ accounts: MOCK_QR_ACCOUNTS, type: KeyringTypes.qr },
13+
{ accounts: MOCK_HD_ACCOUNTS, type: KeyringTypes.hd },
14+
];
15+
export const MOCK_KEYRING_CONTROLLER: KeyringControllerState = {
16+
isUnlocked: true,
17+
keyrings: MOCK_KEYRINGS,
18+
};

0 commit comments

Comments
 (0)