Skip to content

Commit

Permalink
Merge branch 'main' into 8618-reduce-enzyme-usage-in-unit-test-by-25-…
Browse files Browse the repository at this point in the history
…--3-of-3
  • Loading branch information
Daniel-Cross authored Oct 4, 2024
2 parents 086c679 + b3befd8 commit 943936e
Show file tree
Hide file tree
Showing 75 changed files with 2,539 additions and 1,318 deletions.
4 changes: 4 additions & 0 deletions .iyarc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# ReDoS vulnerability, no impact to this application, and fix not backported yet to the versions we use

GHSA-c2qf-rxjj-qqgw

# Sentry SDK Prototype Pollution gadget in JavaScript SDKs

GHSA-593m-55hh-j8gv
90 changes: 90 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,96 @@

## Current Main Branch

## 7.32.0 - Sep 19, 2024

### Added

- [#10294](https://github.com/MetaMask/metamask-mobile/pull/10294): feat: create redux slice for featureFlags (#10294)
- [#11314](https://github.com/MetaMask/metamask-mobile/pull/11314): feat: reject connection properly (#11314)
- [#11132](https://github.com/MetaMask/metamask-mobile/pull/11132): feat: Add performance tracing infrastructure (#11132)
- [#10061](https://github.com/MetaMask/metamask-mobile/pull/10061): feat: new receive flow (#10061)
- [#11174](https://github.com/MetaMask/metamask-mobile/pull/11174): feat(2796): behind feature flag permission settings multichain 2of2 (#11174)
- [#11019](https://github.com/MetaMask/metamask-mobile/pull/11019): feat(2793): mocked UI screen displaying multichain dapp permission summary 2of2 (#11019)
- [#10988](https://github.com/MetaMask/metamask-mobile/pull/10988): feat(2808): add a mocked UI checkbox list that will later allow adding the ability to edit network permission (#10988)
- [#11168](https://github.com/MetaMask/metamask-mobile/pull/11168): feat: add pooled staking input flow screen (#11168)
- [#10964](https://github.com/MetaMask/metamask-mobile/pull/10964): feat: build your earnings component stub in eth token details (#10964)
- [#11051](https://github.com/MetaMask/metamask-mobile/pull/11051): feat: add brand evo font files (#11051)
- [#11285](https://github.com/MetaMask/metamask-mobile/pull/11285): feat: notifications add analytics (#11285)
- [#10755](https://github.com/MetaMask/metamask-mobile/pull/10755): feat: ledger account selection screen add hd options to sync with extension (#10755)
- [#11195](https://github.com/MetaMask/metamask-mobile/pull/11195): feat: add AppState dependency to load notifications (#11195)
- [#11175](https://github.com/MetaMask/metamask-mobile/pull/11175): feat: add product announcements toggle (#11175)

### Changed
- [#11148](https://github.com/MetaMask/metamask-mobile/pull/11148): chore: remove animation and add new splash screen (#11148)
- [#11306](https://github.com/MetaMask/metamask-mobile/pull/11306): chore: update @sentry/react-native to version 5.33.0 (#11306)
- [#11144](https://github.com/MetaMask/metamask-mobile/pull/11144): test: E2E Mocking Setup For Detox Tests (#11144)
- [#11212](https://github.com/MetaMask/metamask-mobile/pull/11212): chore: Update CI workflow triggers to support release branches (#11212)
- [#11243](https://github.com/MetaMask/metamask-mobile/pull/11243): chore(js-ts): Convert ModalNavbarTitle to TypeScript (#11243)
- [#11213](https://github.com/MetaMask/metamask-mobile/pull/11213): test: Appium separate and optimize app launch time measurements (#11213)
- [#11264](https://github.com/MetaMask/metamask-mobile/pull/11264): chore: remove triggers for actions not needed during the merge-queue CI (#11264)
- [#11222](https://github.com/MetaMask/metamask-mobile/pull/11222): chore: add bitrise document link to the bitrise failed comment (#11222)
- [#11145](https://github.com/MetaMask/metamask-mobile/pull/11145): chore: update performance for new allocation (#11145)
- [#11184](https://github.com/MetaMask/metamask-mobile/pull/11184): test: remove notifications launch arg in E2E (#11184)
- [#11186](https://github.com/MetaMask/metamask-mobile/pull/11186): ci: prevent detox E2E lock failure (#11186)
- [#11141](https://github.com/MetaMask/metamask-mobile/pull/11141): chore: update express for all the packages (#11141)
- [#11124](https://github.com/MetaMask/metamask-mobile/pull/11124): docs: Update Appium documentation (#11124)
- [#10865](https://github.com/MetaMask/metamask-mobile/pull/10865): chore: update eslint v^8.44 (#10865)
- [#11096](https://github.com/MetaMask/metamask-mobile/pull/11096): test: detox black list gas api endpoint (#11096)
- [#11246](https://github.com/MetaMask/metamask-mobile/pull/11246): chore: Remove `eth-sign` (#11246)
- [#11220](https://github.com/MetaMask/metamask-mobile/pull/11220): chore: Update package @blockaid/ppom_release to version 1.5.3 (#11220)
- [#11244](https://github.com/MetaMask/metamask-mobile/pull/11244): chore(js-ts): Convert useInterval.js to TypeScript (#11244)
- [#11089](https://github.com/MetaMask/metamask-mobile/pull/11089): chore: add staking team to codeowners file (#11089)
- [#11049](https://github.com/MetaMask/metamask-mobile/pull/11049): chore: update balance design (#11049)
- [#11011](https://github.com/MetaMask/metamask-mobile/pull/11011): chore: Capture currency change in MetaMetrics (#11011)
- [#10468](https://github.com/MetaMask/metamask-mobile/pull/10468): chore: Capture custom rpc url in `trackEvent` (#10468)
- [#11207](https://github.com/MetaMask/metamask-mobile/pull/11207): chore(deps): Bump `@metamask/base-controller` from `^6.0.0` to `^7.0.0` (#11207)
- [#11235](https://github.com/MetaMask/metamask-mobile/pull/11235): ci: avoid running release pipeline on every commit to the release branch (#11235)
- [#11094](https://github.com/MetaMask/metamask-mobile/pull/11094): chore: chore/7.31.0-Changelog (#11094)
- [#10788](https://github.com/MetaMask/metamask-mobile/pull/10788): chore: Add `@metamask/selected-network-controller` & integrate (#10788)
- [#11122](https://github.com/MetaMask/metamask-mobile/pull/11122): test: e2e for auto-lock (#11122)
- [#11143](https://github.com/MetaMask/metamask-mobile/pull/11143): chore: bump react native webview to 14.0.3 version (#11143)
- [#11284](https://github.com/MetaMask/metamask-mobile/pull/11284): chore: add notifications state awareness inapp badge (#11284)
- [#11209](https://github.com/MetaMask/metamask-mobile/pull/11209): chore(runway): cherry-pick fix: freeze during swap with approval (#11209)
- [#11157](https://github.com/MetaMask/metamask-mobile/pull/11157): chore(runway): cherry-pick chore: bump send for all the packages (#11157)
- [#11082](https://github.com/MetaMask/metamask-mobile/pull/11082): chore: bump network controller 20.0.0 (#11082)
- [#11095](https://github.com/MetaMask/metamask-mobile/pull/11095): chore(runway): cherry-pick fix: Intermittent Display Issue of Fiat Currency on Main Wallet View (#11095)
- [#11181](https://github.com/MetaMask/metamask-mobile/pull/11181): chore(runway): cherry-pick fix: fix check token balance is zero (#11181)
- [#11208](https://github.com/MetaMask/metamask-mobile/pull/11208): chore(runway): cherry-pick chore: update performance for new allocation (#11208)
- [#10821](https://github.com/MetaMask/metamask-mobile/pull/10821): chore(deps): bump `accounts-controller` to v18.1.0 and `keyring-api` to v8.1.0 (#10821)

### Fixed
- [#11117](https://github.com/MetaMask/metamask-mobile/pull/11117): fix: add feat flag (#11117)
- [#11084](https://github.com/MetaMask/metamask-mobile/pull/11084): fix: locks api spec version for api spec tests (#11084)
- [#11310](https://github.com/MetaMask/metamask-mobile/pull/11310): fix: quick fix on feature flag & notification state (#11310)
- [#11200](https://github.com/MetaMask/metamask-mobile/pull/11200): fix: add feature flag on profile sync (#11200)
- [#11302](https://github.com/MetaMask/metamask-mobile/pull/11302): fix: cp & resolve merge conflict (#11302)
- [#11130](https://github.com/MetaMask/metamask-mobile/pull/11130): fix(action): add a workaround for known bots (#11130)
- [#11173](https://github.com/MetaMask/metamask-mobile/pull/11173): fix: dset version (#11173)
- [#10899](https://github.com/MetaMask/metamask-mobile/pull/10899): fix: Android crash when svgs use the " html entity (#10899)
- [#11126](https://github.com/MetaMask/metamask-mobile/pull/11126): fix: Skip sonar cloud gate in step instead (#11126)
- [#11121](https://github.com/MetaMask/metamask-mobile/pull/11121): fix: Add new job to verify ""All jobs pass"" job for required PR check (#11121)
- [#11266](https://github.com/MetaMask/metamask-mobile/pull/11266): fix: notification permission flow (#11266)
- [#11252](https://github.com/MetaMask/metamask-mobile/pull/11252): fix: notification permission request message (#11252)
- [#11155](https://github.com/MetaMask/metamask-mobile/pull/11155): fix: android crashing on date formating Intl usage. (#11155)
- [#11137](https://github.com/MetaMask/metamask-mobile/pull/11137): fix: notifications bugs (#11137)
- [#11110](https://github.com/MetaMask/metamask-mobile/pull/11110): fix: accounts notifications switch (#11110)
- [#11146](https://github.com/MetaMask/metamask-mobile/pull/11146): fix: update nativesdk with improved concurrency handling (#11146)
- [#11165](https://github.com/MetaMask/metamask-mobile/pull/11165): fix: freeze during swap with approval (#11165)
- [#11161](https://github.com/MetaMask/metamask-mobile/pull/11161): fix: blockaid loader on confirmation pages (#11161)
- [#10989](https://github.com/MetaMask/metamask-mobile/pull/10989): fix: closing of gas info tooltip (#10989)
- [#10348](https://github.com/MetaMask/metamask-mobile/pull/10348): fix: confirmations UI adjustments (#10348)
- [#10842](https://github.com/MetaMask/metamask-mobile/pull/10842): fix: app crash due to minimal input must be string error (#10842)
- [#11112](https://github.com/MetaMask/metamask-mobile/pull/11112): fix: update token details monetization button (#11112)
- [#11172](https://github.com/MetaMask/metamask-mobile/pull/11172): fix: fix check token balance is zero (#11172)
- [#11087](https://github.com/MetaMask/metamask-mobile/pull/11087): fix: Intermittent Display Issue of Fiat Currency on Main Wallet View (#11087)
- [#11176](https://github.com/MetaMask/metamask-mobile/pull/11176): fix: switch from bundled to url EE (#11176)
- [#11281](https://github.com/MetaMask/metamask-mobile/pull/11281): fix: Fix the styling issue of link in SearchingForDeviceStep component (#11281)
- [#11265](https://github.com/MetaMask/metamask-mobile/pull/11265): fix: notification account syncing (#11265)
- [#11218](https://github.com/MetaMask/metamask-mobile/pull/11218): fix: close icon on notifications list screen (#11218)
- [#11193](https://github.com/MetaMask/metamask-mobile/pull/11193): fix: ItemMenu crash using dayjs (#11193)
- [#11098](https://github.com/MetaMask/metamask-mobile/pull/11098): fix: badge count and ui polishing (#11098)


## 7.31.0 - Sep 6, 2024
### Added
- [#10747](https://github.com/MetaMask/metamask-mobile/pull/10747): feat: 2805 grant permission to network with missmatching rpc url (#10747)
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ android {
applicationId "io.metamask"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1432
versionName "7.31.0"
versionCode 1444
versionName "7.32.0"
testBuildType System.getProperty('testBuildType', 'debug')
missingDimensionStrategy 'react-native-camera', 'general'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#!/usr/bin/env node
/* eslint-disable import/no-commonjs, import/no-nodejs-modules, import/no-nodejs-modules, no-console */
const fs = require('fs');
const path = require('path');
import fs from 'fs';
import path from 'path';

const ASSETS_FOLDER = 'assets';
const GENERATED_ASSETS_FILE = 'Icon.assets.ts';
const TYPES_FILE = 'Icon.types.ts';
const ASSET_EXT = '.svg';
const TYPES_CONTENT_TO_DETECT = '// DO NOT EDIT - Use generate-assets.js';

const getIconNameInTitleCase = (fileName) =>
const getIconNameInTitleCase = (fileName: string) =>
path
.basename(fileName, ASSET_EXT)
.split('-')
Expand Down
100 changes: 50 additions & 50 deletions app/components/Base/ListItem.js → app/components/Base/ListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View } from 'react-native';
import { fontStyles } from '../../styles/common';
import {
StyleSheet,
View,
ViewProps,
TextProps,
StyleProp,
ViewStyle,
TextStyle,
} from 'react-native';
import Text from './Text';
import { useTheme } from '../../util/theme';
import { Theme } from '@metamask/design-tokens';
import { fontStyles } from '../../styles/common';

const createStyles = (colors) =>
const createStyles = (colors: Theme['colors']) =>
StyleSheet.create({
wrapper: {
padding: 15,
Expand Down Expand Up @@ -54,53 +62,81 @@ const createStyles = (colors) =>
},
});

const ListItem = ({ style, ...props }) => {
interface ListItemProps extends ViewProps {
style?: StyleProp<ViewStyle>;
}

interface ListItemTextProps extends TextProps {
style?: StyleProp<TextStyle>;
}

type ListItemComponent = React.FC<ListItemProps> & {
Date: React.FC<ListItemTextProps>;
Content: React.FC<ListItemProps>;
Actions: React.FC<ListItemProps>;
Icon: React.FC<ListItemProps>;
Body: React.FC<ListItemProps>;
Title: React.FC<ListItemTextProps>;
Amounts: React.FC<ListItemProps>;
Amount: React.FC<ListItemTextProps>;
FiatAmount: React.FC<ListItemTextProps>;
};

const ListItem: ListItemComponent = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.wrapper, style]} {...props} />;
};

const ListItemDate = ({ style, ...props }) => {
const ListItemDate: React.FC<ListItemTextProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <Text style={[styles.date, style]} {...props} />;
};
const ListItemContent = ({ style, ...props }) => {

const ListItemContent: React.FC<ListItemProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.content, style]} {...props} />;
};
const ListItemActions = ({ style, ...props }) => {

const ListItemActions: React.FC<ListItemProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.actions, style]} {...props} />;
};
const ListItemIcon = ({ style, ...props }) => {

const ListItemIcon: React.FC<ListItemProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.icon, style]} {...props} />;
};
const ListItemBody = ({ style, ...props }) => {

const ListItemBody: React.FC<ListItemProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.body, style]} {...props} />;
};
const ListItemTitle = ({ style, ...props }) => {

const ListItemTitle: React.FC<ListItemTextProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <Text style={[styles.title, style]} {...props} />;
};
const ListItemAmounts = ({ style, ...props }) => {

const ListItemAmounts: React.FC<ListItemProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <View style={[styles.amounts, style]} {...props} />;
};
const ListItemAmount = ({ style, ...props }) => {

const ListItemAmount: React.FC<ListItemTextProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <Text style={[styles.amount, style]} {...props} />;
};
const ListItemFiatAmount = ({ style, ...props }) => {

const ListItemFiatAmount: React.FC<ListItemTextProps> = ({ style, ...props }) => {
const { colors } = useTheme();
const styles = createStyles(colors);
return <Text style={[styles.fiatAmount, style]} {...props} />;
Expand All @@ -117,39 +153,3 @@ ListItem.Amount = ListItemAmount;
ListItem.FiatAmount = ListItemFiatAmount;

export default ListItem;

/**
* Any other external style defined in props will be applied
*/
const stylePropType = PropTypes.oneOfType([PropTypes.object, PropTypes.array]);

ListItem.propTypes = {
style: stylePropType,
};
ListItemDate.propTypes = {
style: stylePropType,
};
ListItemContent.propTypes = {
style: stylePropType,
};
ListItemActions.propTypes = {
style: stylePropType,
};
ListItemIcon.propTypes = {
style: stylePropType,
};
ListItemBody.propTypes = {
style: stylePropType,
};
ListItemTitle.propTypes = {
style: stylePropType,
};
ListItemAmounts.propTypes = {
style: stylePropType,
};
ListItemAmount.propTypes = {
style: stylePropType,
};
ListItemFiatAmount.propTypes = {
style: stylePropType,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { ReactNode } from 'react';
import useModalHandler from './hooks/useModalHandler';

function ModalHandler({ children }) {
interface ModalHandlerProps {
children: ((props: {
isVisible: boolean;
toggleModal: () => void;
showModal: () => void;
hideModal: () => void;
}) => ReactNode);
}

function ModalHandler({ children }: ModalHandlerProps) {
const [isVisible, toggleModal, showModal, hideModal] = useModalHandler(false);

if (typeof children === 'function') {
Expand Down
2 changes: 1 addition & 1 deletion app/components/Base/RemoteImage/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: jest
.fn()
.mockImplementation(() => 'https://cloudflare-ipfs.com/ipfs/'),
.mockImplementation(() => 'https://gateway.pinata.cloud/ipfs/'),
}));

jest.mock('../../../components/hooks/useIpfsGateway', () => jest.fn());
Expand Down
4 changes: 2 additions & 2 deletions app/components/UI/AssetIcon/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const mockInitialState = {
...backgroundState,
PreferencesController: {
featureFlags: {},
ipfsGateway: 'https://cloudflare-ipfs.com/ipfs/',
ipfsGateway: 'https://gateway.pinata.cloud/ipfs/',
lostIdentities: {},
selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3',
useTokenDetection: true,
Expand All @@ -24,7 +24,7 @@ const mockInitialState = {
_W: {
featureFlags: {},
frequentRpcList: [],
ipfsGateway: 'https://cloudflare-ipfs.com/ipfs/',
ipfsGateway: 'https://gateway.pinata.cloud/ipfs/',
lostIdentities: {},
selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3',
useTokenDetection: true,
Expand Down
4 changes: 2 additions & 2 deletions app/components/UI/Swaps/components/TokenIcon.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('TokenIcon component', () => {
const icon = shallow(
<TokenIcon
symbol="DAI"
icon="https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
icon="https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
/>,
);
expect(icon).toMatchSnapshot();
Expand All @@ -27,7 +27,7 @@ describe('TokenIcon component', () => {
<TokenIcon
medium
symbol="DAI"
icon="https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
icon="https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
/>,
);
expect(iconMedium).toMatchSnapshot();
Expand Down
4 changes: 2 additions & 2 deletions app/components/UI/Swaps/components/TokenSelectButton.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ describe('TokenSelectButton component', () => {
<TokenSelectButton
label="Select a token"
symbol="DAI"
icon="https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
icon="https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
/>,
);
expect(icon).toMatchSnapshot();
const onPress = shallow(
<TokenSelectButton
label="Select a token"
symbol="DAI"
icon="https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
icon="https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ"
onPress={dummyHandler}
/>,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exports[`TokenIcon component should Render correctly 4`] = `
onError={[Function]}
source={
{
"uri": "https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ",
"uri": "https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ",
}
}
style={
Expand Down Expand Up @@ -146,7 +146,7 @@ exports[`TokenIcon component should Render correctly 8`] = `
onError={[Function]}
source={
{
"uri": "https://cloudflare-ipfs.com/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ",
"uri": "https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ",
}
}
style={
Expand Down
Loading

0 comments on commit 943936e

Please sign in to comment.