Skip to content

Commit

Permalink
Merge branch 'main' into add-tokens-search-discovery-controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Bigshmow committed Jan 31, 2025
2 parents a85355b + 711a583 commit 92afe2b
Show file tree
Hide file tree
Showing 30 changed files with 498 additions and 77 deletions.
10 changes: 4 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,10 @@ app/components/UI/Swaps @MetaMask/swaps-engineers
# Notifications Team
app/components/Views/Notifications @MetaMask/notifications
app/components/Views/Settings/NotificationsSettings @MetaMask/notifications
app/components/UI/Notifications @MetaMask/notifications
app/reducers/notification @MetaMask/notifications
app/actions/notification @MetaMask/notifications
app/selectors/notification @MetaMask/notifications
app/util/notifications @MetaMask/notifications
app/store/util/notifications @MetaMask/notifications
**/Notifications/** @MetaMask/notifications
**/Notification/** @MetaMask/notifications
**/notifications/** @MetaMask/notifications
**/notification/** @MetaMask/notifications

# Identity Team
app/actions/identity @MetaMask/identity
Expand Down
5 changes: 5 additions & 0 deletions .js.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,8 @@ export MM_PERMISSIONS_SETTINGS_V1_ENABLED=""

# Feature flag for Stablecoin Lending UI
export MM_STABLECOIN_LENDING_UI_ENABLED="true"

# Activates remote feature flag override mode.
# Remote feature flag values won't be updated,
# and selectors should return their fallback values
export OVERRIDE_REMOTE_FEATURE_FLAGS="false"
12 changes: 1 addition & 11 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ import SDKSessionModal from '../../Views/SDK/SDKSessionModal/SDKSessionModal';
import ExperienceEnhancerModal from '../../../../app/components/Views/ExperienceEnhancerModal';
import { MetaMetrics } from '../../../core/Analytics';
import trackErrorAsAnalytics from '../../../util/metrics/TrackError/trackErrorAsAnalytics';
import generateDeviceAnalyticsMetaData from '../../../util/metrics/DeviceAnalyticsMetaData/generateDeviceAnalyticsMetaData';
import generateUserSettingsAnalyticsMetaData from '../../../util/metrics/UserSettingsAnalyticsMetaData/generateUserProfileAnalyticsMetaData';
import LedgerSelectAccount from '../../Views/LedgerSelectAccount';
import OnboardingSuccess from '../../Views/OnboardingSuccess';
import DefaultSettings from '../../Views/OnboardingSuccess/DefaultSettings';
Expand Down Expand Up @@ -745,15 +743,7 @@ const App = (props) => {

useEffect(() => {
const initMetrics = async () => {
const metrics = MetaMetrics.getInstance();
await metrics.configure();
// identify user with the latest traits
// run only after the MetaMetrics is configured
const consolidatedTraits = {
...generateDeviceAnalyticsMetaData(),
...generateUserSettingsAnalyticsMetaData(),
};
await metrics.addTraitsToUser(consolidatedTraits);
await MetaMetrics.getInstance().configure();
};

initMetrics().catch((err) => {
Expand Down
4 changes: 0 additions & 4 deletions app/components/Nav/App/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ describe('App', () => {
);
await waitFor(() => {
expect(mockMetrics.configure).toHaveBeenCalledTimes(1);
expect(mockMetrics.addTraitsToUser).toHaveBeenNthCalledWith(1, {
deviceProp: 'Device value',
userProp: 'User value',
});
});
});
});
11 changes: 6 additions & 5 deletions app/components/UI/Swaps/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import {
selectCurrentCurrency,
} from '../../../selectors/currencyRateController';
import { selectContractExchangeRates } from '../../../selectors/tokenRatesController';
import { selectAccounts } from '../../../selectors/accountTrackerController';
import { selectAccountsByChainId } from '../../../selectors/accountTrackerController';
import { selectContractBalances } from '../../../selectors/tokenBalancesController';
import { selectSelectedInternalAccountFormattedAddress } from '../../../selectors/accountsController';
import AccountSelector from '../Ramp/components/AccountSelector';
Expand Down Expand Up @@ -182,7 +182,7 @@ const MAX_TOP_ASSETS = 20;
function SwapsAmountView({
swapsTokens,
swapsControllerTokens,
accounts,
accountsByChainId,
selectedAddress,
chainId,
selectedNetworkClientId,
Expand All @@ -196,6 +196,7 @@ function SwapsAmountView({
currentCurrency,
setLiveness,
}) {
const accounts = accountsByChainId[chainId];
const navigation = useNavigation();
const route = useRoute();
const { colors } = useTheme();
Expand Down Expand Up @@ -963,9 +964,9 @@ SwapsAmountView.propTypes = {
tokensWithBalance: PropTypes.arrayOf(PropTypes.object),
tokensTopAssets: PropTypes.arrayOf(PropTypes.object),
/**
* Map of accounts to information objects including balances
* Map of chainId to accounts to information objects including balances
*/
accounts: PropTypes.object,
accountsByChainId: PropTypes.object,
/**
* A string that represents the selected address
*/
Expand Down Expand Up @@ -1011,7 +1012,7 @@ SwapsAmountView.propTypes = {
const mapStateToProps = (state) => ({
swapsTokens: swapsTokensSelector(state),
swapsControllerTokens: swapsControllerTokens(state),
accounts: selectAccounts(state),
accountsByChainId: selectAccountsByChainId(state),
balances: selectContractBalances(state),
selectedAddress: selectSelectedInternalAccountFormattedAddress(state),
conversionRate: selectConversionRate(state),
Expand Down
4 changes: 2 additions & 2 deletions app/components/Views/BrowserTab/BrowserTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1307,10 +1307,10 @@ export const BrowserTab: React.FC<BrowserTabProps> = ({
<ErrorBoundary navigation={navigation} view="BrowserTab">
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.wrapper}
style={[styles.wrapper, !isTabActive && styles.hide]}
>
<View
style={[styles.wrapper, !isTabActive && styles.hide]}
style={styles.wrapper}
{...(Device.isAndroid() ? { collapsable: false } : {})}
>
<BrowserUrlBar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ const mockInitialState = {
balance: '0x0',
},
},
accountsByChainId: {
'0x1': {
'0xd018538C87232FF95acbCe4870629b75640a78E7': {
balance: '0x0',
},
},
},
},
AccountsController: {
internalAccounts: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { useNavigation } from '@react-navigation/native';

import {
newAssetTransaction,
setSelectedAsset,
} from '../../../../../actions/transaction';
import Routes from '../../../../../constants/navigation/Routes';
import { selectAccounts } from '../../../../../selectors/accountTrackerController';
import { selectAccountsByChainId } from '../../../../../selectors/accountTrackerController';
import { selectSelectedInternalAccount } from '../../../../../selectors/accountsController';
import { doENSReverseLookup } from '../../../../../util/ENSUtils';
import { renderFromWei, hexToBN } from '../../../../../util/number';
Expand All @@ -27,11 +25,11 @@ const SendFlowAddressFrom = ({
}: SFAddressFromProps) => {
const navigation = useNavigation();

const accounts = useSelector(selectAccounts);

const ticker = useSelector((state: RootState) =>
selectNativeCurrencyByChainId(state, chainId as Hex),
);
const accountsByChainId = useSelector(selectAccountsByChainId);
const accounts = accountsByChainId[chainId];

const selectedInternalAccount = useSelector(selectSelectedInternalAccount);
const checksummedSelectedAddress = selectedInternalAccount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import Address from '../../UI/InfoRow/InfoValue/Address';
import InfoDate from '../../UI/InfoRow/InfoValue/InfoDate';
import InfoRow from '../../UI/InfoRow';
import TokenValue from '../../UI/InfoRow/InfoValue/TokenValue';
import DataTree from './DataTree';

enum Field {
Expand Down Expand Up @@ -41,10 +42,25 @@ const FIELD_DATE_PRIMARY_TYPES: Record<string, string[]> = {
[Field.ValidTo]: [...PRIMARY_TYPES_ORDER],
};

const FIELD_TOKEN_UTILS_PRIMARY_TYPES: Record<string, string[]> = {
[Field.Amount]: [...PRIMARY_TYPES_PERMIT],
[Field.BuyAmount]: [...PRIMARY_TYPES_ORDER],
[Field.EndAmount]: [...PRIMARY_TYPES_ORDER],
[Field.SellAmount]: [...PRIMARY_TYPES_ORDER],
[Field.StartAmount]: [...PRIMARY_TYPES_ORDER],
[Field.Value]: [...PRIMARY_TYPES_PERMIT],
};

function isDateField(label: string, primaryType?: PrimaryType) {
return (FIELD_DATE_PRIMARY_TYPES[label] || [])?.includes(primaryType || '');
}

function isTokenValueField(label: string, primaryType?: PrimaryType) {
return (FIELD_TOKEN_UTILS_PRIMARY_TYPES[label] || [])?.includes(
primaryType || '',
);
}

const createStyles = (depth: number) =>
StyleSheet.create({
container: {
Expand All @@ -66,13 +82,15 @@ const DataField = memo(
label,
primaryType,
type,
tokenDecimals,
value,
}: {
chainId: string;
depth: number;
label: string;
primaryType?: PrimaryType;
type: string;
tokenDecimals?: number;
value: string;
}) => {
const styles = createStyles(depth);
Expand All @@ -88,13 +106,16 @@ const DataField = memo(
) : (
<InfoDate unixTimestamp={parseInt(value, 10)} />
);
} else if (isTokenValueField(label, primaryType)) {
fieldDisplay = <TokenValue value={value} decimals={tokenDecimals} />;
} else if (typeof value === 'object' && value !== null) {
fieldDisplay = (
<DataTree
data={value}
chainId={chainId}
depth={depth + 1}
primaryType={primaryType}
tokenDecimals={tokenDecimals}
/>
);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ const mockSanitizedTypedSignV3Message = {
value: NONE_DATE_VALUE,
type: 'uint256',
},
buyAmount: {
value: 10000,
type: 'uint256',
},
contents: { value: 'Hello, Bob!', type: 'string' },
};

describe('NoChangeSimulation', () => {
it('displays types sign v1 message', async () => {
const { getByText, queryByText } = renderWithProvider(
it('should display types sign v1 message correctly', async () => {
const { getByText } = renderWithProvider(
<DataTree
data={{
Message: { type: 'string', value: 'Hi, Alice!' },
Expand All @@ -62,8 +66,6 @@ describe('NoChangeSimulation', () => {
expect(getByText('Hi, Alice!')).toBeDefined();
expect(getByText('A Number')).toBeDefined();
expect(getByText('1337')).toBeDefined();
// date field not supported for v1
expect(queryByText('15 March 2022, 15:57')).toBeNull();
});

it('displays types sign v3/v4 message', async () => {
Expand All @@ -72,6 +74,7 @@ describe('NoChangeSimulation', () => {
data={mockSanitizedTypedSignV3Message as unknown as DataTreeInput}
chainId="0x1"
primaryType={PrimaryTypeOrder.Order}
tokenDecimals={2}
/>,
{
state: {
Expand All @@ -88,7 +91,12 @@ describe('NoChangeSimulation', () => {
expect(getByText('To')).toBeDefined();
expect(getByText('Bob')).toBeDefined();
// date field displayed for permit types
expect(getByText('End Time')).toBeDefined();
expect(getByText('15 March 2022, 15:57')).toBeDefined();
expect(getByText('Start Time')).toBeDefined();
expect(getByText('None')).toBeDefined();
// token value field
expect(getByText('Buy Amount')).toBeDefined();
expect(getByText('100')).toBeDefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ const DataTree = ({
chainId,
depth = 0,
primaryType,
tokenDecimals,
}: {
data: DataTreeInput;
chainId: string;
depth?: number;
primaryType?: PrimaryType;
tokenDecimals?: number;
}) => (
<View style={styles.container}>
{Object.keys(data).map((dataKey: string, index: number) => {
Expand All @@ -34,6 +36,7 @@ const DataTree = ({
label={dataKey}
key={`${dataKey}-${index}`}
primaryType={primaryType}
tokenDecimals={tokenDecimals}
{...datum}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { fireEvent } from '@testing-library/react-native';

import renderWithProvider from '../../../../../../../util/test/renderWithProvider';
import { typedSignV4ConfirmationState } from '../../../../../../../util/test/confirm-data-helpers';
// eslint-disable-next-line import/no-namespace
import * as SignatureRequestHook from '../../../../hooks/useSignatureRequest';
import Message from './Message';

jest.mock('../../../../hooks/useTokenDecimalsInTypedSignRequest', () => ({
useTokenDecimalsInTypedSignRequest: () => 2,
}));

describe('Message', () => {
it('render correctly for V4 permit', async () => {
const { getAllByText, getByText } = renderWithProvider(<Message />, {
state: typedSignV4ConfirmationState,
});
expect(getAllByText('Message')).toHaveLength(1);
fireEvent.press(getByText('Message'));
expect(getAllByText('Message')).toHaveLength(3);
expect(getByText('Primary type')).toBeDefined();
expect(getByText('Permit')).toBeDefined();
expect(getByText('Owner')).toBeDefined();
expect(getByText('0x935E7...05477')).toBeDefined();
expect(getByText('Spender')).toBeDefined();
expect(getByText('0x5B38D...eddC4')).toBeDefined();
expect(getByText('Value')).toBeDefined();
expect(getByText('30')).toBeDefined();
expect(getByText('Nonce')).toBeDefined();
expect(getByText('0')).toBeDefined();
expect(getByText('Deadline')).toBeDefined();
expect(getByText('09 June 3554, 16:53')).toBeDefined();
});

it('render null if signature request is not found', async () => {
jest
.spyOn(SignatureRequestHook, 'useSignatureRequest')
.mockReturnValue(undefined);
const { queryByText } = renderWithProvider(<Message />, {
state: typedSignV4ConfirmationState,
});
expect(queryByText('Message')).toBeNull();
});
});
Loading

0 comments on commit 92afe2b

Please sign in to comment.