Skip to content

Commit

Permalink
Merge branch 'main' into brian/multichain-token-rates
Browse files Browse the repository at this point in the history
  • Loading branch information
bergeron authored Nov 15, 2024
2 parents eaeb2c7 + c5cdca9 commit 662797c
Show file tree
Hide file tree
Showing 54 changed files with 1,158 additions and 798 deletions.
27 changes: 27 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,33 @@ module.exports = {
'@metamask/design-tokens/color-no-hex': 'off',
},
},
{
files: [
'app/components/UI/Name/**/*.{js,ts,tsx}',
'app/components/hooks/DisplayName/**/*.{js,ts,tsx}'
],
rules: {
'no-restricted-syntax': [
'error',
{
selector: `ImportSpecifier[imported.name=/${[
'selectChainId',
'selectNetworkClientId',
'selectNetworkStatus',
'selectNickname',
'selectProviderConfig',
'selectProviderType',
'selectRpcUrl',
'selectSelectedNetworkClientId',
'selectTicker'
]
.map((method) => `(${method})`)
.join('|')}/]`,
message: 'Avoid using global network selectors in confirmations',
},
],
},
},
],

globals: {
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Current Main Branch

## 7.34.1 - Nov 8, 2024
### Fixed
- [#12205](https://github.com/MetaMask/metamask-mobile/pull/12205): fix: add contractBalances as dependency
- [#12236](https://github.com/MetaMask/metamask-mobile/pull/12236): fix: Add migration to fix NotificationServicesController bug (#12236)
- [#12228](https://github.com/MetaMask/metamask-mobile/pull/12228): fix: Update transaction-controller version

## 7.34.0 - Oct 28, 2024
### Added
- [#11578](https://github.com/MetaMask/metamask-mobile/pull/11578): feat: 1653 first feature flag poc (#11578)
Expand Down Expand Up @@ -101,7 +107,7 @@
### Fixed
- [#10952](https://github.com/MetaMask/metamask-mobile/pull/10952): refactor(ramp): update ramp copy (#10952)

## 7.33.2 - Oct 29, 2024
## 7.33.1 - Oct 29, 2024
### Fixed
- [#12073](https://github.com/MetaMask/metamask-mobile/pull/12073): feat: Simulation re-trigger (#12073)

Expand Down
46 changes: 19 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,36 @@ git clone git@github.com:MetaMask/metamask-mobile.git && \
cd metamask-mobile
```

### **Firebase Messaging Setup**
#### Firebase Messaging Setup

MetaMask uses Firebase Cloud Messaging (FCM) to enable app communications. To integrate FCM, you’ll need configuration files for both iOS and Android platforms.

#### **Configuration Files Required**
- **`GoogleService-Info.plist`** (iOS)
- **`google-services.json`** (Android)
##### Internal Contributor instructions

These files are essential for FCM integration and are automatically generated when running: `yarn start:ios` or `yarn start:android`
1. Grab the `.js.env` file from 1Password, ask around for the correct vault. This file contains the `GOOGLE_SERVICES_B64_ANDROID` and `GOOGLE_SERVICES_B64_IOS` secrets that will be used to generate the relevant configuration files for IOS/Android.
2. [Install](./README.md#install-dependencies) and [run & start](./README.md#running-the-app) the application as documented below.

**External Contributors**
##### External Contributor instructions

As an external contributor, you need to provide your own Firebase project configuration files:
- **`GoogleService-Info.plist`** (iOS)
- **`google-services.json`** (Android)

1. Create a Free Firebase Project
* Set up a Firebase project in the Firebase Console.
* Configure the project with a client package name matching `io.metamask`.
- Set up a Firebase project in the Firebase Console.
- Configure the project with a client package name matching `io.metamask` (IMPORTANT).
2. Add Configuration Files
* Update the `google-services.json` and `GoogleService-Info.plist` files in:
* `android/app` (for Android)
* `ios` directory (for iOS)

In case you don't have FCM account, you can reference the instructions below. These instructions will generate the required `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` environment variables found in: `.ios.env`, `.js.env`, `.android.env`. They can be locally generated from examples files.

**Internal Contributors**

As an internal contributor, you can access the shared Firebase project config file from 1Password. Ask around for the correct vault.

The values you should provide to `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` are the base64 encoded versions of the example Firebase project config files. These can also be generated locally:

**For Android**
- Create/Update the `google-services.json` and `GoogleService-Info.plist` files in:
- `android/app/google-services.json` (for Android)
- `ios/GoogleServices/GoogleService-Info.plist` directory (for iOS)
3. Create the correct base64 environments variables.

```bash
export GOOGLE_SERVICES_B64_ANDROID="$(base64 -w0 -i ./android/app/google-services-example.json)" && echo "export GOOGLE_SERVICES_B64_ANDROID=\"$GOOGLE_SERVICES_B64_ANDROID\"" | tee -a .js.env .ios.env
```
# Generate Android Base64 Version of Google Services
export GOOGLE_SERVICES_B64_ANDROID="$(base64 -w0 -i ./android/app/google-services.json)" && echo "export GOOGLE_SERVICES_B64_ANDROID=\"$GOOGLE_SERVICES_B64_ANDROID\"" | tee -a .js.env

**For iOS**
```bash
export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)" && echo "export GOOGLE_SERVICES_B64_IOS=\"$GOOGLE_SERVICES_B64_IOS\"" | tee -a .js.env .ios.env
# Generate IOS Base64 Version of Google Services
export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)" && echo "export GOOGLE_SERVICES_B64_IOS=\"$GOOGLE_SERVICES_B64_IOS\"" | tee -a .js.env
```

[!CAUTION]
Expand All @@ -85,7 +77,7 @@ export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleServi
In case of any doubt, please follow the instructions in the link below to get your Firebase project config file.
[Firebase Project Quickstart](https://firebaseopensource.com/projects/firebase/quickstart-js/messaging/readme/#getting_started)

**Install dependencies**
#### Install dependencies

```bash
yarn setup
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 1475
versionName "7.34.0"
versionCode 1482
versionName "7.34.1"
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
Expand Up @@ -35,6 +35,7 @@ const KeyValueRowLabel = ({ label, tooltip }: KeyValueRowLabelProps) => {
const onNavigateToTooltipModal = () => {
if (!hasTooltip) return;
openTooltipModal(tooltip.title, tooltip.content);
tooltip?.onPress?.();
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ interface KeyValueRowTooltip {
* @default TooltipSizes.Md
*/
size?: ButtonIconSizes;
/**
* Optional onPress handler
*/
onPress?: (...args: unknown[]) => unknown;
}

/**
Expand Down
339 changes: 275 additions & 64 deletions app/components/UI/Identicon/__snapshots__/index.test.tsx.snap

Large diffs are not rendered by default.

78 changes: 17 additions & 61 deletions app/components/UI/Identicon/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,33 @@
import React from 'react';
import { shallow } from 'enzyme';
import { render } from '@testing-library/react-native';
import Identicon from './';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import useTokenList from '../../../components/hooks/DisplayName/useTokenList';
import renderWithProvider from '../../../util/test/renderWithProvider';

jest.mock('../../../components/hooks/DisplayName/useTokenList');
const ADDRESS_MOCK = '0x123';
const URI_MOCK = 'https://example.com/image.png';

describe('Identicon', () => {
const mockStore = configureMockStore();
const mockUseTokenList = jest.mocked(useTokenList).mockImplementation(() => [
{
name: 'test',
symbol: 'test',
decimals: 123,
address: '0x123',
occurrences: 1,
aggregators: ['test'],
iconUrl: 'https://test',
},
]);

it('should render correctly when provided address found in tokenList and iconUrl is available', () => {
const addressMock = '0x0439e60f02a8900a951603950d8d4527f400c3f1';
mockUseTokenList.mockImplementation(() => [
{
name: 'test',
symbol: 'test',
decimals: 123,
address: addressMock,
iconUrl: 'https://example.com/icon.png',
occurrences: 1,
aggregators: ['test'],
it('renders Blockie from address', () => {
const wrapper = renderWithProvider(<Identicon address={ADDRESS_MOCK} />, {
state: {
settings: { useBlockieIcon: true },
},
]);

const initialState = {
settings: { useBlockieIcon: true },
};
const store = mockStore(initialState);
});

const wrapper = render(
<Provider store={store}>
<Identicon address={addressMock} />
</Provider>,
);
expect(wrapper).toMatchSnapshot();
});
it('should render correctly when useBlockieIcon is true', () => {
const initialState = {
settings: { useBlockieIcon: true },
};
const store = mockStore(initialState);

const wrapper = shallow(
<Provider store={store}>
<Identicon />
</Provider>,
);
it('renders Jazzicon', () => {
const wrapper = renderWithProvider(<Identicon address={ADDRESS_MOCK} />, {
state: {
settings: { useBlockieIcon: false },
},
});

expect(wrapper).toMatchSnapshot();
});
it('should render correctly when useBlockieIcon is false', () => {
const initialState = {
settings: { useBlockieIcon: false },
};
const store = mockStore(initialState);

const wrapper = shallow(
<Provider store={store}>
<Identicon />
</Provider>,
);
it('renders custom URI', () => {
const wrapper = renderWithProvider(<Identicon imageUri={URI_MOCK} />);
expect(wrapper).toMatchSnapshot();
});
});
47 changes: 17 additions & 30 deletions app/components/UI/Identicon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { Image, ImageStyle, View } from 'react-native';
import { toDataUrl } from '../../../util/blockies';
import FadeIn from 'react-native-fade-in-image';
import Jazzicon from 'react-native-jazzicon';
import { connect } from 'react-redux';
import { useTheme } from '../../../util/theme';
import { useTokenListEntry } from '../../../components/hooks/DisplayName/useTokenListEntry';
import { NameType } from '../../UI/Name/Name.types';
import { RootState } from '../../../reducers';
import { useSelector } from 'react-redux';

interface IdenticonProps {
/**
Expand All @@ -27,9 +26,10 @@ interface IdenticonProps {
*/
noFadeIn?: boolean;
/**
* Show a BlockieIcon instead of JazzIcon
* URI of the image to render
* Overrides the address if also provided
*/
useBlockieIcon?: boolean;
imageUri?: string;
}

/**
Expand All @@ -42,17 +42,14 @@ const Identicon: React.FC<IdenticonProps> = ({
address,
customStyle,
noFadeIn,
useBlockieIcon = true,
imageUri,
}) => {
const { colors } = useTheme();
const tokenListIcon = useTokenListEntry(
address || '',
NameType.EthereumAddress,
)?.iconUrl;

if (!address) return null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const useBlockieIcon = useSelector((state: RootState) => state.settings.useBlockieIcon) ?? true;

const uri = useBlockieIcon && toDataUrl(address);
if (!address && !imageUri) return null;

const styleForBlockieAndTokenIcon = [
{
Expand All @@ -63,17 +60,13 @@ const Identicon: React.FC<IdenticonProps> = ({
customStyle,
];

if (tokenListIcon) {
return (
<Image
source={{ uri: tokenListIcon }}
style={styleForBlockieAndTokenIcon}
/>
);
}

const image = useBlockieIcon ? (
<Image source={{ uri }} style={styleForBlockieAndTokenIcon} />
const image = imageUri ? (
<Image source={{ uri: imageUri }} style={styleForBlockieAndTokenIcon} />
) : useBlockieIcon ? (
<Image
source={{ uri: toDataUrl(address) }}
style={styleForBlockieAndTokenIcon}
/>
) : (
<View style={customStyle}>
<Jazzicon size={diameter} address={address} />
Expand All @@ -93,10 +86,4 @@ const Identicon: React.FC<IdenticonProps> = ({
);
};

// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mapStateToProps = (state: any) => ({
useBlockieIcon: state.settings.useBlockieIcon,
});

export default connect(mapStateToProps)(memo(Identicon));
export default memo(Identicon);
Loading

0 comments on commit 662797c

Please sign in to comment.