Skip to content

Commit 3e45914

Browse files
authored
Merge branch 'main' into mms2154-dest-account-balances
2 parents 2f31aca + 1158dca commit 3e45914

20 files changed

+208
-54
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { TokenRatesControllerInit } from './token-rates-controller-init';
22
export { NftControllerInit } from './nft-controller-init';
3+
export { NftDetectionControllerInit } from './nft-detection-controller-init';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
NftDetectionController,
3+
NftDetectionControllerMessenger,
4+
} from '@metamask/assets-controllers';
5+
import { Messenger } from '@metamask/base-controller';
6+
import { PreferencesController } from '@metamask/preferences-controller';
7+
import { buildControllerInitRequestMock } from '../test/utils';
8+
import { ControllerInitRequest } from '../types';
9+
import { getNftDetectionControllerMessenger } from '../messengers/assets';
10+
import { NftDetectionControllerInit } from './nft-detection-controller-init';
11+
12+
jest.mock('@metamask/assets-controllers');
13+
14+
/**
15+
* Build a mock PreferencesController.
16+
*
17+
* @param partialMock - A partial mock object for the PreferencesController, merged
18+
* with the default mock.
19+
* @returns A mock PreferencesController.
20+
*/
21+
function buildControllerMock(
22+
partialMock?: Partial<PreferencesController>,
23+
): PreferencesController {
24+
const defaultPreferencesControllerMock = {
25+
state: { useNftDetection: true },
26+
};
27+
28+
// @ts-expect-error Incomplete mock, just includes properties used by code-under-test.
29+
return {
30+
...defaultPreferencesControllerMock,
31+
...partialMock,
32+
};
33+
}
34+
35+
function buildInitRequestMock(): jest.Mocked<
36+
ControllerInitRequest<NftDetectionControllerMessenger>
37+
> {
38+
const baseControllerMessenger = new Messenger();
39+
40+
const requestMock = {
41+
...buildControllerInitRequestMock(),
42+
controllerMessenger: getNftDetectionControllerMessenger(
43+
baseControllerMessenger,
44+
),
45+
initMessenger: undefined,
46+
};
47+
// @ts-expect-error Incomplete mock, just includes properties used by code-under-test.
48+
requestMock.getController.mockReturnValue(buildControllerMock());
49+
50+
return requestMock;
51+
}
52+
53+
describe('NftDetectionControllerInit', () => {
54+
const nftDetectionControllerClassMock = jest.mocked(NftDetectionController);
55+
56+
beforeEach(() => {
57+
jest.resetAllMocks();
58+
});
59+
60+
it('returns controller instance', () => {
61+
const requestMock = buildInitRequestMock();
62+
expect(NftDetectionControllerInit(requestMock).controller).toBeInstanceOf(
63+
NftDetectionController,
64+
);
65+
});
66+
67+
it('initializes with correct messenger and state', () => {
68+
const requestMock = buildInitRequestMock();
69+
NftDetectionControllerInit(requestMock);
70+
71+
expect(nftDetectionControllerClassMock).toHaveBeenCalled();
72+
});
73+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { NftDetectionController } from '@metamask/assets-controllers';
2+
import { ControllerInitFunction } from '../types';
3+
import { NftDetectionControllerMessenger } from '../messengers/assets';
4+
5+
/**
6+
* Initialize the NFT detection controller.
7+
*
8+
* @param request - The request object.
9+
* @param request.controllerMessenger - The messenger to use for the controller.
10+
* @param request.getController - The function to get the controller.
11+
* @returns The initialized controller.
12+
*/
13+
export const NftDetectionControllerInit: ControllerInitFunction<
14+
NftDetectionController,
15+
NftDetectionControllerMessenger
16+
> = (request) => {
17+
const { controllerMessenger, getController } = request;
18+
19+
const preferencesController = () => getController('PreferencesController');
20+
const nftController = () => getController('NftController');
21+
22+
const controller = new NftDetectionController({
23+
messenger: controllerMessenger,
24+
addNft: (...args) => nftController().addNft(...args),
25+
getNftState: () => nftController().state,
26+
// added this to track previous value of useNftDetection, should be true on very first initializing of controller[]
27+
disabled: !preferencesController().state.useNftDetection,
28+
});
29+
30+
return {
31+
controller,
32+
};
33+
};

app/scripts/controller-init/controller-list.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
MultichainAssetsRatesController,
1717
MultichainBalancesController,
1818
NftController,
19+
NftDetectionController,
1920
TokenRatesController,
2021
} from '@metamask/assets-controllers';
2122
import { MultichainNetworkController } from '@metamask/multichain-network-controller';
@@ -77,7 +78,8 @@ export type Controller =
7778
})
7879
| UserStorageController
7980
| TokenRatesController
80-
| NftController;
81+
| NftController
82+
| NftDetectionController;
8183

8284
/**
8385
* Flat state object for all controllers supporting or required by modular initialization.
@@ -110,4 +112,5 @@ export type ControllerFlatState = AccountsController['state'] &
110112
SwapsController['state'] &
111113
UserStorageController['state'] &
112114
TokenRatesController['state'] &
113-
NftController['state'];
115+
NftController['state'] &
116+
NftDetectionController['state'];
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
export { getTokenRatesControllerMessenger } from './token-rates-controller-messenger';
2-
32
export type { TokenRatesControllerMessenger } from './token-rates-controller-messenger';
3+
44
export { getNftControllerMessenger } from './nft-controller-messenger';
55
export type { NftControllerMessenger } from './nft-controller-messenger';
6+
7+
export { getNftDetectionControllerMessenger } from './nft-detection-controller-messenger';
8+
export type { NftDetectionControllerMessenger } from './nft-detection-controller-messenger';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Messenger, RestrictedMessenger } from '@metamask/base-controller';
2+
import { getNftDetectionControllerMessenger } from './nft-detection-controller-messenger';
3+
4+
describe('getNftDetectionControllerMessenger', () => {
5+
it('returns a restricted messenger', () => {
6+
const messenger = new Messenger<never, never>();
7+
const nftDetectionControllerMessenger =
8+
getNftDetectionControllerMessenger(messenger);
9+
10+
expect(nftDetectionControllerMessenger).toBeInstanceOf(RestrictedMessenger);
11+
});
12+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Messenger } from '@metamask/base-controller';
2+
import {
3+
NetworkControllerGetNetworkClientByIdAction,
4+
NetworkControllerGetStateAction,
5+
NetworkControllerStateChangeEvent,
6+
} from '@metamask/network-controller';
7+
import { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller';
8+
import { PreferencesControllerStateChangeEvent } from '@metamask/preferences-controller';
9+
import { AddApprovalRequest } from '@metamask/approval-controller';
10+
11+
type Actions =
12+
| AddApprovalRequest
13+
| NetworkControllerGetStateAction
14+
| AccountsControllerGetSelectedAccountAction
15+
| NetworkControllerGetNetworkClientByIdAction;
16+
17+
type Events =
18+
| PreferencesControllerStateChangeEvent
19+
| NetworkControllerStateChangeEvent;
20+
21+
export type NftDetectionControllerMessenger = ReturnType<
22+
typeof getNftDetectionControllerMessenger
23+
>;
24+
25+
/**
26+
* Get a restricted messenger for the NFT detection controller. This is scoped to the
27+
* actions and events that the NFT controller is allowed to handle.
28+
*
29+
* @param messenger - The controller messenger to restrict.
30+
* @returns The restricted controller messenger.
31+
*/
32+
export function getNftDetectionControllerMessenger(
33+
messenger: Messenger<Actions, Events>,
34+
) {
35+
return messenger.getRestricted({
36+
name: 'NftDetectionController',
37+
allowedEvents: [
38+
'NetworkController:stateChange',
39+
'PreferencesController:stateChange',
40+
],
41+
allowedActions: [
42+
'ApprovalController:addRequest',
43+
'NetworkController:getState',
44+
'NetworkController:getNetworkClientById',
45+
'AccountsController:getSelectedAccount',
46+
],
47+
});
48+
}

app/scripts/controller-init/messengers/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
} from './identity';
3232
import {
3333
getNftControllerMessenger,
34+
getNftDetectionControllerMessenger,
3435
getTokenRatesControllerMessenger,
3536
} from './assets';
3637
import {
@@ -119,4 +120,8 @@ export const CONTROLLER_MESSENGERS = {
119120
getMessenger: getNftControllerMessenger,
120121
getInitMessenger: noop,
121122
},
123+
NftDetectionController: {
124+
getMessenger: getNftDetectionControllerMessenger,
125+
getInitMessenger: noop,
126+
},
122127
} as const;

app/scripts/metamask-controller.js

+3-30
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { finished, pipeline } from 'readable-stream';
33
import {
44
AssetsContractController,
55
CurrencyRateController,
6-
NftDetectionController,
76
TokenDetectionController,
87
TokenListController,
98
TokensController,
@@ -373,6 +372,7 @@ import {
373372
} from './controller-init/multichain';
374373
import {
375374
NftControllerInit,
375+
NftDetectionControllerInit,
376376
TokenRatesControllerInit,
377377
} from './controller-init/assets';
378378
import { TransactionControllerInit } from './controller-init/confirmations/transaction-controller-init';
@@ -772,35 +772,6 @@ export default class MetamaskController extends EventEmitter {
772772
chainId: this.#getGlobalChainId(),
773773
});
774774

775-
const nftDetectionControllerMessenger =
776-
this.controllerMessenger.getRestricted({
777-
name: 'NftDetectionController',
778-
allowedEvents: [
779-
'NetworkController:stateChange',
780-
'PreferencesController:stateChange',
781-
],
782-
allowedActions: [
783-
'ApprovalController:addRequest',
784-
'NetworkController:getState',
785-
'NetworkController:getNetworkClientById',
786-
'AccountsController:getSelectedAccount',
787-
],
788-
});
789-
790-
this.nftDetectionController = new NftDetectionController({
791-
messenger: nftDetectionControllerMessenger,
792-
chainId: this.#getGlobalChainId(),
793-
getOpenSeaApiKey: () => this.nftController.openSeaApiKey,
794-
getBalancesInSingleCall:
795-
this.assetsContractController.getBalancesInSingleCall.bind(
796-
this.assetsContractController,
797-
),
798-
addNft: (...args) => this.nftController.addNft(...args),
799-
getNftState: () => this.nftController.state,
800-
// added this to track previous value of useNftDetection, should be true on very first initializing of controller[]
801-
disabled: !this.preferencesController.state.useNftDetection,
802-
});
803-
804775
const metaMetricsControllerMessenger =
805776
this.controllerMessenger.getRestricted({
806777
name: 'MetaMetricsController',
@@ -1847,6 +1818,7 @@ export default class MetamaskController extends EventEmitter {
18471818
PPOMController: PPOMControllerInit,
18481819
TransactionController: TransactionControllerInit,
18491820
NftController: NftControllerInit,
1821+
NftDetectionController: NftDetectionControllerInit,
18501822
///: BEGIN:ONLY_INCLUDE_IF(multichain)
18511823
MultichainAssetsController: MultichainAssetsControllerInit,
18521824
MultichainAssetsRatesController: MultichainAssetsRatesControllerInit,
@@ -1888,6 +1860,7 @@ export default class MetamaskController extends EventEmitter {
18881860
this.ppomController = controllersByName.PPOMController;
18891861
this.txController = controllersByName.TransactionController;
18901862
this.nftController = controllersByName.NftController;
1863+
this.nftDetectionController = controllersByName.NftDetectionController;
18911864
///: BEGIN:ONLY_INCLUDE_IF(multichain)
18921865
this.multichainAssetsController =
18931866
controllersByName.MultichainAssetsController;

test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json

+1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@
189189
"allNfts": "object",
190190
"ignoredNfts": "object"
191191
},
192+
"NftDetectionController": "object",
192193
"NotificationServicesController": {
193194
"subscriptionAccountsSeen": "object",
194195
"isMetamaskNotificationsFeatureSeen": "boolean",

ui/components/app/assets/nfts/nft-details/__snapshots__/nft-details.test.js.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = `
9696
class="mm-box mm-box--display-flex mm-box--align-items-center"
9797
>
9898
<h3
99-
class="mm-box mm-text mm-text--heading-md mm-text--font-weight-bold mm-text--font-style-normal mm-box--color-text-default"
99+
class="mm-box mm-text mm-text--heading-md mm-text--font-weight-medium mm-text--font-style-normal mm-box--color-text-default"
100100
data-testid="nft-details__name"
101101
style="font-size: 24px;"
102102
>

ui/components/app/assets/nfts/nft-details/nft-details.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ export function NftDetailsComponent({
404404
<Box display={Display.Flex} alignItems={AlignItems.center}>
405405
<Text
406406
variant={TextVariant.headingMd}
407-
fontWeight={FontWeight.Bold}
407+
fontWeight={FontWeight.Medium}
408408
color={TextColor.textDefault}
409409
fontStyle={FontStyle.Normal}
410410
style={{ fontSize: '24px' }}

ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ exports[`Token Cell should match snapshot 1`] = `
1414
class="mm-box mm-badge-wrapper mm-box--margin-right-4 mm-box--display-inline-block"
1515
>
1616
<div
17-
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-token mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full"
17+
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-token mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-muted mm-box--rounded-full"
1818
>
1919
<img
2020
alt="TEST logo"
@@ -26,7 +26,7 @@ exports[`Token Cell should match snapshot 1`] = `
2626
class="mm-box mm-badge-wrapper__badge-container mm-badge-wrapper__badge-container--rectangular-bottom-right"
2727
>
2828
<div
29-
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-network mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-default mm-box--rounded-md mm-box--border-color-background-default mm-box--border-width-2 box--border-style-solid"
29+
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-network mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-muted mm-box--rounded-md mm-box--border-color-background-default mm-box--border-width-2 box--border-style-solid"
3030
>
3131
<img
3232
alt="network logo"

ui/components/app/assets/token-cell/cells/token-cell-badge.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ export const TokenCellBadge = React.memo(
3232
size={AvatarNetworkSize.Xs}
3333
name={allNetworks?.[token.chainId as Hex]?.name}
3434
src={getImageForChainId(token.chainId) || undefined}
35-
backgroundColor={BackgroundColor.backgroundDefault}
35+
backgroundColor={BackgroundColor.backgroundMuted}
3636
borderWidth={2}
3737
/>
3838
}
3939
marginRight={4}
4040
>
4141
<AvatarToken
4242
name={token.symbol}
43+
backgroundColor={BackgroundColor.backgroundMuted}
4344
src={
4445
isEvm && token.isNative
4546
? getNativeCurrencyForChain(token.chainId)

ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ exports[`AggregatedPercentageOverview render renders correctly 1`] = `
66
class="mm-box mm-box--display-flex"
77
>
88
<p
9-
class="mm-box mm-text mm-text--body-md-medium mm-text--ellipsis mm-box--color-text-default"
9+
class="mm-box mm-text mm-text--body-md-medium mm-text--ellipsis mm-box--color-text-alternative"
1010
data-testid="aggregated-value-change"
1111
style="white-space: pre;"
1212
>
1313
+$0.00
1414
</p>
1515
<p
16-
class="mm-box mm-text mm-text--body-md-medium mm-text--ellipsis mm-box--color-text-default"
16+
class="mm-box mm-text mm-text--body-md-medium mm-text--ellipsis mm-box--color-text-alternative"
1717
data-testid="aggregated-percentage-change"
1818
>
1919
(+0.00%)

ui/components/app/wallet-overview/aggregated-percentage-overview.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,11 @@ export const AggregatedPercentageOverview = () => {
114114
}
115115
}
116116

117-
let color = TextColor.textDefault;
117+
let color = TextColor.textAlternative;
118118

119119
if (!privacyMode && isValidAmount(amountChange)) {
120120
if ((amountChange as number) === 0) {
121-
color = TextColor.textDefault;
121+
color = TextColor.textAlternative;
122122
} else if ((amountChange as number) > 0) {
123123
color = TextColor.successDefault;
124124
} else {

ui/components/app/wallet-overview/index.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
@include design-system.H2;
8787

8888
color: var(--color-text-default);
89-
font-weight: 700;
89+
font-weight: 500;
9090
}
9191

9292
&__cached-star {

0 commit comments

Comments
 (0)