From c25338a5823052bcbd5726cb47776dc27bd8c341 Mon Sep 17 00:00:00 2001 From: Nicholas Smith Date: Wed, 29 Jan 2025 13:14:12 -0500 Subject: [PATCH 01/18] chore: re-add staking actions when not on supported chain and switch to mainnet (#13244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** 1. What is the reason for the change? We disabled the actions for staking when not on a supported staking chain. We now need to add these actions back after understanding how we can switch the network. 2. What is the improvement/solution? In the case that we are on an unsupported network, we switch to mainnet and then continue with the action ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/STAKE-924 ## **Manual testing steps** 1. Go to an unsupported staking network, i.e. linea mainnet 2. Click on the Mainnet ethereum asset or the staked ethereum asset to get to the eth asset detail page 3. Ensure you have ETH to unstake to test unstake 4. Ensure you have ETH to stake to test stake 5. Ensure you have a claim to test the claim, there should be one on the staking test account 6. Scroll down to test the Stake and Unstake actions, they should switch to mainnet and bring up the stake or unstake pages 7. Click on the claim button and it should switch to mainnet and bring up the claim transaction sheet 8. There should be no flow regressions ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/8faeaf31-0cf8-4d75-a5b6-6b60c5e3acd4 ### **After** https://github.com/user-attachments/assets/0a059ec0-f9c4-436a-97e6-c8815198c422 ## **Pre-merge author checklist** - [x] 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). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] 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. --- .../StakingBalance/StakingBalance.test.tsx | 33 ++-- .../StakingBalance/StakingBalance.tsx | 22 ++- .../ClaimBanner/ClaimBanner.test.tsx | 66 +++++++- .../ClaimBanner/ClaimBanner.tsx | 54 +++++-- .../StakingButtons/StakingButtons.test.tsx | 142 ++++++++++++++++++ .../StakingButtons/StakingButtons.tsx | 16 +- .../StakingBalance.test.tsx.snap | 10 +- 7 files changed, 309 insertions(+), 34 deletions(-) create mode 100644 app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.test.tsx diff --git a/app/components/UI/Stake/components/StakingBalance/StakingBalance.test.tsx b/app/components/UI/Stake/components/StakingBalance/StakingBalance.test.tsx index 347fc5780c7..667d5b0074b 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingBalance.test.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingBalance.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent } from '@testing-library/react-native'; +import { act, fireEvent } from '@testing-library/react-native'; import renderWithProvider from '../../../../../util/test/renderWithProvider'; import StakingBalance from './StakingBalance'; import { strings } from '../../../../../../locales/i18n'; @@ -15,6 +15,7 @@ import { backgroundState } from '../../../../../util/test/initial-root-state'; // eslint-disable-next-line import/no-namespace import * as networks from '../../../../../util/networks'; import { mockNetworkState } from '../../../../../util/test/network'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; const MOCK_ADDRESS_1 = '0x0'; @@ -142,13 +143,15 @@ describe('StakingBalance', () => { expect(toJSON()).toMatchSnapshot(); }); - it('redirects to StakeInputView on stake button click', () => { + it('redirects to StakeInputView on stake button click', async () => { const { getByText } = renderWithProvider( , { state: mockInitialState }, ); - fireEvent.press(getByText(strings('stake.stake_more'))); + await act(() => { + fireEvent.press(getByText(strings('stake.stake_more'))); + }); expect(mockNavigate).toHaveBeenCalledTimes(1); expect(mockNavigate).toHaveBeenCalledWith('StakeScreens', { @@ -156,13 +159,15 @@ describe('StakingBalance', () => { }); }); - it('redirects to UnstakeInputView on unstake button click', () => { + it('redirects to UnstakeInputView on unstake button click', async () => { const { getByText } = renderWithProvider( , { state: mockInitialState }, ); - fireEvent.press(getByText(strings('stake.unstake'))); + await act(() => { + fireEvent.press(getByText(strings('stake.unstake'))); + }); expect(mockNavigate).toHaveBeenCalledTimes(1); expect(mockNavigate).toHaveBeenCalledWith('StakeScreens', { @@ -178,10 +183,10 @@ describe('StakingBalance', () => { expect(queryByTestId('staking-balance-container')).toBeNull(); expect(queryByText(strings('stake.stake_more'))).toBeNull(); expect(queryByText(strings('stake.unstake'))).toBeNull(); - expect(queryByText(strings('stake.claim'))).toBeNull(); + expect(queryByText(`${strings('stake.claim')} ETH`)).toBeNull(); }); - it('should not render claim link or action buttons if asset.chainId is not selected chainId', () => { + it('should render claim link and action buttons if supported asset.chainId is not selected chainId', () => { const { queryByText, queryByTestId } = renderWithProvider( , { @@ -192,16 +197,22 @@ describe('StakingBalance', () => { backgroundState: { ...mockInitialState.engine.backgroundState, NetworkController: { - ...mockNetworkState({ chainId: '0x4268' }), + ...mockNetworkState({ + chainId: CHAIN_IDS.SEPOLIA, + id: 'sepolia', + nickname: 'Sepolia', + ticker: 'ETH', + }), }, }, }, }, }, ); + expect(queryByTestId('staking-balance-container')).toBeTruthy(); - expect(queryByText(strings('stake.stake_more'))).toBeNull(); - expect(queryByText(strings('stake.unstake'))).toBeNull(); - expect(queryByText(strings('stake.claim'))).toBeNull(); + expect(queryByText(strings('stake.stake_more'))).toBeTruthy(); + expect(queryByText(strings('stake.unstake'))).toBeTruthy(); + expect(queryByText(`${strings('stake.claim')} ETH`)).toBeTruthy(); }); }); diff --git a/app/components/UI/Stake/components/StakingBalance/StakingBalance.tsx b/app/components/UI/Stake/components/StakingBalance/StakingBalance.tsx index b5e307b970b..42bdc954291 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingBalance.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingBalance.tsx @@ -43,10 +43,11 @@ import { StakeSDKProvider } from '../../sdk/stakeSdkProvider'; import type { TokenI } from '../../../Tokens/types'; import useBalance from '../../hooks/useBalance'; import { NetworkBadgeSource } from '../../../AssetOverview/Balance/Balance'; -import { selectChainId } from '../../../../../selectors/networkController'; import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics'; import { EVENT_LOCATIONS, EVENT_PROVIDERS } from '../../constants/events'; +import NetworkAssetLogo from '../../../NetworkAssetLogo'; +import { isPortfolioViewEnabled } from '../../../../../util/networks'; export interface StakingBalanceProps { asset: TokenI; @@ -60,7 +61,6 @@ const StakingBalanceContent = ({ asset }: StakingBalanceProps) => { setHasSentViewingStakingRewardsMetric, ] = useState(false); - const chainId = useSelector(selectChainId); const networkName = useSelector(selectNetworkName); const { isEligible: isEligibleForPooledStaking } = useStakingEligibility(); @@ -132,9 +132,6 @@ const StakingBalanceContent = ({ asset }: StakingBalanceProps) => { } const renderStakingContent = () => { - if (chainId !== asset.chainId) { - return <>; - } if (isLoadingPooledStakesData) { return ( @@ -217,13 +214,24 @@ const StakingBalanceContent = ({ asset }: StakingBalanceProps) => { variant={BadgeVariant.Network} imageSource={NetworkBadgeSource( asset.chainId as Hex, - asset.ticker || asset.symbol, + asset.ticker ?? asset.symbol, )} name={networkName} /> } > - + {isPortfolioViewEnabled() ? ( + + ) : ( + + )} {strings('stake.staked_ethereum')} diff --git a/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.test.tsx b/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.test.tsx index bd15a568f15..0034606b5e1 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.test.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.test.tsx @@ -5,6 +5,10 @@ import { fireEvent } from '@testing-library/react-native'; import { createMockAccountsControllerState } from '../../../../../../../util/test/accountsControllerTestUtils'; import { backgroundState } from '../../../../../../../util/test/initial-root-state'; import { MOCK_POOL_STAKING_SDK } from '../../../../__mocks__/mockData'; +import { mockNetworkState } from '../../../../../../../util/test/network'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import Engine from '../../../../../../../core/Engine'; +import useStakingChain from '../../../../hooks/useStakingChain'; const MOCK_CLAIM_AMOUNT = '0.016'; const MOCK_ADDRESS_1 = '0x0123456789abcdef0123456789abcdef01234567'; @@ -14,7 +18,6 @@ const MOCK_ACCOUNTS_CONTROLLER_STATE = createMockAccountsControllerState([ ]); const mockInitialState = { - settings: {}, engine: { backgroundState: { ...backgroundState, @@ -23,11 +26,26 @@ const mockInitialState = { }, }; +jest.mock('../../../../../../../core/Engine', () => ({ + context: { + NetworkController: { + setActiveNetwork: jest.fn(), + }, + }, +})); + jest.mock('../../../../hooks/useStakeContext', () => ({ __esModule: true, useStakeContext: jest.fn(() => MOCK_POOL_STAKING_SDK), })); +jest.mock('../../../../hooks/useStakingChain', () => ({ + __esModule: true, + default: jest.fn(() => ({ + isStakingSupportedChain: true, + })), +})); + const mockAttemptPoolStakedClaimTransaction = jest.fn(); jest.mock('../../../../hooks/usePoolStakedClaim', () => ({ @@ -38,6 +56,13 @@ jest.mock('../../../../hooks/usePoolStakedClaim', () => ({ })); describe('ClaimBanner', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useStakingChain as jest.Mock).mockReturnValue({ + isStakingSupportedChain: true, + }); + }); + it('render matches snapshot', () => { const { toJSON } = renderWithProvider( , @@ -47,6 +72,42 @@ describe('ClaimBanner', () => { expect(toJSON()).toMatchSnapshot(); }); + it('claim button switches to mainnet on press if on unsupported chain', async () => { + (useStakingChain as jest.Mock).mockReturnValue({ + isStakingSupportedChain: false, + }); + const { getByTestId } = renderWithProvider( + , + { + state: { + ...mockInitialState, + engine: { + ...mockInitialState.engine, + backgroundState: { + ...mockInitialState.engine.backgroundState, + NetworkController: { + ...mockNetworkState({ + chainId: CHAIN_IDS.SEPOLIA, + id: 'sepolia', + nickname: 'Sepolia', + ticker: 'ETH', + }), + }, + }, + }, + }, + }, + ); + + const claimButton = getByTestId('claim-banner-claim-eth-button'); + + fireEvent.press(claimButton); + + expect( + Engine.context.NetworkController.setActiveNetwork, + ).toHaveBeenCalledWith('mainnet'); + }); + it('claim button is disabled on subsequent presses', async () => { const { getByTestId } = renderWithProvider( , @@ -58,6 +119,9 @@ describe('ClaimBanner', () => { fireEvent.press(claimButton); expect(claimButton.props.disabled).toBe(true); + expect( + Engine.context.NetworkController.setActiveNetwork, + ).not.toHaveBeenCalled(); expect(mockAttemptPoolStakedClaimTransaction).toHaveBeenCalledTimes(1); }); }); diff --git a/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.tsx b/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.tsx index e99f93880c0..7273be71609 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import Banner, { BannerAlertSeverity, BannerVariant, @@ -18,12 +18,16 @@ import usePoolStakedClaim from '../../../../hooks/usePoolStakedClaim'; import { useSelector } from 'react-redux'; import { selectSelectedInternalAccount } from '../../../../../../../selectors/accountsController'; import usePooledStakes from '../../../../hooks/usePooledStakes'; -import Engine from '../../../../../../../core/Engine'; import { MetaMetricsEvents, useMetrics, } from '../../../../../../hooks/useMetrics'; import { EVENT_LOCATIONS } from '../../../../constants/events'; +import Engine from '../../../../../../../core/Engine'; +import useStakingChain from '../../../../hooks/useStakingChain'; +import { useStakeContext } from '../../../../hooks/useStakeContext'; +import { selectChainId } from '../../../../../../../selectors/networkController'; +import { hexToNumber } from '@metamask/utils'; type StakeBannerProps = Pick & { claimableAmount: string; @@ -32,17 +36,18 @@ type StakeBannerProps = Pick & { const ClaimBanner = ({ claimableAmount, style }: StakeBannerProps) => { const { styles } = useStyles(styleSheet, {}); const { trackEvent, createEventBuilder } = useMetrics(); - const [isSubmittingClaimTransaction, setIsSubmittingClaimTransaction] = useState(false); - + const { NetworkController } = Engine.context; const activeAccount = useSelector(selectSelectedInternalAccount); - + const [shouldAttemptClaim, setShouldAttemptClaim] = useState(false); const { attemptPoolStakedClaimTransaction } = usePoolStakedClaim(); - + const { stakingContract } = useStakeContext(); const { pooledStakesData, refreshPooledStakes } = usePooledStakes(); + const chainId = useSelector(selectChainId); + const { isStakingSupportedChain } = useStakingChain(); - const onClaimPress = async () => { + const attemptClaim = useCallback(async () => { try { if (!activeAccount?.address) return; @@ -90,6 +95,37 @@ const ClaimBanner = ({ claimableAmount, style }: StakeBannerProps) => { } catch (e) { setIsSubmittingClaimTransaction(false); } + }, [ + activeAccount, + pooledStakesData, + attemptPoolStakedClaimTransaction, + createEventBuilder, + trackEvent, + refreshPooledStakes, + ]); + + useEffect(() => { + if ( + shouldAttemptClaim && + isStakingSupportedChain && + Number(stakingContract?.chainId) === hexToNumber(chainId) + ) { + setShouldAttemptClaim(false); + attemptClaim(); + } + }, [ + shouldAttemptClaim, + isStakingSupportedChain, + stakingContract, + chainId, + attemptClaim, + ]); + + const onClaimPress = async () => { + setShouldAttemptClaim(true); + if (!isStakingSupportedChain) { + await NetworkController.setActiveNetwork('mainnet'); + } }; return ( @@ -117,8 +153,8 @@ const ClaimBanner = ({ claimableAmount, style }: StakeBannerProps) => { } onPress={onClaimPress} - disabled={isSubmittingClaimTransaction} - loading={isSubmittingClaimTransaction} + disabled={shouldAttemptClaim || isSubmittingClaimTransaction} + loading={shouldAttemptClaim || isSubmittingClaimTransaction} /> } diff --git a/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.test.tsx b/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.test.tsx new file mode 100644 index 00000000000..c7e5e0e9184 --- /dev/null +++ b/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.test.tsx @@ -0,0 +1,142 @@ +// write tests for StakingButtons.tsx +import React from 'react'; +import StakingButtons from './StakingButtons'; +import renderWithProvider from '../../../../../../util/test/renderWithProvider'; +import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../../../../util/test/accountsControllerTestUtils'; +import { backgroundState } from '../../../../../../util/test/initial-root-state'; +import { act, fireEvent } from '@testing-library/react-native'; +import Engine from '../../../../../../core/Engine'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { mockNetworkState } from '../../../../../../util/test/network'; +import Routes from '../../../../../../constants/navigation/Routes'; +import useStakingChain from '../../../hooks/useStakingChain'; +import { + useNavigation, + NavigationProp, + ParamListBase, +} from '@react-navigation/native'; + +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigation: jest.fn(), +})); + +jest.mock('../../../../../../core/Engine', () => ({ + context: { + NetworkController: { + setActiveNetwork: jest.fn(), + }, + }, +})); + +jest.mock('../../../hooks/useStakingChain', () => ({ + __esModule: true, + default: jest.fn(() => ({ + isStakingSupportedChain: true, + })), +})); + +const mockInitialState = { + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + }, + }, +}; + +const mockSepoliaNetworkState = { + ...mockInitialState, + engine: { + ...mockInitialState.engine, + backgroundState: { + ...mockInitialState.engine.backgroundState, + NetworkController: { + ...mockNetworkState({ + chainId: CHAIN_IDS.SEPOLIA, + id: 'sepolia', + nickname: 'Sepolia', + ticker: 'ETH', + }), + }, + }, + }, +}; + +describe('StakingButtons', () => { + const navigate: jest.Mock = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + ( + useNavigation as jest.MockedFunction + ).mockReturnValue({ + navigate, + setOptions: jest.fn(), + dispatch: jest.fn(), + } as unknown as NavigationProp); + }); + + it('should render the stake and unstake buttons', () => { + const props = { + style: {}, + hasStakedPositions: true, + hasEthToUnstake: true, + }; + const { getByText } = renderWithProvider(, { + state: mockInitialState, + }); + expect(getByText('Unstake')).toBeDefined(); + expect(getByText('Stake more')).toBeDefined(); + }); + + it('should switch to mainnet if the chain is not supported on press of stake button', async () => { + (useStakingChain as jest.Mock).mockReturnValue({ + isStakingSupportedChain: false, + }); + const props = { + style: {}, + hasStakedPositions: true, + hasEthToUnstake: true, + }; + const { getByText } = renderWithProvider(, { + state: mockSepoliaNetworkState, + }); + + await act(async () => { + fireEvent.press(getByText('Stake more')); + }); + + expect( + Engine.context.NetworkController.setActiveNetwork, + ).toHaveBeenCalledWith('mainnet'); + expect(navigate).toHaveBeenCalledWith('StakeScreens', { + screen: Routes.STAKING.STAKE, + }); + }); + + it('should switch to mainnet if the chain is not supported on press of unstake button', async () => { + (useStakingChain as jest.Mock).mockReturnValue({ + isStakingSupportedChain: false, + }); + const props = { + style: {}, + hasStakedPositions: true, + hasEthToUnstake: true, + }; + const { getByText } = renderWithProvider(, { + state: mockSepoliaNetworkState, + }); + + await act(async () => { + fireEvent.press(getByText('Unstake')); + }); + + expect( + Engine.context.NetworkController.setActiveNetwork, + ).toHaveBeenCalledWith('mainnet'); + expect(navigate).toHaveBeenCalledWith('StakeScreens', { + screen: Routes.STAKING.UNSTAKE, + }); + }); +}); diff --git a/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.tsx b/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.tsx index a87ea82fc06..a63d22b40ed 100644 --- a/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.tsx +++ b/app/components/UI/Stake/components/StakingBalance/StakingButtons/StakingButtons.tsx @@ -12,6 +12,8 @@ import { useMetrics, MetaMetricsEvents } from '../../../../../hooks/useMetrics'; import { useSelector } from 'react-redux'; import { selectChainId } from '../../../../../../selectors/networkController'; import { EVENT_LOCATIONS } from '../../../constants/events'; +import useStakingChain from '../../../hooks/useStakingChain'; +import Engine from '../../../../../../core/Engine'; interface StakingButtonsProps extends Pick { hasStakedPositions: boolean; @@ -27,8 +29,17 @@ const StakingButtons = ({ const { styles } = useStyles(styleSheet, {}); const { trackEvent, createEventBuilder } = useMetrics(); const chainId = useSelector(selectChainId); + const { isStakingSupportedChain } = useStakingChain(); + const { NetworkController } = Engine.context; - const onUnstakePress = () => { + const handleIsStakingSupportedChain = async () => { + if (!isStakingSupportedChain) { + await NetworkController.setActiveNetwork('mainnet'); + } + }; + + const onUnstakePress = async () => { + await handleIsStakingSupportedChain(); navigate('StakeScreens', { screen: Routes.STAKING.UNSTAKE, }); @@ -44,7 +55,8 @@ const StakingButtons = ({ ); }; - const onStakePress = () => { + const onStakePress = async () => { + await handleIsStakingSupportedChain(); navigate('StakeScreens', { screen: Routes.STAKING.STAKE }); trackEvent( createEventBuilder(MetaMetricsEvents.STAKE_BUTTON_CLICKED) diff --git a/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap b/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap index 439744862da..a3a8efd1247 100644 --- a/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap +++ b/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap @@ -49,8 +49,8 @@ exports[`StakingBalance render matches snapshot 1`] = ` "width": 24, }, undefined, - undefined, - undefined, + false, + false, { "borderRadius": 16, "height": 32, @@ -59,6 +59,7 @@ exports[`StakingBalance render matches snapshot 1`] = ` }, ] } + testID="staking-balance-asset-logo" /> Date: Wed, 29 Jan 2025 13:20:16 -0500 Subject: [PATCH 02/18] fix: Add fallback for undefined case when destructuring `isUpdatedAfterSecurityCheck` (#13090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - Resolves Sentry error with 131k occurrence count: https://metamask.sentry.io/issues/6032066305/?project=2299799&query=is%3Aunresolved&referrer=issue-stream&sort=freq&statsPeriod=30d&stream_index=15 ## **Related issues** - See https://github.com/MetaMask/MetaMask-planning/issues/3861#:~:text=131K%20errors%20Cannot%20read%20property%20%27isUpdatedAfterSecurityCheck%27%20of%20undefined%20%2D%20Appears%20to%20require%20simple%20fix%20along%20these%20lines%20in%20two%20files%3A ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **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. --- app/components/Views/confirmations/Approval/index.js | 2 +- app/components/Views/confirmations/ApproveView/Approve/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/Views/confirmations/Approval/index.js b/app/components/Views/confirmations/Approval/index.js index de7ac36c521..728720ac2de 100644 --- a/app/components/Views/confirmations/Approval/index.js +++ b/app/components/Views/confirmations/Approval/index.js @@ -502,7 +502,7 @@ class Approval extends PureComponent { transactions, chainId, shouldUseSmartTransaction, - simulationData: { isUpdatedAfterSecurityCheck }, + simulationData: { isUpdatedAfterSecurityCheck } = {}, navigation, } = this.props; let { transaction } = this.props; diff --git a/app/components/Views/confirmations/ApproveView/Approve/index.js b/app/components/Views/confirmations/ApproveView/Approve/index.js index 0b5346e9e4f..a4f89237f96 100644 --- a/app/components/Views/confirmations/ApproveView/Approve/index.js +++ b/app/components/Views/confirmations/ApproveView/Approve/index.js @@ -511,7 +511,7 @@ class Approve extends PureComponent { metrics, chainId, shouldUseSmartTransaction, - simulationData: { isUpdatedAfterSecurityCheck }, + simulationData: { isUpdatedAfterSecurityCheck } = {}, navigation, } = this.props; const { From 17a494675e0a26626177c3a71668fd9fb6b62698 Mon Sep 17 00:00:00 2001 From: sethkfman <10342624+sethkfman@users.noreply.github.com> Date: Wed, 29 Jan 2025 12:42:57 -0700 Subject: [PATCH 03/18] chore: stable sync with main v7.38.1 (#13243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Changes: sync with stable branch ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **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: metamaskbot --- CHANGELOG.md | 4 ++++ android/app/build.gradle | 4 ++-- bitrise.yml | 8 ++++---- ios/MetaMask.xcodeproj/project.pbxproj | 24 ++++++++++++------------ package.json | 2 +- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a753df77c4..72d22fc056d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Current Main Branch +## 7.38.1 - Jan 21, 2024 +### Fixed +- [#13067](https://github.com/MetaMask/metamask-mobile/pull/13067)fix: remove expo changes (#13067) + ## 7.38.0 - Jan 16, 2024 ### Added - [#12427](https://github.com/MetaMask/metamask-mobile/pull/12427): feat: implement remote feature flag controller (#12427) diff --git a/android/app/build.gradle b/android/app/build.gradle index d934382fa02..1b061a18713 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -178,8 +178,8 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionName "7.38.0" - versionCode 1528 + versionName "7.38.1" + versionCode 1533 testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/bitrise.yml b/bitrise.yml index e6140887ecd..184080590e5 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -1800,16 +1800,16 @@ app: PROJECT_LOCATION_IOS: ios - opts: is_expand: false - VERSION_NAME: 7.38.0 + VERSION_NAME: 7.38.1 - opts: is_expand: false - VERSION_NUMBER: 1528 + VERSION_NUMBER: 1533 - opts: is_expand: false - FLASK_VERSION_NAME: 7.38.0 + FLASK_VERSION_NAME: 7.38.1 - opts: is_expand: false - FLASK_VERSION_NUMBER: 1528 + FLASK_VERSION_NUMBER: 1533 - opts: is_expand: false ANDROID_APK_LINK: '' diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 9d6d5f7417e..b1a20a50286 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -1380,7 +1380,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1418,7 +1418,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1449,7 +1449,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1484,7 +1484,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1514,7 +1514,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1551,7 +1551,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1580,7 +1580,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1615,7 +1615,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1739,7 +1739,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1776,7 +1776,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "$(inherited)", @@ -1808,7 +1808,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1528; + CURRENT_PROJECT_VERSION = 1533; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1843,7 +1843,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.38.0; + MARKETING_VERSION = 7.38.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", diff --git a/package.json b/package.json index d48df88919c..775179d4c33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask", - "version": "7.38.0", + "version": "7.38.1", "private": true, "scripts": { "audit:ci": "./scripts/yarn-audit.sh", From de7142049735275ebc90e5769b6f48e99d6fc5e9 Mon Sep 17 00:00:00 2001 From: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:17:37 -0330 Subject: [PATCH 04/18] New Crowdin translations by Github Action (#12690) Co-authored-by: metamaskbot --- locales/languages/de.json | 43 +++++++++++++++++++++++++++------ locales/languages/el.json | 43 +++++++++++++++++++++++++++------ locales/languages/es.json | 43 +++++++++++++++++++++++++++------ locales/languages/fr.json | 41 ++++++++++++++++++++++++++----- locales/languages/hi.json | 41 ++++++++++++++++++++++++++----- locales/languages/id.json | 41 ++++++++++++++++++++++++++----- locales/languages/ja.json | 41 ++++++++++++++++++++++++++----- locales/languages/ko.json | 43 +++++++++++++++++++++++++++------ locales/languages/pt.json | 43 +++++++++++++++++++++++++++------ locales/languages/ru.json | 41 ++++++++++++++++++++++++++----- locales/languages/tl.json | 51 ++++++++++++++++++++++++++++++--------- locales/languages/tr.json | 41 ++++++++++++++++++++++++++----- locales/languages/vi.json | 41 ++++++++++++++++++++++++++----- locales/languages/zh.json | 41 ++++++++++++++++++++++++++----- 14 files changed, 500 insertions(+), 94 deletions(-) diff --git a/locales/languages/de.json b/locales/languages/de.json index 1b4e9588e65..392794e54fe 100644 --- a/locales/languages/de.json +++ b/locales/languages/de.json @@ -48,7 +48,10 @@ "connector": "bei" }, "autocomplete": { - "placeholder": "Suchen oder URL eingeben" + "placeholder": "", + "recents": "Aktuelle", + "favorites": "Favoriten", + "sites": "Websites" }, "navigation": { "back": "Zurück", @@ -449,6 +452,7 @@ "next": "Weiter", "buy_asset": "{{asset}} kaufen", "no_tokens": "Sie haben keine Tokens!", + "show_tokens_without_balance": "Tokens ohne Guthaben anzeigen", "no_nfts_yet": "Noch keine NFTs", "nfts_autodetection_title": "NFT-Erkennung", "nfts_autodetection_desc": "Lassen Sie zu, dass MetaMask NFTs automatisch in Ihrer Wallet erkennt und anzeigt.", @@ -470,7 +474,7 @@ "learn_more": "Mehr erfahren", "add_collectibles": "NFTs importieren", "no_transactions": "Sie haben keine Transaktionen!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Wechseln Sie bitte das Netzwerk, um Transaktionen anzuzeigen", "send_button": "Senden", "deposit_button": "Einzahlen", "copy_address": "Kopieren", @@ -566,7 +570,7 @@ "description_content_1": "Wir würden gerne grundlegende Nutzungsdaten sammeln, um MetaMask zu verbessern. Sie sollten wissen, dass wir die Daten, die Sie uns hier zur Verfügung stellen, niemals verkaufen.", "description_content_2": "Wenn wir Metriken sammeln, wird es immer wie folgt sein ...", "description_content_3": "Erfahren Sie, wie wir Ihre Privatsphäre schützen, während wir Nutzungsdaten für Ihr Profil sammeln.", - "checkbox": "Wir verwenden diese Daten, um zu erfahren, wie Sie mit unserer Marketingkommunikation umgehen. Wir können relevante Neuigkeiten (wie Produktmerkmale) teilen.", + "checkbox": "Wir verwenden diese Daten, um zu erfahren, wie Sie mit unserer Marketingkommunikation interagieren. Wir können relevante Neuigkeiten (wie Produktmerkmale) teilen.", "action_description_1_prefix": "Privat:", "action_description_2_prefix": "Allgemein:", "action_description_3_prefix": "Optional:", @@ -722,6 +726,7 @@ "connected_and_active": "verbunden und aktiv.", "now_active": "jetzt aktiv.", "network_added": "wurde erfolgreich hinzugefügt", + "network_removed": "wurde erfolgreich entfernt", "network_deleted": "wurde erfolgreich gelöscht", "network_permissions_updated": "Netzwerkgenehmigungen aktualisiert", "revoked": "widerrufen.", @@ -1264,16 +1269,19 @@ "sell_button": "Verkaufen", "receive_button": "Empfangen", "portfolio_button": "Portfolio", + "earn_button": "Verdienen", "add_collectible_button": "Hinzufügen", "info": "Info", "swap": "Swap", "bridge": "Bridge", + "earn": "Verdienen", "disabled_button": { "buy": "Kaufen wird für dieses Konto nicht unterstützt", "sell": "Verkaufen wird für dieses Konto nicht unterstützt", "swap": "Swapping wird für dieses Konto nicht unterstützt", "bridge": "Bridging wird für dieses Konto nicht unterstützt", "send": "Senden wird für dieses Konto nicht unterstützt", + "earn": "Verdienen wird für dieses Konto nicht unterstützt", "action": "Diese Aktion wird für dieses Konto nicht unterstützt" }, "description": "Beschreibung", @@ -1290,6 +1298,7 @@ "bridge_description": "Tokens zwischen Netzwerken übertragen", "send_description": "Krypto an ein beliebiges Konto senden", "receive_description": "Krypto empfangen", + "earn_description": "Verdienen Sie Belohnungen für Ihre Tokens", "chart_time_period": { "1d": "Heute", "7d": "Die letzten 7 Tage", @@ -1791,6 +1800,7 @@ "network_chain_id": "Chain-ID", "network_rpc_url": "Netzwerk-URL", "network_rpc_url_label": "Netzwerk-RPC-URL", + "network_rpc_url_warning_punycode": "Angreifer imitieren gelegentlich Websites, indem sie kleine Änderungen an der Adresse der Website vornehmen. Vergewissern Sie sich, dass Sie mit der angestrebten Netzwerk-URL interagieren, bevor Sie fortfahren. Punycode-Version:", "new_default_network_url": "Neue Standard-Netzwerk-URL", "current_label": "Aktuell", "new_label": "Neu", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Hardware-Wallet hinzufügen", "import_account": "Konto importieren", "add_bitcoin_account_testnet": "Ein neues Bitcoin-Konto hinzufügen (Testnet)", - "add_bitcoin_account_mainnet": "Ein neues Bitcoin-Konto hinzufügen (Beta)" + "add_bitcoin_account_mainnet": "Ein neues Bitcoin-Konto hinzufügen (Beta)", + "add_solana_account": "Ein neues Solana-Konto hinzufügen (Beta)" }, "show_nft": { "show_nft_title": "NFT anzeigen", @@ -3571,18 +3582,36 @@ "title": { "signature": "Signaturanfrage" }, + "sub_title": { + "signature": "Überprüfen Sie vor der Bestätigung die Details der Anfrage." + }, "request_from": "Anfrage von", "message": "Nachricht", + "primary_type": "Primäre Art", "personal_sign_tooltip": "Diese Website ersucht um Ihre Signatur", "details": "Details", "account": "Konto", "balance": "Kontostand", "network": "Netzwerk", "simulation": { - "title": "Geschätzte Änderungen", + "decoded_tooltip_bid_nft": "Der NFT wird in Ihrer Wallet angezeigt, sobald das Gebot akzeptiert wird.", + "decoded_tooltip_list_nft": "Änderungen sind nur zu erwarten, wenn jemand Ihre NFTs kauft.", + "info_permit": "Sie erteilen dem Spender die Genehmigung, diese Menge an Tokens von Ihrem Konto auszugeben.", + "label_change_type_bidding": "Sie bieten", + "label_change_type_listing": "Sie listen auf", + "label_change_type_nft_listing": "Listenpreis", + "label_change_type_permit": "Ausgabenobergrenze", + "label_change_type_permit_nft": "Auszahlen", + "label_change_type_receive": "Sie empfangen", + "label_change_type_revoke": "Widerrufen", + "label_change_type_transfer": "Sie senden", "personal_sign_info": "Sie melden sich bei einer Website an und es sind keine Änderungen an Ihrem Konto vorgesehen.", - "tooltip": "Die geschätzten Änderungen beziehen sich auf das, was passieren könnte, wenn Sie diese Transaktion durchführen. Es handelt sich hierbei lediglich um eine Prognose, nicht um eine Garantie." - } + "title": "Geschätzte Änderungen", + "tooltip": "Die geschätzten Änderungen beziehen sich auf das, was passieren könnte, wenn Sie diese Transaktion durchführen. Es handelt sich hierbei lediglich um eine Prognose, nicht um eine Garantie.", + "unavailable": "Nicht verfügbar" + }, + "unlimited": "Unbegrenzt", + "none": "None" }, "change_in_simulation_modal": { "title": "Ergebnisse haben sich geändert", diff --git a/locales/languages/el.json b/locales/languages/el.json index f9ad9ac0de3..b288c62b768 100644 --- a/locales/languages/el.json +++ b/locales/languages/el.json @@ -48,7 +48,10 @@ "connector": "σε" }, "autocomplete": { - "placeholder": "Αναζητήστε ή πληκτρολογήστε μια διεύθυνση URL" + "placeholder": "Αναζήτηση ανά ιστότοπο ή διεύθυνση", + "recents": "Πρόσφατα", + "favorites": "Αγαπημένα", + "sites": "Ιστότοποι" }, "navigation": { "back": "Πίσω", @@ -449,6 +452,7 @@ "next": "Επόμενο", "buy_asset": "Αγοράστε {{asset}}", "no_tokens": "Δεν έχετε καθόλου tokens!", + "show_tokens_without_balance": "Εμφάνιση token χωρίς υπόλοιπο", "no_nfts_yet": "Δεν έχετε ακόμη NFT", "nfts_autodetection_title": "Εντοπισμός NFT", "nfts_autodetection_desc": "Επιτρέψτε στο MetaMask να ανιχνεύσει και να εμφανίσει αυτόματα τα NFT στο πορτοφόλι σας.", @@ -470,7 +474,7 @@ "learn_more": "Μάθετε περισσότερα", "add_collectibles": "Εισαγωγή NFT", "no_transactions": "Δεν έχετε συναλλαγές!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Παρακαλούμε αλλάξτε δίκτυο για να δείτε τις συναλλαγές", "send_button": "Αποστολή", "deposit_button": "Κατάθεση", "copy_address": "Αντιγραφή", @@ -566,7 +570,7 @@ "description_content_1": "Θέλουμε να συλλέξουμε βασικά δεδομένα χρήσης για να βελτιώσουμε το MetaMask. Λάβετε υπόψη ότι δεν πουλάμε ποτέ τα δεδομένα που μας παρέχετε εδώ.", "description_content_2": "Όταν συγκεντρώνουμε μετρήσεις, θα είναι πάντα...", "description_content_3": "Μάθετε πώς προστατεύουμε το απόρρητό σας ενώ συλλέγουμε δεδομένα χρήσης από το προφίλ σας.", - "checkbox": "Θα χρησιμοποιήσουμε αυτά τα δεδομένα για να μάθουμε πώς αλληλεπιδράτε με τις επικοινωνίες μάρκετινγκ. Ενδέχεται να κοινοποιήσουμε σχετικές ειδήσεις (όπως χαρακτηριστικά προϊόντων).", + "checkbox": "Θα χρησιμοποιήσουμε αυτά τα δεδομένα για να μάθουμε πώς αλληλεπιδράτε με τις διαφημιστικές επικοινωνίες μας. Ενδέχεται να κοινοποιήσουμε σχετικές ειδήσεις (όπως χαρακτηριστικά προϊόντων).", "action_description_1_prefix": "Ιδιωτικές:", "action_description_2_prefix": "Γενικές:", "action_description_3_prefix": "Προαιρετικές:", @@ -722,6 +726,7 @@ "connected_and_active": "συνδεδεμένοι και ενεργοί.", "now_active": "τώρα ενεργοί.", "network_added": "προστέθηκε με επιτυχία", + "network_removed": "αφαιρέθηκε με επιτυχία", "network_deleted": "διαγράφηκε με επιτυχία", "network_permissions_updated": "Ενημερωμένες άδειες χρήσης δικτύων", "revoked": "ανακλήθηκαν.", @@ -1264,16 +1269,19 @@ "sell_button": "Πώληση", "receive_button": "Λήψη", "portfolio_button": "Χαρτοφυλάκιο", + "earn_button": "Κερδίστε", "add_collectible_button": "Προσθήκη", "info": "Πληροφορίες", "swap": "Ανταλλαγή", "bridge": "Διασύνδεση", + "earn": "Κερδίστε", "disabled_button": { "buy": "Η αγορά δεν υποστηρίζεται για αυτόν τον λογαριασμό", "sell": "Η πώληση δεν υποστηρίζεται για αυτόν τον λογαριασμό", "swap": "Η ανταλλαγή δεν υποστηρίζεται για αυτόν τον λογαριασμό", "bridge": "Η διασύνδεση δεν υποστηρίζεται για αυτόν τον λογαριασμό", "send": "Η αποστολή δεν υποστηρίζεται για αυτόν τον λογαριασμό", + "earn": "Μη υποστήριξη των κερδών για αυτόν τον λογαριασμό", "action": "Αυτή η ενέργεια δεν υποστηρίζεται για αυτόν τον λογαριασμό" }, "description": "Περιγραφή", @@ -1290,6 +1298,7 @@ "bridge_description": "Μεταφορά token μεταξύ δικτύων", "send_description": "Στείλτε κρυπτονομίσματα σε οποιονδήποτε λογαριασμό", "receive_description": "Λάβετε κρυπτονομίσματα", + "earn_description": "Κερδίστε ανταμοιβές για τα token σας", "chart_time_period": { "1d": "Σήμερα", "7d": "Προηγούμενες 7 ημέρες", @@ -1791,6 +1800,7 @@ "network_chain_id": "Αναγνωριστικό Αλυσίδας", "network_rpc_url": "Διεύθυνση URL του Δικτύου", "network_rpc_url_label": "Διεύθυνση URL του δικτύου RPC", + "network_rpc_url_warning_punycode": "Οι δράστες μερικές φορές αντιγράφουν τους ιστότοπους κάνοντας μικρές αλλαγές στη διεύθυνση του ιστότοπου. Βεβαιωθείτε ότι αλληλεπιδράτε με την προβλεπόμενη διεύθυνση URL του δικτύου πριν συνεχίσετε. Έκδοση Punycode:", "new_default_network_url": "Νέα προεπιλεγμένη διεύθυνση URL δικτύου", "current_label": "Τρέχουσα", "new_label": "Νέα", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Προσθήκη πορτοφολιού υλικού", "import_account": "Εισαγωγή λογαριασμού", "add_bitcoin_account_testnet": "Προσθήκη νέου λογαριασμού Bitcoin (Testnet)", - "add_bitcoin_account_mainnet": "Προσθήκη νέου λογαριασμού Bitcoin (Beta)" + "add_bitcoin_account_mainnet": "Προσθήκη νέου λογαριασμού Bitcoin (Beta)", + "add_solana_account": "Προσθήκη νέου λογαριασμού Solana (Beta)" }, "show_nft": { "show_nft_title": "Εμφάνιση των NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Αίτημα υπογραφής" }, + "sub_title": { + "signature": "Ελέγξτε τις λεπτομέρειες του αιτήματος πριν επιβεβαιώσετε." + }, "request_from": "Ζητήθηκε από", "message": "Μήνυμα", + "primary_type": "Πρωτεύων τύπος", "personal_sign_tooltip": "Αυτός ο ιστότοπος ζητάει την υπογραφή σας", "details": "Λεπτομέρειες", "account": "Λογαριασμός", "balance": "Υπόλοιπο", "network": "Δίκτυο", "simulation": { - "title": "Εκτιμώμενες αλλαγές", + "decoded_tooltip_bid_nft": "Το NFT θα εμφανιστεί στο πορτοφόλι σας, όταν η προσφορά γίνει αποδεκτή.", + "decoded_tooltip_list_nft": "Αναμένετε αλλαγές μόνο αν κάποιος αγοράσει τα NFT σας.", + "info_permit": "Δίνετε στον χρήστη την άδεια να ξοδέψει αυτά τα token από τον λογαριασμό σας.", + "label_change_type_bidding": "Θα δώσετε προσφορά", + "label_change_type_listing": "Θα καταχωρήσετε", + "label_change_type_nft_listing": "Τιμή καταχώρησης", + "label_change_type_permit": "Ανώτατο όριο δαπανών", + "label_change_type_permit_nft": "Ανάληψη", + "label_change_type_receive": "Θα λάβετε", + "label_change_type_revoke": "Αναίρεση", + "label_change_type_transfer": "Θα στείλετε", "personal_sign_info": "Συνδέεστε σε έναν ιστότοπο και δεν προβλέπονται αλλαγές στον λογαριασμό σας.", - "tooltip": "Οι εκτιμώμενες αλλαγές είναι αυτό που μπορεί να συμβεί αν προχωρήσετε σε αυτή τη συναλλαγή. Πρόκειται απλώς για μια πρόβλεψη, δεν αποτελεί εγγύηση." - } + "title": "Εκτιμώμενες αλλαγές", + "tooltip": "Οι εκτιμώμενες αλλαγές είναι αυτό που μπορεί να συμβεί αν προχωρήσετε σε αυτή τη συναλλαγή. Πρόκειται απλώς για μια πρόβλεψη, δεν αποτελεί εγγύηση.", + "unavailable": "Μη διαθέσιμο" + }, + "unlimited": "Απεριόριστα", + "none": "None" }, "change_in_simulation_modal": { "title": "Τα αποτελέσματα έχουν αλλάξει", diff --git a/locales/languages/es.json b/locales/languages/es.json index 5e236dff020..127835ed522 100644 --- a/locales/languages/es.json +++ b/locales/languages/es.json @@ -48,7 +48,10 @@ "connector": "en" }, "autocomplete": { - "placeholder": "Buscar o escribir dirección URL" + "placeholder": "Búsqueda por sitio o dirección", + "recents": "Recientes", + "favorites": "Favoritos", + "sites": "Sitios" }, "navigation": { "back": "Volver", @@ -449,6 +452,7 @@ "next": "Siguiente", "buy_asset": "Comprar {{asset}}", "no_tokens": "No tiene ningún token.", + "show_tokens_without_balance": "Mostrar tokens sin saldo", "no_nfts_yet": "No hay ningún NFT aún", "nfts_autodetection_title": "Detección de NFT", "nfts_autodetection_desc": "Deje que MetaMask detecte y muestre automáticamente los NFT en su monedero.", @@ -470,7 +474,7 @@ "learn_more": "Más información", "add_collectibles": "AGREGAR NFT", "no_transactions": "No tiene transacciones.", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Cambie de red para ver las transacciones", "send_button": "Enviar", "deposit_button": "Depositar", "copy_address": "Copie", @@ -566,7 +570,7 @@ "description_content_1": "Nos gustaría recopilar datos básicos de uso para mejorar MetaMask. Tenga en cuenta que nunca venderemos los datos que nos proporcione aquí.", "description_content_2": "Al recopilar métricas, siempre serán...", "description_content_3": "Conozca cómo protegemos su privacidad mientras recopilamos datos de uso para su perfil.", - "checkbox": "Utilizaremos estos datos para saber cómo interactúa con nuestras comunicaciones de marketing. Podemos compartir noticias relevantes (como características de productos).", + "checkbox": "Utilizaremos estos datos para saber cómo usted interactúa con nuestras comunicaciones de marketing. Podremos compartir noticias relevantes (como características de productos).", "action_description_1_prefix": "Privadas:", "action_description_2_prefix": "Generales:", "action_description_3_prefix": "Opcionales:", @@ -722,6 +726,7 @@ "connected_and_active": "conectado y activo.", "now_active": "activo ahora.", "network_added": "se agregó correctamente", + "network_removed": "se eliminó correctamente", "network_deleted": "se eliminó correctamente", "network_permissions_updated": "Permisos de red actualizados", "revoked": "revocada.", @@ -1264,16 +1269,19 @@ "sell_button": "Vender", "receive_button": "Recibir", "portfolio_button": "Cartera", + "earn_button": "Ganar", "add_collectible_button": "Agregar", "info": "Información", "swap": "Intercambiar", "bridge": "Bridge", + "earn": "Ganar", "disabled_button": { "buy": "No es posible comprar en esta cuenta", "sell": "No es posible vender en esta cuenta", "swap": "No es posible realizar intercambios en esta cuenta", "bridge": "No es posible realizar puentes en esta cuenta", "send": "No es posible enviar en esta cuenta", + "earn": "No es posible ganar en esta cuenta", "action": "Esta acción no se admite en esta cuenta" }, "description": "Descripción", @@ -1290,6 +1298,7 @@ "bridge_description": "Transferir tokens entre redes", "send_description": "Enviar criptomonedas a cualquier cuenta", "receive_description": "Recibir criptomonedas", + "earn_description": "Gane recompensas con sus tokens", "chart_time_period": { "1d": "Hoy", "7d": "Últimos 7 días", @@ -1791,6 +1800,7 @@ "network_chain_id": "Identificador de cadena", "network_rpc_url": "URL de la red", "network_rpc_url_label": "URL de RPC de la red", + "network_rpc_url_warning_punycode": "A veces, los atacantes simulan sitios realizando cambios pequeños en la dirección del sitio. Asegúrese de estar interactuando con la URL de la red deseada antes de continuar. Versión Punycode:", "new_default_network_url": "Nueva URL de red por defecto", "current_label": "Actual", "new_label": "Nuevo", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Añadir monedero físico", "import_account": "Importar cuenta", "add_bitcoin_account_testnet": "Añadir una nueva cuenta de Bitcoin (Testnet)", - "add_bitcoin_account_mainnet": "Añadir una nueva cuenta de Bitcoin (Beta)" + "add_bitcoin_account_mainnet": "Añadir una nueva cuenta de Bitcoin (Beta)", + "add_solana_account": "Añadir una nueva cuenta de Solana (Beta)" }, "show_nft": { "show_nft_title": "Mostrar NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Solicitud de firma" }, + "sub_title": { + "signature": "Revise los detalles de la solicitud antes de confirmar." + }, "request_from": "Solicitud de", "message": "Mensaje", + "primary_type": "Tipo primario", "personal_sign_tooltip": "Este sitio solicita su firma", "details": "Detalles", "account": "Cuenta", "balance": "Saldo", "network": "Red", "simulation": { + "decoded_tooltip_bid_nft": "Una vez aceptada la oferta, el NFT se reflejará en su monedero.", + "decoded_tooltip_list_nft": "Espere cambios solamente si alguien compra sus NFT.", + "info_permit": "Le está dando permiso al gastador para gastar esta cantidad de tokens de su cuenta.", + "label_change_type_bidding": "Usted hace una oferta", + "label_change_type_listing": "Usted publica una oferta", + "label_change_type_nft_listing": "Precio de venta", + "label_change_type_permit": "Límite de gasto", + "label_change_type_permit_nft": "Retirar", + "label_change_type_receive": "Usted recibe", + "label_change_type_revoke": "Revocar", + "label_change_type_transfer": "Usted envía", + "personal_sign_info": "Está entrando en un sitio y no hay cambios previstos en su cuenta.", "title": "Cambios estimados", - "personal_sign_info": "Está iniciando sesión en un sitio y no se prevén cambios en su cuenta.", - "tooltip": "Los cambios estimados son lo que podría ocurrir si se lleva a cabo esta transacción. Esto es solo una predicción, no una garantía." - } + "tooltip": "Los cambios estimados son lo que podría ocurrir si se lleva a cabo esta transacción. Esto es solo una predicción, no una garantía.", + "unavailable": "No disponible" + }, + "unlimited": "Ilimitado", + "none": "None" }, "change_in_simulation_modal": { "title": "Los resultados cambiaron", diff --git a/locales/languages/fr.json b/locales/languages/fr.json index 63b029dfe4a..b6a640c083b 100644 --- a/locales/languages/fr.json +++ b/locales/languages/fr.json @@ -48,7 +48,10 @@ "connector": "à" }, "autocomplete": { - "placeholder": "Rechercher ou saisir l’URL" + "placeholder": "Rechercher par site ou par adresse", + "recents": "Récents", + "favorites": "Favoris", + "sites": "Sites" }, "navigation": { "back": "Retour", @@ -449,6 +452,7 @@ "next": "Suivant", "buy_asset": "Acheter {{asset}}", "no_tokens": "Vous n’avez aucun jeton !", + "show_tokens_without_balance": "Afficher les jetons sans solde", "no_nfts_yet": "Aucun NFT pour le moment", "nfts_autodetection_title": "Détection de NFT", "nfts_autodetection_desc": "Laissez MetaMask détecter et afficher automatiquement les NFT dans votre portefeuille.", @@ -470,7 +474,7 @@ "learn_more": "En savoir plus", "add_collectibles": "Importer des NFT", "no_transactions": "Vous n’avez aucune transaction !", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Veuillez changer de réseau pour visualiser les transactions", "send_button": "Envoyer", "deposit_button": "Dépôt", "copy_address": "Copiez", @@ -722,6 +726,7 @@ "connected_and_active": "connecté et actif.", "now_active": "maintenant actif.", "network_added": "a été ajouté avec succès", + "network_removed": "a été supprimé avec succès", "network_deleted": "a été supprimé", "network_permissions_updated": "Les autorisations réseau ont été mises à jour", "revoked": "révoqué.", @@ -1264,16 +1269,19 @@ "sell_button": "Vendre", "receive_button": "Recevoir", "portfolio_button": "Portefeuille", + "earn_button": "Gagner", "add_collectible_button": "Ajouter", "info": "Infos", "swap": "Échanger", "bridge": "Passerelle", + "earn": "Gagner", "disabled_button": { "buy": "Impossible d’effectuer un achat en utilisant ce compte", "sell": "Impossible d’effectuer une vente en utilisant ce compte", "swap": "Impossible d’effectuer un swap en utilisant ce compte", "bridge": "Impossible d’établir une passerelle en utilisant ce compte", "send": "Impossible d’effectuer un envoi en utilisant ce compte", + "earn": "Les gains ne sont pas pris en charge pour ce compte", "action": "Cette action ne peut pas être effectuée en utilisant ce compte" }, "description": "Description", @@ -1290,6 +1298,7 @@ "bridge_description": "Transférer des jetons entre différents réseaux", "send_description": "Envoyer des crypto-actifs vers n’importe quel compte", "receive_description": "Recevoir des crypto-actifs", + "earn_description": "Gagnez des récompenses avec vos jetons", "chart_time_period": { "1d": "Aujourd’hui", "7d": "Les 7 derniers jours", @@ -1791,6 +1800,7 @@ "network_chain_id": "Identifiant de la chaîne", "network_rpc_url": "URL du réseau", "network_rpc_url_label": "URL de RPC du réseau", + "network_rpc_url_warning_punycode": "Les pirates informatiques reproduisent parfois des sites en modifiant légèrement l’adresse URL. Avant de continuer, vérifiez l’URL du réseau. Version Punycode :", "new_default_network_url": "Nouvelle URL par défaut du réseau", "current_label": "Actuel", "new_label": "Nouveau", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Ajouter un portefeuille matériel", "import_account": "Importer le compte", "add_bitcoin_account_testnet": "Ajouter un nouveau compte Bitcoin (Testnet)", - "add_bitcoin_account_mainnet": "Ajouter un nouveau compte Bitcoin (Bêta)" + "add_bitcoin_account_mainnet": "Ajouter un nouveau compte Bitcoin (Bêta)", + "add_solana_account": "Ajouter un nouveau compte Solana (Bêta)" }, "show_nft": { "show_nft_title": "Afficher le NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Demande de signature" }, + "sub_title": { + "signature": "Vérifiez les détails de la demande avant de la confirmer." + }, "request_from": "Demande de", "message": "Message", + "primary_type": "Type primaire", "personal_sign_tooltip": "Ce site demande votre signature", "details": "Détails", "account": "Compte", "balance": "Solde", "network": "Réseau", "simulation": { - "title": "Changements estimés", + "decoded_tooltip_bid_nft": "Le NFT sera affiché dans votre portefeuille si l’offre est acceptée.", + "decoded_tooltip_list_nft": "Ne vous attendez à des changements que si quelqu’un achète vos NFT.", + "info_permit": "Vous donnez au dépenseur l’autorisation de retirer ce nombre de jetons de votre compte.", + "label_change_type_bidding": "Vous enchérissez", + "label_change_type_listing": "Vous mettez en vente", + "label_change_type_nft_listing": "Prix de vente", + "label_change_type_permit": "Plafond de dépenses", + "label_change_type_permit_nft": "Retirer", + "label_change_type_receive": "Vous recevez", + "label_change_type_revoke": "Révoquer", + "label_change_type_transfer": "Vous envoyez", "personal_sign_info": "Vous êtes en train de vous connecter à un site. Aucun changement ne devrait être apporté à votre compte.", - "tooltip": "Les changements estimés représentent ce qui pourrait se produire si vous effectuez cette transaction. Il s’agit juste d’une estimation fournie à titre d’information." - } + "title": "Changements estimés", + "tooltip": "Les changements estimés représentent ce qui pourrait se produire si vous effectuez cette transaction. Il s’agit juste d’une estimation fournie à titre d’information.", + "unavailable": "Non disponible" + }, + "unlimited": "Illimité", + "none": "None" }, "change_in_simulation_modal": { "title": "Les résultats ont changé", diff --git a/locales/languages/hi.json b/locales/languages/hi.json index b5dd44ca7e6..d8c80bfca63 100644 --- a/locales/languages/hi.json +++ b/locales/languages/hi.json @@ -48,7 +48,10 @@ "connector": "पर" }, "autocomplete": { - "placeholder": "ढूंढें या URL टाइप करें" + "placeholder": "साइट या एड्रेस से ढूंढें", + "recents": "हालिया", + "favorites": "पसंदीदा", + "sites": "साइट्स" }, "navigation": { "back": "वापस", @@ -449,6 +452,7 @@ "next": "अगला", "buy_asset": "{{asset}} खरीदें", "no_tokens": "आपके पास कोई टोकन नहीं है!", + "show_tokens_without_balance": "बैलेंस के बिना टोकन दिखाएं", "no_nfts_yet": "अभी तक कोई NFT नहीं है", "nfts_autodetection_title": "NFT का पता लगाना", "nfts_autodetection_desc": "MetaMask को ऑटोमेटिक तरीके से NFTs का पता लगाने और आपके वॉलेट में दिखाने के लिए अनुमति दें।", @@ -470,7 +474,7 @@ "learn_more": "ज्यादा जानें।", "add_collectibles": "NFT इम्पोर्ट करें", "no_transactions": "आपके पास कोई लेन-देन नहीं है!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "कृपया ट्रांसेक्शन देखने के लिए नेटवर्क बदलें", "send_button": "भेजें", "deposit_button": "जमा करें", "copy_address": "कॉपी करें", @@ -722,6 +726,7 @@ "connected_and_active": "कनेक्ट किया हुआ और सक्रिय।", "now_active": "अब सक्रिय है", "network_added": "सफलतापूर्वक जोड़ा गया", + "network_removed": "सफलतापूर्वक हटाया गया", "network_deleted": "सफलतापूर्वक डिलीट किया गया", "network_permissions_updated": "नेटवर्क अनुमतियाँ अपडेट की गईं", "revoked": "निरस्त किया हुआ।", @@ -1264,16 +1269,19 @@ "sell_button": "बेचें", "receive_button": "प्राप्त करें", "portfolio_button": "पोर्टफोलियो", + "earn_button": "कमाएं", "add_collectible_button": "जोड़ें", "info": "जानकारी", "swap": "स्वैप", "bridge": "ब्रिज", + "earn": "कमाएं", "disabled_button": { "buy": "इस अकाउंट के लिए खरीदारी सपोर्ट नहीं करती है", "sell": "इस अकाउंट के लिए बेचना सपोर्ट नहीं करती है", "swap": "इस अकाउंट के लिए स्वैप करना सपोर्ट नहीं करती है", "bridge": "इस अकाउंट के लिए ब्रिज करना सपोर्ट नहीं करती है", "send": "इस अकाउंट के लिए भेजना सपोर्ट नहीं करती है", + "earn": "इस अकाउंट के लिए कमाना सपोर्टेड नहीं है", "action": "यह एक्शन इस अकाउंट के लिए सपोर्ट नहीं करती है" }, "description": "विवरण", @@ -1290,6 +1298,7 @@ "bridge_description": "अलग-अलग नेटवर्कों के बीच टोकन ट्रांसफर करें", "send_description": "किसी भी खाते में क्रिप्टो भेजें", "receive_description": "क्रिप्टो प्राप्त करें", + "earn_description": "अपने टोकन पर पुरस्कार अर्जित करें", "chart_time_period": { "1d": "आज", "7d": "पिछले 7 दिन", @@ -1791,6 +1800,7 @@ "network_chain_id": "चेन आईडी", "network_rpc_url": "नेटवर्क यूआरएल", "network_rpc_url_label": "नेटवर्क RPC URL", + "network_rpc_url_warning_punycode": "हमलावर कभी-कभी साइट के एड्रेस में छोटे-छोटे बदलाव करके साइटों की नकल करते हैं। जारी रखने से पहले सुनिश्चित करें कि आप इच्छित नेटवर्क URL के साथ इंटरैक्ट कर रहे हैं। पुनीकोड ​​वर्शन:", "new_default_network_url": "नया डिफॉल्ट नेटवर्क URL", "current_label": "मौजूदा", "new_label": "नया", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "हार्डवेयर वॉलेट जोड़ें", "import_account": "अकाउंट इम्पोर्ट करें", "add_bitcoin_account_testnet": "एक नया Bitcoin अकाउंट - टैस्टनेट (testnet) जोड़ें", - "add_bitcoin_account_mainnet": "एक नया Bitcoin अकाउंट (बीटा) जोड़ें" + "add_bitcoin_account_mainnet": "एक नया Bitcoin अकाउंट (बीटा) जोड़ें", + "add_solana_account": "एक नया Solana अकाउंट (बीटा) जोड़ें" }, "show_nft": { "show_nft_title": "NFT दिखाएं", @@ -3571,18 +3582,36 @@ "title": { "signature": "हस्ताक्षर का अनुरोध" }, + "sub_title": { + "signature": "कन्फर्म करने से पहले अनुरोध विवरण की समीक्षा करें।" + }, "request_from": "इनसे मिला अनुरोध", "message": "संदेश", + "primary_type": "प्राइमरी प्रकार", "personal_sign_tooltip": "यह साइट आपका सिग्नेचर मांग रही है", "details": "विवरण", "account": "अकाउंट", "balance": "बैलेंस", "network": "नेटवर्क", "simulation": { - "title": "अनुमानित बदलाव", + "decoded_tooltip_bid_nft": "बिड स्वीकार होने पर NFT आपके वॉलेट में दिखाई देगा।", + "decoded_tooltip_list_nft": "बदलाव की उम्मीद तभी करें जब कोई आपके NFTs खरीद ले।", + "info_permit": "आप खर्च करने वाले को अपने अकाउंट से इतने सारे टोकन खर्च करने की अनुमति दे रहे हैं।", + "label_change_type_bidding": "आप बिड करते हैं", + "label_change_type_listing": "आप लिस्ट करते हैं", + "label_change_type_nft_listing": "लिस्टिंग प्राइस", + "label_change_type_permit": "खर्च करने की सीमा", + "label_change_type_permit_nft": "निकालें", + "label_change_type_receive": "आप प्राप्त करते हैं", + "label_change_type_revoke": "निरस्त करें", + "label_change_type_transfer": "आप भेजते हैं", "personal_sign_info": "आप किसी साइट पर साइन इन कर रहे हैं और आपके अकाउंट में कोई अनुमानित परिवर्तन नहीं हैं।", - "tooltip": "अगर आप यह ट्रांसेक्शन करते हैं तो अनुमानित परिवर्तन हो सकते हैं। यह सिर्फ एक अनुमान है, कोई गारंटी नहीं।" - } + "title": "अनुमानित बदलाव", + "tooltip": "अगर आप यह ट्रांसेक्शन करते हैं तो अनुमानित परिवर्तन हो सकते हैं। यह सिर्फ एक अनुमान है, कोई गारंटी नहीं।", + "unavailable": "अनुपलब्ध" + }, + "unlimited": "असीमित", + "none": "None" }, "change_in_simulation_modal": { "title": "परिणाम बदल गए हैं", diff --git a/locales/languages/id.json b/locales/languages/id.json index f57afde2be6..13f9dff5350 100644 --- a/locales/languages/id.json +++ b/locales/languages/id.json @@ -48,7 +48,10 @@ "connector": "pada" }, "autocomplete": { - "placeholder": "Cari atau Ketik URL" + "placeholder": "Cari berdasarkan situs atau alamat", + "recents": "Terbaru", + "favorites": "Favorit", + "sites": "Situs" }, "navigation": { "back": "Kembali", @@ -449,6 +452,7 @@ "next": "Berikutnya", "buy_asset": "Beli {{asset}}", "no_tokens": "Anda tidak memiliki token!", + "show_tokens_without_balance": "Tampilkan token tanpa saldo", "no_nfts_yet": "Belum ada NFT", "nfts_autodetection_title": "Deteksi NFT", "nfts_autodetection_desc": "Izinkan MetaMask mendeteksi dan menampilkan NFT di dompet Anda secara otomatis.", @@ -470,7 +474,7 @@ "learn_more": "Pelajari selengkapnya", "add_collectibles": "Impor NFT", "no_transactions": "Belum ada transaksi!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Alihkan jaringan untuk melihat transaksi", "send_button": "Kirim", "deposit_button": "Deposit", "copy_address": "Salin", @@ -722,6 +726,7 @@ "connected_and_active": "terhubung dan aktif.", "now_active": "sekarang aktif.", "network_added": "berhasil ditambahkan", + "network_removed": "berhasil dihapus", "network_deleted": "berhasil dihapus", "network_permissions_updated": "Izin jaringan diperbarui", "revoked": "dicabut.", @@ -1264,16 +1269,19 @@ "sell_button": "Jual", "receive_button": "Terima", "portfolio_button": "Portofolio", + "earn_button": "Hasilkan", "add_collectible_button": "Tambahkan", "info": "Informasi", "swap": "Tukar", "bridge": "Bridge", + "earn": "Hasilkan", "disabled_button": { "buy": "Pembelian tidak didukung untuk akun ini", "sell": "Penjualan tidak didukung untuk akun ini", "swap": "Swap tidak didukung untuk akun ini", "bridge": "Bridge tidak didukung untuk akun ini", "send": "Pengiriman tidak didukung untuk akun ini", + "earn": "Penghasilan tidak didukung untuk akun ini", "action": "Tindakan ini tidak didukung untuk akun ini" }, "description": "Deskripsi", @@ -1290,6 +1298,7 @@ "bridge_description": "Transfer token antar jaringan", "send_description": "Kirim kripto ke akun mana pun", "receive_description": "Terima kripto", + "earn_description": "Dapatkan imbalan atas token Anda", "chart_time_period": { "1d": "Hari ini", "7d": "7 hari terakhir", @@ -1791,6 +1800,7 @@ "network_chain_id": "ID Chain", "network_rpc_url": "URL Jaringan", "network_rpc_url_label": "URL RPC Jaringan", + "network_rpc_url_warning_punycode": "Penyerang terkadang meniru situs dengan membuat perubahan kecil pada alamat situs. Pastikan Anda berinteraksi dengan URL Jaringan yang dituju sebelum melanjutkan. Versi Punycode:", "new_default_network_url": "URL jaringan default baru", "current_label": "Saat ini", "new_label": "Baru", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Tambahkan dompet perangkat keras", "import_account": "Impor akun", "add_bitcoin_account_testnet": "Tambahkan Akun Bitcoin baru (Testnet)", - "add_bitcoin_account_mainnet": "Tambahkan Akun Bitcoin baru (Beta)" + "add_bitcoin_account_mainnet": "Tambahkan Akun Bitcoin baru (Beta)", + "add_solana_account": "Tambahkan Akun Solana baru (Beta)" }, "show_nft": { "show_nft_title": "Tampilkan NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Permintaan tanda tangan" }, + "sub_title": { + "signature": "Tinjau detail permintaan sebelum mengonfirmasi." + }, "request_from": "Permintaan dari", "message": "Pesan", + "primary_type": "Tipe primer", "personal_sign_tooltip": "Situs ini meminta tanda tangan Anda", "details": "Detail", "account": "Akun", "balance": "Saldo", "network": "Jaringan", "simulation": { + "decoded_tooltip_bid_nft": "NFT akan terlihat di dompet Anda saat tawaran diterima.", + "decoded_tooltip_list_nft": "Nantikan perubahan hanya jika seseorang membeli NFT Anda.", + "info_permit": "Anda memberi izin kepada spender untuk menggunakan sejumlah token ini dari akun Anda.", + "label_change_type_bidding": "Anda menawar", + "label_change_type_listing": "Anda mendaftar", + "label_change_type_nft_listing": "Harga yang terdaftar", + "label_change_type_permit": "Batas penggunaan", + "label_change_type_permit_nft": "Tarik", + "label_change_type_receive": "Anda menerima", + "label_change_type_revoke": "Cabut", + "label_change_type_transfer": "Anda mengirim", + "personal_sign_info": "Anda masuk ke sebuah situs dan tidak ada perubahan yang terprediksi pada akun Anda.", "title": "Estimasi perubahan", - "personal_sign_info": "Anda masuk ke sebuah situs dan tidak ada perkiraan perubahan pada akun Anda.", - "tooltip": "Estimasi perubahan merupakan hal yang mungkin terjadi jika Anda melakukan transaksi ini. Ini hanyalah prediksi, bukan jaminan." - } + "tooltip": "Estimasi perubahan merupakan hal yang mungkin terjadi jika Anda melakukan transaksi ini. Ini hanyalah prediksi, bukan jaminan.", + "unavailable": "Tidak tersedia" + }, + "unlimited": "Tak terbatas", + "none": "None" }, "change_in_simulation_modal": { "title": "Hasil telah berubah", diff --git a/locales/languages/ja.json b/locales/languages/ja.json index ba6d0496744..36b565c6622 100644 --- a/locales/languages/ja.json +++ b/locales/languages/ja.json @@ -48,7 +48,10 @@ "connector": "at" }, "autocomplete": { - "placeholder": "URLを検索または入力してください" + "placeholder": "サイトまたはアドレスで検索", + "recents": "最近", + "favorites": "お気に入り", + "sites": "サイト" }, "navigation": { "back": "戻る", @@ -449,6 +452,7 @@ "next": "次へ", "buy_asset": "{{asset}}を購入", "no_tokens": "トークンがありません!", + "show_tokens_without_balance": "残高なしでトークンを表示", "no_nfts_yet": "まだNFTがありません", "nfts_autodetection_title": "NFTの検出", "nfts_autodetection_desc": "MetaMaskによるウォレット内のNFTの自動検出と表示を許可します。", @@ -470,7 +474,7 @@ "learn_more": "詳細", "add_collectibles": "NFTをインポート", "no_transactions": "トランザクションがありません!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "トランザクションを表示するにはネットワークを切り替えてください", "send_button": "送信", "deposit_button": "入金", "copy_address": "コピー", @@ -722,6 +726,7 @@ "connected_and_active": "接続済みかつ有効です。", "now_active": "有効になりました。", "network_added": "が追加されました", + "network_removed": "が削除されました", "network_deleted": "が削除されました", "network_permissions_updated": "ネットワークのアクセス許可が更新されました", "revoked": "取り消されました。", @@ -1264,16 +1269,19 @@ "sell_button": "売却", "receive_button": "受取", "portfolio_button": "Portfolio", + "earn_button": "獲得", "add_collectible_button": "追加", "info": "情報", "swap": "スワップ", "bridge": "ブリッジ", + "earn": "獲得", "disabled_button": { "buy": "このアカウントでは購入はサポートされていません", "sell": "このアカウントでは売却はサポートされていません", "swap": "このアカウントではスワップはサポートされていません", "bridge": "このアカウントではブリッジはサポートされていません", "send": "このアカウントでは送金はサポートされていません", + "earn": "このアカウントでは獲得はサポートされていません", "action": "このアカウントではこの操作はサポートされていません" }, "description": "説明", @@ -1290,6 +1298,7 @@ "bridge_description": "ネットワーク間でトークンを転送します", "send_description": "仮想通貨を任意のアカウントに送金します", "receive_description": "仮想通貨を受け取ります", + "earn_description": "トークンに対してリワードを獲得します", "chart_time_period": { "1d": "今日", "7d": "過去7日間", @@ -1791,6 +1800,7 @@ "network_chain_id": "チェーンID", "network_rpc_url": "ネットワークURL", "network_rpc_url_label": "ネットワークRPC URL", + "network_rpc_url_warning_punycode": "攻撃者はサイトのアドレスを若干変更してサイトを模倣することがあります。続行する前に、意図したネットワークURLとやり取りしていることを確認してください。Punycodeバージョン:", "new_default_network_url": "新しいデフォルトのネットワークURL", "current_label": "現在", "new_label": "新", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "ハードウェアウォレットを追加", "import_account": "アカウントをインポート", "add_bitcoin_account_testnet": "新しいビットコインアカウントを追加 (テストネット)", - "add_bitcoin_account_mainnet": "新しいビットコインアカウントを追加 (ベータ)" + "add_bitcoin_account_mainnet": "新しいビットコインアカウントを追加 (ベータ)", + "add_solana_account": "新しいSolanaアカウントを追加 (ベータ)" }, "show_nft": { "show_nft_title": "NFTを表示", @@ -3571,18 +3582,36 @@ "title": { "signature": "署名要求" }, + "sub_title": { + "signature": "確定する前にリクエストの詳細を確認してください。" + }, "request_from": "要求元", "message": "メッセージ", + "primary_type": "プライマリタイプ", "personal_sign_tooltip": "このサイトが署名を求めています", "details": "詳細", "account": "アカウント", "balance": "残高", "network": "ネットワーク", "simulation": { + "decoded_tooltip_bid_nft": "NFTは、入札が受け入れられるとウォレットに反映されます。", + "decoded_tooltip_list_nft": "誰かがNFTを購入した場合にのみ変化します。", + "info_permit": "アカウントからこの量のトークンを使用する、使用者権限を付与しようとしています。", + "label_change_type_bidding": "入札する", + "label_change_type_listing": "出品する", + "label_change_type_nft_listing": "出品価格", + "label_change_type_permit": "使用上限", + "label_change_type_permit_nft": "出金", + "label_change_type_receive": "受け取る", + "label_change_type_revoke": "取り消す", + "label_change_type_transfer": "送る", + "personal_sign_info": "サイトにサインインしようとしていて、アカウントの変更は予想されていません。", "title": "予測される増減額", - "personal_sign_info": "サイトにサインインしようとしていて、予想されるアカウントの変更はありません。", - "tooltip": "予測される増減額は、このトランザクションを実行すると発生する可能性がある増減額です。これは単に予測に過ぎず、保証されたものではありません。" - } + "tooltip": "予測される増減額は、このトランザクションを実行すると発生する可能性がある増減額です。これは単に予測に過ぎず、保証されたものではありません。", + "unavailable": "利用不可" + }, + "unlimited": "無制限", + "none": "None" }, "change_in_simulation_modal": { "title": "結果が変更になりました", diff --git a/locales/languages/ko.json b/locales/languages/ko.json index d6203dc0377..7b62551bf21 100644 --- a/locales/languages/ko.json +++ b/locales/languages/ko.json @@ -48,7 +48,10 @@ "connector": ":" }, "autocomplete": { - "placeholder": "URL 검색 또는 입력" + "placeholder": "사이트 또는 주소로 검색", + "recents": "최근", + "favorites": "즐겨찾기", + "sites": "사이트" }, "navigation": { "back": "뒤로", @@ -449,6 +452,7 @@ "next": "다음", "buy_asset": "{{asset}} 구매", "no_tokens": "토큰이 없습니다!", + "show_tokens_without_balance": "잔액 없는 토큰 표시", "no_nfts_yet": "아직 NFT가 없습니다", "nfts_autodetection_title": "NFT 감지", "nfts_autodetection_desc": "MetaMask를 통해 자동으로 NFT를 감지하여 지갑에 표시할 수 있습니다.", @@ -470,7 +474,7 @@ "learn_more": "더 알아보기", "add_collectibles": "NFT 가져오기", "no_transactions": "트랜잭션이 없습니다!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "트랜잭션을 보려면 네트워크를 전환하세요", "send_button": "보내기", "deposit_button": "예금", "copy_address": "복사", @@ -566,7 +570,7 @@ "description_content_1": "MetaMask를 개선하기 위해 기본적인 데이터 사용 데이터를 수집하고자 합니다. MetaMask는 제공받은 데이터를 절대 판매하지 않습니다.", "description_content_2": "메트릭을 수집할 때는 항상...", "description_content_3": "프로필 사용 데이터를 수집하는 동안 개인정보 보호 방법을 알아보세요.", - "checkbox": "당사는 이 데이터를 사용하여 사용자가 마케팅 커뮤니케이션과 어떻게 상호 작용하는지 파악합니다. 관련 뉴스(예: 제품 기능)를 공유할 수 있습니다.", + "checkbox": "당사는 사용자가 마케팅 커뮤니케이션과 상호작용하는 방식을 파악하기 위해 이 데이터를 사용합니다. 관련 소식(제품 기능 등)을 공유할 수 있습니다.", "action_description_1_prefix": "개인 정보:", "action_description_2_prefix": "일반:", "action_description_3_prefix": "선택 사항:", @@ -722,6 +726,7 @@ "connected_and_active": "연결되어 활성화됨.", "now_active": "지금 활성화됨.", "network_added": "(을)를 성공적으로 추가했습니다", + "network_removed": "제거되었습니다", "network_deleted": "이(가) 삭제되었습니다", "network_permissions_updated": "네트워크 권한 업데이트됨", "revoked": "취소됨.", @@ -1264,16 +1269,19 @@ "sell_button": "매도", "receive_button": "받기", "portfolio_button": "포트폴리오", + "earn_button": "수익", "add_collectible_button": "추가", "info": "정보", "swap": "스와프", "bridge": "브릿지", + "earn": "수익", "disabled_button": { "buy": "이 계정에서는 매수가 지원되지 않음", "sell": "이 계정에서는 매도가 지원되지 않음", "swap": "이 계정에서는 스왑이 지원되지 않음", "bridge": "이 계정에서는 브릿징이 지원되지 않음", "send": "이 계정에서는 전송이 지원되지 않음", + "earn": "이 계정은 수익 기능을 지원하지 않습니다", "action": "이 계정에서는 이 작업이 지원되지 않습니다" }, "description": "설명", @@ -1290,6 +1298,7 @@ "bridge_description": "네트워크간 토큰 전송", "send_description": "원하는 계정에 암호화폐 보내기", "receive_description": "암호화폐 수령", + "earn_description": "토큰으로 보상을 획득하세요", "chart_time_period": { "1d": "오늘", "7d": "지난 7일", @@ -1791,6 +1800,7 @@ "network_chain_id": "체인 ID", "network_rpc_url": "네트워크 URL", "network_rpc_url_label": "네트워크 RPC URL", + "network_rpc_url_warning_punycode": "공격자는 종종 사이트 주소를 약간 변경하여 사이트를 모방합니다. 계속하기 전에 정상적인 네트워크 URL과 상호작용하고 있는지 확인하세요. 퓨니코드 버전:", "new_default_network_url": "새 기본 네트워크 URL", "current_label": "현재", "new_label": "신규", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "하드웨어 지갑 추가", "import_account": "계정 가져오기", "add_bitcoin_account_testnet": "새 비트코인 계정(테스트넷) 추가", - "add_bitcoin_account_mainnet": "새 비트코인 계정(베타) 추가" + "add_bitcoin_account_mainnet": "새 비트코인 계정(베타) 추가", + "add_solana_account": "새 Solana 계정 추가(베타)" }, "show_nft": { "show_nft_title": "NFT 표시", @@ -3571,18 +3582,36 @@ "title": { "signature": "서명 요청" }, + "sub_title": { + "signature": "컨펌하기 전에 요청 세부 사항을 검토하세요." + }, "request_from": "요청자:", "message": "메시지", + "primary_type": "기본 유형", "personal_sign_tooltip": "서명이 필요한 사이트입니다", "details": "세부 정보", "account": "계정", "balance": "잔액", "network": "네트워크", "simulation": { - "title": "예상 변동 사항", + "decoded_tooltip_bid_nft": "입찰이 수락되면 NFT가 지갑에 반영됩니다.", + "decoded_tooltip_list_nft": "누군가 NFT를 구매할 경우에만 변경이 예상됩니다.", + "info_permit": "지출자에게 내 계정에서 이 정도의 토큰을 지출할 수 있는 권한을 부여합니다.", + "label_change_type_bidding": "내 입찰", + "label_change_type_listing": "내 리스트", + "label_change_type_nft_listing": "리스팅 가격", + "label_change_type_permit": "지출 한도", + "label_change_type_permit_nft": "출금", + "label_change_type_receive": "받음:", + "label_change_type_revoke": "취소", + "label_change_type_transfer": "보냄:", "personal_sign_info": "사이트에 로그인 중이며 계정에 예상되는 변동 사항이 없습니다.", - "tooltip": "예상 변동 사항은 이 트랜잭션을 진행할 경우 발생하는 결과를 예측한 것입니다. 이는 예측일 뿐 결과를 보장하지는 않습니다." - } + "title": "예상 변동 사항", + "tooltip": "예상 변동 사항은 이 트랜잭션을 진행할 경우 발생하는 결과를 예측한 것입니다. 이는 예측일 뿐 결과를 보장하지는 않습니다.", + "unavailable": "사용 불가" + }, + "unlimited": "무제한", + "none": "None" }, "change_in_simulation_modal": { "title": "결과가 변경되었습니다", diff --git a/locales/languages/pt.json b/locales/languages/pt.json index 403249b8762..42f991c6776 100644 --- a/locales/languages/pt.json +++ b/locales/languages/pt.json @@ -48,7 +48,10 @@ "connector": "em" }, "autocomplete": { - "placeholder": "Pesquise ou digite um URL" + "placeholder": "Pesquisar por site ou por endereço", + "recents": "Recentes", + "favorites": "Favoritos", + "sites": "Sites" }, "navigation": { "back": "Voltar", @@ -449,6 +452,7 @@ "next": "Avançar", "buy_asset": "Comprar {{asset}}", "no_tokens": "Você não tem nenhum token!", + "show_tokens_without_balance": "Mostrar tokens sem saldo", "no_nfts_yet": "Nenhum NFT até agora", "nfts_autodetection_title": "Detecção de NFTs", "nfts_autodetection_desc": "Permita que a MetaMask detecte e exiba automaticamente os NFTs em sua carteira.", @@ -470,7 +474,7 @@ "learn_more": "Saiba mais", "add_collectibles": "Importar NFTs", "no_transactions": "Você não tem nenhuma transação!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Mude de rede para ver as transações", "send_button": "Enviar", "deposit_button": "Depositar", "copy_address": "Copiar", @@ -566,7 +570,7 @@ "description_content_1": "Gostaríamos de coletar dados básicos de uso para melhorar a MetaMask. Saiba que nunca vendemos os dados que você fornece aqui.", "description_content_2": "Quando coletamos as métricas, elas sempre são...", "description_content_3": "Saiba como protegemos sua privacidade durante a coleta de dados de uso relacionados ao seu perfil.", - "checkbox": "Usaremos esses dados para saber como você interage com nossas comunicações de marketing. Podemos compartilhar novidades relevantes (como recursos de produtos).", + "checkbox": "Usaremos esses dados para saber como você interage com nossas comunicações de marketing. Poderemos compartilhar novidades relevantes (como recursos de produtos).", "action_description_1_prefix": "Privadas:", "action_description_2_prefix": "Gerais:", "action_description_3_prefix": "Opcionais:", @@ -722,6 +726,7 @@ "connected_and_active": "conectada e ativa.", "now_active": "agora ativa.", "network_added": "foi adicionada com sucesso", + "network_removed": "foi removido com sucesso", "network_deleted": "foi excluída com sucesso", "network_permissions_updated": "Permissões de rede atualizadas", "revoked": "revogada.", @@ -1264,16 +1269,19 @@ "sell_button": "Vender", "receive_button": "Receber", "portfolio_button": "Portfólio", + "earn_button": "Ganhar", "add_collectible_button": "Adicionar", "info": "Informações", "swap": "Troca", "bridge": "Ponte", + "earn": "Ganhar", "disabled_button": { "buy": "Não há suporte para compras nesta conta", "sell": "Não há suporte para vendas nesta conta", "swap": "Não há suporte para swaps nesta conta", "bridge": "Não há suporte para pontes nesta conta", "send": "Não há suporte para envios nesta conta", + "earn": "Não há suporte para ganhos nesta conta", "action": "Não há suporte para esta ação nesta conta" }, "description": "Descrição", @@ -1290,6 +1298,7 @@ "bridge_description": "Transferir tokens entre redes", "send_description": "Envie criptomoedas para qualquer conta", "receive_description": "Receba criptomoedas", + "earn_description": "Ganhe recompensas sobre seus tokens", "chart_time_period": { "1d": "Hoje", "7d": "Últimos 7 dias", @@ -1791,6 +1800,7 @@ "network_chain_id": "ID da cadeia", "network_rpc_url": "URL da rede", "network_rpc_url_label": "URL da RPC da rede", + "network_rpc_url_warning_punycode": "Invasores às vezes simulam sites alterando ligeiramente o endereço da web. Certifique-se de que está interagindo com o URL correto antes de continuar. Versão Punycode:", "new_default_network_url": "URL da nova rede padrão", "current_label": "Atual", "new_label": "Nova", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Adicionar carteira de hardware", "import_account": "Importar conta", "add_bitcoin_account_testnet": "Adicionar uma nova conta Bitcoin (testnet)", - "add_bitcoin_account_mainnet": "Adicionar uma nova conta Bitcoin (beta)" + "add_bitcoin_account_mainnet": "Adicionar uma nova conta Bitcoin (beta)", + "add_solana_account": "Adicionar uma nova conta Solana (beta)" }, "show_nft": { "show_nft_title": "Exibir NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Solicitação de assinatura" }, + "sub_title": { + "signature": "Revise os detalhes da solicitação antes de confirmar." + }, "request_from": "Solicitação de", "message": "Mensagem", + "primary_type": "Tipo primário", "personal_sign_tooltip": "Este site está solicitando sua assinatura", "details": "Detalhes", "account": "Conta", "balance": "Saldo", "network": "Rede", "simulation": { - "title": "Alterações estimadas", + "decoded_tooltip_bid_nft": "O NFT será refletido em sua carteira quando o lance for aceito.", + "decoded_tooltip_list_nft": "Espere alterações somente se alguém comprar seus NFTs.", + "info_permit": "Você está autorizando um consumidor a gastar esta quantidade de tokens de sua conta.", + "label_change_type_bidding": "Seu lance", + "label_change_type_listing": "Sua lista", + "label_change_type_nft_listing": "Preço de listagem", + "label_change_type_permit": "Limite de gastos", + "label_change_type_permit_nft": "Sacar", + "label_change_type_receive": "Você recebe", + "label_change_type_revoke": "Revogar", + "label_change_type_transfer": "Você envia", "personal_sign_info": "Você está fazendo login em um site, e não há alterações previstas em sua conta.", - "tooltip": "Alterações estimadas são o que pode acontecer se você prosseguir com essa transação. Isso é apenas uma previsão, não uma garantia." - } + "title": "Alterações estimadas", + "tooltip": "Alterações estimadas são o que pode acontecer se você prosseguir com essa transação. Isso é apenas uma previsão, não uma garantia.", + "unavailable": "Indisponível" + }, + "unlimited": "Ilimitado", + "none": "None" }, "change_in_simulation_modal": { "title": "Os resultados mudaram", diff --git a/locales/languages/ru.json b/locales/languages/ru.json index 0a6e3da8ced..15df859d947 100644 --- a/locales/languages/ru.json +++ b/locales/languages/ru.json @@ -48,7 +48,10 @@ "connector": "в" }, "autocomplete": { - "placeholder": "Найдите или введите URL" + "placeholder": "Поиск по сайту или адресу", + "recents": "Недавние", + "favorites": "Избранное", + "sites": "Сайты" }, "navigation": { "back": "Назад", @@ -449,6 +452,7 @@ "next": "Далее", "buy_asset": "Купить {{asset}}", "no_tokens": "У вас нет токенов!", + "show_tokens_without_balance": "Показать токены без баланса", "no_nfts_yet": "Пока нет NFT", "nfts_autodetection_title": "Определение NFT", "nfts_autodetection_desc": "Разрешите MetaMask автоматически определять и отображать NFT в вашем кошельке.", @@ -470,7 +474,7 @@ "learn_more": "Подробнее", "add_collectibles": "Импорт NFT", "no_transactions": "У вас нет транзакций!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Смените сеть для просмотра транзакций", "send_button": "Отправить", "deposit_button": "Депозит", "copy_address": "Копировать", @@ -722,6 +726,7 @@ "connected_and_active": "подключен и активен.", "now_active": "сейчас активен.", "network_added": "успешно добавлена", + "network_removed": "успешно удален", "network_deleted": "успешно удален", "network_permissions_updated": "Сетевые разрешения обновлены", "revoked": "отозван.", @@ -1264,16 +1269,19 @@ "sell_button": "Продать", "receive_button": "Получить", "portfolio_button": "Portfolio", + "earn_button": "Заработать", "add_collectible_button": "Добавить", "info": "Информация", "swap": "Своп", "bridge": "Мост", + "earn": "Заработать", "disabled_button": { "buy": "Этот счет не поддерживает покупку", "sell": "Этот счет не поддерживает продажу", "swap": "Этот счет не поддерживает обмен", "bridge": "Этот счет не поддерживает создание моста", "send": "Этот счет не поддерживает отправку", + "earn": "Зарабатывание не поддерживается для этого счета", "action": "Этот счет не поддерживает создание данное действие" }, "description": "Описание", @@ -1290,6 +1298,7 @@ "bridge_description": "Передача токенов между сетями", "send_description": "Отправляйте криптовалюту на любой счет", "receive_description": "Получить криптовалюту", + "earn_description": "Зарабатывайте награды за свои токены", "chart_time_period": { "1d": "Сегодня", "7d": "Последние 7 дней", @@ -1791,6 +1800,7 @@ "network_chain_id": "ID блокчейна", "network_rpc_url": "URL сети", "network_rpc_url_label": "URL-адрес сетевого RPC", + "network_rpc_url_warning_punycode": "Злоумышленники иногда имитируют сайты, внося небольшие изменения в адрес сайта. Прежде чем продолжить, убедитесь, что вы взаимодействуете с предполагаемым URL-адресом сети. Версия Punycode:", "new_default_network_url": "Новый URL-адрес сети по умолчанию", "current_label": "Текущая", "new_label": "Новая", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Добавить аппаратный кошелек", "import_account": "Импорт счета", "add_bitcoin_account_testnet": "Добавить новый счет Биткойн (тестнет)", - "add_bitcoin_account_mainnet": "Добавить новый счет Биткойн (бета-версия)" + "add_bitcoin_account_mainnet": "Добавить новый счет Биткойн (бета-версия)", + "add_solana_account": "Добавить новый счет Solana (бета-версия)" }, "show_nft": { "show_nft_title": "Показать NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Запрос подписи" }, + "sub_title": { + "signature": "Прежде чем подтвердить запрос, просмотрите детали запроса." + }, "request_from": "Запрос от", "message": "Сообщение", + "primary_type": "Первичный тип", "personal_sign_tooltip": "Этот сайт запрашивает вашу подпись", "details": "Подробности", "account": "Счет", "balance": "Баланс", "network": "Сеть", "simulation": { - "title": "Прогнозируемые изменения", + "decoded_tooltip_bid_nft": "NFT отобразится в вашем кошельке, когда ставка будет принята.", + "decoded_tooltip_list_nft": "Ожидайте изменений, только если кто-то купит ваши NFT.", + "info_permit": "Вы даете отправителю разрешение потратить такое количество токенов с вашего счета.", + "label_change_type_bidding": "Вы ставите", + "label_change_type_listing": "Вы размещаете для продажи", + "label_change_type_nft_listing": "Цена выставления на продажу", + "label_change_type_permit": "Лимит расходов", + "label_change_type_permit_nft": "Вывести", + "label_change_type_receive": "Вы получаете", + "label_change_type_revoke": "Отозвать", + "label_change_type_transfer": "Вы отправляете", "personal_sign_info": "Вы входите на сайт, и в вашем счете не происходит никаких прогнозируемых изменений.", - "tooltip": "Прогнозируемые изменения — это то, что может произойти, если вы завершите эту транзакцию. Это всего лишь прогноз, а не гарантия." - } + "title": "Прогнозируемые изменения", + "tooltip": "Прогнозируемые изменения — это то, что может произойти, если вы завершите эту транзакцию. Это всего лишь прогноз, а не гарантия.", + "unavailable": "Недоступно" + }, + "unlimited": "Неограничено", + "none": "None" }, "change_in_simulation_modal": { "title": "Результаты изменились", diff --git a/locales/languages/tl.json b/locales/languages/tl.json index 8800ea77f61..4e142bb6748 100644 --- a/locales/languages/tl.json +++ b/locales/languages/tl.json @@ -48,7 +48,10 @@ "connector": "sa" }, "autocomplete": { - "placeholder": "Hanapin o I-type ang URL" + "placeholder": "Maghanap ayon sa site o address", + "recents": "Mga Kamakailan", + "favorites": "Mga Favorite", + "sites": "Mga Site" }, "navigation": { "back": "Bumalik", @@ -449,6 +452,7 @@ "next": "Susunod", "buy_asset": "Bumili ng {{asset}}", "no_tokens": "Wala kang anumang token!", + "show_tokens_without_balance": "Ipakita ang mga token na walang balanse", "no_nfts_yet": "Wala pang mga NFT", "nfts_autodetection_title": "Pagtuklas ng NFT", "nfts_autodetection_desc": "Hayaan ang MetaMask na awtomatikong i-detect at ipakita ang mga NFT sa iyong wallet.", @@ -470,7 +474,7 @@ "learn_more": "Matuto pa", "add_collectibles": "Mag-import ng mga NFT", "no_transactions": "Wala kang transaksyon!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Pakisuyong lumipat ng network para tingnan ang mga transaksyon", "send_button": "Magpadala", "deposit_button": "Magdeposito", "copy_address": "Kopyahin", @@ -566,7 +570,7 @@ "description_content_1": "Nais naming mangalap ng data para sa batayang paggamit upang mapahusay ang MetaMask. Dapat mong malaman na hindi namin ibebenta ang data na iyong ibibigay rito.", "description_content_2": "Kapag kami ay nangangalap ng metrics, ito ay palaging...", "description_content_3": "Matuto kung paano namin pinoprotektahan ang iyong privacy habang nangongolekta ng data ng paggamit para sa iyong profile.", - "checkbox": "Gagamitin namin ang data na ito upang matutunan paano ka nakikipag-ugnayan sa aming mga komunikasyon sa marketing. Maaari kaming magbahagi ng kaugnay na balita (tulad ng mga tampok ng produkto).", + "checkbox": "Gagamitin namin ang data na ito para matutunan kung paano ka nakikipag-ugnayan sa aming mga komunikasyon sa marketing. Maaari kaming magbahagi ng kaugnay na balita (tulad ng mga tampok ng produkto).", "action_description_1_prefix": "Pribado:", "action_description_2_prefix": "Pangkalahatan:", "action_description_3_prefix": "Opsyonal:", @@ -722,6 +726,7 @@ "connected_and_active": "konektado at aktibo.", "now_active": "aktibo ngayon.", "network_added": "matagumpay na naidagdag", + "network_removed": "matagumpay na naalis", "network_deleted": "matagumpay na natanggal", "network_permissions_updated": "Na-update ang mga pahintulot sa network", "revoked": "binawi.", @@ -1264,16 +1269,19 @@ "sell_button": "Magbenta", "receive_button": "Tumanggap", "portfolio_button": "Portfolio", + "earn_button": "Kumita", "add_collectible_button": "Magdagdag", "info": "Impormasyon", "swap": "I-swap", "bridge": "Bridge", + "earn": "Kumita", "disabled_button": { "buy": "Hindi sinusuportahan ang pagbili para sa account na ito", "sell": "Hindi sinusuportahan ang pagbebenta para sa account na ito", "swap": "Hindi sinusuportahan ang pag-swap para sa account na ito", "bridge": "Hindi sinusuportahan ang pag-bridge para sa account na ito", "send": "Hindi sinusuportahan ang pagpapadala para sa account na ito", + "earn": "Hindi sinusuportahan na kumita para sa account na ito", "action": "Hindi sinusuportahan ang aksyong ito para sa account na ito" }, "description": "Deskripsyon", @@ -1290,6 +1298,7 @@ "bridge_description": "Maglipat ng mga token sa pagitan ng mga network", "send_description": "Magpadala ng crypto sa anumang account", "receive_description": "Tumanggap ng crypto", + "earn_description": "Kumita ng mga reward sa iyong mga token", "chart_time_period": { "1d": "Ngayong araw", "7d": "Nakalipas na 7 araw", @@ -1791,6 +1800,7 @@ "network_chain_id": "ID ng Chain", "network_rpc_url": "URL ng Network", "network_rpc_url_label": "RPC URL ng Network", + "network_rpc_url_warning_punycode": "Ginagaya minsan ng mga umaatake ang mga site sa pamamagitan ng kaunting mga pagbabago sa site address. Tiyaking nakikipag-ugnayan ka sa tamang Network URL bago ka magpatuloy. Bersyon ng punycode:", "new_default_network_url": "Bagong URL ng default network", "current_label": "Kasalukuyan", "new_label": "Bago", @@ -3340,9 +3350,9 @@ "user_reject_transaction": "Tinanggihan ng user ang transaksyon", "user_reject_transaction_message": "Tinanggihan ng user ang transaksyon sa Ledger device.", "multiple_devices_error_message": "Hindi pa sinusuportahan ang maraming device. Para magdagdag ng bagong Ledger device, kakailanganin mong mag-alis ng lumang device.", - "hd_path_error": "HD Path is invalid: {{path}}", - "unspecified_error_during_connect": "Unspecified error when connect Ledger Hardware,", - "account_name_existed": "Account {{accountName}} already exists" + "hd_path_error": "Hindi balido ang HD Path: {{path}}", + "unspecified_error_during_connect": "Hindi tiyak na error sa pagkonekta ng Ledger Hardware,", + "account_name_existed": "Mayroon nang account na {{accountName}}" }, "account_actions": { "edit_name": "I-edit ang pangalan ng account", @@ -3351,8 +3361,9 @@ "add_new_account": "Magdagdag ng bagong account", "add_hardware_wallet": "Magdagdag ng wallet na hardware", "import_account": "Mag-import ng account", - "add_bitcoin_account_testnet": "Add a new Bitcoin Account (Testnet)", - "add_bitcoin_account_mainnet": "Add a new Bitcoin Account (Beta)" + "add_bitcoin_account_testnet": "Magdagdag ng bagong Bitcoin Account (Testnet)", + "add_bitcoin_account_mainnet": "Magdagdag ng bagong Bitcoin Account (Beta)", + "add_solana_account": "Magdagdag ng bagong Solana Account (Beta)" }, "show_nft": { "show_nft_title": "Ipakita ang NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Kahilingan sa paglagda" }, + "sub_title": { + "signature": "Suriin ang mga detalye ng kahilingan bago mo kumpirmahin." + }, "request_from": "Hiling mula sa/kay", "message": "Mensahe", + "primary_type": "Pangunahing uri", "personal_sign_tooltip": "Hinihingi ng site na ito ang iyong pirma", "details": "Mga detalye", "account": "Account", "balance": "Balanse", "network": "Network", "simulation": { + "decoded_tooltip_bid_nft": "Makikita ang NFT sa wallet mo, kapag tinanggap ang bid.", + "decoded_tooltip_list_nft": "Asahan lang ang mga pagbabago kapag may bumili sa mga NFT mo.", + "info_permit": "Binibigyan mo ng pahintulot ang gumagastos na gastusin ang ganito karaming token mula sa account mo.", + "label_change_type_bidding": "Nag-bid ka ng", + "label_change_type_listing": "Nag-list ka ng", + "label_change_type_nft_listing": "Presyo ng listing", + "label_change_type_permit": "Limitasyon sa paggastos", + "label_change_type_permit_nft": "I-withdraw", + "label_change_type_receive": "Nakatanggap ka ng", + "label_change_type_revoke": "Ipawalang-bisa", + "label_change_type_transfer": "Nagpadala ka ng", + "personal_sign_info": "Nagsa-sign in ka sa isang site at walang inaasahang pagbabago sa iyong account.", "title": "Tinantyang mga pagbabago", - "personal_sign_info": "Nagsa-sign in ka sa isang site at walang mga inaasahang pagbabago sa iyong account.", - "tooltip": "Ang tinantyang mga pagbabago ay ang maaaring mangyari kung magpapatuloy ka sa transaksyon ito. Ito ay isang hula lamang, hindi isang garantiya." - } + "tooltip": "Ang tinantyang mga pagbabago ay ang maaaring mangyari kung magpapatuloy ka sa transaksyon ito. Ito ay isang hula lamang, hindi isang garantiya.", + "unavailable": "Hindi available" + }, + "unlimited": "Walang limitasyon", + "none": "None" }, "change_in_simulation_modal": { "title": "Nagbago ang mga resulta", diff --git a/locales/languages/tr.json b/locales/languages/tr.json index 8247e48fcc8..73ae31fde9b 100644 --- a/locales/languages/tr.json +++ b/locales/languages/tr.json @@ -48,7 +48,10 @@ "connector": "saat" }, "autocomplete": { - "placeholder": "Ara veya URL Gir" + "placeholder": "Siteye veya adrese göre ara", + "recents": "Son Ziyaret Edilenler", + "favorites": "Favoriler", + "sites": "Siteler" }, "navigation": { "back": "Geri", @@ -449,6 +452,7 @@ "next": "Sonraki", "buy_asset": "{{asset}} satın alın", "no_tokens": "Tokeniniz yok!", + "show_tokens_without_balance": "Bakiyesi olmayan token'leri göster", "no_nfts_yet": "Henüz NFT yok", "nfts_autodetection_title": "NFT algılama", "nfts_autodetection_desc": "MetaMask'in otomatik olarak cüzdanınızdaki NFT'leri algılayıp göstermesine izin verin.", @@ -470,7 +474,7 @@ "learn_more": "Daha fazlasını öğren", "add_collectibles": "NFT'leri içe aktar", "no_transactions": "Hiç işleminiz yok!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "İşlemleri görüntülemek için lütfen ağ değiştirin", "send_button": "Gönder", "deposit_button": "Para Yatır", "copy_address": "Hata", @@ -722,6 +726,7 @@ "connected_and_active": "bağlandı ve aktif.", "now_active": "şimdi aktif.", "network_added": "başarılı bir şekilde eklendi", + "network_removed": "başarılı bir şekilde kaldırıldı", "network_deleted": "başarılı bir şekilde silindi", "network_permissions_updated": "Ağ izinleri güncellendi", "revoked": "iptal edildi.", @@ -1264,16 +1269,19 @@ "sell_button": "Sat", "receive_button": "Al", "portfolio_button": "Portföy", + "earn_button": "Kazan", "add_collectible_button": "Ekle", "info": "Bilgi", "swap": "Kaydır", "bridge": "Köprü", + "earn": "Kazan", "disabled_button": { "buy": "Bu hesap için satın alma desteklenmiyor", "sell": "Bu hesap için satma desteklenmiyor", "swap": "Bu hesap için swap desteklenmiyor", "bridge": "Bu hesap için köprü desteklenmiyor", "send": "Bu hesap için gönderme desteklenmiyor", + "earn": "Kazanma bu hesap için desteklenmiyor", "action": "Bu hesap için bu işlem desteklenmiyor" }, "description": "Açıklama", @@ -1290,6 +1298,7 @@ "bridge_description": "Farklı ağlar arasında token transfer et", "send_description": "Dilediğin hesaba kripto gönderin", "receive_description": "Kripto alın", + "earn_description": "Token'lerinizden ödül kazanın", "chart_time_period": { "1d": "Bugün", "7d": "Son 7 gün", @@ -1791,6 +1800,7 @@ "network_chain_id": "Zincir Kimliği", "network_rpc_url": "Ağ URL adresi", "network_rpc_url_label": "Ağ RPC URL adresi", + "network_rpc_url_warning_punycode": "Saldırganlar bazen site adresinde küçük değişiklikler yaparak siteleri taklit edebilir. Devam etmeden önce istenilen Ağ URL adresi ile etkileşim kurduğunuzdan emin olun. Punycode sürümü:", "new_default_network_url": "Yeni varsayılan ağ URL adresi", "current_label": "Mevcut", "new_label": "Yeni", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Donanım cüzdanı ekleyin", "import_account": "Hesabı içe aktar", "add_bitcoin_account_testnet": "Yeni bir Bitcoin Hesabı ekle (Test Ağı)", - "add_bitcoin_account_mainnet": "Yeni bir Bitcoin Hesabı Ekle (Beta)" + "add_bitcoin_account_mainnet": "Yeni bir Bitcoin Hesabı Ekle (Beta)", + "add_solana_account": "Yeni bir Solana Hesabı ekle (Beta)" }, "show_nft": { "show_nft_title": "NFT'yi göster", @@ -3571,18 +3582,36 @@ "title": { "signature": "İmza talebi" }, + "sub_title": { + "signature": "Onaylamadan önce talep bilgilerini inceleyin." + }, "request_from": "Talebi gönderen", "message": "Mesaj", + "primary_type": "Birincil tür", "personal_sign_tooltip": "Bu site imzanızı istiyor", "details": "Ayrıntılar", "account": "Hesap", "balance": "Bakiye", "network": "Ağ", "simulation": { + "decoded_tooltip_bid_nft": "Teklif kabul edildiğinde NFT cüzdanınıza yansıyacak.", + "decoded_tooltip_list_nft": "Sadece biri NFT'lerinizi satın alırsa değişiklik olmasını bekleyin.", + "info_permit": "Harcama yapan tarafa hesabınızdan bu kadar token harcama izni veriyorsunuz.", + "label_change_type_bidding": "Teklifiniz", + "label_change_type_listing": "Listelediğiniz", + "label_change_type_nft_listing": "Liste fiyatı", + "label_change_type_permit": "Harcama üst limiti", + "label_change_type_permit_nft": "Çek", + "label_change_type_receive": "Aldığınız", + "label_change_type_revoke": "İptal et", + "label_change_type_transfer": "Gönderdiğiniz", + "personal_sign_info": "Bir siteye giriş yapıyorsunuz ve hesabınız için öngörülen herhangi bir değişiklik yok.", "title": "Tahmini değişiklikler", - "personal_sign_info": "Bir siteye giriş yapıyorsunuz ve hesabınızda öngörülen herhangi bir değişiklik yok.", - "tooltip": "Tahmini değişiklikler bu işlemi gerçekleştirirseniz meydana gelebilecek değişikliklerdir. Bu bir garanti değil, sadece bir tahmindir." - } + "tooltip": "Tahmini değişiklikler bu işlemi gerçekleştirirseniz meydana gelebilecek değişikliklerdir. Bu bir garanti değil, sadece bir tahmindir.", + "unavailable": "Mevcut değil" + }, + "unlimited": "Sınırsız", + "none": "None" }, "change_in_simulation_modal": { "title": "Sonuçlar değişti", diff --git a/locales/languages/vi.json b/locales/languages/vi.json index 9e795f80775..47defa9f5df 100644 --- a/locales/languages/vi.json +++ b/locales/languages/vi.json @@ -48,7 +48,10 @@ "connector": "tại" }, "autocomplete": { - "placeholder": "Tìm hoặc nhập URL" + "placeholder": "Tìm kiếm theo trang web hoặc địa chỉ", + "recents": "Gần đây", + "favorites": "Yêu thích", + "sites": "Trang web" }, "navigation": { "back": "Quay lại", @@ -449,6 +452,7 @@ "next": "Tiếp theo", "buy_asset": "Mua {{asset}}", "no_tokens": "Bạn không có token nào!", + "show_tokens_without_balance": "Hiển thị token không kèm số dư", "no_nfts_yet": "Chưa có NFT", "nfts_autodetection_title": "Phát hiện NFT", "nfts_autodetection_desc": "Cho phép MetaMask tự động phát hiện và hiển thị NFT trong ví của bạn.", @@ -470,7 +474,7 @@ "learn_more": "Tìm hiểu thêm", "add_collectibles": "Nhập NFT", "no_transactions": "Bạn không có giao dịch nào!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "Vui lòng chuyển mạng để xem giao dịch", "send_button": "Gửi", "deposit_button": "Nạp", "copy_address": "Sao chép", @@ -722,6 +726,7 @@ "connected_and_active": "đã được kết nối và đang hoạt động.", "now_active": "đang hoạt động.", "network_added": "đã được thêm thành công", + "network_removed": "đã được xóa thành công", "network_deleted": "đã xóa thành công", "network_permissions_updated": "Đã cập nhật quyền truy cập mạng", "revoked": "đã bị thu hồi.", @@ -1264,16 +1269,19 @@ "sell_button": "Bán", "receive_button": "Nhận", "portfolio_button": "Danh mục đầu tư", + "earn_button": "Kiếm tiền", "add_collectible_button": "Thêm", "info": "Thông tin", "swap": "Hoán đổi", "bridge": "Cầu nối", + "earn": "Kiếm tiền", "disabled_button": { "buy": "Không hỗ trợ mua cho tài khoản này", "sell": "Không hỗ trợ bán cho tài khoản này", "swap": "Không hỗ trợ hoán đổi cho tài khoản này", "bridge": "Không hỗ trợ cầu nối cho tài khoản này", "send": "Không hỗ trợ gửi cho tài khoản này", + "earn": "Không hỗ trợ kiếm tiền cho tài khoản này", "action": "Hành động này không được hỗ trợ cho tài khoản này" }, "description": "Mô tả", @@ -1290,6 +1298,7 @@ "bridge_description": "Chuyển token giữa các mạng", "send_description": "Gửi tiền mã hóa đến bất kỳ tài khoản nào", "receive_description": "Nhận tiền mã hóa", + "earn_description": "Kiếm phần thưởng trên token của bạn", "chart_time_period": { "1d": "Hôm nay", "7d": "7 ngày qua", @@ -1791,6 +1800,7 @@ "network_chain_id": "Mã chuỗi", "network_rpc_url": "URL mạng", "network_rpc_url_label": "URL Mạng RPC", + "network_rpc_url_warning_punycode": "Những kẻ tấn công đôi khi bắt chước các trang web bằng cách thực hiện các thay đổi nhỏ trong địa chỉ trang web. Hãy chắc chắn rằng bạn đang tương tác với URL Mạng mà bạn dự định trước khi tiếp tục. Phiên bản Punycode:", "new_default_network_url": "URL mạng mặc định mới", "current_label": "Hiện tại", "new_label": "Mới", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "Thêm ví cứng", "import_account": "Nhập tài khoản", "add_bitcoin_account_testnet": "Thêm Tài khoản Bitcoin mới (Mạng thử nghiệm)", - "add_bitcoin_account_mainnet": "Thêm Tài khoản Bitcoin mới (Beta)" + "add_bitcoin_account_mainnet": "Thêm Tài khoản Bitcoin mới (Beta)", + "add_solana_account": "Thêm Tài khoản Solana mới (Beta)" }, "show_nft": { "show_nft_title": "Hiển thị NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "Yêu cầu chữ ký" }, + "sub_title": { + "signature": "Xem lại thông tin yêu cầu trước khi bạn xác nhận." + }, "request_from": "Yêu cầu từ", "message": "Thông báo", + "primary_type": "Loại chính", "personal_sign_tooltip": "Trang web này đang yêu cầu chữ ký của bạn", "details": "Chi tiết", "account": "Tài khoản", "balance": "Số dư", "network": "Mạng", "simulation": { - "title": "Thay đổi ước tính", + "decoded_tooltip_bid_nft": "NFT sẽ được hiển thị trong ví của bạn khi giá thầu được chấp nhận.", + "decoded_tooltip_list_nft": "Chỉ thay đổi khi có người mua NFT của bạn.", + "info_permit": "Bạn đang cho phép người chi tiêu sử dụng số lượng token này từ tài khoản của bạn.", + "label_change_type_bidding": "Bạn đặt giá", + "label_change_type_listing": "Bạn niêm yết", + "label_change_type_nft_listing": "Giá niêm yết", + "label_change_type_permit": "Giới hạn chi tiêu", + "label_change_type_permit_nft": "Rút tiền", + "label_change_type_receive": "Bạn nhận được", + "label_change_type_revoke": "Thu hồi", + "label_change_type_transfer": "Bạn gửi", "personal_sign_info": "Bạn đang đăng nhập vào một trang web và dự kiến không có thay đổi nào đối với tài khoản của bạn.", - "tooltip": "Thay đổi ước tính là những gì có thể xảy ra nếu bạn thực hiện giao dịch này. Đây chỉ là dự đoán, không phải là đảm bảo." - } + "title": "Thay đổi ước tính", + "tooltip": "Thay đổi ước tính là những gì có thể xảy ra nếu bạn thực hiện giao dịch này. Đây chỉ là dự đoán, không phải là đảm bảo.", + "unavailable": "Không khả dụng" + }, + "unlimited": "Không giới hạn", + "none": "None" }, "change_in_simulation_modal": { "title": "Kết quả đã thay đổi", diff --git a/locales/languages/zh.json b/locales/languages/zh.json index 8e349ded662..b2f3972e1a3 100644 --- a/locales/languages/zh.json +++ b/locales/languages/zh.json @@ -48,7 +48,10 @@ "connector": "于" }, "autocomplete": { - "placeholder": "搜索或键入 URL" + "placeholder": "按网站或地址搜索", + "recents": "最近", + "favorites": "收藏", + "sites": "网站" }, "navigation": { "back": "返回", @@ -449,6 +452,7 @@ "next": "下一步", "buy_asset": "购买{{asset}}", "no_tokens": "您没有任何代币!", + "show_tokens_without_balance": "显示没有余额的代币", "no_nfts_yet": "尚无 NFT", "nfts_autodetection_title": "NFT 检测", "nfts_autodetection_desc": "让 MetaMask 自动检测并显示您钱包中的 NFT。", @@ -470,7 +474,7 @@ "learn_more": "了解更多", "add_collectibles": "添加收藏品", "no_transactions": "您没有交易!", - "switch_network_to_view_transactions": "Please switch network to view transactions", + "switch_network_to_view_transactions": "请切换网络以查看交易", "send_button": "发送", "deposit_button": "保证金", "copy_address": "复制", @@ -722,6 +726,7 @@ "connected_and_active": "已连接且处于活动状态。", "now_active": "现处于活动状态。", "network_added": "已成功添加", + "network_removed": "已成功去除", "network_deleted": "已成功删除", "network_permissions_updated": "网络许可已更新", "revoked": "已撤销。", @@ -1264,16 +1269,19 @@ "sell_button": "卖出", "receive_button": "接收", "portfolio_button": "投资组合", + "earn_button": "赚取", "add_collectible_button": "添加", "info": "信息", "swap": "兑换", "bridge": "跨链桥", + "earn": "赚取", "disabled_button": { "buy": "此账户不支持买入", "sell": "此账户不支持卖出", "swap": "此账户不支持兑换", "bridge": "此账户不支持跨链桥", "send": "此账户不支持发送", + "earn": "此账户不支持赚取", "action": "此账户不支持此操作" }, "description": "描述", @@ -1290,6 +1298,7 @@ "bridge_description": "在不同网络间传送代币", "send_description": "向任何账户发送加密货币", "receive_description": "接收加密货币", + "earn_description": "通过您的代币赚取奖励", "chart_time_period": { "1d": "今天", "7d": "过去 7 天", @@ -1791,6 +1800,7 @@ "network_chain_id": "链 ID", "network_rpc_url": "网络URL", "network_rpc_url_label": "网络 RPC(远程过程调用)URL", + "network_rpc_url_warning_punycode": "攻击者有时会通过对网站地址进行细微更改来模仿网站。在继续操作之前,请确保您正在与目标网络 URL 进行交互。Punycode 版本:", "new_default_network_url": "新的默认网络 URL", "current_label": "当前", "new_label": "新增", @@ -3352,7 +3362,8 @@ "add_hardware_wallet": "添加硬件钱包", "import_account": "导入账户", "add_bitcoin_account_testnet": "添加新的比特币账户(测试网)", - "add_bitcoin_account_mainnet": "添加新的比特币账户(测试版)" + "add_bitcoin_account_mainnet": "添加新的比特币账户(测试版)", + "add_solana_account": "添加新的 Solana 账户(测试版)" }, "show_nft": { "show_nft_title": "显示NFT", @@ -3571,18 +3582,36 @@ "title": { "signature": "签名请求" }, + "sub_title": { + "signature": "在确认之前检查请求详情。" + }, "request_from": "请求来自", "message": "消息", + "primary_type": "主要类型", "personal_sign_tooltip": "此网站要求您签名", "details": "详情", "account": "账户", "balance": "余额", "network": "网络", "simulation": { - "title": "预计变化", + "decoded_tooltip_bid_nft": "当接受出价时,NFT 将反映在您的钱包中。", + "decoded_tooltip_list_nft": "只有当有人购买您的 NFT 时才会发生变化。", + "info_permit": "您将授予支出者许可,才能从您的账户花费这些代币。", + "label_change_type_bidding": "您出价", + "label_change_type_listing": "您挂牌", + "label_change_type_nft_listing": "挂牌价格", + "label_change_type_permit": "支出上限", + "label_change_type_permit_nft": "提款", + "label_change_type_receive": "您收到", + "label_change_type_revoke": "撤销", + "label_change_type_transfer": "您发送", "personal_sign_info": "您正在登录某个网站,并且您的账户没有预期变化。", - "tooltip": "预期变化是指您完成该交易可能发生的变化。这只是预测,而不是保证。" - } + "title": "预计变化", + "tooltip": "预期变化是指您完成该交易可能发生的变化。这只是预测,而不是保证。", + "unavailable": "不可用" + }, + "unlimited": "无限制", + "none": "None" }, "change_in_simulation_modal": { "title": "结果已发生变化", From 96b7a882b5c20784c57627bc2737cc33487c7e48 Mon Sep 17 00:00:00 2001 From: OGPoyraz Date: Thu, 30 Jan 2025 11:04:46 +0100 Subject: [PATCH 05/18] fix: Fix the case of undefined `networkClientId` & `chainId` (#13262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to fix sentry error : https://metamask.sentry.io/issues/6139255474 ## **Related issues** Fixes: https://github.com/MetaMask/metamask-mobile/issues/13101 ## **Manual testing steps** N/A ## **Screenshots/Recordings** ### **Before** ### **After** ## **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. --- app/util/transactions/index.js | 2 +- app/util/transactions/index.test.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/util/transactions/index.js b/app/util/transactions/index.js index eadb29d6e21..dd9840b8e54 100644 --- a/app/util/transactions/index.js +++ b/app/util/transactions/index.js @@ -432,7 +432,7 @@ export async function getTransactionActionKey(transaction, chainId) { const toSmartContract = transaction.toSmartContract !== undefined ? transaction.toSmartContract - : await isSmartContractAddress(to, undefined, networkClientId); + : await isSmartContractAddress(to, chainId, networkClientId); if (toSmartContract) { return SMART_CONTRACT_INTERACTION_ACTION_KEY; diff --git a/app/util/transactions/index.test.ts b/app/util/transactions/index.test.ts index aa3d10495e0..c18d2dfab9f 100644 --- a/app/util/transactions/index.test.ts +++ b/app/util/transactions/index.test.ts @@ -73,6 +73,11 @@ ENGINE_MOCK.context = { provider: {} as Provider, }), }, + TokenListController: { + state: { + tokenList: {}, + }, + }, }; const spyOnQueryMethod = (returnValue: string | undefined) => From 237691a3ea0717426ad64d2efce21fcd57797bca Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:10:51 +0300 Subject: [PATCH 06/18] feat(network): validate RPC URL for popular networks on add network from dapp connection (#13198) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** **Issue**: if the dapp propose a rpc url different than the expected one, the user might expect the one from the popular network to be used, while in fact the dapp is proposing a different rpc url **Solution**: This PR adds validation to check if a dapp-initiated network addition matches a popular network's RPC URL. Shows a review button when there's a mismatch, allowing users to compare the provided RPC URL with the expected one. ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/4035 ## **Manual testing steps** 1. Open the browser to uniswap and select arbitrum one as network to connect to, then click connect 2. The bottom sheet comes up and since the rpc url differs from the expected one from the corresponding popular network, it displays a tag button to review the current rpc url from popular netoworks and new rpc url proposed by the dapp 3. After having review, click back and click confirm to accept adding the network and rpc url to enabled networks. ## **Screenshots/Recordings** | Before | After | |--------------|--------------| | Screenshot 2024-04-18 at 3 56 43 PM |Screenshot 2024-04-18 at 3 56 43 PM | ## **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. --- .../NetworkVerificationInfo.constants.ts | 2 + .../NetworkVerificationInfo.ff-on.test.tsx | 133 ++++++++++++++++++ .../NetworkVerificationInfo.tsx | 36 +++-- 3 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.constants.ts create mode 100644 app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.ff-on.test.tsx diff --git a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.constants.ts b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.constants.ts new file mode 100644 index 00000000000..26fecc38932 --- /dev/null +++ b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.constants.ts @@ -0,0 +1,2 @@ +export const MISSMATCH_RPC_URL_TEST_ID = + 'networks.rpc-url-missmatch-review-and-compare'; diff --git a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.ff-on.test.tsx b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.ff-on.test.tsx new file mode 100644 index 00000000000..23eb8f3b01c --- /dev/null +++ b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.ff-on.test.tsx @@ -0,0 +1,133 @@ +/** + * This separate test file was created to test the component with isMultichainVersion1Enabled=true. + * Due to the way feature flags are imported and used, it's cleaner to mock them in a separate file. + * When the feature flag is removed, these tests should be merged into the main NetworkVerificationInfo.test.tsx file. + */ +import React from 'react'; +import NetworkVerificationInfo from './NetworkVerificationInfo'; +import { BannerAlertSeverity } from '../../../component-library/components/Banners/Banner'; +import { strings } from '../../../../locales/i18n'; +import { useSelector } from 'react-redux'; +import renderWithProvider from '../../../util/test/renderWithProvider'; +import { PopularList } from '../../../util/networks/customNetworks'; +import { MISSMATCH_RPC_URL_TEST_ID } from './NetworkVerificationInfo.constants'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +// Mock feature flags +jest.mock('../../../util/networks/index.js', () => ({ + ...jest.requireActual('../../../util/networks/index.js'), + isMultichainVersion1Enabled: true, + isChainPermissionsFeatureEnabled: true, +})); + +const mockNetworkInfo = { + chainName: 'Test Chain', + chainId: '0xa', + rpcUrl: 'http://test.com', + ticker: 'TEST', + blockExplorerUrl: 'http://explorer.test.com', + alerts: [ + { + alertError: strings('add_custom_network.unrecognized_chain_name'), + alertSeverity: BannerAlertSeverity.Warning, + alertOrigin: 'chain_name', + }, + ], + icon: 'test-icon', +}; + +describe('NetworkVerificationInfo with Feature Flag ON', () => { + // Setup and cleanup for PopularList mock + const originalPopularList = [PopularList]; + + beforeEach(() => { + (useSelector as jest.Mock).mockClear(); + }); + + afterEach(() => { + // Restore original PopularList after each test + PopularList.length = 0; + PopularList.push(...originalPopularList[0]); + }); + + describe('RPC URL Mismatch Detection', () => { + const createMockPopularNetwork = (rpcUrl: string) => ({ + chainId: '0xa' as `0x${string}`, + rpcUrl, + rpcPrefs: { + imageSource: 'test-image', + blockExplorerUrl: 'https://test-explorer.com', + imageUrl: 'https://test-image.com', + }, + nickname: 'Test Network', + ticker: 'TEST', + warning: false, + }); + + const createNetworkWithPageMeta = (url: string) => ({ + ...mockNetworkInfo, + pageMeta: { url }, + }); + + it('hides RPC mismatch UI for non-dapp requests', () => { + const { queryByTestId } = renderWithProvider( + undefined} + onConfirm={() => undefined} + isCustomNetwork={false} + />, + ); + + expect(queryByTestId(MISSMATCH_RPC_URL_TEST_ID)).toBeNull(); + }); + + it('displays RPC mismatch UI when URLs differ', () => { + const mockPopularNetwork = createMockPopularNetwork( + 'https://different.rpc.url', + ); + PopularList.length = 0; + PopularList.push(mockPopularNetwork); + + const networkInfoWithPageMeta = createNetworkWithPageMeta( + 'https://app.uniswap.org', + ); + + const { queryByTestId } = renderWithProvider( + undefined} + onConfirm={() => undefined} + isCustomNetwork={false} + />, + ); + + expect(queryByTestId(MISSMATCH_RPC_URL_TEST_ID)).toBeDefined(); + }); + + it('hides RPC mismatch UI when URLs match', () => { + const mockPopularNetwork = createMockPopularNetwork('http://test.com'); + PopularList.length = 0; + PopularList.push(mockPopularNetwork); + + const networkInfoWithPageMeta = createNetworkWithPageMeta( + 'https://app.uniswap.org', + ); + + const { queryByTestId } = renderWithProvider( + undefined} + onConfirm={() => undefined} + isCustomNetwork={false} + />, + ); + + expect(queryByTestId(MISSMATCH_RPC_URL_TEST_ID)).toBeNull(); + }); + }); +}); diff --git a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx index 50db0e9fa36..3961eb214b7 100644 --- a/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx +++ b/app/components/UI/NetworkVerificationInfo/NetworkVerificationInfo.tsx @@ -44,6 +44,8 @@ import { NetworkApprovalBottomSheetSelectorsIDs } from '../../../../e2e/selector import hideKeyFromUrl from '../../../util/hideKeyFromUrl'; import { convertHexToDecimal } from '@metamask/controller-utils'; import { isValidASCIIURL, toPunycodeURL } from '../../../util/url'; +import { PopularList } from '../../../util/networks/customNetworks'; +import { MISSMATCH_RPC_URL_TEST_ID } from './NetworkVerificationInfo.constants'; interface Alert { alertError: string; @@ -59,13 +61,11 @@ const NetworkVerificationInfo = ({ onReject, onConfirm, isCustomNetwork = false, - isMissmatchingRPCUrl = false, }: { customNetworkInformation: CustomNetworkInformation; onReject: () => void; onConfirm: () => void; isCustomNetwork?: boolean; - isMissmatchingRPCUrl?: boolean; }) => { const [networkInfoMaxHeight, setNetworkInfoMaxHeight] = useState< number | null @@ -86,6 +86,24 @@ const NetworkVerificationInfo = ({ const customRpcUrl = customNetworkInformation.rpcUrl; + const isDappRequest = useMemo( + // @ts-expect-error - The CustomNetworkInformation type is missing the pageMeta property + () => Boolean(customNetworkInformation.pageMeta?.url), + [customNetworkInformation], + ); + + const matchingPopularNetwork = useMemo(() => { + if (!isDappRequest) return null; + return PopularList.find( + (network) => network.chainId === customNetworkInformation.chainId, + ); + }, [isDappRequest, customNetworkInformation.chainId]); + + const hasRpcMismatch = useMemo(() => { + if (!matchingPopularNetwork) return false; + return matchingPopularNetwork.rpcUrl !== customNetworkInformation.rpcUrl; + }, [matchingPopularNetwork, customNetworkInformation.rpcUrl]); + const goToLearnMore = () => { Linking.openURL( 'https://support.metamask.io/networks-and-sidechains/managing-networks/verifying-custom-network-information/', @@ -169,19 +187,19 @@ const NetworkVerificationInfo = ({ const renderNetworkRpcUrlLabel = () => ( {strings('networks.network_rpc_url_label')} - {isMissmatchingRPCUrl && ( + {hasRpcMismatch && ( { showReviewDefaultRpcUrlChangesModal(); }} > - + {strings('networks.current_label')} - {customRpcUrl} + + {hideKeyFromUrl(matchingPopularNetwork?.rpcUrl)} + {strings('networks.new_label')} - - {'https://flashbots.polygon-mainnet.com'} - + {hideKeyFromUrl(customRpcUrl)} From 8c3f3954a2fec13622ccb835e3608e85e0e44a9d Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Thu, 30 Jan 2025 15:05:49 +0100 Subject: [PATCH 07/18] fix: update token balances on pull tokenlist pull down (#13208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** PR to add updating balances as part of pulling down on the tokenList ## **Related issues** Fixes: ## **Manual testing steps** 1. Make a swap between any 2 tokens 2. Go back to home page and notice your balance is not updated for the two tokens. 3. Pull down on the tokenList 4. Your balances should now be refreshed ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/585f8789-3509-443f-be69-eab8e4ef1ac5 ## **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. --- app/components/UI/Tokens/index.test.tsx | 6 ++++++ app/components/UI/Tokens/index.tsx | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/app/components/UI/Tokens/index.test.tsx b/app/components/UI/Tokens/index.test.tsx index 748728e89b8..f183dacc113 100644 --- a/app/components/UI/Tokens/index.test.tsx +++ b/app/components/UI/Tokens/index.test.tsx @@ -45,6 +45,9 @@ jest.mock('../../../core/Engine', () => ({ TokenRatesController: { updateExchangeRatesByChainId: jest.fn(() => Promise.resolve()), }, + TokenBalancesController: { + updateBalances: jest.fn(() => Promise.resolve()), + }, NetworkController: { getNetworkClientById: () => ({ configuration: { @@ -438,6 +441,9 @@ describe('Tokens', () => { expect( Engine.context.TokenDetectionController.detectTokens, ).toHaveBeenCalled(); + expect( + Engine.context.TokenBalancesController.updateBalances, + ).toHaveBeenCalled(); expect( Engine.context.AccountTrackerController.refresh, ).toHaveBeenCalled(); diff --git a/app/components/UI/Tokens/index.tsx b/app/components/UI/Tokens/index.tsx index ac758e82b19..48684d1f0d3 100644 --- a/app/components/UI/Tokens/index.tsx +++ b/app/components/UI/Tokens/index.tsx @@ -368,6 +368,7 @@ const Tokens: React.FC = memo(({ tokens }) => { AccountTrackerController, CurrencyRateController, TokenRatesController, + TokenBalancesController, } = Engine.context; const actions = [ @@ -376,6 +377,12 @@ const Tokens: React.FC = memo(({ tokens }) => { ? (Object.keys(networkConfigurationsByChainId) as Hex[]) : [currentChainId], }), + + TokenBalancesController.updateBalances({ + chainIds: isPortfolioViewEnabled() + ? (Object.keys(networkConfigurationsByChainId) as Hex[]) + : [currentChainId], + }), AccountTrackerController.refresh(), CurrencyRateController.updateExchangeRate(nativeCurrencies), ...(isPortfolioViewEnabled() From 999bcea65709e8047607cdd14b61904af7cf4fb1 Mon Sep 17 00:00:00 2001 From: Davide Brocchetto Date: Thu, 30 Jan 2025 10:09:38 -0800 Subject: [PATCH 08/18] test: Added back ramps smoke tests to Bitrise (#13272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The ramps smoke test were remove accidentally from Bitrise. This PR adds them back ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] 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). - [x] 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. --- bitrise.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/bitrise.yml b/bitrise.yml index 184080590e5..b45fc4779ee 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -161,6 +161,7 @@ stages: - run_tag_smoke_confirmations_ios: {} - run_tag_smoke_confirmations_android: {} - run_tag_smoke_confirmations_redesigned_ios: {} + - run_tag_smoke_ramps_android: {} - run_tag_smoke_swaps_ios: {} - run_tag_smoke_swaps_android: {} - run_tag_smoke_core_ios: {} From 4be52cd9912fede34d1b16dc5daf1f38c179c47b Mon Sep 17 00:00:00 2001 From: jake-perkins <128608287+jake-perkins@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:03:36 -0600 Subject: [PATCH 09/18] feat: shared-platform rls process (#13280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This change introduces a V2 release workflow that leverages a shared release workflow used across both mobile & extension ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3641 ## **Manual testing steps** Manually tested using various CI/CD runs ## **Screenshots/Recordings** ### **Before** N/A - CI/CD Only ### **After** N/A - CI/CD Only ## **Pre-merge author checklist** - [x] 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). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] 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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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: sethkfman <10342624+sethkfman@users.noreply.github.com> --- .github/workflows/create-release-pr-v2.yml | 35 + .gitignore | 3 + CHANGELOG.md | 1079 +++++++++++++------- 3 files changed, 740 insertions(+), 377 deletions(-) create mode 100644 .github/workflows/create-release-pr-v2.yml diff --git a/.github/workflows/create-release-pr-v2.yml b/.github/workflows/create-release-pr-v2.yml new file mode 100644 index 00000000000..02cf14f6098 --- /dev/null +++ b/.github/workflows/create-release-pr-v2.yml @@ -0,0 +1,35 @@ +name: Create Release Pull Request V2 + +on: + workflow_dispatch: + inputs: + base-branch: + description: 'The base branch, tag, or SHA for git operations and the pull request.' + required: true + semver-version: + description: 'A semantic version. eg: x.x.x' + required: true + previous-version-tag: + description: 'Previous release version tag. eg: v7.7.0' + required: true +jobs: + generate-build-version: + uses: MetaMask/metamask-mobile-build-version/.github/workflows/metamask-mobile-build-version.yml@v0.2.0 + permissions: + id-token: write + + create-release-pr: + needs: generate-build-version + uses: MetaMask/github-tools/.github/workflows/create-release-pr.yml@v0.1.0 + with: + platform: mobile + base-branch: ${{ inputs.base-branch }} + semver-version: ${{ inputs.semver-version }} + previous-version-tag: ${{ inputs.previous-version-tag }} + mobile-build-version: ${{ needs.generate-build-version.outputs.build-version }} + secrets: + # This token needs read permissions to metamask-planning & write permissions to metamask-mobile + github-token: ${{ secrets.PR_TOKEN }} + permissions: + contents: write + pull-requests: write diff --git a/.gitignore b/.gitignore index 092fc633fdf..599383be36e 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,6 @@ android/app/src/main/assets/modules.json .expo dist/ web-build/ + +# CICD +github-tools/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d22fc056d..91b356991ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ # Changelog +All notable changes to this project will be documented in this file. -## Current Main Branch +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 7.38.1 - Jan 21, 2024 +## [Unreleased] + +## [7.38.1] ### Fixed - [#13067](https://github.com/MetaMask/metamask-mobile/pull/13067)fix: remove expo changes (#13067) -## 7.38.0 - Jan 16, 2024 +## [7.38.0] ### Added - [#12427](https://github.com/MetaMask/metamask-mobile/pull/12427): feat: implement remote feature flag controller (#12427) - [#12507](https://github.com/MetaMask/metamask-mobile/pull/12507): feat: activate portfolio view (#12507) @@ -77,13 +81,13 @@ - [#12567](https://github.com/MetaMask/metamask-mobile/pull/12567): fix: update input handling in useInputHandler to support BACK key functionality (#12567) - [#12630](https://github.com/MetaMask/metamask-mobile/pull/12630): fix: hide tokens without balance for multichain (#12630) -## 7.37.1 - Dec 16, 2024 +## [7.37.1] ### Fixed - [#12577](https://github.com/MetaMask/metamask-mobile/pull/12577): chore: bump {gas-fee,network,selected-network,notification-services,profile-sync,signature}-controller (#12577) - [#12694](https://github.com/MetaMask/metamask-mobile/pull/12694): fix: small refactoring of the latest migration script + add a new migration case (#12694) - [#12664](https://github.com/MetaMask/metamask-mobile/pull/12664): fix: mark transactions as failed for cancelled / unknown smart transactions (#12664) -## 7.37.0 - Nov 28, 2024 +## [7.37.0] ### Added - [#12091](https://github.com/MetaMask/metamask-mobile/pull/12091): feat: 2020 Add a performance test for iOS in Bitrise (#12091) - [#12148](https://github.com/MetaMask/metamask-mobile/pull/12148): feat: Enable smart transactions for new users (#12148) @@ -145,7 +149,7 @@ - [#12371](https://github.com/MetaMask/metamask-mobile/pull/12371): fix: fix patch missing variable sentry error (#12371) - [#12375](https://github.com/MetaMask/metamask-mobile/pull/12375): fix: breaking selector due to missing controller state (#12375) -## 7.36.0 - Nov 15, 2024 +## [7.36.0] ### Added - [#12015](https://github.com/MetaMask/metamask-mobile/pull/12015): feat: 1957 crash screen redesign (#12015) - [#12186](https://github.com/MetaMask/metamask-mobile/pull/12186): feat (cherry-pick): display staking transaction methods (#12110) (#12186) @@ -213,11 +217,11 @@ - [#12235](https://github.com/MetaMask/metamask-mobile/pull/12235): fix: privacy mode is enabled in account selector by params (#12235) - [#12282](https://github.com/MetaMask/metamask-mobile/pull/12282): fix: Lock ruby version to 3.1.6 and bump pod to 1.16.2 (#12282) -## 7.35.1 - Nov 20, 2024 +## [7.35.1] ### Fixed - [#12331](https://github.com/MetaMask/metamask-mobile/pull/12331): fix: tags pending approvals receiving undefined (#12331) -## 7.35.0 - Nov 4, 2024 +## [7.35.0] ### Added - [#12078](https://github.com/MetaMask/metamask-mobile/pull/12078): chore(runway): cherry-pick feat: add favorites to browser menu (#12078) - [#12107](https://github.com/MetaMask/metamask-mobile/pull/12107): feat: Add re-simulation feature (#12107) @@ -326,13 +330,13 @@ - [#11989](https://github.com/MetaMask/metamask-mobile/pull/11989): fix: Remove unnecessary re renders activity view (#11989) - [#11769](https://github.com/MetaMask/metamask-mobile/pull/11769): fix: Fix the mobile crash due to ledger bluetooth relative exception (#11769) -## 7.34.1 - Nov 8, 2024 +## [7.34.1] ### 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 +## [7.34.0] ### Added - [#11578](https://github.com/MetaMask/metamask-mobile/pull/11578): feat: 1653 first feature flag poc (#11578) - [#11705](https://github.com/MetaMask/metamask-mobile/pull/11705): feat: Transition from Multiple Networks with Same ChainID to Unique Networks with Distinct ChainIDs and Multiple RPC URLs (#11705) @@ -427,15 +431,15 @@ - [#11633](https://github.com/MetaMask/metamask-mobile/pull/11633): fix(ramp): disable button while confirming off-ramp transaction (#11633) - [#11431](https://github.com/MetaMask/metamask-mobile/pull/11431): fix: refactor notifications unit tests (#11431) -## 7.33.2 - Nov 1, 2024 +## [7.33.2] ### Fixed - [#10952](https://github.com/MetaMask/metamask-mobile/pull/10952): refactor(ramp): update ramp copy (#10952) -## 7.33.1 - Oct 29, 2024 +## [7.33.1] ### Fixed - [#12073](https://github.com/MetaMask/metamask-mobile/pull/12073): feat: Simulation re-trigger (#12073) -## 7.33.0 - Oct 17, 2024 +## [7.33.0] ### Added - [#11507](https://github.com/MetaMask/metamask-mobile/pull/11507): feat: 10550 Re-introduce test for measuring cold app start + JS bundle load time (#11507) - [#11318](https://github.com/MetaMask/metamask-mobile/pull/11318): feat: app event manager and attribution id parameters (#11318) @@ -540,7 +544,7 @@ - [#11552](https://github.com/MetaMask/metamask-mobile/pull/11552): fix(11481): android system alert respects dark mode themes (#11552) - [#11518](https://github.com/MetaMask/metamask-mobile/pull/11518): fix(11482): incorrect QR code error (#11518) -## 7.32.0 - Oct 7, 2024 +## [7.32.0] ### 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) @@ -627,11 +631,11 @@ - [#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.1 - Oct 4, 2024 +## [7.31.1] ### Fixed - [#11631](https://github.com/MetaMask/metamask-mobile/pull/11631): fix: Fixes UI issue in token details (#11631) -## 7.31.0 - Sep 6, 2024 +## [7.31.0] ### Added - [#10747](https://github.com/MetaMask/metamask-mobile/pull/10747): feat: 2805 grant permission to network with missmatching rpc url (#10747) - [#10715](https://github.com/MetaMask/metamask-mobile/pull/10715): feat: 2795 disconnect all account permission multichain edit account screen (#10715) @@ -643,6 +647,7 @@ - [#2796](https://github.com/MetaMask/metamask-mobile/pull/2796): feat(2796): permission settings for multichain - [#10727](https://github.com/MetaMask/metamask-mobile/pull/10727): feat: add ledger live deviation path support (#10727) + ### Changed - [#10749](https://github.com/MetaMask/metamask-mobile/pull/10749): chore(deps): bump rexml from 3.3.3 to 3.3.6 in the bundler group across 1 directory (#10749) - [#10794](https://github.com/MetaMask/metamask-mobile/pull/10794): Release-update-BS-URL (#10794) @@ -730,7 +735,7 @@ - [#10795](https://github.com/MetaMask/metamask-mobile/pull/10795): fix: small UI polishings (#10795) - [#10792](https://github.com/MetaMask/metamask-mobile/pull/10792): fix: refactor notifications utils (#10792) -## 7.30.0 - Sep 6, 2024 +## [7.30.0] ### Added - [#10748](https://github.com/MetaMask/metamask-mobile/pull/10748): feat: Add yarn flipper script (#10748) - [#10739](https://github.com/MetaMask/metamask-mobile/pull/10739): feat: Feat/add redux debugger (#10739) @@ -827,16 +832,16 @@ - [#10640](https://github.com/MetaMask/metamask-mobile/pull/10640): fix: notification small fixes (#10640) - [#10693](https://github.com/MetaMask/metamask-mobile/pull/10693): fix: notification second round fixes (#10693) -## 7.29.2 - Sep 2, 2024 +## [7.29.2] ### Fixed - [#10965](https://github.com/MetaMask/metamask-mobile/pull/10965): fix: gas never loading during send + high gas fee after deep link (#10965) - [#11005](https://github.com/MetaMask/metamask-mobile/pull/11005): fix: Add missing allowedAction NetworkController:findNetworkClientIdByChainId to transactionController (#11005) -## 7.29.1 - Aug 29, 2024 +## [7.29.1] ### Fixed - [#10831](https://github.com/MetaMask/metamask-mobile/pull/10831): feat: Update Polygon from MATIC to POL (#10831) -## 7.29.0 - Aug 6, 2024 +## [7.29.0] ### Added - [#9578](https://github.com/MetaMask/metamask-mobile/pull/9578): feat: type `renderHookWithProvider` (#9578) - [#10277](https://github.com/MetaMask/metamask-mobile/pull/10277): feat: New nft details page (#10277) @@ -901,12 +906,12 @@ - [#10365](https://github.com/MetaMask/metamask-mobile/pull/10365): fix: attribution link (#10365) - [#10303](https://github.com/MetaMask/metamask-mobile/pull/10303): fix: page navigation during QR accounts selection (#10303) -## 7.28.1 - Aug 15, 2024 +## [7.28.1] ### Fixed - [#10637](https://github.com/MetaMask/metamask-mobile/pull/10637): fix: swap button blocked by SwapsController polling issue (#10637) - [#10654](https://github.com/MetaMask/metamask-mobile/pull/10654): fix: hot fix for ledger account select screen to provide disclaimer copy information. (#10654) -## 7.28.0 - Jul 19, 2024 +## [7.28.0] ### Added - [#10252](https://github.com/MetaMask/metamask-mobile/pull/10252): feat: regression label (#10252) - [#10214](https://github.com/MetaMask/metamask-mobile/pull/10214): feat: Partially local WebView for Snaps (#10214) @@ -946,11 +951,11 @@ - [#10266](https://github.com/MetaMask/metamask-mobile/pull/10266): fix: blockaid loader on confirmation pages (#10266) - [#10279](https://github.com/MetaMask/metamask-mobile/pull/10279): fix: use ACTIONS_WRITE_TOKEN in attributions workflow (#10279) -## 7.27.1 - Jul 25, 2024 +## [7.27.1] ### Fixed - [#10438](https://github.com/MetaMask/metamask-mobile/pull/10438): cherry-pick: update @blockaid/ppom_release package to version 1.5.1 (#10435) #10438 -## 7.27.0 - Jul 19, 2024 +## [7.27.0] ### Added - [#7759](https://github.com/MetaMask/metamask-mobile/pull/7759): feat: upgrade react-native-webview (#7759) - [#10000](https://github.com/MetaMask/metamask-mobile/pull/10000): feat: support security alerts API (#10000) @@ -1018,11 +1023,11 @@ - [#9843](https://github.com/MetaMask/metamask-mobile/pull/9843): fix: deeplink is not opening the site in the inapp-browser when the wallet is locked (#9843) - [#10064](https://github.com/MetaMask/metamask-mobile/pull/10064): fix: Always mark the STX Opt In modal as seen (#10064) -## 7.26.1 - Jul 17, 2024 -### Fixed +## [7.26.1] +### Fixed - [#9724](https://github.com/MetaMask/metamask-mobile/pull/9724): feat: remove selectIdentities in favour of selectInternalAccounts -## 7.26.0 - Jul 5, 2024 +## [7.26.0] ### Added - [#9937](https://github.com/MetaMask/metamask-mobile/pull/9937): feat: modification of the network bottom sheet to use the new UI redesign by adding the popular network section as additional network (#9937) - [#9856](https://github.com/MetaMask/metamask-mobile/pull/9856): feat: new attribution github workflow (#9856) @@ -1121,24 +1126,24 @@ - [#9891](https://github.com/MetaMask/metamask-mobile/pull/9891): fix: bug report template - remove reference to recordit (#9891) - [#9755](https://github.com/MetaMask/metamask-mobile/pull/9755): fix: display the DApp URL in connect screen for MetaMask IOS-SDK (#9755) -## 7.24.4 - Jun 25, 2024 +## [7.24.4] ### Fixed - [10064](https://github.com/MetaMask/metamask-mobile/pull/10064) fix: Always mark the STX Opt In modal as seen - [10088](https://github.com/MetaMask/metamask-mobile/pull/10088) fix: Swap with unapproved token - [10099](https://github.com/MetaMask/metamask-mobile/pull/10099) fix: stx on ramps missing origin -## 7.24.3 - Jun 19, 2024 +## [7.24.3] ### Fixed - [#10045](https://github.com/MetaMask/metamask-mobile/pull/10045): fix: Update ppom package to 1.4.8 (#10041) -## 7.24.2 - Jun 13, 2024 +## [7.24.2] ### Added - [#9687](https://github.com/MetaMask/metamask-mobile/pull/9687): feat: adds "data collection for marketing" toggles -### Fixed +### Fixed - [#9905](https://github.com/MetaMask/metamask-mobile/pull/9905): fix: remove metametrics redundant calls and improve compliance -## 7.24.1 - Jun 13, 2024 +## [7.24.1] ### Fixed - [#9943](https://github.com/MetaMask/metamask-mobile/pull/9943): fix: Remove duplicate accounts (#9943) - [#10006](https://github.com/MetaMask/metamask-mobile/pull/10006): fix: Fix order of accounts (#10006) @@ -1146,7 +1151,7 @@ - [#9974](https://github.com/MetaMask/metamask-mobile/pull/9974): fix: Fix freeze on buy and sell flow (#9974) - [#9980](https://github.com/MetaMask/metamask-mobile/pull/9980): fix: Fix initialization crash / login error "Engine does not exist (#9980) -## 7.24.0 - Jun 11, 2024 +## [7.24.0] ### Added - [#9767](https://github.com/MetaMask/metamask-mobile/pull/9767): feat: push Privacy policy date to 2024 Jun 18 12:00 UTC (#9767) - [#9707](https://github.com/MetaMask/metamask-mobile/pull/9707): feat: adds strings for the opt in toggles (#9707) @@ -1211,7 +1216,7 @@ - [#9568](https://github.com/MetaMask/metamask-mobile/pull/9568): fix: 9559 issue android json parse (#9568) - [#9616](https://github.com/MetaMask/metamask-mobile/pull/9616): fix: fix the issue 9560 which QR code accounts has been reappeared aftter user `remove wallets` (#9616) -## 7.23.0 - May 10, 2024 +## [7.23.0] ### Added - [#9595](https://github.com/MetaMask/metamask-mobile/pull/9595): feat: Upgrade to react-native-svg to 15.2.0 (#9595) - [#9305](https://github.com/MetaMask/metamask-mobile/pull/9305): feat: Update SignatureController v6.1.3 + LoggingController v2.0.0 (#9305) @@ -1292,7 +1297,7 @@ - [#9482](https://github.com/MetaMask/metamask-mobile/pull/9482): fix: remove resolution react-native-svg-asset-plugin/sharp@^0.30.5 (#9482) - [#9143](https://github.com/MetaMask/metamask-mobile/pull/9143): fix: Yarn 1.22.22 (#9143) -## 7.22.0 - Apr 25, 2024 +## [7.22.0] ### Added - [#9329](https://github.com/MetaMask/metamask-mobile/pull/9329): feat: Added log to capture failing exception for getItem (#9329) - [#9271](https://github.com/MetaMask/metamask-mobile/pull/9271): feat: update phishing controller v8.0.0 (#9271) @@ -1367,7 +1372,7 @@ - [#9284](https://github.com/MetaMask/metamask-mobile/pull/9284): fix: invalid url on inapp-browser (#9284) - [#9283](https://github.com/MetaMask/metamask-mobile/pull/9283): fix: missing walletConnect prop (#9283) -## 7.21.0 - Apr 25, 2024 +## [7.21.0] ### Added - [#9222](https://github.com/MetaMask/metamask-mobile/pull/9222): feat: Cherry pick controller utils v5 (#9222) - [#9218](https://github.com/MetaMask/metamask-mobile/pull/9218): feat: cherry-pick assets controller v14 (#9218) @@ -1422,11 +1427,11 @@ - [#9202](https://github.com/MetaMask/metamask-mobile/pull/9202): fix: Revert PR 9075 (#9202) - [#9075](https://github.com/MetaMask/metamask-mobile/pull/9075): fix: Send ppom metrics when transaction is cancelled. (#9075) -## 7.20.1 - Apr 18, 2024 +## [7.20.1] ### Fixed - [#9092](https://github.com/MetaMask/metamask-mobile/pull/9092): fix: check HD keyring -## 7.20.0 - Apr 12, 2024 +## [7.20.0] ### Added - [#8982](https://github.com/MetaMask/metamask-mobile/pull/8982): feat: Update gas fee controller to version 6.1.2 - [#9079](https://github.com/MetaMask/metamask-mobile/pull/9079): feat: Update controller utils to 5.0.2 @@ -1482,11 +1487,11 @@ - [#9021](https://github.com/MetaMask/metamask-mobile/pull/9021): fix: Network not updating when changing account connected the first time on a DAPP - [#8932](https://github.com/MetaMask/metamask-mobile/pull/8932): fix: breaking change from `@metamask/transaction-controller` regarding Ledger transactions -## 7.19.1 - Apr 10, 2024 +## [7.19.1] ### Fixed - [#9193](https://github.com/MetaMask/metamask-mobile/pull/9193): fix(ramp): default networks state to array -## 7.19.0 - Mar 19, 2024 +## [7.19.0] ### Added - [#8935](https://github.com/MetaMask/metamask-mobile/pull/8935): feat: Remove powered by blockaid line - [#8908](https://github.com/MetaMask/metamask-mobile/pull/8908): feat: add linea sepolia network and deprecate Linea Goerli network @@ -1565,7 +1570,7 @@ - [#8808](https://github.com/MetaMask/metamask-mobile/pull/8808): fix: unnecessary, unsafe base-controller patch - [#8496](https://github.com/MetaMask/metamask-mobile/pull/8496): fix: redirection issue after chain switch on sign request -## 7.18.0 - Mar 18, 2024 +## [7.18.0] ### Added - [#8729](https://github.com/MetaMask/metamask-mobile/pull/8729): feat(ramp): add event when user expands quotes - [#8787](https://github.com/MetaMask/metamask-mobile/pull/8787): feat: add MetaMetrics custom flush vars and log @@ -1641,12 +1646,12 @@ - [#8631](https://github.com/MetaMask/metamask-mobile/pull/8631): fix: remove inexistent style - [#8615](https://github.com/MetaMask/metamask-mobile/pull/8615): fix: Fix add custom rpc detox test script -## 7.17.1 - Mar 2, 2024 -## Fixed +## [7.17.1] +### Fixed - [#8870](https://github.com/MetaMask/metamask-mobile/pull/8870): fix: update PPOM to v1.4.4 - [#8892](https://github.com/MetaMask/metamask-mobile/pull/8892): fix: Tokens disappearing -## 7.17.0 - Feb 16, 2024 +## [7.17.0] ### Added - [#8520](https://github.com/MetaMask/metamask-mobile/pull/8520): feat: Feature/1300 dapp visit event - [#8354](https://github.com/MetaMask/metamask-mobile/pull/8354): feat(ramp): add Terms of Service provider link to quotes @@ -1714,7 +1719,7 @@ - [#8126](https://github.com/MetaMask/metamask-mobile/pull/8126): fix: Update navigation bar on start loading - [#8476](https://github.com/MetaMask/metamask-mobile/pull/8476): fix: Fix title color type in settings drawer -## 7.16.0 - Jan 29, 2024 +## [7.16.0] ### Added - [#8093](https://github.com/MetaMask/metamask-mobile/pull/8093): feat: decouple account selector from qr code connector - [#8383](https://github.com/MetaMask/metamask-mobile/pull/8383): feat: add translation for privacy toggle @@ -1807,7 +1812,7 @@ - [#8247](https://github.com/MetaMask/metamask-mobile/pull/8247): fix: fix inconsistency in the popular tab -## 7.15.0 - Jan 11, 2024 +## [7.15.0] ### Added - [#8080](https://github.com/MetaMask/metamask-mobile/pull/8080): feat(ramp): add sell quick amounts with gas estimations - [#8204](https://github.com/MetaMask/metamask-mobile/pull/8204): feat: update blockaid dependency to latest version @@ -1888,7 +1893,7 @@ - [#8085](https://github.com/MetaMask/metamask-mobile/pull/8085): fix: PPOMController related issues in blockaid integration - [#8029](https://github.com/MetaMask/metamask-mobile/pull/8029): fix: blockaid analytics code typos -## 7.14.0 - Jan 11, 2024 +## [7.14.0] ### Added - [#8016](https://github.com/MetaMask/metamask-mobile/pull/8016): feat(ramp): add sell deeplink - [#7962](https://github.com/MetaMask/metamask-mobile/pull/7962): feat(ramp): add sell notification texts @@ -1957,26 +1962,26 @@ - [#7971](https://github.com/MetaMask/metamask-mobile/pull/7971): fix: Updated ButtonLink to use text when size is auto - [#7976](https://github.com/MetaMask/metamask-mobile/pull/7976): fix: blockaid mobile performance improvements -## 7.12.5 - Jan 4, 2024 +## [7.12.5] ### Added - [#8156](https://github.com/MetaMask/metamask-mobile/pull/8156): feat: migrate to latest Token rates controller -### Fixed +### Fixed - [#8155](https://github.com/MetaMask/metamask-mobile/pull/8155): fix: OpenSea V1 -> V2 patch -## 7.12.3 - Dec 18, 2023 -### Fixed +## [7.12.3] +### Fixed - [#8102](https://github.com/MetaMask/metamask-mobile/pull/8102): fix: prevent bad svg urls in react-native-svg -## 7.12.2 - Dec 8, 2023 -### Fixed +## [7.12.2] +### Fixed - [#8057](https://github.com/MetaMask/metamask-mobile/pull/8057): fix: Disable SES on iOS -## 7.12.1 - Dec 5, 2023 +## [7.12.1] ### Fixed - [#7991](https://github.com/MetaMask/metamask-mobile/pull/7991): fix: patch for token rates controller with coin gecko endpoint -## 7.12.0 - Dec 4, 2023 +## [7.12.0] ### Added - [#7037](https://github.com/MetaMask/metamask-mobile/pull/7037): feat(off-ramp): add off-ramp feature - [#7734](https://github.com/MetaMask/metamask-mobile/pull/7734): feat: enable code fence capabilities on mobile app. @@ -2061,7 +2066,7 @@ - [#7662](https://github.com/MetaMask/metamask-mobile/pull/7662): fix: update PPOM Validator to address blockaid performance issues - [#7642](https://github.com/MetaMask/metamask-mobile/pull/7642): fix: action view btn not able translate -## 7.11.0 - Nov 17, 2023 +## [7.11.0] ### Added - [#7251](https://github.com/MetaMask/metamask-mobile/pull/7251): feat: #999 - RTK consolidate reducers - [#7628](https://github.com/MetaMask/metamask-mobile/pull/7628): feat: sdk batch rpc calls @@ -2137,7 +2142,7 @@ - [#7811](https://github.com/MetaMask/metamask-mobile/pull/7811): fix: Lock yarn to 1.22.19 - [#7733](https://github.com/MetaMask/metamask-mobile/pull/7733): fix: silence PollingBlockTracker Sentry -## 7.10.0 - Nov 3, 2023 +## [7.10.0] ### Added - [#7588](https://github.com/MetaMask/metamask-mobile/pull/7588): chore: cherry pick #7584 - re-create connect_sign feature - [#7154](https://github.com/MetaMask/metamask-mobile/pull/7154): feat: incoming transactions by network @@ -2218,11 +2223,11 @@ - [#7371](https://github.com/MetaMask/metamask-mobile/pull/7371): fix(action): bug report creation was not working - [#7362](https://github.com/MetaMask/metamask-mobile/pull/7362): fix(action): update fetch-depth parameter to fetch only the last commit -## 7.9.1 - Nov 1, 2023 +## [7.9.1] ### Fixed - [#7653](https://github.com/MetaMask/metamask-mobile/pull/7653): fix: revert nonce logic in transaction controller -## 7.9.0 - Oct 10, 2023 +## [7.9.0] ### Added - [#7341](https://github.com/MetaMask/metamask-mobile/pull/7341): feat(ramp): add webview debug by env vars - [#7345](https://github.com/MetaMask/metamask-mobile/pull/7345): feat: remove unused react-native-webrtc package @@ -2263,7 +2268,7 @@ - [#7278](https://github.com/MetaMask/metamask-mobile/pull/7278): fix: Fix console errors upon switching networks -## 7.8.0 - Sep 18, 2023 +## [7.8.0] ### Added - [#7068](https://github.com/MetaMask/metamask-mobile/pull/7068): feat: Adding blockaid banner to confirmation pages - [#7186](https://github.com/MetaMask/metamask-mobile/pull/7186): feat: translation ipfs banner @@ -2317,7 +2322,7 @@ - [#7211](https://github.com/MetaMask/metamask-mobile/pull/7211): fix: Fix Sentry sourcemap upload step - [#7096](https://github.com/MetaMask/metamask-mobile/pull/7096): fix: Fix Engine `controllerMessenger` type errors -## 7.7.0 - Sep 18, 2023 +## [7.7.0] ### Added - [#7090](https://github.com/MetaMask/metamask-mobile/pull/7090): feat: add translations for new contextual sheet display nft media - [#6727](https://github.com/MetaMask/metamask-mobile/pull/6727): style: Update Button's pressed and disabled states @@ -2357,7 +2362,7 @@ - [#6962](https://github.com/MetaMask/metamask-mobile/pull/6962): fix: remove outdated ipfs gateways - [#7024](https://github.com/MetaMask/metamask-mobile/pull/7024): fix(action): octokit not supported on MetaMask repos -## 7.6.0 - Aug 31, 2023 +## [7.6.0] ### Added - [#6938](https://github.com/MetaMask/metamask-mobile/pull/6938): feat(release): 7.5.0 - [#7026](https://github.com/MetaMask/metamask-mobile/pull/7026): feat: new translations for nft media @@ -2399,7 +2404,7 @@ - [#6931](https://github.com/MetaMask/metamask-mobile/pull/6931): fix: Remove splash animation wait step from Cold Start Launch time test script - [#6864](https://github.com/MetaMask/metamask-mobile/pull/6864): fix: custom position logic for badgeWrapper -## 7.5.0 - Aug 21, 2023 +## [7.5.0] ### Added - [#6865](https://github.com/MetaMask/metamask-mobile/pull/6865): feat: Create a performance E2E test for warm starts - [#6187](https://github.com/MetaMask/metamask-mobile/pull/6187): feat: Add guidelines for contributors @@ -2454,7 +2459,7 @@ access - [#6828](https://github.com/MetaMask/metamask-mobile/pull/6828): fix: wallet connect v1 is fully deprecated - [#6903](https://github.com/MetaMask/metamask-mobile/pull/6903): fix: Fix crash when switching to Linea -## 7.4.0 - Jul 14, 2023 +## [7.4.0] ### Added - [#6805](https://github.com/MetaMask/metamask-mobile/pull/6805): feat(on-ramp): upgrade on-ramp SDK with apple pay support - [#6679](https://github.com/MetaMask/metamask-mobile/pull/6679): feat(on-ramp): upgrade on-ramp-sdk to v1.22.0 with abort controller support @@ -2481,11 +2486,11 @@ access - [#6739](https://github.com/MetaMask/metamask-mobile/pull/6739): fix: deeplink connection using metamask://connect - [#6753](https://github.com/MetaMask/metamask-mobile/pull/6753): fix: Delete collectible media reproductor -## 7.3.1 - Jul 26, 2023 +## [7.3.1] ### Fixed - [#6833](https://github.com/MetaMask/metamask-mobile/pull/6833): fix: invalid transaction data used for approve transaction -## 7.3.0 - Jul 13, 2023 +## [7.3.0] ### Added - [#6220](https://github.com/MetaMask/metamask-mobile/pull/6220): feat: Upgrade React Native to 0.71.6 - [#6596](https://github.com/MetaMask/metamask-mobile/pull/6596): feat: Memoise token balance controler hook @@ -2518,7 +2523,7 @@ access - [#6671](https://github.com/MetaMask/metamask-mobile/pull/6671): fix: added contact alias to destination address on send flow - [#6637](https://github.com/MetaMask/metamask-mobile/pull/6637): fix: Support Decimal Comma for Token Custom Spend Cap -## 7.2.0 - Jun 05, 2023 +## [7.2.0] ### Added - [#6632](https://github.com/MetaMask/metamask-mobile/pull/6632): feat: add linea mainnet alert message - [#6496](https://github.com/MetaMask/metamask-mobile/pull/6496): feat(551): add Linea Mainnet @@ -2564,158 +2569,185 @@ access - [#6473](https://github.com/MetaMask/metamask-mobile/pull/6473): fix: fix for swaps button displaying on unsupported networks - [#6464](https://github.com/MetaMask/metamask-mobile/pull/6464): fix: bug domain not shown on signature - [#6517](https://github.com/MetaMask/metamask-mobile/pull/6517): fix: remove duplicate ganache steps definitions -- [#6299](https://github.com/MetaMask/metamask-mobile/pull/6299): fix: for from address balance shown for ERC20 transfers +- [#6299](https://github.com/MetaMask/metamask-mobile/pull/6299): fix: for from address balance shown for ERC20 transfers - [#6471](https://github.com/MetaMask/metamask-mobile/pull/6471): fix: Approve default ERC20 -## 7.1.0 - Jun 20, 2023 - - [#6334](https://github.com/MetaMask/metamask-mobile/pull/6334): feat: Aurora Token Detection - - [#6351](https://github.com/MetaMask/metamask-mobile/pull/6351): feat: use thunk to handle processed order side effects - - [#5829](https://github.com/MetaMask/metamask-mobile/pull/5829): feat: order of browser page load events - - [#6230](https://github.com/MetaMask/metamask-mobile/pull/6230): feat: Asset Overview / Token Detail view redesign - - [#6381](https://github.com/MetaMask/metamask-mobile/pull/6381): feat: add params validation to useSDKMethod hook - - [#6365](https://github.com/MetaMask/metamask-mobile/pull/6365): feat: remove hardcoded selected network name - - [#6421](https://github.com/MetaMask/metamask-mobile/pull/6421): feat: exclude legacy types from rate limiting - - [#6354](https://github.com/MetaMask/metamask-mobile/pull/6354): feat: Trigger signing modals from approval requests - - [#6432](https://github.com/MetaMask/metamask-mobile/pull/6432): ci(sonar): Configure SonarCloud Analysis on CI - - [#6441](https://github.com/MetaMask/metamask-mobile/pull/6441): feat: use screen in on-ramp views tests - - [#6442](https://github.com/MetaMask/metamask-mobile/pull/6442): fix(ci): Remove `restore-build` steps - - [#6040](https://github.com/MetaMask/metamask-mobile/pull/6040): feat: validation to send amount input box - - [#6311](https://github.com/MetaMask/metamask-mobile/pull/6311): fix: token balance displayed in approval pages - - [#6406](https://github.com/MetaMask/metamask-mobile/pull/6406): chore: Use core signature controller - - [#6439](https://github.com/MetaMask/metamask-mobile/pull/6439): fix: remove invalid accessibilityRole value - - [#6427](https://github.com/MetaMask/metamask-mobile/pull/6427): refactor: Refactor unit tests for React Native 0.71.6 upgrade - - [#6289](https://github.com/MetaMask/metamask-mobile/pull/6289): feat(ci): Sonar Action to work with SonarCloud - - [#6366](https://github.com/MetaMask/metamask-mobile/pull/6366): feat(ci): Convert Bitrise Workflows to Pipelines - - [#6350](https://github.com/MetaMask/metamask-mobile/pull/6350): fix: ENS name displayed on confirm send page - - [#6192](https://github.com/MetaMask/metamask-mobile/pull/6192): chore: Show account balance in signature screen - - [#6394](https://github.com/MetaMask/metamask-mobile/pull/6394): feat(ci): removed the matrix option from unit testing - - [#6227](https://github.com/MetaMask/metamask-mobile/pull/6227): feat: [MC 0.5] Modal network selector replace by network selector sheet - - [#6393](https://github.com/MetaMask/metamask-mobile/pull/6393): feat(ci): upgrade ruby to 3.0.0 - - [#6274](https://github.com/MetaMask/metamask-mobile/pull/6274): chore: Empty SiteURL and Null TagURL in modal - - [#6137](https://github.com/MetaMask/metamask-mobile/pull/6137): chore: Clicking toAddress to add it to address book - - [#6079](https://github.com/MetaMask/metamask-mobile/pull/6079): chore: Refactor sanitization middleware - - [#6234](https://github.com/MetaMask/metamask-mobile/pull/6234): chore: Clear Privacy section - - [#6342](https://github.com/MetaMask/metamask-mobile/pull/6342): chore: Improve processing of redirection URL - - [#6374](https://github.com/MetaMask/metamask-mobile/pull/6374): chore: en.json with eth_sign - - [#6214](https://github.com/MetaMask/metamask-mobile/pull/6214): chore: core signature controller - - [#6328](https://github.com/MetaMask/metamask-mobile/pull/6328): chore(devDeps): bump webdriverio packages - - [#6362](https://github.com/MetaMask/metamask-mobile/pull/6362): chore: Added retries - - [#6125](https://github.com/MetaMask/metamask-mobile/pull/6125): chore: controller packages to match core v42 - - [#6124](https://github.com/MetaMask/metamask-mobile/pull/6124): chore: controller packages to match core v40 - - [#6345](https://github.com/MetaMask/metamask-mobile/pull/6345): chore: es.js file - - [#6339](https://github.com/MetaMask/metamask-mobile/pull/6339): fix: yarn watch clean - -## 7.0.1 - Jun 7, 2023 +## [7.1.0] +### Added +- [#6351](https://github.com/MetaMask/metamask-mobile/pull/6351): feat: use thunk to handle processed order side effects +- [#5829](https://github.com/MetaMask/metamask-mobile/pull/5829): feat: order of browser page load events +- [#6230](https://github.com/MetaMask/metamask-mobile/pull/6230): feat: Asset Overview / Token Detail view redesign +- [#6381](https://github.com/MetaMask/metamask-mobile/pull/6381): feat: add params validation to useSDKMethod hook +- [#6365](https://github.com/MetaMask/metamask-mobile/pull/6365): feat: remove hardcoded selected network name +- [#6421](https://github.com/MetaMask/metamask-mobile/pull/6421): feat: exclude legacy types from rate limiting +- [#6354](https://github.com/MetaMask/metamask-mobile/pull/6354): feat: Trigger signing modals from approval requests +- [#6432](https://github.com/MetaMask/metamask-mobile/pull/6432): ci(sonar): Configure SonarCloud Analysis on CI +- [#6441](https://github.com/MetaMask/metamask-mobile/pull/6441): feat: use screen in on-ramp views tests +- [#6040](https://github.com/MetaMask/metamask-mobile/pull/6040): feat: validation to send amount input box +- [#6394](https://github.com/MetaMask/metamask-mobile/pull/6394): feat(ci): removed the matrix option from unit testing +- [#6227](https://github.com/MetaMask/metamask-mobile/pull/6227): feat: [MC 0.5] Modal network selector replace by network selector sheet +- [#6393](https://github.com/MetaMask/metamask-mobile/pull/6393): feat(ci): upgrade ruby to 3.0.0 +- [#6289](https://github.com/MetaMask/metamask-mobile/pull/6289): feat(ci): Sonar Action to work with SonarCloud +- [#6366](https://github.com/MetaMask/metamask-mobile/pull/6366): feat(ci): Convert Bitrise Workflows to Pipelines +- [#6334](https://github.com/MetaMask/metamask-mobile/pull/6334): feat: Aurora Token Detection + +### Changed +- [#6406](https://github.com/MetaMask/metamask-mobile/pull/6406): chore: Use core signature controller +- [#6427](https://github.com/MetaMask/metamask-mobile/pull/6427): refactor: Refactor unit tests for React Native 0.71.6 upgrade +- [#6192](https://github.com/MetaMask/metamask-mobile/pull/6192): chore: Show account balance in signature screen +- [#6274](https://github.com/MetaMask/metamask-mobile/pull/6274): chore: Empty SiteURL and Null TagURL in modal +- [#6137](https://github.com/MetaMask/metamask-mobile/pull/6137): chore: Clicking toAddress to add it to address book +- [#6079](https://github.com/MetaMask/metamask-mobile/pull/6079): chore: Refactor sanitization middleware +- [#6234](https://github.com/MetaMask/metamask-mobile/pull/6234): chore: Clear Privacy section +- [#6342](https://github.com/MetaMask/metamask-mobile/pull/6342): chore: Improve processing of redirection URL +- [#6374](https://github.com/MetaMask/metamask-mobile/pull/6374): chore: en.json with eth_sign +- [#6214](https://github.com/MetaMask/metamask-mobile/pull/6214): chore: core signature controller +- [#6328](https://github.com/MetaMask/metamask-mobile/pull/6328): chore(devDeps): bump webdriverio packages +- [#6362](https://github.com/MetaMask/metamask-mobile/pull/6362): chore: Added retries +- [#6125](https://github.com/MetaMask/metamask-mobile/pull/6125): chore: controller packages to match core v42 +- [#6124](https://github.com/MetaMask/metamask-mobile/pull/6124): chore: controller packages to match core v40 +- [#6345](https://github.com/MetaMask/metamask-mobile/pull/6345): chore: es.js file + +### Fixed +- [#6439](https://github.com/MetaMask/metamask-mobile/pull/6439): fix: remove invalid accessibilityRole value +- [#6442](https://github.com/MetaMask/metamask-mobile/pull/6442): fix(ci): Remove `restore-build` steps +- [#6311](https://github.com/MetaMask/metamask-mobile/pull/6311): fix: token balance displayed in approval pages +- [#6339](https://github.com/MetaMask/metamask-mobile/pull/6339): fix: yarn watch clean +- [#6350](https://github.com/MetaMask/metamask-mobile/pull/6350): fix: ENS name displayed on confirm send page + +## [7.0.1] +### Changed - [#6558](https://github.com/MetaMask/metamask-mobile/pull/6558): refactor(whats-new-modal): remove onramp content -## 7.0.0 - Jun 6, 2023 +## [7.0.0] +### Added - [#6536](https://github.com/MetaMask/metamask-mobile/pull/6380): [FEATURE] WalletConnect v2 Integration (#6380) -## 6.6.0 - May 25, 2023 -- [#5866](https://github.com/MetaMask/metamask-mobile/pull/5866): [FIX] sturdier check -- [#6340](https://github.com/MetaMask/metamask-mobile/pull/6340): [FIX] Missing network name onramp +## [6.6.0] +### Added - [#6325](https://github.com/MetaMask/metamask-mobile/pull/6325): [FEATURE] Add development environment to onramp-sdk -- [#6309](https://github.com/MetaMask/metamask-mobile/pull/6309): [FIX] Missing handler on mandatory modal - [#6165](https://github.com/MetaMask/metamask-mobile/pull/6165): [FEATURE] Edit account name view -- [#5876](https://github.com/MetaMask/metamask-mobile/pull/5876): [FIX] Gas is not re-calculated when updating a transaction - [#6093](https://github.com/MetaMask/metamask-mobile/pull/6093): [FEATURE] Account actions on wallet view -- [#6253](https://github.com/MetaMask/metamask-mobile/pull/6253): [FIX] Confirm button should be disabled if account has no balance - [#6097](https://github.com/MetaMask/metamask-mobile/pull/6097): [UPDATE] Extracting out signature request related code from RootRPCMethodsUI conponent -- [#6246](https://github.com/MetaMask/metamask-mobile/pull/6246): [FIX] Wrong to account information on confirmation page - [#6085](https://github.com/MetaMask/metamask-mobile/pull/6085): [FEATURE] Update account section with card + +### Changed +- [#6228](https://github.com/MetaMask/metamask-mobile/pull/6228): [UPDATE] Checkbox component +- [#6226](https://github.com/MetaMask/metamask-mobile/pull/6226): [UPDATE] Button's icon props and button org - [#6255](https://github.com/MetaMask/metamask-mobile/pull/6255): [UPDATE] Onboarding translation updated - [#6210](https://github.com/MetaMask/metamask-mobile/pull/6210): [UPDATE] Extend the readme documentation to cover E2E testing in more detail. + +### Fixed - [#6249](https://github.com/MetaMask/metamask-mobile/pull/6249): [FIX] Terms of Use checkbox test id -- [#6228](https://github.com/MetaMask/metamask-mobile/pull/6228): [UPDATE] Checkbox component -- [#6226](https://github.com/MetaMask/metamask-mobile/pull/6226): [UPDATE] Button's icon props and button org +- [#5866](https://github.com/MetaMask/metamask-mobile/pull/5866): [FIX] sturdier check +- [#6340](https://github.com/MetaMask/metamask-mobile/pull/6340): [FIX] Missing network name onramp +- [#6309](https://github.com/MetaMask/metamask-mobile/pull/6309): [FIX] Missing handler on mandatory modal +- [#5876](https://github.com/MetaMask/metamask-mobile/pull/5876): [FIX] Gas is not re-calculated when updating a transaction +- [#6246](https://github.com/MetaMask/metamask-mobile/pull/6246): [FIX] Wrong to account information on confirmation page +- [#6253](https://github.com/MetaMask/metamask-mobile/pull/6253): [FIX] Confirm button should be disabled if account has no balance -## 6.5.0 - May 4, 2023 -- [#5743](https://github.com/MetaMask/metamask-mobile/pull/5743): [FEATURE] On-ramp: Add buy-crypto deeplink -- [#6201](https://github.com/MetaMask/metamask-mobile/pull/6201): [FIX] [SDK] Missing redirect breaking backward compatibility -- [#6232](https://github.com/MetaMask/metamask-mobile/pull/6232): [FIX] bottom margin for detecting end of the page -- [#6166](https://github.com/MetaMask/metamask-mobile/pull/6166): [FEATURE] trigger walletconnect modal using approval controller + + +## [6.5.0] +### Added +- [#5743](https://github.com/MetaMask/metamask-mobile/pull/5743): [FEATURE] On-ramp: Add buy-crypto deeplink +- [#6166](https://github.com/MetaMask/metamask-mobile/pull/6166): [FEATURE] trigger walletconnect modal using approval controller - [#6223](https://github.com/MetaMask/metamask-mobile/pull/6223): [IMPROVEMENT] Update to Node.js v16 - [#6051](https://github.com/MetaMask/metamask-mobile/pull/6051): [FEATURE] Total balance and portfolio button changed - [#6156](https://github.com/MetaMask/metamask-mobile/pull/6156): [IMPROVEMENT] On-ramp: Use dynamic list of networks - [#6145](https://github.com/MetaMask/metamask-mobile/pull/6145): [IMPROVEMENT] Synced and optimized icons - [#6138](https://github.com/MetaMask/metamask-mobile/pull/6138): [FEATURE] On-ramp: Add orderProcessor exponential backoff for orders -- [#6139](https://github.com/MetaMask/metamask-mobile/pull/6139): [FEATURE] On-ramp: Add same amount rendering as the order details to the order list -- [#6189](https://github.com/MetaMask/metamask-mobile/pull/6189): [FEATURE] On-ramp: Remove hiding the provider modal when quotes refresh +- [#6139](https://github.com/MetaMask/metamask-mobile/pull/6139): [FEATURE] On-ramp: Add same amount rendering as the order details to the order list +- [#6189](https://github.com/MetaMask/metamask-mobile/pull/6189): [FEATURE] On-ramp: Remove hiding the provider modal when quotes refresh - [#6216](https://github.com/MetaMask/metamask-mobile/pull/6216): [IMPROVEMENT] account icon matches user's preferred identicon - [#5956](https://github.com/MetaMask/metamask-mobile/pull/5956): [IMPROVEMENT] Show token symbol in verify contract details - [#5458](https://github.com/MetaMask/metamask-mobile/pull/5458): [IMPROVEMENT] Support sepolia network -- [#6185](https://github.com/MetaMask/metamask-mobile/pull/6185): [FIX] remove pubnub package and associated sync with extension code - [#6181](https://github.com/MetaMask/metamask-mobile/pull/6181): [IMPROVEMENT] Componentize Header Component - [#6153](https://github.com/MetaMask/metamask-mobile/pull/6153): [IMPROVEMENT] On-ramp: Refactor order selector by id - [#6044](https://github.com/MetaMask/metamask-mobile/pull/6044): [IMPROVEMENT] Componentize Badge and Badge Wrapper - [#6180](https://github.com/MetaMask/metamask-mobile/pull/6180): [IMPROVEMENT] Componentized Overlay Component -- [#6173](https://github.com/MetaMask/metamask-mobile/pull/6173): [REFACTOR] Auto Lock section - [#6174](https://github.com/MetaMask/metamask-mobile/pull/6174): [IMPROVEMENT] Update Tab bar styles - [#6056](https://github.com/MetaMask/metamask-mobile/pull/6056): [IMPROVEMENT] Show Identicon for unknown token and if token icon is unknown -- [#6076](https://github.com/MetaMask/metamask-mobile/pull/6076): [BUGFIX] Fixes WalletConnect deep links (wc:// schema) not working properly + +### Changed - [#6157](https://github.com/MetaMask/metamask-mobile/pull/6157): [REFACTOR] Change Password setting +- [#6173](https://github.com/MetaMask/metamask-mobile/pull/6173): [REFACTOR] Auto Lock section + +### Fixed +- [#6201](https://github.com/MetaMask/metamask-mobile/pull/6201): [FIX] [SDK] Missing redirect breaking backward compatibility +- [#6232](https://github.com/MetaMask/metamask-mobile/pull/6232): [FIX] bottom margin for detecting end of the page +- [#6185](https://github.com/MetaMask/metamask-mobile/pull/6185): [FIX] remove pubnub package and associated sync with extension code - [#5718](https://github.com/MetaMask/metamask-mobile/pull/5718): [FIX] Nonce Too Low for Approve Transaction +- [#6076](https://github.com/MetaMask/metamask-mobile/pull/6076): [BUGFIX] Fixes WalletConnect deep links (wc:// schema) not working properly -## 6.4.0 - Apr 20, 2023 + +## [6.4.0] +### Added - [#6144](https://github.com/MetaMask/metamask-mobile/pull/6144): [FEATURE] New Crowdin translations by Github Action - [#6143](https://github.com/MetaMask/metamask-mobile/pull/6143): [UPDATE] Crowdin token to use METAMASKBOT_CROWDIN_TOKEN - [#5627](https://github.com/MetaMask/metamask-mobile/pull/5627): [IMPROVEMENT] Refactor remaining `web3-provider-engine` methods - [#6082](https://github.com/MetaMask/metamask-mobile/pull/6082): [IMPROVEMENT] Remove inactive IPFS providers - [#5620](https://github.com/MetaMask/metamask-mobile/pull/5620): [IMPROVEMENT] Refactor RPC `getAccounts` usage -- [#6122](https://github.com/MetaMask/metamask-mobile/pull/6122): [FIX] TypeError: undefined is not an object (evaluating 'n.find') -- [#6134](https://github.com/MetaMask/metamask-mobile/pull/6134): [REFACTOR] Reveal Private Key section - [#6009](https://github.com/MetaMask/metamask-mobile/pull/6009): [FEATURE] On-ramp: Add what's new modal content -- [#5619](https://github.com/MetaMask/metamask-mobile/pull/5619): [IMPROVEMENT] Refactor `eth_sendTransaction` handler -- [#6058](https://github.com/MetaMask/metamask-mobile/pull/6058): [FIX] broken erc721 approve token link - [#6020](https://github.com/MetaMask/metamask-mobile/pull/6020): [FEATURE][MC] Token list with network logo and token name - [#5992](https://github.com/MetaMask/metamask-mobile/pull/5992): [FEATURE][MC] - Wallet actions on Tab bar - [#5937](https://github.com/MetaMask/metamask-mobile/pull/5937): [FEATURE]Show internet protocol on confirmation screens -- [#6015](https://github.com/MetaMask/metamask-mobile/pull/6015): [UPDATE] sentry version and enable performance metrics -- [#6109](https://github.com/MetaMask/metamask-mobile/pull/6109): [FIX] linea network order in dropdown + remove feature toggle for linea (#6072) -- [#6081](https://github.com/MetaMask/metamask-mobile/pull/6081): [UPDATE] ESLint rules for scripts -- [#6006](https://github.com/MetaMask/metamask-mobile/pull/6006): [UPDATE] Upgrade xcode version - [#6003](https://github.com/MetaMask/metamask-mobile/pull/6003): [IMPROVEMENT] Adding document to refactor send flow -- [#6060](https://github.com/MetaMask/metamask-mobile/pull/6060): [IMPROVEMENT] Refactor send transaction v2 - [#6037](https://github.com/MetaMask/metamask-mobile/pull/6037): [FEATURE] update sdk persistence - [#5900](https://github.com/MetaMask/metamask-mobile/pull/5900): [IMPROVEMENT] Creating reusable address from/to component. - [#5933](https://github.com/MetaMask/metamask-mobile/pull/5933): [IMPROVEMENT] Componentize Banner Component - [#5927](https://github.com/MetaMask/metamask-mobile/pull/5927): [IMPROVEMENT] Componentize Form Components +- [#5619](https://github.com/MetaMask/metamask-mobile/pull/5619): [IMPROVEMENT] Refactor `eth_sendTransaction` handler +- [#6060](https://github.com/MetaMask/metamask-mobile/pull/6060): [IMPROVEMENT] Refactor send transaction v2 -## 6.3.0 - Apr 05, 2023 -- [#6025](https://github.com/MetaMask/metamask-mobile/pull/6025): [FIX] Add url-parse lib to our MainNavigator +### Changed +- [#6134](https://github.com/MetaMask/metamask-mobile/pull/6134): [REFACTOR] Reveal Private Key section + +- [#6015](https://github.com/MetaMask/metamask-mobile/pull/6015): [UPDATE] sentry version and enable performance metrics +- [#6081](https://github.com/MetaMask/metamask-mobile/pull/6081): [UPDATE] ESLint rules for scripts +- [#6006](https://github.com/MetaMask/metamask-mobile/pull/6006): [UPDATE] Upgrade xcode version + +### Fixed +- [#6109](https://github.com/MetaMask/metamask-mobile/pull/6109): [FIX] linea network order in dropdown + remove feature toggle for linea (#6072) +- [#6058](https://github.com/MetaMask/metamask-mobile/pull/6058): [FIX] broken erc721 approve token link +- [#6122](https://github.com/MetaMask/metamask-mobile/pull/6122): [FIX] TypeError: undefined is not an object (evaluating 'n.find') + +## [6.3.0] +### Added - [#6039](https://github.com/MetaMask/metamask-mobile/pull/6039): [ENHANCEMENT] Improve Android setup instructions - [#5996](https://github.com/MetaMask/metamask-mobile/pull/5996): [ENHANCEMENT] Add document to refactor signature request code -- [#5961](https://github.com/MetaMask/metamask-mobile/pull/5961): [FIX] #5898 - Converting native ETH to fiat and fiat to native ETH results in wrong values beign displayed on the Amount screen - [#5958](https://github.com/MetaMask/metamask-mobile/pull/5958): [FEATURE] add consensys zkevm (Linea) support - [#5997](https://github.com/MetaMask/metamask-mobile/pull/5997): [FEATURE] Account selector on swaps screen - [#6019](https://github.com/MetaMask/metamask-mobile/pull/6019): [ENHANCEMENT] On-ramp: Add #6009 strings - [#6023](https://github.com/MetaMask/metamask-mobile/pull/6023): [ENHANCEMENT] disable back press and add margin to the bottom for accept ToU modal - [#6016](https://github.com/MetaMask/metamask-mobile/pull/6016): [ENHANCEMENT] On-ramp: Add accessibility label to custom action images - [#5948](https://github.com/MetaMask/metamask-mobile/pull/5948): [FEATURE] SDK Session Persistence -- [#5882](https://github.com/MetaMask/metamask-mobile/pull/5882): [FIX] Skip type checking library declaration files -- [#5975](https://github.com/MetaMask/metamask-mobile/pull/5975): [FIX] 18 JS type errors for TSC to output 683 TS/TSX errors - [#5910](https://github.com/MetaMask/metamask-mobile/pull/5910): [ENHANCEMENT] E2E Permission system tests -- [#5839](https://github.com/MetaMask/metamask-mobile/pull/5839): [FIX] Clear Hex data when Token Transfer reverts ETH - [#5930](https://github.com/MetaMask/metamask-mobile/pull/5930): [ENHANCEMENT] dispaly nft info in browser - [#5785](https://github.com/MetaMask/metamask-mobile/pull/5785): [FEATURE] add portfolio button to asset action buttons - [#5242](https://github.com/MetaMask/metamask-mobile/pull/5242): [FEATURE] Use Terms Modal -- [#5941](https://github.com/MetaMask/metamask-mobile/pull/5941): [FIX] bundle video in app to prevent crash when not available -- [#5669](https://github.com/MetaMask/metamask-mobile/pull/5669): [UPDATE] http-cache-semantics from 4.1.0 to 4.1.1 -- [#5959](https://github.com/MetaMask/metamask-mobile/pull/5959): [UPDATE] @xmldom/xmldom from 0.8.3 to 0.8.6 -- [#5962](https://github.com/MetaMask/metamask-mobile/pull/5962): [FIX] Remove select address as a prop on App index.js - [#5964](https://github.com/MetaMask/metamask-mobile/pull/5964): [FEATURE] Added translations for MC 0.5 - [#4421](https://github.com/MetaMask/metamask-mobile/pull/4421): [FEATURE] Vault corruption recovery flow - [#5327](https://github.com/MetaMask/metamask-mobile/pull/5327): [FEATURE] Verify Contract Details -## 6.2.0 - Mar 21, 2023 -- [#5890](https://github.com/MetaMask/metamask-mobile/pull/5890): [FIX] Swap with wallet connect +### Changed +- [#5669](https://github.com/MetaMask/metamask-mobile/pull/5669): [UPDATE] http-cache-semantics from 4.1.0 to 4.1.1 +- [#5959](https://github.com/MetaMask/metamask-mobile/pull/5959): [UPDATE] @xmldom/xmldom from 0.8.3 to 0.8.6 + +### Fixed +- [#5962](https://github.com/MetaMask/metamask-mobile/pull/5962): [FIX] Remove select address as a prop on App index.js +- [#5941](https://github.com/MetaMask/metamask-mobile/pull/5941): [FIX] bundle video in app to prevent crash when not available +- [#5839](https://github.com/MetaMask/metamask-mobile/pull/5839): [FIX] Clear Hex data when Token Transfer reverts ETH +- [#5975](https://github.com/MetaMask/metamask-mobile/pull/5975): [FIX] 18 JS type errors for TSC to output 683 TS/TSX errors +- [#5882](https://github.com/MetaMask/metamask-mobile/pull/5882): [FIX] Skip type checking library declaration files +- [#5961](https://github.com/MetaMask/metamask-mobile/pull/5961): [FIX] #5898 - Converting native ETH to fiat and fiat to native ETH results in wrong values beign displayed on the Amount screen +- [#6025](https://github.com/MetaMask/metamask-mobile/pull/6025): [FIX] Add url-parse lib to our MainNavigator + +## [6.2.0] +### Added - [#5807](https://github.com/MetaMask/metamask-mobile/pull/5807): [IMPROVEMENT] "preview build" support to Bitrise -- [#5924](https://github.com/MetaMask/metamask-mobile/pull/5924): [UPDATE] the README setup steps -- [#5901](https://github.com/MetaMask/metamask-mobile/pull/5901): [UPDATE] assets-controllers patch - [#5870](https://github.com/MetaMask/metamask-mobile/pull/5870): [IMPROVEMENT] On-ramp: Add buy crypto home button -- [#5880](https://github.com/MetaMask/metamask-mobile/pull/5880): [UPDATE] Display internet protocol on the new origin pill - [#5529](https://github.com/MetaMask/metamask-mobile/pull/5529): [IMPROVEMENT] Network Controller refactor to use the same selector -- [#5859](https://github.com/MetaMask/metamask-mobile/pull/5859): [UPDATE] scan icon on wallet view - [#5868](https://github.com/MetaMask/metamask-mobile/pull/5868): [IMPROVEMENT] permitted account balance - [#5842](https://github.com/MetaMask/metamask-mobile/pull/5842): [IMPROVEMENT] show the url protocol - [#5309](https://github.com/MetaMask/metamask-mobile/pull/5309): [IMPROVEMENT] New transaction header for approve and approval modal @@ -2724,108 +2756,126 @@ access - [#5855](https://github.com/MetaMask/metamask-mobile/pull/5855): [IMPROVEMENT] dont render suspect links - [#5827](https://github.com/MetaMask/metamask-mobile/pull/5827): [IMPROVEMENT] analytics: add missing property to connect completed event - [#5711](https://github.com/MetaMask/metamask-mobile/pull/5711): [IMPROVEMENT] Improve signature request message -- [#5750](https://github.com/MetaMask/metamask-mobile/pull/5750): [FIX] Enable clipboard for private credentials - [#5374](https://github.com/MetaMask/metamask-mobile/pull/5374): [IMPROVEMENT] Authentication refactor + +### Changed +- [#5924](https://github.com/MetaMask/metamask-mobile/pull/5924): [UPDATE] the README setup steps - [#5775](https://github.com/MetaMask/metamask-mobile/pull/5775): [UPDATE] Security Privacy Remember me feature - [#5803](https://github.com/MetaMask/metamask-mobile/pull/5803): [UPDATE] Sentry: remove DSN value from codebase - [#5796](https://github.com/MetaMask/metamask-mobile/pull/5796): [UPDATE] `@metamask/phishing-controller` to v2 +- [#5859](https://github.com/MetaMask/metamask-mobile/pull/5859): [UPDATE] scan icon on wallet view +- [#5880](https://github.com/MetaMask/metamask-mobile/pull/5880): [UPDATE] Display internet protocol on the new origin pill +- [#5901](https://github.com/MetaMask/metamask-mobile/pull/5901): [UPDATE] assets-controllers patch + +### Fixed +- [#5890](https://github.com/MetaMask/metamask-mobile/pull/5890): [FIX] Swap with wallet connect +- [#5750](https://github.com/MetaMask/metamask-mobile/pull/5750): [FIX] Enable clipboard for private credentials -## 6.1.2 - Mar 03, 2023 + +## [6.1.2] +### Fixed - [#5925](https://github.com/MetaMask/metamask-mobile/pull/5925): [FIX] handle all ios biometric errors and create wallet - [#5906](https://github.com/MetaMask/metamask-mobile/pull/5906): [FIX] Add try-catch to recreateVault -## 6.1.1 - Mar 01, 2023 +## [6.1.1] +### Fixed - [#5848](https://github.com/MetaMask/metamask-mobile/pull/5848): [FIX] Remove default eth sign -## 6.1.0 - Feb 27, 2023 -- [#5851](https://github.com/MetaMask/metamask-mobile/pull/5851): [FIX] Fix search network crasher -- [#5809](https://github.com/MetaMask/metamask-mobile/pull/5809): [FIX] Resolve tab bar merge conflicts +## [6.1.0] +### Added - [#5461](https://github.com/MetaMask/metamask-mobile/pull/5461): [IMPROVEMENT] On-ramp: Refactor Payment Methods view to componentization - [#5813](https://github.com/MetaMask/metamask-mobile/pull/5813): [FEATURE] Add copy for portfolio button for translations -- [#5729](https://github.com/MetaMask/metamask-mobile/pull/5729): [FIX] Bump react-native-reanimated to 2.14.0 - [#5797](https://github.com/MetaMask/metamask-mobile/pull/5797): [IMPROVEMENT] Remove phishing list update engine removal - [#5812](https://github.com/MetaMask/metamask-mobile/pull/5812): [CONTENT] Ledger Integration english content -- [#5806](https://github.com/MetaMask/metamask-mobile/pull/5806): [FIX] Screenshot Crash -- [#5678](https://github.com/MetaMask/metamask-mobile/pull/5678): [FIX] Updated hardware label to have the correct color -- [#5801](https://github.com/MetaMask/metamask-mobile/pull/5801): [FIX] Update icon name in SRPQuiz -- [#5800](https://github.com/MetaMask/metamask-mobile/pull/5800): [FIX] TabBarIconKey to TabBarLabel + - [#5725](https://github.com/MetaMask/metamask-mobile/pull/5725): [IMPROVEMENT] Show transfer view to user for approve with value -- [#5780](https://github.com/MetaMask/metamask-mobile/pull/5780): [FIX] Show token symbol when approving - [#5791](https://github.com/MetaMask/metamask-mobile/pull/5791): [IMPROVEMENT] Adds 'ios' and 'android' to possible sources for MM SDK events - [#5340](https://github.com/MetaMask/metamask-mobile/pull/5340): [IMPROVEMENT]Align icon names -- [#5399](https://github.com/MetaMask/metamask-mobile/pull/5399): [FIX] Fix bug with updating gas price for legacy transactions - [#5778](https://github.com/MetaMask/metamask-mobile/pull/5778): [IMPROVEMENT] Set different CPU capacity in jest tests -- [#5777](https://github.com/MetaMask/metamask-mobile/pull/5777): [FIX] Fix/primary currency fiat insufficient funds error - [#5776](https://github.com/MetaMask/metamask-mobile/pull/5776): [IMPROVEMENT] Add test for change password scenario -- [#5753](https://github.com/MetaMask/metamask-mobile/pull/5753): [FIX] Fix Slack e2e announcement -- [#5683](https://github.com/MetaMask/metamask-mobile/pull/5683): [FIX] RN Patch Version -- [#5768](https://github.com/MetaMask/metamask-mobile/pull/5768): [UPGRADE] Segment Analytics 2.13.0 -- [#5587](https://github.com/MetaMask/metamask-mobile/pull/5587): [FIX] ERC721 Approve view - [#5748](https://github.com/MetaMask/metamask-mobile/pull/5748): [IMPROVEMENT] E2e appium/add splash animation step -- [#5749](https://github.com/MetaMask/metamask-mobile/pull/5749): [FIX] Back navigation CTAs in RevealPrivateCredential view - [#5744](https://github.com/MetaMask/metamask-mobile/pull/5744): [IMPROVEMENT] Fix sideway/formula audit -- [#5738](https://github.com/MetaMask/metamask-mobile/pull/5738): [FIX] On-ramp: upgrade on-ramp-sdk to v1.8.1 -- [#5739](https://github.com/MetaMask/metamask-mobile/pull/5739): [FIX] Fix CVE-2023-25166 by resolving @sideway/formula to 3.0.1 - [#5666](https://github.com/MetaMask/metamask-mobile/pull/5666): [IMPROVEMENT] E2E appium/app launch times -- [#5719](https://github.com/MetaMask/metamask-mobile/pull/5719): [FIX] Remove false showBack param from order details - [#5595](https://github.com/MetaMask/metamask-mobile/pull/5595): [IMPROVEMENT] On-ramp: Add orderProcessor index test -- [#5730](https://github.com/MetaMask/metamask-mobile/pull/5730): [FIX] French content for SRP Quiz -- [#5726](https://github.com/MetaMask/metamask-mobile/pull/5726): [FIX] Minor UI bugs in credential views -- [#5656](https://github.com/MetaMask/metamask-mobile/pull/5656): [FIX] ENS Resolves to Wrong Address when DeepLink - [#5717](https://github.com/MetaMask/metamask-mobile/pull/5717): [IMPROVEMENT] Updated button usage to use full width -- [#5722](https://github.com/MetaMask/metamask-mobile/pull/5722): [FIX] Fix env variables syntax in step - [#5679](https://github.com/MetaMask/metamask-mobile/pull/5679): [IMPROVEMENT] Update design-tokens version and remove screen size from TextVariants - [#5713](https://github.com/MetaMask/metamask-mobile/pull/5713): [IMPROVEMENT] Updated ButtonBase to use flex-start instead of baseline - [#5546](https://github.com/MetaMask/metamask-mobile/pull/5546): [IMPROVEMENT] Adding smoke and regression tags to tests - [#5694](https://github.com/MetaMask/metamask-mobile/pull/5694): [IMPROVEMENT] Added missing step definition - [#5343](https://github.com/MetaMask/metamask-mobile/pull/5343): [IMPROVEMENT] Align buttons with Figma - [#5682](https://github.com/MetaMask/metamask-mobile/pull/5682): [IMPROVEMENT] Componentize TextInput -- [#5657](https://github.com/MetaMask/metamask-mobile/pull/5657): [FIX] fix the RequestTokenFlow E2E test -- [#5675](https://github.com/MetaMask/metamask-mobile/pull/5675): [FIX] Fix eslint commit hook - [#5621](https://github.com/MetaMask/metamask-mobile/pull/5621): [IMPROVEMENT] Refactor static method middlware - [#5218](https://github.com/MetaMask/metamask-mobile/pull/5218): [IMPROVEMENT] Improve deeplinks experience + +### Changed +- [#5768](https://github.com/MetaMask/metamask-mobile/pull/5768): [UPGRADE] Segment Analytics 2.13.0 + +### Fixed +- [#5657](https://github.com/MetaMask/metamask-mobile/pull/5657): [FIX] fix the RequestTokenFlow E2E test +- [#5675](https://github.com/MetaMask/metamask-mobile/pull/5675): [FIX] Fix eslint commit hook - [#5608](https://github.com/MetaMask/metamask-mobile/pull/5608): [FIX] SRP recover when an error is thrown +- [#5722](https://github.com/MetaMask/metamask-mobile/pull/5722): [FIX] Fix env variables syntax in step +- [#5730](https://github.com/MetaMask/metamask-mobile/pull/5730): [FIX] French content for SRP Quiz +- [#5726](https://github.com/MetaMask/metamask-mobile/pull/5726): [FIX] Minor UI bugs in credential views +- [#5656](https://github.com/MetaMask/metamask-mobile/pull/5656): [FIX] ENS Resolves to Wrong Address when DeepLink +- [#5719](https://github.com/MetaMask/metamask-mobile/pull/5719): [FIX] Remove false showBack param from order details +- [#5739](https://github.com/MetaMask/metamask-mobile/pull/5739): [FIX] Fix CVE-2023-25166 by resolving @sideway/formula to 3.0.1 +- [#5738](https://github.com/MetaMask/metamask-mobile/pull/5738): [FIX] On-ramp: upgrade on-ramp-sdk to v1.8.1 +- [#5749](https://github.com/MetaMask/metamask-mobile/pull/5749): [FIX] Back navigation CTAs in RevealPrivateCredential view +- [#5587](https://github.com/MetaMask/metamask-mobile/pull/5587): [FIX] ERC721 Approve view +- [#5683](https://github.com/MetaMask/metamask-mobile/pull/5683): [FIX] RN Patch Version +- [#5753](https://github.com/MetaMask/metamask-mobile/pull/5753): [FIX] Fix Slack e2e announcement +- [#5777](https://github.com/MetaMask/metamask-mobile/pull/5777): [FIX] Fix/primary currency fiat insufficient funds error +- [#5399](https://github.com/MetaMask/metamask-mobile/pull/5399): [FIX] Fix bug with updating gas price for legacy transactions +- [#5780](https://github.com/MetaMask/metamask-mobile/pull/5780): [FIX] Show token symbol when approving +- [#5806](https://github.com/MetaMask/metamask-mobile/pull/5806): [FIX] Screenshot Crash +- [#5678](https://github.com/MetaMask/metamask-mobile/pull/5678): [FIX] Updated hardware label to have the correct color +- [#5801](https://github.com/MetaMask/metamask-mobile/pull/5801): [FIX] Update icon name in SRPQuiz +- [#5800](https://github.com/MetaMask/metamask-mobile/pull/5800): [FIX] TabBarIconKey to TabBarLabel +- [#5851](https://github.com/MetaMask/metamask-mobile/pull/5851): [FIX] Fix search network crasher +- [#5809](https://github.com/MetaMask/metamask-mobile/pull/5809): [FIX] Resolve tab bar merge conflicts +- [#5729](https://github.com/MetaMask/metamask-mobile/pull/5729): [FIX] Bump react-native-reanimated to 2.14.0 -## 6.0.1 - Feb 21, 2023 +## [6.0.1] +### Fixed - [#5799](https://github.com/MetaMask/metamask-mobile/pull/5799): [FIX] Browser: handle unsupported URLs -## 6.0.0 - Feb 15, 2023 -- [#5724](https://github.com/MetaMask/metamask-mobile/pull/5724): [FIX] Migrate dapps access into permission controller state -- [#5742](https://github.com/MetaMask/metamask-mobile/pull/5742): [FIX] ENS Resolves to Wrong Address when DeepLink -- [#5714](https://github.com/MetaMask/metamask-mobile/pull/5714): [FIX] Importing private key via QR code redirects to browser -- [#5709](https://github.com/MetaMask/metamask-mobile/pull/5709): [FIX] Settings networks icons were missing +## [6.0.0] +### Added - [#5062](https://github.com/MetaMask/metamask-mobile/pull/5062): [FEATURE] Implement Permission System - [#5659](https://github.com/MetaMask/metamask-mobile/pull/5659): [IMPROVEMENT] E2E fix tapReminder step - [#5641](https://github.com/MetaMask/metamask-mobile/pull/5641): [IMPROVEMENT] Use Set when filtering blocklist -- [#5655](https://github.com/MetaMask/metamask-mobile/pull/5655): [FIX] E2E adjust get started wait - [#5650](https://github.com/MetaMask/metamask-mobile/pull/5650): [IMPROVEMENT] E2E appium request token - [#5647](https://github.com/MetaMask/metamask-mobile/pull/5647): [IMPROVEMENT] Add introductory image to SRP Quiz - [#5640](https://github.com/MetaMask/metamask-mobile/pull/5640): [IMPROVEMENT] Middleware - Include the request in the error params - [#5632](https://github.com/MetaMask/metamask-mobile/pull/5632): [IMPROVEMENT] E2E appium folder structure change - [#5579](https://github.com/MetaMask/metamask-mobile/pull/5579): [FEAT] Add friction to SRP reveal - [#5551](https://github.com/MetaMask/metamask-mobile/pull/5551): [IMPROVEMENT] Refactor Personal Signature -- [#5626](https://github.com/MetaMask/metamask-mobile/pull/5626): [FIX] SRP Quiz content and translations -- [#5612](https://github.com/MetaMask/metamask-mobile/pull/5612): [FIX] Make Prettier work in wdio directory -- [#5605](https://github.com/MetaMask/metamask-mobile/pull/5605): [FIX] Handle ENS Address Error - [#5600](https://github.com/MetaMask/metamask-mobile/pull/5600): [IMPROVEMENT] Refactor ProtectYourWallet section in the security section - [#5586](https://github.com/MetaMask/metamask-mobile/pull/5586): [IMPROVEMENT] Stablize Addressbook and Networks flow tests +- [#5575](https://github.com/MetaMask/metamask-mobile/pull/5575): [CONTENT] Add translations to SRP Reveal feature +- [#5559](https://github.com/MetaMask/metamask-mobile/pull/5559): [ANALYTICS] Add analytics events for SRP reveal + +### Changed - [#5594](https://github.com/MetaMask/metamask-mobile/pull/5594): [UPGRADE] bumped ua-parser-js to 0.7.33 - [#5580](https://github.com/MetaMask/metamask-mobile/pull/5580): [UPGRADE] Bump cookiejar from 2.1.2 to 2.1.4 - [#5471](https://github.com/MetaMask/metamask-mobile/pull/5471): [UPGRADE] Bump luxon from 3.1.1 to 3.2.1 - [#5450](https://github.com/MetaMask/metamask-mobile/pull/5450): [UPGRADE] Bump json5 from 1.0.1 to 1.0.2 -- [#5575](https://github.com/MetaMask/metamask-mobile/pull/5575): [CONTENT] Add translations to SRP Reveal feature -- [#5559](https://github.com/MetaMask/metamask-mobile/pull/5559): [ANALYTICS] Add analytics events for SRP reveal -## 5.14.0 - Jan 27, 2023 -- [#5631](https://github.com/MetaMask/metamask-mobile/pull/5631): [FIX] Modal confirmation refactoring -- [#5624](https://github.com/MetaMask/metamask-mobile/pull/5624): [FIX] Fix currency display -- [#5615](https://github.com/MetaMask/metamask-mobile/pull/5615): [FIX] Fix analytics events -- [#5585](https://github.com/MetaMask/metamask-mobile/pull/5585): [FIX] Token Detection not persisting -- [#5556](https://github.com/MetaMask/metamask-mobile/pull/5556): [FIX] Swaps disabled on fresh install on some networks -- [#5550](https://github.com/MetaMask/metamask-mobile/pull/5550): [FIX] On-ramp: Fix order link in details screen +### Fixed +- [#5626](https://github.com/MetaMask/metamask-mobile/pull/5626): [FIX] SRP Quiz content and translations +- [#5612](https://github.com/MetaMask/metamask-mobile/pull/5612): [FIX] Make Prettier work in wdio directory +- [#5605](https://github.com/MetaMask/metamask-mobile/pull/5605): [FIX] Handle ENS Address Error +- [#5655](https://github.com/MetaMask/metamask-mobile/pull/5655): [FIX] E2E adjust get started wait +- [#5724](https://github.com/MetaMask/metamask-mobile/pull/5724): [FIX] Migrate dapps access into permission controller state +- [#5742](https://github.com/MetaMask/metamask-mobile/pull/5742): [FIX] ENS Resolves to Wrong Address when DeepLink +- [#5714](https://github.com/MetaMask/metamask-mobile/pull/5714): [FIX] Importing private key via QR code redirects to browser +- [#5709](https://github.com/MetaMask/metamask-mobile/pull/5709): [FIX] Settings networks icons were missing + + +## [5.14.0] +### Added - [#5535](https://github.com/MetaMask/metamask-mobile/pull/5535): [IMPROVEMENT] Add content for "Add friction to revealing SRP" -- [#5538](https://github.com/MetaMask/metamask-mobile/pull/5538): [FIX] E2e appium test failure fix -- [#5444](https://github.com/MetaMask/metamask-mobile/pull/5444): [FIX] Fix unecessary executions of useEffect - [#5506](https://github.com/MetaMask/metamask-mobile/pull/5506): [IMPROVEMENT] On-ramp: Add NavBar tests to GetStarted and Regions Views - [#5495](https://github.com/MetaMask/metamask-mobile/pull/5495): [IMPROVEMENT] Copy update for metamask fee on swaps - [#5525](https://github.com/MetaMask/metamask-mobile/pull/5525): [IMPROVEMENT] On-ramp: add fiatOrders reducer tests @@ -2838,27 +2888,21 @@ access - [#5524](https://github.com/MetaMask/metamask-mobile/pull/5524): [IMPROVEMENT] On-ramp: Add order processor tests - [#5512](https://github.com/MetaMask/metamask-mobile/pull/5512): [IMPROVEMENT] Remove redundant browser feature file - [#5511](https://github.com/MetaMask/metamask-mobile/pull/5511): [IMPROVEMENT] On-ramp: Rename applePay hook to useApplePay -- [#5499](https://github.com/MetaMask/metamask-mobile/pull/5499): [FIX] Remove duplicate property -- [#5496](https://github.com/MetaMask/metamask-mobile/pull/5496): [REVERT] Onramp - Remove Text as any ocurrences - [#5474](https://github.com/MetaMask/metamask-mobile/pull/5474): [IMPROVEMENT] Screenshot deterrent alert - [#5489](https://github.com/MetaMask/metamask-mobile/pull/5489): [IMPROVEMENT] Renaming Step files to include ".steps" - [#5460](https://github.com/MetaMask/metamask-mobile/pull/5460): [IMPROVEMENT] E2e test/browser flow - [#5488](https://github.com/MetaMask/metamask-mobile/pull/5488): [IMPROVEMENT] Add Browserstack step to Bitrise -- [#5486](https://github.com/MetaMask/metamask-mobile/pull/5486): [FIX] Add providerValues to renderScreen - [#5484](https://github.com/MetaMask/metamask-mobile/pull/5484): [IMPROVEMENT] Isolate e2e-Appium Feature scenarios - [#5483](https://github.com/MetaMask/metamask-mobile/pull/5483): [IMPROVEMENT] Add renderScreen test util - [#5476](https://github.com/MetaMask/metamask-mobile/pull/5476): [IMPROVEMENT] README.md: update "Install the Android NDK" - [#5479](https://github.com/MetaMask/metamask-mobile/pull/5479): [IMPROVEMENT] Mount SeedPhraseVideo Video Player after transition -- [#5475](https://github.com/MetaMask/metamask-mobile/pull/5475): [FIX] Fix import of `isEIP1559Transaction` - [#5473](https://github.com/MetaMask/metamask-mobile/pull/5473): [DEPENDENCIES] On-ramp: upgrade on-ramp-sdk to v1.6.1 - [#5465](https://github.com/MetaMask/metamask-mobile/pull/5465): [strings] vault corruption recovery strings - [#5433](https://github.com/MetaMask/metamask-mobile/pull/5433): [IMPROVEMENT] Add WebdriverIO test reports and Browserstack Integration - [#5270](https://github.com/MetaMask/metamask-mobile/pull/5270): [DEPENDENCIES] Migrate to new controller packages - [#5449](https://github.com/MetaMask/metamask-mobile/pull/5449): [IMPROVEMENT] Remove deeplink warning for SDK and SDK as dependency -- [#5468](https://github.com/MetaMask/metamask-mobile/pull/5468): [FIX] Screenshot deterrent analytics - [#5462](https://github.com/MetaMask/metamask-mobile/pull/5462): [IMPROVEMENT] On-ramp: Remove unused constants - [#5413](https://github.com/MetaMask/metamask-mobile/pull/5413): [IMPROVEMENT] On-ramp: Refactor Regions view to componentization -- [#5440](https://github.com/MetaMask/metamask-mobile/pull/5440): [FIX] Approval error when insufficient balance - [#5459](https://github.com/MetaMask/metamask-mobile/pull/5459): [IMPROVEMENT] Remove extra zero balance account potentially created from seeking ahead - [#5454](https://github.com/MetaMask/metamask-mobile/pull/5454): [IMPROVEMENT] Refactor Analytics Events - [#5453](https://github.com/MetaMask/metamask-mobile/pull/5453): [IMPROVEMENT] Use "ModalConfirmation" component for the QR Reader security alert @@ -2868,66 +2912,103 @@ access - [#5428](https://github.com/MetaMask/metamask-mobile/pull/5428): [IMPROVEMENT] Add accessibilityRole button to StyledButton - [#5437](https://github.com/MetaMask/metamask-mobile/pull/5437): [IMPROVEMENT] On-ramp: Move useSDKMethod to its own file - [#5448](https://github.com/MetaMask/metamask-mobile/pull/5448): [IMPROVEMENT] Add translations to "Safe QR" feature -- [#5219](https://github.com/MetaMask/metamask-mobile/pull/5219): [FIX] Update selected network when delete network manually inserted - [#5430](https://github.com/MetaMask/metamask-mobile/pull/5430): [IMPROVEMENT] Remove Text as any occurrences -## 5.13.0 - Jan 17, 2022 -- [#5381](https://github.com/MetaMask/metamask-mobile/pull/5381): [UPDATE] Bumped contract-metadata to 2.1.0 +### Changed +- [#5496](https://github.com/MetaMask/metamask-mobile/pull/5496): [REVERT] Onramp - Remove Text as any ocurrences + +### Fixed +- [#5219](https://github.com/MetaMask/metamask-mobile/pull/5219): [FIX] Update selected network when delete network manually inserted +- [#5440](https://github.com/MetaMask/metamask-mobile/pull/5440): [FIX] Approval error when insufficient balance +- [#5468](https://github.com/MetaMask/metamask-mobile/pull/5468): [FIX] Screenshot deterrent analytics +- [#5475](https://github.com/MetaMask/metamask-mobile/pull/5475): [FIX] Fix import of `isEIP1559Transaction` +- [#5486](https://github.com/MetaMask/metamask-mobile/pull/5486): [FIX] Add providerValues to renderScreen +- [#5499](https://github.com/MetaMask/metamask-mobile/pull/5499): [FIX] Remove duplicate property +- [#5631](https://github.com/MetaMask/metamask-mobile/pull/5631): [FIX] Modal confirmation refactoring +- [#5624](https://github.com/MetaMask/metamask-mobile/pull/5624): [FIX] Fix currency display +- [#5615](https://github.com/MetaMask/metamask-mobile/pull/5615): [FIX] Fix analytics events +- [#5585](https://github.com/MetaMask/metamask-mobile/pull/5585): [FIX] Token Detection not persisting +- [#5556](https://github.com/MetaMask/metamask-mobile/pull/5556): [FIX] Swaps disabled on fresh install on some networks +- [#5550](https://github.com/MetaMask/metamask-mobile/pull/5550): [FIX] On-ramp: Fix order link in details screen +- [#5538](https://github.com/MetaMask/metamask-mobile/pull/5538): [FIX] E2e appium test failure fix +- [#5444](https://github.com/MetaMask/metamask-mobile/pull/5444): [FIX] Fix unecessary executions of useEffect + +## [5.13.0] +### Added - [#5424](https://github.com/MetaMask/metamask-mobile/pull/5424): [IMPROVEMENT] Add Screenshot Warning to ImportPrivateKey - [#4670](https://github.com/MetaMask/metamask-mobile/pull/4670): [FEAT] Screenshot Warning -- [#5422](https://github.com/MetaMask/metamask-mobile/pull/5422): [UPDATE] Add custom network and Import custom token - [#5376](https://github.com/MetaMask/metamask-mobile/pull/5376): [IMPROVEMENT] Include L1 fee in the Send flow and on the tx detail page for Optimism -- [#5351](https://github.com/MetaMask/metamask-mobile/pull/5351): [REMOVE] On-ramp: remove old on-ramp experience -- [#5352](https://github.com/MetaMask/metamask-mobile/pull/5352): [UPDATE] Bump decode-uri-component from 0.2.0 to 0.2.2 -- [#5246](https://github.com/MetaMask/metamask-mobile/pull/5246): [UPDATE] Bump loader-utils from 1.4.0 to 1.4.2 - [#5191](https://github.com/MetaMask/metamask-mobile/pull/5191): [IMPROVEMENT] Support for ens on deeplink transactions -- [#5115](https://github.com/MetaMask/metamask-mobile/pull/5115): [FIX] cancelling transaction when user does not give dapp permission to transfer funds -- [#5400](https://github.com/MetaMask/metamask-mobile/pull/5400): [FIX] jest expect type - [#4546](https://github.com/MetaMask/metamask-mobile/pull/4546): [IMPROVEMENT] Support downloading Apple Wallet passes on iOS -- [#5200](https://github.com/MetaMask/metamask-mobile/pull/5200): [UPDATE] Update Controllers to version 33.0.0 - [#5083](https://github.com/MetaMask/metamask-mobile/pull/5083): [IMPROVEMENT] Component: Custom Spending Cap -## 5.12.3 - Dec 16, 2022 +### Changed +- [#5381](https://github.com/MetaMask/metamask-mobile/pull/5381): [UPDATE] Bumped contract-metadata to 2.1.0 +- [#5422](https://github.com/MetaMask/metamask-mobile/pull/5422): [UPDATE] Add custom network and Import custom token +- [#5200](https://github.com/MetaMask/metamask-mobile/pull/5200): [UPDATE] Update Controllers to version 33.0.0 +- [#5352](https://github.com/MetaMask/metamask-mobile/pull/5352): [UPDATE] Bump decode-uri-component from 0.2.0 to 0.2.2 +- [#5246](https://github.com/MetaMask/metamask-mobile/pull/5246): [UPDATE] Bump loader-utils from 1.4.0 to 1.4.2 +- [#5351](https://github.com/MetaMask/metamask-mobile/pull/5351): [REMOVE] On-ramp: remove old on-ramp experience + +### Fixed +- [#5400](https://github.com/MetaMask/metamask-mobile/pull/5400): [FIX] jest expect type +- [#5115](https://github.com/MetaMask/metamask-mobile/pull/5115): [FIX] cancelling transaction when user does not give dapp permission to transfer funds + + +## [5.12.3] +### Changed - Hotfix version bump for iOS only release, no code changes -## 5.12.1 - Dec 6, 2022 -- [#5366](https://github.com/MetaMask/metamask-mobile/pull/5366): [UPDATE] On-ramp Refactor wyre authentication URL approach -- [#5362](https://github.com/MetaMask/metamask-mobile/pull/5362): [UPDATE] Copy for Opt in metrics screen and enable custom mainnet RPC -- [#5360](https://github.com/MetaMask/metamask-mobile/pull/5360): [FIX] Onboarding wizard automatic update modal +## [5.12.1] +### Added - [#5307](https://github.com/MetaMask/metamask-mobile/pull/5307): [IMPROVEMENT] Remove RPC URL, Block Explorer URL, Network Name from metrics - [#5355](https://github.com/MetaMask/metamask-mobile/pull/5355): [IMPROVEMENT] Sanitize privacy settings before sending to Sentry -## 5.12.0 - Dec 5, 2022 +### Changed +- [#5362](https://github.com/MetaMask/metamask-mobile/pull/5362): [UPDATE] Copy for Opt in metrics screen and enable custom mainnet RPC +- [#5366](https://github.com/MetaMask/metamask-mobile/pull/5366): [UPDATE] On-ramp Refactor wyre authentication URL approach + +### Fixed +- [#5360](https://github.com/MetaMask/metamask-mobile/pull/5360): [FIX] Onboarding wizard automatic update modal + +## [5.12.0] +### Added - [#5335](https://github.com/MetaMask/metamask-mobile/pull/5335): [IMPROVEMENT] On-ramp: Add useRegions hook and fix availablePaymentMethods -- [#5337](https://github.com/MetaMask/metamask-mobile/pull/5337): [FIX] Send ERC-20 tokens on legacy networks - [#5333](https://github.com/MetaMask/metamask-mobile/pull/5333): [IMPROVEMENT] Only fetch minimum versions if permissions enabled -- [#5331](https://github.com/MetaMask/metamask-mobile/pull/5331): [UPDATE] Bump @metamask/swaps-controller -- [#5169](https://github.com/MetaMask/metamask-mobile/pull/5169): [FIX] Miscalculation on toWei func when passing valid numbers in scientific notation - [#5238](https://github.com/MetaMask/metamask-mobile/pull/5238): [IMPROVEMENT] Browser experience -- [#5318](https://github.com/MetaMask/metamask-mobile/pull/5318): [FIX] Estimated gas fee calculation on the transaction detail page - [#5294](https://github.com/MetaMask/metamask-mobile/pull/5294): [IMPROVEMENT] On-ramp: allow amount formatting on android -- [#5292](https://github.com/MetaMask/metamask-mobile/pull/5292): [FIX] On-ramp: fix default payment method selection -- [#5103](https://github.com/MetaMask/metamask-mobile/pull/5103): [FIX] WalletConnect signed typed and eth sign throwing error back to the dapp -- [#5263](https://github.com/MetaMask/metamask-mobile/pull/5263): [UPDATE] Updates WebRTC and Socket.io client to the latest versions - [#5273](https://github.com/MetaMask/metamask-mobile/pull/5273): [IMPROVEMENT] Enable new networks for Swaps -- [#5244](https://github.com/MetaMask/metamask-mobile/pull/5244): [UPDATE] Change SDK URL -- [#5262](https://github.com/MetaMask/metamask-mobile/pull/5262): [FIX] Fixes and configuration updates related to Branch.io Deep Links - [#5289](https://github.com/MetaMask/metamask-mobile/pull/5289): [IMPROVEMENT] Add strings to feature "Screenshot Warning" -- [#5243](https://github.com/MetaMask/metamask-mobile/pull/5243): [FIX] Only trigger onLoadEnd when urls are equal - [#5287](https://github.com/MetaMask/metamask-mobile/pull/5287): [IMPROVEMENT] Add translations to feature "Easy Delete Data" - [#4917](https://github.com/MetaMask/metamask-mobile/pull/4917): [IMPROVEMENT] Trigger UpdateNeeded screen - [#5280](https://github.com/MetaMask/metamask-mobile/pull/5280): [IMPROVEMENT] On-ramp: Add usePaymentMethods hook with customAction filter by chainId - [#5265](https://github.com/MetaMask/metamask-mobile/pull/5265): [IMPROVEMENT] On-ramp: Add order pending description in details view -- [#5269](https://github.com/MetaMask/metamask-mobile/pull/5269): [FIX] On-Ramp: Fix 1.3.1 creating undefined custom order ids - [#5267](https://github.com/MetaMask/metamask-mobile/pull/5267): [IMPROVEMENT] On-ramp: Change 0 amount to a pending state in order details -- [#5266](https://github.com/MetaMask/metamask-mobile/pull/5266): [REMOVE] On-ramp: Remove disabled button in amount to buy screen -- [#5268](https://github.com/MetaMask/metamask-mobile/pull/5268): [FIX] On-Ramp: Fix typos from payment method icon and contact support -- [#5220](https://github.com/MetaMask/metamask-mobile/pull/5220): [UPDATE] On-ramp-sdk@1.3.1: Wyre Apple Pay auth support and inAppBrowser hook -- [#5264](https://github.com/MetaMask/metamask-mobile/pull/5264): [FIX] Date msBetweenDates test - [#5194](https://github.com/MetaMask/metamask-mobile/pull/5194): [FEATURE] Add more granular killswitches for swaps + +### Changed - [#5237](https://github.com/MetaMask/metamask-mobile/pull/5237): [DEPENDENCIES] Update Segment dependencies +- [#5220](https://github.com/MetaMask/metamask-mobile/pull/5220): [UPDATE] On-ramp-sdk@1.3.1: Wyre Apple Pay auth support and inAppBrowser hook +- [#5266](https://github.com/MetaMask/metamask-mobile/pull/5266): [REMOVE] On-ramp: Remove disabled button in amount to buy screen +- [#5244](https://github.com/MetaMask/metamask-mobile/pull/5244): [UPDATE] Change SDK URL +- [#5263](https://github.com/MetaMask/metamask-mobile/pull/5263): [UPDATE] Updates WebRTC and Socket.io client to the latest versions +- [#5331](https://github.com/MetaMask/metamask-mobile/pull/5331): [UPDATE] Bump @metamask/swaps-controller + +### Fixed +- [#5264](https://github.com/MetaMask/metamask-mobile/pull/5264): [FIX] Date msBetweenDates test +- [#5268](https://github.com/MetaMask/metamask-mobile/pull/5268): [FIX] On-Ramp: Fix typos from payment method icon and contact support +- [#5269](https://github.com/MetaMask/metamask-mobile/pull/5269): [FIX] On-Ramp: Fix 1.3.1 creating undefined custom order ids +- [#5243](https://github.com/MetaMask/metamask-mobile/pull/5243): [FIX] Only trigger onLoadEnd when urls are equal +- [#5262](https://github.com/MetaMask/metamask-mobile/pull/5262): [FIX] Fixes and configuration updates related to Branch.io Deep Links +- [#5103](https://github.com/MetaMask/metamask-mobile/pull/5103): [FIX] WalletConnect signed typed and eth sign throwing error back to the dapp +- [#5292](https://github.com/MetaMask/metamask-mobile/pull/5292): [FIX] On-ramp: fix default payment method selection +- [#5318](https://github.com/MetaMask/metamask-mobile/pull/5318): [FIX] Estimated gas fee calculation on the transaction detail page +- [#5169](https://github.com/MetaMask/metamask-mobile/pull/5169): [FIX] Miscalculation on toWei func when passing valid numbers in scientific notation +- [#5337](https://github.com/MetaMask/metamask-mobile/pull/5337): [FIX] Send ERC-20 tokens on legacy networks -## 5.11.0 - Nov 21, 2022 + +## [5.11.0] +### Added - [#5088](https://github.com/MetaMask/metamask-mobile/pull/5088): [IMPROVEMENT] Add no payment methods screen - [#5223](https://github.com/MetaMask/metamask-mobile/pull/5223): [IMPROVEMENT] Add payment method icons support - [#5198](https://github.com/MetaMask/metamask-mobile/pull/5198): [IMPROVEMENT] Improve loading experience @@ -2935,118 +3016,142 @@ access - [#5214](https://github.com/MetaMask/metamask-mobile/pull/5214): [IMPROVEMENT] On-ramp: add payment method custom action analytics - [#5188](https://github.com/MetaMask/metamask-mobile/pull/5188): [IMPROVEMENT] Networks-flow appium feature file -## 5.10.0 - Nov 10, 2022 -- [#5209](https://github.com/MetaMask/metamask-mobile/pull/5209): [FIX] On-ramp: multiple redirection handling -- [#5217](https://github.com/MetaMask/metamask-mobile/pull/5217): [FIX] Send to the wrong address +## [5.10.0] +### Added - [#5202](https://github.com/MetaMask/metamask-mobile/pull/5202): [FEAT] On-Ramp: allow Harmony ONE - [#5195](https://github.com/MetaMask/metamask-mobile/pull/5195): [FEAT] Onramp: Add exclude from purchases to onramp aggregator orders -- [#5064](https://github.com/MetaMask/metamask-mobile/pull/5064): [UPDATE] Refactor Approve Component - [#5158](https://github.com/MetaMask/metamask-mobile/pull/5158): [FEAT] On-Ramp: Provider payment method custom action and custom order ids -- [#5119](https://github.com/MetaMask/metamask-mobile/pull/5119): [FIX] Crash when reject two times connect wallet on in app browser -- [#5173](https://github.com/MetaMask/metamask-mobile/pull/5173): [FIX] Android build cMake -- [#5167](https://github.com/MetaMask/metamask-mobile/pull/5167): [FIX] Fixed Button Base Size issue -- [#4868](https://github.com/MetaMask/metamask-mobile/pull/4868): [UPDATE] Refactor ApprovalTransaction Component -- [#5142](https://github.com/MetaMask/metamask-mobile/pull/5142): [FIX] Fix high severity audit issues -- [#4235](https://github.com/MetaMask/metamask-mobile/pull/4235): [FIX] Delete contact on android fixed -- [#5116](https://github.com/MetaMask/metamask-mobile/pull/5116): [FIX] Updated EditLegacy Component -- [#4835](https://github.com/MetaMask/metamask-mobile/pull/4835): [UPDATE] Refactor SendTransaction Component -- [#5113](https://github.com/MetaMask/metamask-mobile/pull/5113): [UPDATE] avoid using Rinkeby in wallet & import network test - [#4922](https://github.com/MetaMask/metamask-mobile/pull/4922): [FEAT] Segment Integration - [#5041](https://github.com/MetaMask/metamask-mobile/pull/5041): [FEAT] Add accordion component to Design System -- [#5091](https://github.com/MetaMask/metamask-mobile/pull/5091): [UPDATE] Standardized Storybook Structure +- [#5067](https://github.com/MetaMask/metamask-mobile/pull/5067): [FEAT] Component: Contract Box component - [#4888](https://github.com/MetaMask/metamask-mobile/pull/4888): [FEAT] Extend popular network list + +### Changed - [#5096](https://github.com/MetaMask/metamask-mobile/pull/5096): [UPDATE] Update audit list -- [#5067](https://github.com/MetaMask/metamask-mobile/pull/5067): [FEAT] Component: Contract Box component +- [#4835](https://github.com/MetaMask/metamask-mobile/pull/4835): [UPDATE] Refactor SendTransaction Component +- [#5113](https://github.com/MetaMask/metamask-mobile/pull/5113): [UPDATE] avoid using Rinkeby in wallet & import network test +- [#5091](https://github.com/MetaMask/metamask-mobile/pull/5091): [UPDATE] Standardized Storybook Structure +- [#4868](https://github.com/MetaMask/metamask-mobile/pull/4868): [UPDATE] Refactor ApprovalTransaction Component +- [#5064](https://github.com/MetaMask/metamask-mobile/pull/5064): [UPDATE] Refactor Approve Component + +### Fixed +- [#5142](https://github.com/MetaMask/metamask-mobile/pull/5142): [FIX] Fix high severity audit issues +- [#4235](https://github.com/MetaMask/metamask-mobile/pull/4235): [FIX] Delete contact on android fixed +- [#5116](https://github.com/MetaMask/metamask-mobile/pull/5116): [FIX] Updated EditLegacy Component +- [#5119](https://github.com/MetaMask/metamask-mobile/pull/5119): [FIX] Crash when reject two times connect wallet on in app browser +- [#5173](https://github.com/MetaMask/metamask-mobile/pull/5173): [FIX] Android build cMake +- [#5167](https://github.com/MetaMask/metamask-mobile/pull/5167): [FIX] Fixed Button Base Size issue +- [#5209](https://github.com/MetaMask/metamask-mobile/pull/5209): [FIX] On-ramp: multiple redirection handling +- [#5217](https://github.com/MetaMask/metamask-mobile/pull/5217): [FIX] Send to the wrong address -## 5.9.1 - Oct 28, 2022 +## [5.9.1] +### Fixed - [#5172](https://github.com/MetaMask/metamask-mobile/pull/5172): [FIX] ENS name being resolved correctly -## 5.9.0 - Oct 10, 2022 - - [#5035](https://github.com/MetaMask/metamask-mobile/pull/5035): [FIX] On-Ramp: Fix autolock dispatch for apple pay - - [#4804](https://github.com/MetaMask/metamask-mobile/pull/4804): [UPDATE] GasPolling refactor UpdateEIP1559Transaction Component - - [#5079](https://github.com/MetaMask/metamask-mobile/pull/5079): [FIX] Network switch during QR scan in Send Flow - - [#5077](https://github.com/MetaMask/metamask-mobile/pull/5077): [FEATURE] translations for permission system - - [#5044](https://github.com/MetaMask/metamask-mobile/pull/5044): [FIX] evaluating ‘transaction.status’ - - [#5040](https://github.com/MetaMask/metamask-mobile/pull/5040): [ADD] Component/4721-card - - [#5034](https://github.com/MetaMask/metamask-mobile/pull/5034): [FIX] Wallet Connect PR#4934 and PR#4861 - - [#5065](https://github.com/MetaMask/metamask-mobile/pull/5065): [ENHANCEMENT] added shadows to useAppTheme - - [#5039](https://github.com/MetaMask/metamask-mobile/pull/5039): [UPDATE] update shadow tokens - - [#5010](https://github.com/MetaMask/metamask-mobile/pull/5010): [ADD] InApp Browser package - - [#5058](https://github.com/MetaMask/metamask-mobile/pull/5058): [UPDATE] patch vm2 via resolution - - [#5042](https://github.com/MetaMask/metamask-mobile/pull/5042): [ADD] Component/4723-estimatedtext - - [#4999](https://github.com/MetaMask/metamask-mobile/pull/4999): [ADD] Component: Account and balance component - - [#5030](https://github.com/MetaMask/metamask-mobile/pull/5030): [ENHANCEMENT] PR template with working link for mobile coding standards - - [#5033](https://github.com/MetaMask/metamask-mobile/pull/5033): [UPDATE] default iOS simulator - - [#5028](https://github.com/MetaMask/metamask-mobile/pull/5028): [FIX] variable interpolation in build.sh - - [#5031](https://github.com/MetaMask/metamask-mobile/pull/5031): [ENHANCEMENT] Deprecate snake case from feature flags - - [#5025](https://github.com/MetaMask/metamask-mobile/pull/5025): [ENHANCEMENT] Remove all "Ooops" copies - - [#4404](https://github.com/MetaMask/metamask-mobile/pull/4404): [FIX] Fixed ERC20 token transfer from Dapps - - [#5024](https://github.com/MetaMask/metamask-mobile/pull/5024): [UPDATE] app name for release-to-store step - - [#5006](https://github.com/MetaMask/metamask-mobile/pull/5006): [UPDATE] Bump @keystonehq/ur-decoder from 0.3.0 to 0.6.1 - -## 5.8.1 - Oct 5, 2022 +## [5.9.0] +### Added +- [#5077](https://github.com/MetaMask/metamask-mobile/pull/5077): [FEATURE] translations for permission system +- [#5040](https://github.com/MetaMask/metamask-mobile/pull/5040): [ADD] Component/4721-card +- [#5065](https://github.com/MetaMask/metamask-mobile/pull/5065): [ENHANCEMENT] added shadows to useAppTheme +- [#5010](https://github.com/MetaMask/metamask-mobile/pull/5010): [ADD] InApp Browser package +- [#5042](https://github.com/MetaMask/metamask-mobile/pull/5042): [ADD] Component/4723-estimatedtext +- [#4999](https://github.com/MetaMask/metamask-mobile/pull/4999): [ADD] Component: Account and balance component +- [#5030](https://github.com/MetaMask/metamask-mobile/pull/5030): [ENHANCEMENT] PR template with working link for mobile coding standards +- [#5031](https://github.com/MetaMask/metamask-mobile/pull/5031): [ENHANCEMENT] Deprecate snake case from feature flags +- [#5025](https://github.com/MetaMask/metamask-mobile/pull/5025): [ENHANCEMENT] Remove all "Ooops" copies + +### Changed +- [#5024](https://github.com/MetaMask/metamask-mobile/pull/5024): [UPDATE] app name for release-to-store step +- [#5006](https://github.com/MetaMask/metamask-mobile/pull/5006): [UPDATE] Bump @keystonehq/ur-decoder from 0.3.0 to 0.6.1 +- [#5033](https://github.com/MetaMask/metamask-mobile/pull/5033): [UPDATE] default iOS simulator +- [#5058](https://github.com/MetaMask/metamask-mobile/pull/5058): [UPDATE] patch vm2 via resolution +- [#5039](https://github.com/MetaMask/metamask-mobile/pull/5039): [UPDATE] update shadow tokens +- [#4804](https://github.com/MetaMask/metamask-mobile/pull/4804): [UPDATE] GasPolling refactor UpdateEIP1559Transaction Component + +### Fixed +- [#5035](https://github.com/MetaMask/metamask-mobile/pull/5035): [FIX] On-Ramp: Fix autolock dispatch for apple pay +- [#5079](https://github.com/MetaMask/metamask-mobile/pull/5079): [FIX] Network switch during QR scan in Send Flow +- [#5034](https://github.com/MetaMask/metamask-mobile/pull/5034): [FIX] Wallet Connect PR#4934 and PR#4861 +- [#4404](https://github.com/MetaMask/metamask-mobile/pull/4404): [FIX] Fixed ERC20 token transfer from Dapps +- [#5028](https://github.com/MetaMask/metamask-mobile/pull/5028): [FIX] variable interpolation in build.sh +- [#5044](https://github.com/MetaMask/metamask-mobile/pull/5044): [FIX] evaluating ‘transaction.status’ + +## [5.8.1] +### Added - [#4286](https://github.com/MetaMask/metamask-mobile/pull/4286): [ENHANCEMENT] Integrates MetaMask SDK support -## 5.8.0 - Sept 22, 2022 -- [#5018](https://github.com/MetaMask/metamask-mobile/pull/5018): [FIX] Vault corruption error log -- [#4972](https://github.com/MetaMask/metamask-mobile/pull/4972): [FIX] Unable to Speedup/Cancel legacy transactions +## [5.8.0] +### Added - [#4833](https://github.com/MetaMask/metamask-mobile/pull/4833): [ENHANCEMENT] Implement new QA builds for both Android and iOS - [#4993](https://github.com/MetaMask/metamask-mobile/pull/4993): [ENHANCEMENT] On-Ramp: Add scrolling to payment methods and make logo property optional - [#4997](https://github.com/MetaMask/metamask-mobile/pull/4997): [ENHANCEMENT] SRP Reveal Timestamp - [#5002](https://github.com/MetaMask/metamask-mobile/pull/5002): [FEAT] ENS Wildcard and offchain resolution -- [#4430](https://github.com/MetaMask/metamask-mobile/pull/4430): [FIX] Keystone: Pagination and missing addresses -- [#3438](https://github.com/MetaMask/metamask-mobile/pull/3438): [DEPENDENCIES] Bump metro from 0.59.0 to 0.66.2 - [#4649](https://github.com/MetaMask/metamask-mobile/pull/4649): [ENHANCEMENT] Url redirection from QR code -- [#4980](https://github.com/MetaMask/metamask-mobile/pull/4980): [DEPENDENCIES] On-ramp: Add compact payment method selector -- [#4982](https://github.com/MetaMask/metamask-mobile/pull/4982): [FIX] typo in faucet name -- [#4983](https://github.com/MetaMask/metamask-mobile/pull/4983): [FIX] Navigation comment spell -- [#4755](https://github.com/MetaMask/metamask-mobile/pull/4755): [UPDATE] - New template fields added to reflect newer requirements for PRs - [#4978](https://github.com/MetaMask/metamask-mobile/pull/4978): [ENHANCEMENT] Store distinct id for consistency -- [#4958](https://github.com/MetaMask/metamask-mobile/pull/4958): [FIX] WebView Origin Allowlist -- [#4941](https://github.com/MetaMask/metamask-mobile/pull/4941): [DEPENDENCIES] Replace "@react-native-community/async-storage" for "@react-native-async-storage/async-storage" - [#4947](https://github.com/MetaMask/metamask-mobile/pull/4947): [IMPROVEMENT] WebView Error Copy - [#4946](https://github.com/MetaMask/metamask-mobile/pull/4946): [ENHANCEMENT] Swaps: Add copy for 0% fee in quotes info modal - [#4942](https://github.com/MetaMask/metamask-mobile/pull/4942): [ENHANCEMENT] Add unit tests to useDeleteWallet hook - [#4939](https://github.com/MetaMask/metamask-mobile/pull/4939): [ENHANCEMENT] Update "Usability enhancement" template - [#4938](https://github.com/MetaMask/metamask-mobile/pull/4938): [ENHANCEMENT] Bump git-clone version to 6 in Bitrise machines + +### Changed +- [#4755](https://github.com/MetaMask/metamask-mobile/pull/4755): [UPDATE] - New template fields added to reflect newer requirements for PRs - [#4782](https://github.com/MetaMask/metamask-mobile/pull/4782): [DEPENDENCIES] Detox version bump from 19.6.5 to 19.7.1 +- [#4941](https://github.com/MetaMask/metamask-mobile/pull/4941): [DEPENDENCIES] Replace "@react-native-community/async-storage" for "@react-native-async-storage/async-storage" +- [#4980](https://github.com/MetaMask/metamask-mobile/pull/4980): [DEPENDENCIES] On-ramp: Add compact payment method selector +- [#3438](https://github.com/MetaMask/metamask-mobile/pull/3438): [DEPENDENCIES] Bump metro from 0.59.0 to 0.66.2 -## 5.7.0 - Sept 21, 2022 -- [#4905](https://github.com/MetaMask/metamask-mobile/pull/4905): [FIX] Update send flow +### Fixed +- [#5018](https://github.com/MetaMask/metamask-mobile/pull/5018): [FIX] Vault corruption error log +- [#4972](https://github.com/MetaMask/metamask-mobile/pull/4972): [FIX] Unable to Speedup/Cancel legacy transactions +- [#4430](https://github.com/MetaMask/metamask-mobile/pull/4430): [FIX] Keystone: Pagination and missing addresses +- [#4982](https://github.com/MetaMask/metamask-mobile/pull/4982): [FIX] typo in faucet name +- [#4983](https://github.com/MetaMask/metamask-mobile/pull/4983): [FIX] Navigation comment spell +- [#4958](https://github.com/MetaMask/metamask-mobile/pull/4958): [FIX] WebView Origin Allowlist + +## [5.7.0] +### Added - [#4897](https://github.com/MetaMask/metamask-mobile/pull/4897): [IMPROVEMENT] Automatic security checks settings - [#4902](https://github.com/MetaMask/metamask-mobile/pull/4902): [IMPROVEMENT] Deprecated networks Alert border fixed - [#4885](https://github.com/MetaMask/metamask-mobile/pull/4885): [IMPROVEMENT] Implement warning for deprecated test networks, kovan, ropsten and rinkeby -- [#4898](https://github.com/MetaMask/metamask-mobile/pull/4898): [FIX] Test sanitizeUrlInput error -- [#4882](https://github.com/MetaMask/metamask-mobile/pull/4882): [FIX] Missing token detection event properties -- [#4869](https://github.com/MetaMask/metamask-mobile/pull/4869): [FIX] Remove decimals for on-ramp order details exchange rate -- [#4896](https://github.com/MetaMask/metamask-mobile/pull/4896): [DEPENDENCIES] Upgrade on-ramp-sdk to 1.2.0 - [#4860](https://github.com/MetaMask/metamask-mobile/pull/4860): [IMPROVEMENT] Change skip to payment method in on-ramp flow - [#4892](https://github.com/MetaMask/metamask-mobile/pull/4892): [IMPROVEMENT] Increase polling cycles for on-ramp quotes to 6 -- [#4407](https://github.com/MetaMask/metamask-mobile/pull/4407): [FIX] Add browser cookies support on Android - [#4530](https://github.com/MetaMask/metamask-mobile/pull/4530): [IMPROVEMENT] Apply Test network prefix to token values to help educate users - [#4841](https://github.com/MetaMask/metamask-mobile/pull/4841): [IMPROVEMENT] Component/4080 Badge - [#4856](https://github.com/MetaMask/metamask-mobile/pull/4856): [IMPROVEMENT] Update Cell Account component -- [#4799](https://github.com/MetaMask/metamask-mobile/pull/4799): [FIX] Reveal SRP or Private Key wrong password error - [#4305](https://github.com/MetaMask/metamask-mobile/pull/4305): [FEAT] Hide remember me -- [#4878](https://github.com/MetaMask/metamask-mobile/pull/4878): [FIX] Add testnets condition to blockchain explorer - [#4862](https://github.com/MetaMask/metamask-mobile/pull/4862): [IMPROVEMENT] Fetch and parse app config - [#4798](https://github.com/MetaMask/metamask-mobile/pull/4798): [ANALYTICS] Improve SRP reveal metrics -- [#4016](https://github.com/MetaMask/metamask-mobile/pull/4016): [FIX] ypo in conversion/index.js -- [#4503](https://github.com/MetaMask/metamask-mobile/pull/4503): [FIX] Jazz icons constantly changing -- [#4595](https://github.com/MetaMask/metamask-mobile/pull/4595): [DEPENDENCIES] Upgrade react-native-device-info to 9.0.2 -- [#4684](https://github.com/MetaMask/metamask-mobile/pull/4684): [FIX] Account nickname is always defined -- [#4830](https://github.com/MetaMask/metamask-mobile/pull/4830): [FIX] Add user agent from property as default -- [#4828](https://github.com/MetaMask/metamask-mobile/pull/4828): [FIX] Image styling +- [#4809](https://github.com/MetaMask/metamask-mobile/pull/4809): [IMPROVEMENT] Component/4779 Audit + +### Changed - [#4839](https://github.com/MetaMask/metamask-mobile/pull/4839): [DEPENDENCIES] Introduce @testing-library/react-hooks dependency +- [#4595](https://github.com/MetaMask/metamask-mobile/pull/4595): [DEPENDENCIES] Upgrade react-native-device-info to 9.0.2 - [#4748](https://github.com/MetaMask/metamask-mobile/pull/4748): [UPGRADE] Patch bump for SoLoader version on Android +- [#4896](https://github.com/MetaMask/metamask-mobile/pull/4896): [DEPENDENCIES] Upgrade on-ramp-sdk to 1.2.0 + +### Fixed +- [#4905](https://github.com/MetaMask/metamask-mobile/pull/4905): [FIX] Update send flow +- [#4407](https://github.com/MetaMask/metamask-mobile/pull/4407): [FIX] Add browser cookies support on Android +- [#4898](https://github.com/MetaMask/metamask-mobile/pull/4898): [FIX] Test sanitizeUrlInput error +- [#4882](https://github.com/MetaMask/metamask-mobile/pull/4882): [FIX] Missing token detection event properties +- [#4869](https://github.com/MetaMask/metamask-mobile/pull/4869): [FIX] Remove decimals for on-ramp order details exchange rate - [#4824](https://github.com/MetaMask/metamask-mobile/pull/4824): [Fix] Fix password not being set as authentication type for login metrics -- [#4809](https://github.com/MetaMask/metamask-mobile/pull/4809): [IMPROVEMENT] Component/4779 Audit +- [#4828](https://github.com/MetaMask/metamask-mobile/pull/4828): [FIX] Image styling +- [#4830](https://github.com/MetaMask/metamask-mobile/pull/4830): [FIX] Add user agent from property as default +- [#4684](https://github.com/MetaMask/metamask-mobile/pull/4684): [FIX] Account nickname is always defined +- [#4503](https://github.com/MetaMask/metamask-mobile/pull/4503): [FIX] Jazz icons constantly changing +- [#4016](https://github.com/MetaMask/metamask-mobile/pull/4016): [FIX] ypo in conversion/index.js +- [#4878](https://github.com/MetaMask/metamask-mobile/pull/4878): [FIX] Add testnets condition to blockchain explorer +- [#4799](https://github.com/MetaMask/metamask-mobile/pull/4799): [FIX] Reveal SRP or Private Key wrong password error -## 5.6.1 - Sept 9, 2022 +## [5.6.1] +### Uncategorized - [#4966](https://github.com/MetaMask/metamask-mobile/pull/4966): [FIX] Add http and https protocol to webview origin whitelist - [#4967](https://github.com/MetaMask/metamask-mobile/pull/4967): [FIX] Correct url parse -## 5.6.0 - Aug 15, 2022 +## [5.6.0] +### Uncategorized - [#4821](https://github.com/MetaMask/metamask-mobile/pull/4821): [FIX] Staging env redirection url for onramp - [#4742](https://github.com/MetaMask/metamask-mobile/pull/4742): [ADD] On-Ramp generic error view event - [#4743](https://github.com/MetaMask/metamask-mobile/pull/4743): [ADD] Payment Method logos @@ -3065,10 +3170,12 @@ access - [#4613](https://github.com/MetaMask/metamask-mobile/pull/4613): [ADD] Component/4079 avatar group - [#4636](https://github.com/MetaMask/metamask-mobile/pull/4636): [FIX] NFT transfer with big token id -## 5.5.1 - Aug 16, 2022 +## [5.5.1] +### Changed - [UPDATE](https://github.com/MetaMask/dapps/pull/137): [UPDATE] Disable iOS explore links -## 5.5.0 - Jul 27, 2022 +## [5.5.0] +### Uncategorized - [#4475](https://github.com/MetaMask/metamask-mobile/pull/4475): [IMPROVEMENT] Swaps support for hardware wallet - [#4627](https://github.com/MetaMask/metamask-mobile/pull/4627): [IMPROVEMENT] Add typing support for payment methods to be used instead of payment IDs - [#4625](https://github.com/MetaMask/metamask-mobile/pull/4625): [FIX] Handle SecureKeychain failed access while passcode enabled @@ -3085,7 +3192,8 @@ access - [#4689](https://github.com/MetaMask/metamask-mobile/pull/4689): [IMPROVEMENT] Componentize Account Picker - [#4612](https://github.com/MetaMask/metamask-mobile/pull/4612): [IMPROVEMENT] Componentize Token Avatar -## 5.4.0 - Jul 12, 2022 +## [5.4.0] +### Uncategorized - [#4604](https://github.com/MetaMask/metamask-mobile/pull/4604): [IMPROVEMENT] Change quotes error to individual events - [#4497](https://github.com/MetaMask/metamask-mobile/pull/4497): [IMPROVEMENT] Add amount to onramp analytics events - [#4496](https://github.com/MetaMask/metamask-mobile/pull/4496): [IMPROVEMENT] Add currency destination symbol to purchase submitted @@ -3123,7 +3231,8 @@ access - [#4559](https://github.com/MetaMask/metamask-mobile/pull/4559): [FIX] Add resolution for shell-quote & got - [#4531](https://github.com/MetaMask/metamask-mobile/pull/4531): [IMPROVEMENT] Add delete wallet step spec -## 5.3.0 - Jun 16, 2022 +## [5.3.0] +### Uncategorized - [#4506](https://github.com/MetaMask/metamask-mobile/pull/4506): [IMPROVEMENT] Add OnRamp aggregator translations - [#4389](https://github.com/MetaMask/metamask-mobile/pull/4389): [FEAT] Easy delete data - [#4510](https://github.com/MetaMask/metamask-mobile/pull/4510): [IMPROVEMENT] Update RPC URL for xDai @@ -3152,7 +3261,8 @@ access - [#4178](https://github.com/MetaMask/metamask-mobile/pull/4178): [FIX] Prevent crash when funds warning is pressed - [#4367](https://github.com/MetaMask/metamask-mobile/pull/4367): [IMPROVEMENT] Make text hex data selectable -## 5.2.0 - May 17, 2022 +## [5.2.0] +### Uncategorized - [#4349](https://github.com/MetaMask/metamask-mobile/pull/4349): [FIX] Subtitle mapping - [#4344](https://github.com/MetaMask/metamask-mobile/pull/4344): [FIX] Fix homepage scripts and env import - [#4345](https://github.com/MetaMask/metamask-mobile/pull/4345): [FIX] Fix check for empty tokens list @@ -3171,7 +3281,8 @@ access - [#4182](https://github.com/MetaMask/metamask-mobile/pull/4182): [IMPROVEMENT] Standardize prettier configuration - [#4183](https://github.com/MetaMask/metamask-mobile/pull/4183): [FIX] excluded audit because no available patch -## 5.1.0 - May 5, 2022 +## [5.1.0] +### Uncategorized - [#3929](https://github.com/MetaMask/metamask-mobile/pull/3929): [IMPROVEMENT] Defaults to current network if chain id not specified in QR codes - [#4159](https://github.com/MetaMask/metamask-mobile/pull/4159): [IMPROVEMENT] - iCloud Backup Restriction - [#4035](https://github.com/MetaMask/metamask-mobile/pull/4035): [FIX] Issue #207 @@ -3191,10 +3302,12 @@ access - [#4154](https://github.com/MetaMask/metamask-mobile/pull/4154): [FIX] Update react-native-webview+11.13.0.patch - [#4135](https://github.com/MetaMask/metamask-mobile/pull/4135): [IMPROVEMENT]browser improvement -## 5.0.1 - April 20, 2022 +## [5.0.1] +### Fixed - [FIX] iOS Hotfix - Add LinkPresentation library -## 5.0.0 - April 13, 2022 +## [5.0.0] +### Uncategorized - [#3971](https://github.com/MetaMask/metamask-mobile/pull/3971): [FIX] Fix issues releated to deep/universal links - [#3925](https://github.com/MetaMask/metamask-mobile/pull/3925): [FEAT] Allow ApplePay in Transak webview. - [#4047](https://github.com/MetaMask/metamask-mobile/pull/4047): [FIX] Fix attribution url @@ -3204,7 +3317,8 @@ access - [#3979](https://github.com/MetaMask/metamask-mobile/pull/3979): [FIX] TransactionDetails speed up and cancel CTA - [#3948](https://github.com/MetaMask/metamask-mobile/pull/3948): [FIX] Update button on WebviewError -## v4.4.0 - March 28, 2022 +## [4.4.0] +### Uncategorized - [#3910](https://github.com/MetaMask/metamask-mobile/pull/3910): [IMPROVEMENT] Network Specific Asset Education - [#3877](https://github.com/MetaMask/metamask-mobile/pull/3877): [IMPROVEMENT] Add OSS attribution - [#3731](https://github.com/MetaMask/metamask-mobile/pull/3731): [FIX] Fix formatting of gas price for all conversion currencies @@ -3213,12 +3327,14 @@ access - [#3902](https://github.com/MetaMask/metamask-mobile/pull/3902): [IMPROVEMENT] Add better messaging around ENS validation - [#3969](https://github.com/MetaMask/metamask-mobile/pull/3969): [FIX] Fix typo in network modal -## v4.3.1 - March 23, 2022 +## [4.3.1] +### Fixed - [#3946](https://github.com/MetaMask/metamask-mobile/pull/3946): [FIX] Fix error boundary SRP - [#3947](https://github.com/MetaMask/metamask-mobile/pull/3947): [FIX] Fix gas carousel price estimate - [#3940](https://github.com/MetaMask/metamask-mobile/pull/3940): [FIX] Fix browser crash -## v4.3.0 - March 16, 2022 +## [4.3.0] +### Uncategorized - [#3916](https://github.com/MetaMask/metamask-mobile/pull/3916): [FIX] Patch Android clipboard crasher - [#3776](https://github.com/MetaMask/metamask-mobile/pull/3776): [IMPROVEMENT] Enable dark mode - [#3899](https://github.com/MetaMask/metamask-mobile/pull/3899): [IMPROVEMENT] Improve WalletConnect checks @@ -3242,7 +3358,8 @@ access - [#3825](https://github.com/MetaMask/metamask-mobile/pull/3825): [FIX] Fix lack of full ENS namespace support - [#3638](https://github.com/MetaMask/metamask-mobile/pull/3638): [IMPROVEMENT] Upgrade controllers to 25.1.0 -## v4.2.2 - February 24, 2022 +## [4.2.2] +### Uncategorized - [#3841](https://github.com/MetaMask/metamask-mobile/pull/3841): [FIX] Fix custom network icons on Wallet Overview - [#3839](https://github.com/MetaMask/metamask-mobile/pull/3839): [FIX] Update en.json - [#3838](https://github.com/MetaMask/metamask-mobile/pull/3838): [FIX] Fix onramp BUSD address. Add wc_description string @@ -3267,10 +3384,12 @@ access - [#3548](https://github.com/MetaMask/metamask-mobile/pull/3548): [FIX] Fixes text field frame got cut off - [#3690](https://github.com/MetaMask/metamask-mobile/pull/3690): [FIX] Revert svg crash -## v4.1.1 - February 23, 2022 +## [4.1.1] +### Uncategorized - [3810](https://github.com/MetaMask/metamask-mobile/pull/3810) [FIX] Avalanche token crash -## v4.1.0 - February 9, 2022 +## [4.1.0] +### Uncategorized - [#3741](https://github.com/MetaMask/metamask-mobile/pull/3741): [FIX] Potential error message from missing transactions details - [#3738](https://github.com/MetaMask/metamask-mobile/pull/3738): [FIX] Error message for missing chain ID in deeplink - [#3725](https://github.com/MetaMask/metamask-mobile/pull/3725): [FIX] Login decrypt bug @@ -3295,16 +3414,19 @@ access - [#3374](https://github.com/MetaMask/metamask-mobile/pull/3374): [IMPROVEMENT] Storybook install, stories and guidelines - [#3672](https://github.com/MetaMask/metamask-mobile/pull/3672): [IMPROVEMENT] Bump simple-get from 2.8.1 to 4.0.1 -## v4.0.1 - January 31, 2022 +## [4.0.1] +### Fixed - [#3658](https://github.com/MetaMask/metamask-mobile/pull/3658): [HOTFIX] 4.0.1 - BN crash and NFT Improvement -## v4.0.0 - January 20, 2022 +## [4.0.0] +### Uncategorized - [#3509](https://github.com/MetaMask/metamask-mobile/pull/3509): [IMPROVEMENT] Upgrade to React Native 0.66.3 - [#3623](https://github.com/MetaMask/metamask-mobile/pull/3623): [FIX] Fix swaps slider button re-rendering - [#3481](https://github.com/MetaMask/metamask-mobile/pull/3481): [FIX] Fix confirm button disabled on txn confirmation - [#3495](https://github.com/MetaMask/metamask-mobile/pull/3495): [IMPROVEMENT] Reduce png file image weight using TinyPng cli tool -## v3.8.0 - December 3 2021 +## [3.8.0] +### Uncategorized - [#3457](https://github.com/MetaMask/metamask-mobile/pull/3457): [FEAT] User review prompt - [#3465](https://github.com/MetaMask/metamask-mobile/pull/3465): [FIX] 3464 fix login bug - [#3430](https://github.com/MetaMask/metamask-mobile/pull/3430): [IMPROVEMENT] Add better initial state for swaps loading tokens @@ -3315,7 +3437,8 @@ access - [#3423](https://github.com/MetaMask/metamask-mobile/pull/3423): [IMPROVEMENT] Android APK Size, App Load Time - [#3443](https://github.com/MetaMask/metamask-mobile/pull/3443): [UPDATE] Disable Sync with Extension -## v3.7.0 - November 16 2021 +## [3.7.0] +### Uncategorized - [#3405](https://github.com/MetaMask/metamask-mobile/pull/3405): [FIX] Remove Metric Opt In event - [#3412](https://github.com/MetaMask/metamask-mobile/pull/3412): [UPGRADE] Android SDK and dependencies to support SDK 30 - [#3371](https://github.com/MetaMask/metamask-mobile/pull/3371): [FIX] iOS FaceID Deny Handler @@ -3330,14 +3453,16 @@ access - [#3378](https://github.com/MetaMask/metamask-mobile/pull/3378): [FIX] patch validator via resolution - [#3357](https://github.com/MetaMask/metamask-mobile/pull/3357): [FIX] 404 dead links in readme -## v3.6.0 - November 1 2021 +## [3.6.0] +### Uncategorized - [#3301](https://github.com/MetaMask/metamask-mobile/pull/3301): [FEATURE] ERC-1155 and custom network support - [#3343](https://github.com/MetaMask/metamask-mobile/pull/3343): [IMPROVEMENT] Add IPFS support for NFTs - [#3352](https://github.com/MetaMask/metamask-mobile/pull/3352): [FIX] Fix rendering issue when viewing data on transaction review screen - [#3348](https://github.com/MetaMask/metamask-mobile/pull/3348): [IMPROVEMENT] Add webview deeplink support for Android - [#3290](https://github.com/MetaMask/metamask-mobile/pull/3290): [FIX] Fix lost data when using wallet connect for ERC20 token transaction -## v3.5.0 - October 26 2021 +## [3.5.0] +### Uncategorized - [#3340](https://github.com/MetaMask/metamask-mobile/pull/3340): [IMPROVEMENT] Reduce persisted data - [#3330](https://github.com/MetaMask/metamask-mobile/pull/3330): [IMPROVEMENT] Refactor EngineService - [#3325](https://github.com/MetaMask/metamask-mobile/pull/3325): [IMPROVEMENT] Isolate persisted data @@ -3355,7 +3480,8 @@ access - [#3272](https://github.com/MetaMask/metamask-mobile/pull/3272): [IMPROVEMENT] Update recommended node.js version - [#3271](https://github.com/MetaMask/metamask-mobile/pull/3271): [FIX] Update React Native dependecy links in README.md -## v3.4.1 - October 5 2021 +## [3.4.1] +### Uncategorized - [#3260](https://github.com/MetaMask/metamask-mobile/pull/3260): [FIX] Turn off token detection by default - [#3261](https://github.com/MetaMask/metamask-mobile/pull/3261): [FIX] Fix blank screen on fresh start - [#3254](https://github.com/MetaMask/metamask-mobile/pull/3254): [IMPROVEMENT] Isolate LICENSE file @@ -3384,7 +3510,8 @@ access - [#3117](https://github.com/MetaMask/metamask-mobile/pull/3117): [FIX] Moved the newTab method to the componentdidmount - [#3115](https://github.com/MetaMask/metamask-mobile/pull/3115): [IMPROVEMENT] Update README.md -## v3.3.0 - September 9 2021 +## [3.3.0] +### Uncategorized - [#3099](https://github.com/MetaMask/metamask-mobile/pull/3099): [FEATURE] Transaction state improvement - [UPGRADE] react-native-webview 11.0.2 -> 11.13.0 - [#3101](https://github.com/MetaMask/metamask-mobile/pull/3101): [UPDATE] update swaps-controller and send clientId on fetchSwapsFeatureLiveness @@ -3405,7 +3532,8 @@ access - [#3028](https://github.com/MetaMask/metamask-mobile/pull/3028): [FEATURE] Update Recents - [#3057](https://github.com/MetaMask/metamask-mobile/pull/3057): [UPDATE] Remove SwapsLiveness checks for non supported networks -## v3.2.0 - August 24 2021 +## [3.2.0] +### Uncategorized - [#3046](https://github.com/MetaMask/metamask-mobile/pull/3046): [FIX] Token Transfer to address - [#2878](https://github.com/MetaMask/metamask-mobile/pull/2878): [2783] Change default account name for ENS reversed-resolved name - [#3029](https://github.com/MetaMask/metamask-mobile/pull/3029): [FIX] Video Subtitles Not Loading Properly @@ -3413,7 +3541,8 @@ access - [#3013](https://github.com/MetaMask/metamask-mobile/pull/3013): Swaps V2 Integration - [#2718](https://github.com/MetaMask/metamask-mobile/pull/2718): Switched to sslip.io instead of xip.io -## v3.1.0 - August 12 2021 +## [3.1.0] +### Uncategorized - [#3026](https://github.com/MetaMask/metamask-mobile/pull/3026): [FIX] Fix edit button - [#2981](https://github.com/MetaMask/metamask-mobile/pull/2981): [FIX] Delete Message - [#3017](https://github.com/MetaMask/metamask-mobile/pull/3017): [FIX] Fix deep links bug related to branch updates @@ -3430,10 +3559,12 @@ access - [#2893](https://github.com/MetaMask/metamask-mobile/pull/2893): [FIX] Address bar icon - [#2973](https://github.com/MetaMask/metamask-mobile/pull/2973): [FEATURE] On-Ramp: Add on-ramp analytics -## v3.0.1 - August 4 2021 +## [3.0.1] +### Uncategorized - Patch to fix Wyre and Transak -## v3.0.0 - July 28 2021 +## [3.0.0] +### Uncategorized - [#2959](https://github.com/MetaMask/metamask-mobile/pull/2959): UI fixes - [#2957](https://github.com/MetaMask/metamask-mobile/pull/2957): Fix gas information info modal on swaps - [#2955](https://github.com/MetaMask/metamask-mobile/pull/2955): [EIP1559] Improve time estimates @@ -3449,14 +3580,16 @@ access - [#2889](https://github.com/MetaMask/metamask-mobile/pull/2889): Feature/bitrise - [#2890](https://github.com/MetaMask/metamask-mobile/pull/2890): Bump addressable from 2.7.0 to 2.8.0 in /ios -## v2.6.0 - July 9 2021 +## [2.6.0] +### Uncategorized - [#2865](https://github.com/MetaMask/metamask-mobile/pull/2865): Added support for custom network gas estimates - [#2854](https://github.com/MetaMask/metamask-mobile/pull/2854): Fix time formatting on transactions - [#2883](https://github.com/MetaMask/metamask-mobile/pull/2883): Swaps: Fix isZero undefined error - [#2731](https://github.com/MetaMask/metamask-mobile/pull/2731): Improvement/react navigation upgrade 5 - [#2709](https://github.com/MetaMask/metamask-mobile/pull/2709): Remove Picker deprecation warning -## v2.5.0 - June 15 2021 +## [2.5.0] +### Uncategorized - [#2809](https://github.com/MetaMask/metamask-mobile/pull/2809): Optional chaining dollarBalance - [#2776](https://github.com/MetaMask/metamask-mobile/pull/2776): Fix: empty state when using fiat on non-mainnet transactions - [#2777](https://github.com/MetaMask/metamask-mobile/pull/2777): Add isInteraction: false @@ -3481,7 +3614,8 @@ access - [#2737](https://github.com/MetaMask/metamask-mobile/pull/2737): Add resolution for ws to address security vuln - [#2727](https://github.com/MetaMask/metamask-mobile/pull/2727): Add missing required prop in tests -## v2.4.0 - May 21 2021 +## [2.4.0] +### Uncategorized - [#2618](https://github.com/MetaMask/metamask-mobile/pull/2618): Collectibles experience - [#2698](https://github.com/MetaMask/metamask-mobile/pull/2698): bugfix: navigation routeName is null - [#2692](https://github.com/MetaMask/metamask-mobile/pull/2692): Fix custom gas crash @@ -3495,7 +3629,8 @@ access - [#2640](https://github.com/MetaMask/metamask-mobile/pull/2640): Swaps: Add name from metadata to swaps tokens - [#2628](https://github.com/MetaMask/metamask-mobile/pull/2628): Feature/use toLowerCaseCompare -## v2.3.0 - May 5 2021 +## [2.3.0] +### Uncategorized - [#2674](https://github.com/MetaMask/metamask-mobile/pull/2674): Fix deploy contract and create token testnets - [#2669](https://github.com/MetaMask/metamask-mobile/pull/2669): Key off accounts - [#2670](https://github.com/MetaMask/metamask-mobile/pull/2670): Bump hosted-git-info from 2.8.8 to 2.8.9 @@ -3537,7 +3672,8 @@ access - [#2539](https://github.com/MetaMask/metamask-mobile/pull/2539): Use node 14 - [#2568](https://github.com/MetaMask/metamask-mobile/pull/2568): resolve isENS without case sensitivity (#2545) -## v2.2.0 - Apr 21 2021 +## [2.2.0] +### Uncategorized - [#2547](https://github.com/MetaMask/metamask-mobile/pull/2547): Include decimalsToShow in balanceToFiatNumber - [#2554](https://github.com/MetaMask/metamask-mobile/pull/2554): Bug fix/sync import time - [#2546](https://github.com/MetaMask/metamask-mobile/pull/2546): Fix analytics try catch @@ -3563,16 +3699,20 @@ access - [#2403](https://github.com/MetaMask/metamask-mobile/pull/2403): Bump babel-eslint from 10.0.3 to 10.1.0 - [#2381](https://github.com/MetaMask/metamask-mobile/pull/2381): Display correct number of decimals for 'usd' fiat -## v2.1.3 - Apr 19 2021 +## [2.1.3] +### Uncategorized - [#2548](https://github.com/MetaMask/metamask-mobile/pull/2548): Hotfix analytics try catch -## v2.1.2 - Apr 16 2021 +## [2.1.2] +### Uncategorized - [#2538](https://github.com/MetaMask/metamask-mobile/pull/2538): fix/connection change handler -## v2.1.1 - Apr 14 2021 +## [2.1.1] +### Uncategorized - [#2520](https://github.com/MetaMask/metamask-mobile/pull/2520): Check provider status -## v2.1.0 - Apr 12 2021 +## [2.1.0] +### Uncategorized - [#2487](https://github.com/MetaMask/metamask-mobile/pull/2487): Fix/analytics v1 priority1 - [#2456](https://github.com/MetaMask/metamask-mobile/pull/2456): Analytics v2 (priority 1) - [#2408](https://github.com/MetaMask/metamask-mobile/pull/2408): Fix/gas estimations @@ -3593,7 +3733,8 @@ access - [#2413](https://github.com/MetaMask/metamask-mobile/pull/2413): remove "git add" per husky warning - [#2431](https://github.com/MetaMask/metamask-mobile/pull/2431): Update BN import -## v2.0.1 - Mar 24 2021 +## [2.0.1] +### Uncategorized - [#2430](https://github.com/MetaMask/metamask-mobile/pull/2430): Fix/send to style - [#2426](https://github.com/MetaMask/metamask-mobile/pull/2426): bugfix/allow seedphrases when locked - [#2422](https://github.com/MetaMask/metamask-mobile/pull/2422): bugfix/delete wallet with random password @@ -3601,7 +3742,8 @@ access - [#2418](https://github.com/MetaMask/metamask-mobile/pull/2418): V2 fixes - [#2156](https://github.com/MetaMask/metamask-mobile/pull/2156): Translations with update script -## v2.0.0 - Mar 16 2021 +## [2.0.0] +### Uncategorized - [#2383](https://github.com/MetaMask/metamask-mobile/pull/2383): swaps/received destination amount - [#2379](https://github.com/MetaMask/metamask-mobile/pull/2379): Swaps/fix decode tx render amounts - [#2377](https://github.com/MetaMask/metamask-mobile/pull/2377): bugfix/dont modify local transactions @@ -3621,7 +3763,8 @@ access - [#2272](https://github.com/MetaMask/metamask-mobile/pull/2272): Update twitter handle in README - [#2265](https://github.com/MetaMask/metamask-mobile/pull/2265): Fix input state -## v1.0.11 - Feb 15 2021 +## [1.0.11] +### Uncategorized - [#2257](https://github.com/MetaMask/metamask-mobile/pull/2257): bugfix/use bignumber for transfer deeplinks - [#2256](https://github.com/MetaMask/metamask-mobile/pull/2256): Fix account list scroll - [#2243](https://github.com/MetaMask/metamask-mobile/pull/2243): TransactionController from controllers @@ -3647,11 +3790,13 @@ access - [#2060](https://github.com/MetaMask/metamask-mobile/pull/2060): MetaSwaps Alpha - [#2142](https://github.com/MetaMask/metamask-mobile/pull/2142): Display boolean values when signing typed data -## v1.0.10 - Jan 25 2021 +## [1.0.10] +### Uncategorized - [#2164](https://github.com/MetaMask/metamask-mobile/pull/2164): Initialize NetworkController.provider with chainId (#2164) - [#2161](https://github.com/MetaMask/metamask-mobile/pull/2161): chainid migration (#2161) -## v1.0.9 - Jan 21 2021 +## [1.0.9] +### Uncategorized - [#2149](https://github.com/MetaMask/metamask-mobile/pull/2149): update tests for new logic - [#2145](https://github.com/MetaMask/metamask-mobile/pull/2145): Add missing brew installation steps - [#2146](https://github.com/MetaMask/metamask-mobile/pull/2146): @metamask/mobile-provider@2.0.1 @@ -3680,7 +3825,8 @@ access - [#2000](https://github.com/MetaMask/metamask-mobile/pull/2000): Remove unused views (#2000) - [#1994](https://github.com/MetaMask/metamask-mobile/pull/1994): Feature: Initial Swaps amount view (#1994) -## v1.0.8 - Dec 2 2020 +## [1.0.8] +### Uncategorized - [#2040](https://github.com/MetaMask/metamask-mobile/pull/2040): Update vault error message (#2040) - [#2034](https://github.com/MetaMask/metamask-mobile/pull/2034): Fix asyncstorage limit (#2034) - [#2038](https://github.com/MetaMask/metamask-mobile/pull/2038): metamask wc deeplink (#2038) @@ -3688,7 +3834,8 @@ access - [#2019](https://github.com/MetaMask/metamask-mobile/pull/2019): bugfix/qr code (#2019) - [#2008](https://github.com/MetaMask/metamask-mobile/pull/2008): Add Apple Pay correct label (#2008) -## v1.0.7 - Nov 17 2020 +## [1.0.7] +### Uncategorized - [#2005](https://github.com/MetaMask/metamask-mobile/pull/2005): Fix activeTabUrl (#2005) - [#2003](https://github.com/MetaMask/metamask-mobile/pull/2003): Bugfix/android choose password (#2003) - [#1992](https://github.com/MetaMask/metamask-mobile/pull/1992): Android api level (#1992) @@ -3698,7 +3845,8 @@ access - [#1967](https://github.com/MetaMask/metamask-mobile/pull/1967): Add Keypad component (#1967) -## v1.0.6 - Nov 12 2020 +## [1.0.6] +### Uncategorized - [#1990](https://github.com/MetaMask/metamask-mobile/pull/1990): Fixed importing accounts when reseting password (#1990) - [#1988](https://github.com/MetaMask/metamask-mobile/pull/1988): bugfix/protect wallet modal (#1988) - [#1985](https://github.com/MetaMask/metamask-mobile/pull/1985): Fix seedphrase handling in QRScanner (#1985) @@ -3737,13 +3885,16 @@ access - [#1866](https://github.com/MetaMask/metamask-mobile/pull/1866): Fix proptype warning for WebviewError (#1866) - [#1861](https://github.com/MetaMask/metamask-mobile/pull/1861): Get e2e working for seedphrase and login (#1861) -## v1.0.5 - Oct 26 2020 +## [1.0.5] +### Uncategorized - [#1889](https://github.com/MetaMask/metamask-mobile/pull/1889): Fix scientific notation string not convertable to BN (#1889) -## v1.0.4 - Oct 9 2020 +## [1.0.4] +### Uncategorized - [#1882](https://github.com/MetaMask/metamask-mobile/pull/1882): Error boundary (#1882) -## v1.0.3 - Sept 30 2020 +## [1.0.3] +### Uncategorized - [#1865](https://github.com/MetaMask/metamask-mobile/pull/1865): bugfix/login (#1865) - [#1863](https://github.com/MetaMask/metamask-mobile/pull/1863): transak countries update (#1863) - [#1829](https://github.com/MetaMask/metamask-mobile/pull/1829): Improvement/browser refactor (#1829) @@ -3774,14 +3925,17 @@ access - [#1728](https://github.com/MetaMask/metamask-mobile/pull/1728): Add /constants (#1728) - [#1787](https://github.com/MetaMask/metamask-mobile/pull/1787): Add missing currency conversions (#1787) -## v1.0.2 - Sept 2 2020 +## [1.0.2] +### Uncategorized - [#1812](https://github.com/MetaMask/metamask-mobile/pull/1812): Add logger on login (#1812) -## v1.0.1 - Sept 1 2020 +## [1.0.1] +### Uncategorized - [#1795](https://github.com/MetaMask/metamask-mobile/pull/1795): Update react native aes crypto forked (#1795) - [#1796](https://github.com/MetaMask/metamask-mobile/pull/1796): bugfix/mixpanel android in app notifications (#1796) -## v1.0.0 - Aug 26 2020 +## [1.0.0] +### Uncategorized - [#1790](https://github.com/MetaMask/metamask-mobile/pull/1790): Bugfix/payment request and wallet connect origin on tx (#1790) - [#1791](https://github.com/MetaMask/metamask-mobile/pull/1791): Fix send receive buttons style (#1791) - [#1785](https://github.com/MetaMask/metamask-mobile/pull/1785): Use @metamask/controllers@2.0.5 (#1785) @@ -3808,7 +3962,8 @@ access - [#1733](https://github.com/MetaMask/metamask-mobile/pull/1733): @metamask/controllers 2.0.3 (#1733) - [#1727](https://github.com/MetaMask/metamask-mobile/pull/1727): Bump json from 2.2.0 to 2.3.1 in /ios (#1727) -## v0.2.20 - Aug 6 2020 +## [0.2.20] +### Uncategorized - [#1751](https://github.com/MetaMask/metamask-mobile/pull/1751): bugfix/payment requests & deeplinks (#1751) - [#1732](https://github.com/MetaMask/metamask-mobile/pull/1732): Copy edits (#1732) - [#1750](https://github.com/MetaMask/metamask-mobile/pull/1750): Don't allow for zero in custom gas price (#1750) @@ -3859,17 +4014,19 @@ access - [#1558](https://github.com/MetaMask/metamask-mobile/pull/1558): Complete redesigns for approval flow (#1558) - [#1640](https://github.com/MetaMask/metamask-mobile/pull/1640): enable-apple-pay (#1640) -## v0.2.19 - Jun 29 2020 +## [0.2.19] +### Uncategorized - [#1661](https://github.com/MetaMask/metamask-mobile/pull/1661): bugfix/Use eth gas API - [#1653](https://github.com/MetaMask/metamask-mobile/pull/1653): Add ETH_GAS_STATION_API_KEY (#1653) -## v0.2.18 - Jun 15 2020 +## [0.2.18] +### Uncategorized - [#1636](https://github.com/MetaMask/metamask-mobile/pull/1636): Add padding to CustomGas back button (#1636) - [#1637](https://github.com/MetaMask/metamask-mobile/pull/1637): Bugfix/incoming notifications (#1637) - [#1628](https://github.com/MetaMask/metamask-mobile/pull/1628): Fix network color indicator on transactionHeader for connect screens (#1628) -## v0.2.17 - Jun 12 2020 - +## [0.2.17] +### Uncategorized - [#1629](https://github.com/MetaMask/metamask-mobile/pull/1629): bugfix/custom gas modal (#1629) - [#1625](https://github.com/MetaMask/metamask-mobile/pull/1625): Bugfix/wc connect on app closed (#1625) - [#1624](https://github.com/MetaMask/metamask-mobile/pull/1624): Wallet connect update + Support for simple notifications (#1624) @@ -3905,7 +4062,8 @@ access - [#1590](https://github.com/MetaMask/metamask-mobile/pull/1590): Add CODEOWNERS (#1590) - [#1584](https://github.com/MetaMask/metamask-mobile/pull/1584): make sign tests great again (#1584) -## v0.2.16 - May 15 2020 +## [0.2.16] +### Uncategorized - [#1582](https://github.com/MetaMask/metamask-mobile/pull/1582): Instapay deposit navbar cancel (#1582) - [#1570](https://github.com/MetaMask/metamask-mobile/pull/1570): Disable confirm screen edit button when no tokens of a payment request (#1570) - [#1574](https://github.com/MetaMask/metamask-mobile/pull/1574): Ensure collectibles that use 'transfer' method show a fee in tx history list (#1574) @@ -3929,7 +4087,8 @@ access - [#1545](https://github.com/MetaMask/metamask-mobile/pull/1545): bugfix/check for sai method (#1545) - [#1524](https://github.com/MetaMask/metamask-mobile/pull/1524): Loosen nvmrc (#1524) -## v0.2.15 - May 1 2020 +## [0.2.15] +### Uncategorized - [#1529](https://github.com/MetaMask/metamask-mobile/pull/1529): sentry android production (#1529) - [#1528](https://github.com/MetaMask/metamask-mobile/pull/1528): Bugfix/sentry in circle ci (#1528) - [#1527](https://github.com/MetaMask/metamask-mobile/pull/1527): env to production (#1527) @@ -3972,7 +4131,8 @@ access - [#1418](https://github.com/MetaMask/metamask-mobile/pull/1418): Improvement: remove addresslist comment (#1418) - [#1425](https://github.com/MetaMask/metamask-mobile/pull/1425): Detox: Upate dapp-initated-txn tests (#1425) -## v0.2.14 - Mar 11 2020 +## [0.2.14] +### Uncategorized - [#1413](https://github.com/MetaMask/metamask-mobile/pull/1413): Fix accountsChanged notification (#1413) - [#1411](https://github.com/MetaMask/metamask-mobile/pull/1411): bugfix: payment request (#1411) - [#1410](https://github.com/MetaMask/metamask-mobile/pull/1410): bugfix: ios close icon (#1410) @@ -4024,13 +4184,15 @@ access - [#1258](https://github.com/MetaMask/metamask-mobile/pull/1258): Update iOS Builds (#1258) - [#1252](https://github.com/MetaMask/metamask-mobile/pull/1252): Bugfix: cancel and speedup insufficient funds (#1252) -## v0.2.13 - Dic 30 2019 +## [0.2.13] +### Uncategorized - [#1250](https://github.com/MetaMask/metamask-mobile/pull/1250): Bump excon from 0.64.0 to 0.71.0 in /ios (#1250) - [#1246](https://github.com/MetaMask/metamask-mobile/pull/1246): bugfix: wizard back (#1246) - [#1235](https://github.com/MetaMask/metamask-mobile/pull/1235): Detox: Request token flow (#1235) - [#1234](https://github.com/MetaMask/metamask-mobile/pull/1234): bump migration version (#1234) -## v0.2.12 - Nov 25 2019 +## [0.2.12] +### Uncategorized - [#1224](https://github.com/MetaMask/metamask-mobile/pull/1224): Bugfix: asset ens tx (#1224) - [#1225](https://github.com/MetaMask/metamask-mobile/pull/1225): update bug report link (#1225) - [#1215](https://github.com/MetaMask/metamask-mobile/pull/1215): Detox: Fix Android e2e Tests (#1215) @@ -4038,12 +4200,14 @@ access - [#1222](https://github.com/MetaMask/metamask-mobile/pull/1222): bugfix: android show hex input instapay send (#1222) - [#1214](https://github.com/MetaMask/metamask-mobile/pull/1214): pass metametrics context to homepage (#1214) -## v0.2.11 - Nov 18 2019 +## [0.2.11] +### Uncategorized - [#1212](https://github.com/MetaMask/metamask-mobile/pull/1212): Provider missing properties (#1212) - [#1207](https://github.com/MetaMask/metamask-mobile/pull/1207): Fix typo on Import Account screen (#1207) - [#1198](https://github.com/MetaMask/metamask-mobile/pull/1198): Migrate to SAI (#1198) -## v0.2.10 - Nov 16 2019 +## [0.2.10] +### Uncategorized - [#1205](https://github.com/MetaMask/metamask-mobile/pull/1205): Disable speedup instapay (#1205) - [#1204](https://github.com/MetaMask/metamask-mobile/pull/1204): Fix injection on Android (#1204) - [#1203](https://github.com/MetaMask/metamask-mobile/pull/1203): Update support email (#1203) @@ -4077,17 +4241,20 @@ access - [#1156](https://github.com/MetaMask/metamask-mobile/pull/1156): Fix linter on CI (#1156) - [#1146](https://github.com/MetaMask/metamask-mobile/pull/1146): fix instapay logs app version (#1146) -## v0.2.8 - Oct 9 2019 +## [0.2.8] +### Uncategorized - [#1145](https://github.com/MetaMask/metamask-mobile/pull/1145): Support URLs on QR code scanner (#1145) -## v0.2.7 - Oct 7 2019 +## [0.2.7] +### Uncategorized - [#1143](https://github.com/MetaMask/metamask-mobile/pull/1143): Minor bugfixes (#1143) -## v0.2.6 - Oct 4 2019 +## [0.2.6] +### Uncategorized - [#1139](https://github.com/MetaMask/metamask-mobile/pull/1139): Fix onboarding carousel dimensions (#1139) -## v0.2.5 - Oct 4 2019 - +## [0.2.5] +### Uncategorized - [#1136](https://github.com/MetaMask/metamask-mobile/pull/1136): Select correct profiles (#1136) - [#1135](https://github.com/MetaMask/metamask-mobile/pull/1135): Fix fastlane config (#1135) - [#1134](https://github.com/MetaMask/metamask-mobile/pull/1134): renew certs if needed (#1134) @@ -4152,7 +4319,8 @@ access - [#1045](https://github.com/MetaMask/metamask-mobile/pull/1045): More UIWebview cleanup (#1045) - [#1044](https://github.com/MetaMask/metamask-mobile/pull/1044): remove uiwebview ocurrences (#1044) -## v0.2.4 - Aug 28 2019 +## [0.2.4] +### Uncategorized - [#1038](https://github.com/MetaMask/metamask-mobile/pull/1038): Fix Approval (#1038) : [#1037](https://github.com/MetaMask/metamask-mobile/pull/1037): Fix walletconnect :#1037) - [#1036](https://github.com/MetaMask/metamask-mobile/pull/1036): Bugfix: browser crash (#1036) @@ -4171,7 +4339,8 @@ access - [#1009](https://github.com/MetaMask/metamask-mobile/pull/1009): Bugfix: Allow file uploads on android (#1009) - [#1008](https://github.com/MetaMask/metamask-mobile/pull/1008): bump walletconnect (#1008) -## v0.2.3 - Aug 19 2019 +## [0.2.3] +### Uncategorized - [#972](https://github.com/MetaMask/metamask-mobile/pull/972): bump version (#972) - [#989](https://github.com/MetaMask/metamask-mobile/pull/989): Bugfix: Fix mobile sync & Security options (#989) - [#1000](https://github.com/MetaMask/metamask-mobile/pull/1000): bugfix: tx edit dropdowns in small devices (#1000) @@ -4201,3 +4370,159 @@ access - [#955](https://github.com/MetaMask/metamask-mobile/pull/955): dont ignore calls while initial reload (#955) - [#957](https://github.com/MetaMask/metamask-mobile/pull/957): fix timeouts (#957) - [#954](https://github.com/MetaMask/metamask-mobile/pull/954): Bugfix: onboarding navigation (#954) + +[Unreleased]: https://github.com/metamask/metamask-mobile/compare/v7.38.2...HEAD +[7.38.2]: https://github.com/metamask/metamask-mobile/compare/v7.38.1...v7.38.2 +[7.38.1]: https://github.com/metamask/metamask-mobile/compare/v7.38.0...v7.38.1 +[7.38.0]: https://github.com/metamask/metamask-mobile/compare/v7.37.1...v7.38.0 +[7.37.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.37.0...v7.37.1 +[7.37.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.36.0...v7.37.0 +[7.36.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.35.1...v7.36.0 +[7.35.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.35.0...v7.35.1 +[7.35.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.34.1...v7.35.0 +[7.34.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.34.0...v7.34.1 +[7.34.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.33.2...v7.34.0 +[7.33.2]: https://github.com/MetaMask/metamask-mobile/compare/v7.33.1...v7.33.2 +[7.33.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.33.0...v7.33.1 +[7.33.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.32.0...v7.33.0 +[7.32.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.31.1...v7.32.0 +[7.31.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.31.0...v7.31.1 +[7.31.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.30.0...v7.31.0 +[7.30.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.29.2...v7.30.0 +[7.29.2]: https://github.com/MetaMask/metamask-mobile/compare/v7.29.1...v7.29.2 +[7.29.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.29.0...v7.29.1 +[7.29.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.28.1...v7.29.0 +[7.28.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.28.0...v7.28.1 +[7.28.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.27.1...v7.28.0 +[7.27.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.27.0...v7.27.1 +[7.27.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.26.1...v7.27.0 +[7.26.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.26.0...v7.26.1 +[7.26.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.24.4...v7.26.0 +[7.24.4]: https://github.com/MetaMask/metamask-mobile/compare/v7.24.3...v7.24.4 +[7.24.3]: https://github.com/MetaMask/metamask-mobile/compare/v7.24.2...v7.24.3 +[7.24.2]: https://github.com/MetaMask/metamask-mobile/compare/v7.24.1...v7.24.2 +[7.24.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.24.0...v7.24.1 +[7.24.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.23.0...v7.24.0 +[7.23.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.22.0...v7.23.0 +[7.22.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.21.0...v7.22.0 +[7.21.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.20.1...v7.21.0 +[7.20.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.20.0...v7.20.1 +[7.20.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.19.1...v7.20.0 +[7.19.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.19.0...v7.19.1 +[7.19.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.18.0...v7.19.0 +[7.18.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.17.1...v7.18.0 +[7.17.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.17.0...v7.17.1 +[7.17.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.16.0...v7.17.0 +[7.16.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.15.0...v7.16.0 +[7.15.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.14.0...v7.15.0 +[7.14.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.12.5...v7.14.0 +[7.12.5]: https://github.com/MetaMask/metamask-mobile/compare/v7.12.3...v7.12.5 +[7.12.3]: https://github.com/MetaMask/metamask-mobile/compare/v7.12.2...v7.12.3 +[7.12.2]: https://github.com/MetaMask/metamask-mobile/compare/v7.12.1...v7.12.2 +[7.12.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.12.0...v7.12.1 +[7.12.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.11.0...v7.12.0 +[7.11.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.10.0...v7.11.0 +[7.10.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.9.1...v7.10.0 +[7.9.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.9.0...v7.9.1 +[7.9.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.8.0...v7.9.0 +[7.8.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.7.0...v7.8.0 +[7.7.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.6.0...v7.7.0 +[7.6.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.5.0...v7.6.0 +[7.5.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.4.0...v7.5.0 +[7.4.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.3.1...v7.4.0 +[7.3.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.3.0...v7.3.1 +[7.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.2.0...v7.3.0 +[7.2.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.1.0...v7.2.0 +[7.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.0.1...v7.1.0 +[7.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.0.0...v7.0.1 +[7.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.6.0...v7.0.0 +[6.6.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.5.0...v6.6.0 +[6.5.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.4.0...v6.5.0 +[6.4.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.3.0...v6.4.0 +[6.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.2.0...v6.3.0 +[6.2.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.1.2...v6.2.0 +[6.1.2]: https://github.com/MetaMask/metamask-mobile/compare/v6.1.1...v6.1.2 +[6.1.1]: https://github.com/MetaMask/metamask-mobile/compare/v6.1.0...v6.1.1 +[6.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v6.0.1...v6.1.0 +[6.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v6.0.0...v6.0.1 +[6.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.14.0...v6.0.0 +[5.14.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.13.0...v5.14.0 +[5.13.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.12.3...v5.13.0 +[5.12.3]: https://github.com/MetaMask/metamask-mobile/compare/v5.12.1...v5.12.3 +[5.12.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.12.0...v5.12.1 +[5.12.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.11.0...v5.12.0 +[5.11.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.10.0...v5.11.0 +[5.10.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.9.1...v5.10.0 +[5.9.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.9.0...v5.9.1 +[5.9.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.8.1...v5.9.0 +[5.8.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.8.0...v5.8.1 +[5.8.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.7.0...v5.8.0 +[5.7.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.6.1...v5.7.0 +[5.6.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.6.0...v5.6.1 +[5.6.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.5.1...v5.6.0 +[5.5.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.5.0...v5.5.1 +[5.5.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.4.0...v5.5.0 +[5.4.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.3.0...v5.4.0 +[5.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.2.0...v5.3.0 +[5.2.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.1.0...v5.2.0 +[5.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v5.0.1...v5.1.0 +[5.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v5.0.0...v5.0.1 +[5.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v4.4.0...v5.0.0 +[4.4.0]: https://github.com/MetaMask/metamask-mobile/compare/v4.3.1...v4.4.0 +[4.3.1]: https://github.com/MetaMask/metamask-mobile/compare/v4.3.0...v4.3.1 +[4.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v4.2.2...v4.3.0 +[4.2.2]: https://github.com/MetaMask/metamask-mobile/compare/v4.1.1...v4.2.2 +[4.1.1]: https://github.com/MetaMask/metamask-mobile/compare/v4.1.0...v4.1.1 +[4.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v4.0.1...v4.1.0 +[4.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v4.0.0...v4.0.1 +[4.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.8.0...v4.0.0 +[3.8.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.7.0...v3.8.0 +[3.7.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.6.0...v3.7.0 +[3.6.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.5.0...v3.6.0 +[3.5.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.4.1...v3.5.0 +[3.4.1]: https://github.com/MetaMask/metamask-mobile/compare/v3.3.0...v3.4.1 +[3.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.2.0...v3.3.0 +[3.2.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.1.0...v3.2.0 +[3.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v3.0.1...v3.1.0 +[3.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v3.0.0...v3.0.1 +[3.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.6.0...v3.0.0 +[2.6.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.5.0...v2.6.0 +[2.5.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.4.0...v2.5.0 +[2.4.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.3.0...v2.4.0 +[2.3.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.2.0...v2.3.0 +[2.2.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.1.3...v2.2.0 +[2.1.3]: https://github.com/MetaMask/metamask-mobile/compare/v2.1.2...v2.1.3 +[2.1.2]: https://github.com/MetaMask/metamask-mobile/compare/v2.1.1...v2.1.2 +[2.1.1]: https://github.com/MetaMask/metamask-mobile/compare/v2.1.0...v2.1.1 +[2.1.0]: https://github.com/MetaMask/metamask-mobile/compare/v2.0.1...v2.1.0 +[2.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v2.0.0...v2.0.1 +[2.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.11...v2.0.0 +[1.0.11]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.10...v1.0.11 +[1.0.10]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.9...v1.0.10 +[1.0.9]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.8...v1.0.9 +[1.0.8]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.7...v1.0.8 +[1.0.7]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.6...v1.0.7 +[1.0.6]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.5...v1.0.6 +[1.0.5]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.4...v1.0.5 +[1.0.4]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.3...v1.0.4 +[1.0.3]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.2...v1.0.3 +[1.0.2]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.1...v1.0.2 +[1.0.1]: https://github.com/MetaMask/metamask-mobile/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.20...v1.0.0 +[0.2.20]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.19...v0.2.20 +[0.2.19]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.18...v0.2.19 +[0.2.18]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.17...v0.2.18 +[0.2.17]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.16...v0.2.17 +[0.2.16]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.15...v0.2.16 +[0.2.15]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.14...v0.2.15 +[0.2.14]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.13...v0.2.14 +[0.2.13]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.12...v0.2.13 +[0.2.12]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.11...v0.2.12 +[0.2.11]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.10...v0.2.11 +[0.2.10]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.8...v0.2.10 +[0.2.8]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.7...v0.2.8 +[0.2.7]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.6...v0.2.7 +[0.2.6]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.5...v0.2.6 +[0.2.5]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.4...v0.2.5 +[0.2.4]: https://github.com/MetaMask/metamask-mobile/compare/v0.2.3...v0.2.4 +[0.2.3]: https://github.com/MetaMask/metamask-mobile/releases/tag/v0.2.3 From b5992b0f1a883ee1c7f46704cc807e9e838f453d Mon Sep 17 00:00:00 2001 From: Nico MASSART Date: Thu, 30 Jan 2025 22:25:53 +0100 Subject: [PATCH 10/18] fix: metrics call during onboarding (#13226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - refactor track trackOnboarding calls to pass an event built with MetricsEventBuilder - pass the properties with MetricsEventBuilder.addProperties ## **Related issues** Fixes https://github.com/MetaMask/mobile-planning/issues/2122 ## **Manual testing steps** ```gherkin Feature: track metrics during onboarding Scenario: user creates new wallet Given a freshly installed app And user opted in for metrics When user creates a new wallet And user enters a new password Then no 'TRACK event saved {"event": undefined, "properties": {}, "type": "track"}' log is visible And the "Wallet Setup Started", "Wallet Created" and "Wallet Setup Completed" log is visible Scenario: user imports wallet Given a freshly installed app And user opted in for metrics When user imports a wallet And user enters a new password Then no 'TRACK event saved {"event": undefined, "properties": {}, "type": "track"}' log is visible And the "Wallet Import Started", "Wallet Imported" and "Wallet Setup Completed" log is visible Scenario: user manually backs the wallet up Given a freshly installed app And user opted in for metrics And user created a new wallet When user saves SRP Then no 'TRACK event saved {"event": undefined, "properties": {}, "type": "track"}' log is visible And the "Wallet Security Started", "Manual Backup Initiated", "Phrase Revealed", "Phrase Confirmed" and "Wallet Security Completed" log is visible Scenario: user skips wallet backup Given a freshly installed app And user opted in for metrics And user created a new wallet When user skips SRP backup by touching "remind me later" Then no 'TRACK event saved {"event": undefined, "properties": {}, "type": "track"}' log is visible And the "Wallet Security Skip Initiated", "Wallet Security Skip Confirmed" and "Automatic Security Checks Prompt Viewed" log is visible ``` ## **Screenshots/Recordings** ### **Before** ``` INFO TRACK event saved {"event": undefined, "properties": {}, "type": "track"} ``` ### **After** examples of fixed event tracking ``` INFO TRACK event saved {"event": "Wallet Setup Started", "properties": {}, "type": "track"} INFO TRACK event saved {"event": "Wallet Created", "properties": {"biometrics_enabled": false}, "type": "track"} INFO TRACK event saved {"event": "Wallet Setup Completed", "properties": {"new_wallet": true, "wallet_setup_type": "new"}, "type": "track"} ``` ``` INFO TRACK event saved {"event": "Wallet Import Started", "properties": {}, "type": "track"} INFO TRACK event saved {"event": "Wallet Imported", "properties": {"biometrics_enabled": false}, "type": "track"} INFO TRACK event saved {"event": "Wallet Setup Completed", "properties": {"new_wallet": false, "wallet_setup_type": "import"}, "type": "track"} ``` ``` INFO TRACK event saved {"event": "Wallet Security Skip Initiated", "properties": {}, "type": "track"} INFO TRACK event saved {"event": "Wallet Security Skip Confirmed", "properties": {}, "type": "track"} INFO TRACK event saved {"event": "Automatic Security Checks Prompt Viewed", "properties": {"applicationVersion": "7.37.1", "currentBuildNumber": "1520", "deviceBrand": "Apple", "operatingSystemVersion": "18.2", "platform": "ios"}, "type": "track"} INFO TRACK event saved {"event": "Wallet Security Reminder Dismissed", "properties": {"source": "Backup Alert", "wallet_protection_required": false}, "type": "track"} ``` ## **Pre-merge author checklist** - [x] 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). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] 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: sethkfman <10342624+sethkfman@users.noreply.github.com> --- app/components/Views/AccountBackupStep1/index.js | 5 ++++- app/components/Views/ChoosePassword/index.js | 5 ++++- .../Views/ImportFromSecretRecoveryPhrase/index.js | 5 ++++- app/components/Views/ManualBackupStep3/index.js | 6 +++++- app/components/Views/Onboarding/index.js | 3 ++- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/components/Views/AccountBackupStep1/index.js b/app/components/Views/AccountBackupStep1/index.js index 8e00be8bf73..8b9638ec355 100644 --- a/app/components/Views/AccountBackupStep1/index.js +++ b/app/components/Views/AccountBackupStep1/index.js @@ -32,6 +32,7 @@ import { useTheme } from '../../../util/theme'; import { ManualBackUpStepsSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ManualBackUpSteps.selectors'; import trackOnboarding from '../../../util/metrics/TrackOnboarding/trackOnboarding'; import Routes from '../../../../app/constants/navigation/Routes'; +import { MetricsEventBuilder } from '../../../core/Analytics/MetricsEventBuilder'; const createStyles = (colors) => StyleSheet.create({ @@ -129,7 +130,9 @@ const AccountBackupStep1 = (props) => { const styles = createStyles(colors); const track = (event, properties) => { - trackOnboarding(event, properties); + const eventBuilder = MetricsEventBuilder.createEventBuilder(event); + eventBuilder.addProperties(properties); + trackOnboarding(eventBuilder.build()); }; useEffect(() => { diff --git a/app/components/Views/ChoosePassword/index.js b/app/components/Views/ChoosePassword/index.js index 9a836a433db..562ab15e06d 100644 --- a/app/components/Views/ChoosePassword/index.js +++ b/app/components/Views/ChoosePassword/index.js @@ -64,6 +64,7 @@ import navigateTermsOfUse from '../../../util/termsOfUse/termsOfUse'; import { ChoosePasswordSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ChoosePassword.selectors'; import trackOnboarding from '../../../util/metrics/TrackOnboarding/trackOnboarding'; import { enableProfileSyncing } from '../../../actions/identity'; +import {MetricsEventBuilder} from '../../../core/Analytics/MetricsEventBuilder'; const createStyles = (colors) => StyleSheet.create({ mainWrapper: { @@ -256,7 +257,9 @@ class ChoosePassword extends PureComponent { keyringControllerPasswordSet = false; track = (event, properties) => { - trackOnboarding(event, properties); + const eventBuilder = MetricsEventBuilder.createEventBuilder(event); + eventBuilder.addProperties(properties); + trackOnboarding(eventBuilder.build()); }; updateNavBar = () => { diff --git a/app/components/Views/ImportFromSecretRecoveryPhrase/index.js b/app/components/Views/ImportFromSecretRecoveryPhrase/index.js index 1f6036f6f56..62d36f8b3fc 100644 --- a/app/components/Views/ImportFromSecretRecoveryPhrase/index.js +++ b/app/components/Views/ImportFromSecretRecoveryPhrase/index.js @@ -65,6 +65,7 @@ import { ImportFromSeedSelectorsIDs } from '../../../../e2e/selectors/Onboarding import { ChoosePasswordSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ChoosePassword.selectors'; import trackOnboarding from '../../../util/metrics/TrackOnboarding/trackOnboarding'; import { useProfileSyncing } from '../../../util/identity/hooks/useProfileSyncing'; +import {MetricsEventBuilder} from '../../../core/Analytics/MetricsEventBuilder'; const MINIMUM_SUPPORTED_CLIPBOARD_VERSION = 9; @@ -108,7 +109,9 @@ const ImportFromSecretRecoveryPhrase = ({ const confirmPasswordInput = React.createRef(); const track = (event, properties) => { - trackOnboarding(event, properties); + const eventBuilder = MetricsEventBuilder.createEventBuilder(event); + eventBuilder.addProperties(properties); + trackOnboarding(eventBuilder.build()); }; const updateNavBar = () => { diff --git a/app/components/Views/ManualBackupStep3/index.js b/app/components/Views/ManualBackupStep3/index.js index ecbc61a00eb..9f754165948 100644 --- a/app/components/Views/ManualBackupStep3/index.js +++ b/app/components/Views/ManualBackupStep3/index.js @@ -173,7 +173,11 @@ class ManualBackupStep3 extends PureComponent { SEED_PHRASE_HINTS, JSON.stringify({ ...parsedHints, manualBackup: hintText }), ); - this.track(MetaMetricsEvents.WALLET_SECURITY_RECOVERY_HINT_SAVED); + trackOnboarding( + MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.WALLET_SECURITY_RECOVERY_HINT_SAVED, + ).build(), + ); }; done = async () => { diff --git a/app/components/Views/Onboarding/index.js b/app/components/Views/Onboarding/index.js index af9e6f634ad..042afda81c8 100644 --- a/app/components/Views/Onboarding/index.js +++ b/app/components/Views/Onboarding/index.js @@ -50,6 +50,7 @@ import Routes from '../../../constants/navigation/Routes'; import { selectAccounts } from '../../../selectors/accountTrackerController'; import trackOnboarding from '../../../util/metrics/TrackOnboarding/trackOnboarding'; import { trace, TraceName, TraceOperation } from '../../../util/trace'; +import { MetricsEventBuilder } from '../../../core/Analytics/MetricsEventBuilder'; const createStyles = (colors) => StyleSheet.create({ @@ -321,7 +322,7 @@ class Onboarding extends PureComponent { }; track = (event) => { - trackOnboarding(event); + trackOnboarding(MetricsEventBuilder.createEventBuilder(event).build()); }; alertExistingUser = (callback) => { From c28efe4d73815378b059f57cfa6ee7bfce435aa3 Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Thu, 30 Jan 2025 22:26:05 +0100 Subject: [PATCH 11/18] fix: fix sort feature (#13277) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fix a regression on sort token feature ## **Related issues** Fixes: #13260 ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/b9ccdfd4-6a9f-47b9-93f6-ec2687487158 ## **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. --- .../Tokens/__snapshots__/index.test.tsx.snap | 164 +++++++++--------- app/components/UI/Tokens/index.tsx | 66 +++---- e2e/pages/wallet/TokenSortBottomSheet.js | 25 +++ e2e/pages/wallet/WalletView.js | 14 ++ .../assets/multichain/asset-sort.spec.js | 89 ++++++++++ e2e/utils/Gestures.js | 1 - 6 files changed, 235 insertions(+), 124 deletions(-) create mode 100644 e2e/pages/wallet/TokenSortBottomSheet.js create mode 100644 e2e/specs/assets/multichain/asset-sort.spec.js diff --git a/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap b/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap index 3fe1837784e..5afc5733b5d 100644 --- a/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap @@ -476,7 +476,7 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is tokens={ [ { - "address": "0x0", + "address": "0x01", "balanceFiat": "", "chainId": "0x1", "decimals": 18, @@ -484,13 +484,13 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "isETH": false, "isNative": false, "isStaked": false, - "name": "Ethereum", - "symbol": "ETH", - "token": "Ethereum", + "name": "Bat", + "symbol": "BAT", + "token": "Bat", "tokenFiatAmount": 0, }, { - "address": "0x01", + "address": "0x0", "balanceFiat": "", "chainId": "0x1", "decimals": 18, @@ -498,10 +498,10 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "isETH": false, "isNative": false, "isStaked": false, - "name": "Bat", - "symbol": "BAT", - "token": "Bat", - "tokenFiatAmount": 0, + "name": "Ethereum", + "symbol": "ETH", + "token": "Ethereum", + "tokenFiatAmount": undefined, }, ] } @@ -510,7 +510,7 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is data={ [ { - "address": "0x0", + "address": "0x01", "balanceFiat": "", "chainId": "0x1", "decimals": 18, @@ -518,13 +518,13 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "isETH": false, "isNative": false, "isStaked": false, - "name": "Ethereum", - "symbol": "ETH", - "token": "Ethereum", + "name": "Bat", + "symbol": "BAT", + "token": "Bat", "tokenFiatAmount": 0, }, { - "address": "0x01", + "address": "0x0", "balanceFiat": "", "chainId": "0x1", "decimals": 18, @@ -532,10 +532,10 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "isETH": false, "isNative": false, "isStaked": false, - "name": "Bat", - "symbol": "BAT", - "token": "Bat", - "tokenFiatAmount": 0, + "name": "Ethereum", + "symbol": "ETH", + "token": "Ethereum", + "tokenFiatAmount": undefined, }, ] } @@ -587,7 +587,7 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "paddingVertical": 10, } } - testID="asset-ETH" + testID="asset-BAT" > - Ethereum + Bat @@ -809,35 +809,7 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is } testID="fiat-balance-test-id" > - + < 0.00001 BAT - + $0 @@ -905,7 +849,7 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is "paddingVertical": 10, } } - testID="asset-BAT" + testID="asset-ETH" > - Bat + Ethereum @@ -1127,7 +1071,35 @@ exports[`Tokens Portfolio View should match the snapshot when portfolio view is } testID="fiat-balance-test-id" > - < 0.00001 BAT + - $0 + diff --git a/app/components/UI/Tokens/index.tsx b/app/components/UI/Tokens/index.tsx index 48684d1f0d3..74d98faa16e 100644 --- a/app/components/UI/Tokens/index.tsx +++ b/app/components/UI/Tokens/index.tsx @@ -207,51 +207,29 @@ const Tokens: React.FC = memo(({ tokens }) => { return [...nativeTokens, ...nonNativeTokens]; }; - const calculateTokenFiatBalances = (assets: TokenI[]) => { - const tokenFiatBalances: number[] = []; - - for (const token of assets) { + const calculateFiatBalances = (assets: TokenI[]) => + assets.map((token) => { const chainId = token.chainId as Hex; - const multiChainExchangeRates = debouncedMultiChainMarketData?.[chainId]; + const multiChainExchangeRates = multiChainMarketData?.[chainId]; const multiChainTokenBalances = - debouncedMultiChainTokenBalance?.[ - selectedInternalAccountAddress as Hex - ]?.[chainId]; + multiChainTokenBalance?.[selectedInternalAccountAddress as Hex]?.[ + chainId + ]; const nativeCurrency = networkConfigurationsByChainId[chainId].nativeCurrency; const multiChainConversionRate = - debouncedMultiChainCurrencyRates?.[nativeCurrency]?.conversionRate || 0; - - // Calculate fiat balance for the token - const fiatBalance = - token.isETH || token.isNative - ? parseFloat(token.balance) * multiChainConversionRate - : deriveBalanceFromAssetMarketDetails( - token, - multiChainTokenBalances || {}, - multiChainExchangeRates || {}, - multiChainConversionRate || 0, - currentCurrency || '', - ).balanceFiatCalculation; - - // Add the calculated balance to the array - tokenFiatBalances.push(fiatBalance || 0); - } - - const tokensWithBalances: typeof assets = []; - - for (let i = 0; i < assets.length; i++) { - const token = assets[i]; - const tokenWithBalance = { - ...token, - tokenFiatAmount: tokenFiatBalances[i], - }; - - tokensWithBalances.push(tokenWithBalance); - } - - return tokensWithBalances; - }; + multiChainCurrencyRates?.[nativeCurrency]?.conversionRate || 0; + + return token.isETH || token.isNative + ? parseFloat(token.balance) * multiChainConversionRate + : deriveBalanceFromAssetMarketDetails( + token, + multiChainExchangeRates || {}, + multiChainTokenBalances || {}, + multiChainConversionRate || 0, + currentCurrency || '', + ).balanceFiatCalculation; + }); const filterTokensByNetwork = (tokensToDisplay: TokenI[]): TokenI[] => { if (isAllNetworks && isPopularNetwork) { @@ -286,7 +264,13 @@ const Tokens: React.FC = memo(({ tokens }) => { const assets = categorizeTokens(filteredTokens); - const tokensWithBalances = calculateTokenFiatBalances(assets); + // Calculate fiat balances for tokens + const tokenFiatBalances = calculateFiatBalances(assets); + + const tokensWithBalances = assets.map((token, i) => ({ + ...token, + tokenFiatAmount: tokenFiatBalances[i], + })); const tokensSorted = sortAssets(tokensWithBalances, tokenSortConfig); endTrace({ diff --git a/e2e/pages/wallet/TokenSortBottomSheet.js b/e2e/pages/wallet/TokenSortBottomSheet.js new file mode 100644 index 00000000000..2d48522d96e --- /dev/null +++ b/e2e/pages/wallet/TokenSortBottomSheet.js @@ -0,0 +1,25 @@ +import { WalletViewSelectorsIDs } from '../../selectors/wallet/WalletView.selectors'; +import Gestures from '../../utils/Gestures'; +import Matchers from '../../utils/Matchers'; + +class SortModal { + get sortAlphabetically() { + return Matchers.getElementByID(WalletViewSelectorsIDs.SORT_ALPHABETICAL); + } + + get sortFiatAmount() { + return Matchers.getElementByID( + WalletViewSelectorsIDs.SORT_DECLINING_BALANCE, + ); + } + + async tapSortAlphabetically() { + await Gestures.waitAndTap(this.sortAlphabetically); + } + + async tapSortFiatAmount() { + await Gestures.waitAndTap(this.sortFiatAmount); + } +} + +export default new SortModal(); diff --git a/e2e/pages/wallet/WalletView.js b/e2e/pages/wallet/WalletView.js index e812774b37e..761c0d0428b 100644 --- a/e2e/pages/wallet/WalletView.js +++ b/e2e/pages/wallet/WalletView.js @@ -90,6 +90,10 @@ class WalletView { return Matchers.getElementByID(WalletViewSelectorsIDs.TOKEN_NETWORK_FILTER); } + get sortBy() { + return Matchers.getElementByID(WalletViewSelectorsIDs.SORT_BY); + } + get tokenNetworkFilterAll() { return Matchers.getElementByID( WalletViewSelectorsIDs.TOKEN_NETWORK_FILTER_ALL, @@ -172,6 +176,12 @@ class WalletView { return Matchers.getElementByText(tokenName); } + async getTokensInWallet() { + return Matchers.getElementByID( + WalletViewSelectorsIDs.TOKENS_CONTAINER_LIST, + ); + } + async nftIDInWallet(nftId) { return Matchers.getElementByID(nftId); } @@ -192,6 +202,10 @@ class WalletView { await Gestures.waitAndTap(this.tokenNetworkFilter); } + async tapSortBy() { + await Gestures.waitAndTap(this.sortBy); + } + async tapTokenNetworkFilterAll() { await Gestures.waitAndTap(this.tokenNetworkFilterAll); } diff --git a/e2e/specs/assets/multichain/asset-sort.spec.js b/e2e/specs/assets/multichain/asset-sort.spec.js new file mode 100644 index 00000000000..10ed60d0ad8 --- /dev/null +++ b/e2e/specs/assets/multichain/asset-sort.spec.js @@ -0,0 +1,89 @@ +import { SmokeAssets } from '../../../tags'; +import WalletView from '../../../pages/wallet/WalletView'; +import SortModal from '../../../pages/wallet/TokenSortBottomSheet'; +import FixtureBuilder, { + DEFAULT_FIXTURE_ACCOUNT, +} from '../../../fixtures/fixture-builder'; +import { + loadFixture, + startFixtureServer, +} from '../../../fixtures/fixture-helper'; +import FixtureServer from '../../../fixtures/fixture-server'; +import { getFixturesServerPort } from '../../../fixtures/utils'; +import { loginToApp } from '../../../viewHelper'; +import Assertions from '../../../utils/Assertions'; +import ConfirmAddAssetView from '../../../pages/wallet/ImportTokenFlow/ConfirmAddAsset'; +import TestHelpers from '../../../helpers'; + +import Tenderly from '../../../tenderly'; +import { CustomNetworks } from '../../../resources/networks.e2e'; +import ImportTokensView from '../../../pages/wallet/ImportTokenFlow/ImportTokensView'; + +const fixtureServer = new FixtureServer(); + +describe(SmokeAssets('Import Tokens'), () => { + beforeAll(async () => { + await Tenderly.addFunds( + CustomNetworks.Tenderly.Mainnet.providerConfig.rpcUrl, + DEFAULT_FIXTURE_ACCOUNT, + ); + + await TestHelpers.reverseServerPort(); + const fixture = new FixtureBuilder() + .withNetworkController(CustomNetworks.Tenderly.Mainnet) + .build(); + await startFixtureServer(fixtureServer); + await loadFixture(fixtureServer, { fixture }); + await TestHelpers.launchApp({ + permissions: { notifications: 'YES' }, + launchArgs: { fixtureServerPort: `${getFixturesServerPort()}` }, + }); + await loginToApp(); + }); + + it('should add a aave token', async () => { + await WalletView.tapImportTokensButton(); + await ImportTokensView.searchToken('AAVE'); + await ImportTokensView.tapOnToken(); // taps the first token in the returned list + await ImportTokensView.tapOnNextButton(); + + await TestHelpers.delay(500); + await Assertions.checkIfVisible(ConfirmAddAssetView.container); + + await ConfirmAddAssetView.tapOnConfirmButton(); + + await Assertions.checkIfVisible(WalletView.container); + }); + + it('should sort tokens alphabetically', async () => { + await WalletView.tapSortBy(); + await SortModal.tapSortAlphabetically(); + + const tokens = await WalletView.getTokensInWallet(); + const tokensAttributes = await tokens.getAttributes(); + const label = tokensAttributes.label; + + // Ensure `label` contains "Aave" followed (somewhere) by "Ethereum". + const textOrderRegex = new RegExp('Aave([\\s\\S]*?)Ethereum', 'i'); + const isMatch = label.match(textOrderRegex); + if (!isMatch) { + throw new Error('Expected label to match the regex, but it did not.'); + } + }); + + it('should sort tokens by fiat amount', async () => { + await WalletView.tapSortBy(); + await SortModal.tapSortFiatAmount(); + + const tokens = await WalletView.getTokensInWallet(); + const tokensAttributes = await tokens.getAttributes(); + const label = tokensAttributes.label; + + // Ensure `label` contains "Ethereum" followed (somewhere) by "Aave". + const textOrderRegex = new RegExp('Ethereum([\\s\\S]*?)Aave', 'i'); + const isMatch = label.match(textOrderRegex); + if (!isMatch) { + throw new Error('Expected label to match the regex, but it did not.'); + } + }); +}); diff --git a/e2e/utils/Gestures.js b/e2e/utils/Gestures.js index d7753b980a6..275f3e70ab9 100644 --- a/e2e/utils/Gestures.js +++ b/e2e/utils/Gestures.js @@ -47,7 +47,6 @@ class Gestures { await element(by.text(new RegExp(`^/${textPattern} .*$/`))).tap(); } - /** * Wait for an element to be visible and then tap it. * From 2e66f6dd561d614e3ef074be2b675aa188597a8f Mon Sep 17 00:00:00 2001 From: Curtis David Date: Thu, 30 Jan 2025 16:35:11 -0500 Subject: [PATCH 12/18] test: Add e2e for app restart after adding contact address (#13273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Add scenario for restarting mobile app after adding contacts. Possibly update existing test e2e/specs/settings/addressbook-tests.spec.js to restart app before removing contact. Scenario Scenario: Restart app after adding contact GIVEN I added a contact WHEN I restart app THEN added contact is shown in Settings AND added contact is shown in Send flow for selected network ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **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. --- .../settings/addressbook-relaunch-app.spec.js | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 e2e/specs/settings/addressbook-relaunch-app.spec.js diff --git a/e2e/specs/settings/addressbook-relaunch-app.spec.js b/e2e/specs/settings/addressbook-relaunch-app.spec.js new file mode 100644 index 00000000000..2a2a20a9a32 --- /dev/null +++ b/e2e/specs/settings/addressbook-relaunch-app.spec.js @@ -0,0 +1,62 @@ +'use strict'; +import { SmokeCore } from '../../tags'; +import SettingsView from '../../pages/Settings/SettingsView'; +import ContactsView from '../../pages/Settings/Contacts/ContactsView'; +import AddContactView from '../../pages/Settings/Contacts/AddContactView'; +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import WalletActionsBottomSheet from '../../pages/wallet/WalletActionsBottomSheet'; + +import { loginToApp } from '../../viewHelper'; +import FixtureBuilder from '../../fixtures/fixture-builder'; + +import TestHelpers from '../../helpers'; +import { getFixturesServerPort } from '../../fixtures/utils'; +import Assertions from '../../utils/Assertions'; +import { withFixtures } from '../../fixtures/fixture-helper'; + +const MEMO = 'Address for testing 123123123'; + +describe(SmokeCore('Relaunch App after Adding Address to Contact Book'), () => { + beforeAll(async () => { + jest.setTimeout(150000); + await TestHelpers.reverseServerPort(); + }); + + it('should terminate and relaunch the app after adding a contact', async () => { + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder().withPermissionController().build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.disableSynchronization(); + await TabBarComponent.tapSettings(); + await SettingsView.tapContacts(); + await device.enableSynchronization(); + + await ContactsView.tapAddContactButton(); + await AddContactView.typeInName('Curtis'); + + await AddContactView.typeInAddress('curtis.eth'); + await AddContactView.typeInMemo(MEMO); + await AddContactView.tapAddContactButton(); + await ContactsView.isContactAliasVisible('Curtis'); + await device.terminateApp(); + await TestHelpers.launchApp({ + launchArgs: { fixtureServerPort: `${getFixturesServerPort()}` }, + }); + await loginToApp(); + await TabBarComponent.tapSettings(); + await SettingsView.tapContacts(); + await Assertions.checkIfVisible(ContactsView.container); + await ContactsView.isContactAliasVisible('Curtis'); + await TabBarComponent.tapWallet(); + await TabBarComponent.tapActions(); + await WalletActionsBottomSheet.tapSendButton(); + await Assertions.checkIfTextIsDisplayed('Curtis'); + }, + ); + }); +}); From d48cff9ca2aa1fcd3c46763d8bcce3d82043b472 Mon Sep 17 00:00:00 2001 From: Nicholas Smith Date: Thu, 30 Jan 2025 16:45:12 -0500 Subject: [PATCH 13/18] feat: add user earning history graph and list on history button click (#12746) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR adds a pooled staking user rewards history button to the asset detail page for ETH. This button leads to a bar chart graph of the user rewards over a 2 year period. A user can switch to 7D, M or Y to get 7 days, monthly or yearly data in the graph and can select different bars to see the amount of that bar's time period in the chart header. Default view with no selected bars shows the total amount of rewards earned. 1. What is the reason for the change? To add a chart view for the user to look at their historical rewards in detail 2. What is the improvement/solution? A chart view has been added that will allow the user to look at their historical rewards in detail ## **Related issues** [Fixes:](https://consensyssoftware.atlassian.net/browse/STAKE-705) ## **Manual testing steps** - Go to the asset view for eth by clicking on eth or staked eth in the token list on the home page - Note the total rewards on the asset detail page, it should be the same as in the chart - Click the button for earnings history where staking details are to see the chart, it should load - If there is any delay, there should be placeholders for the loading state - If there is an error and there is no data for some reason, the loading state is currently the default - The chart should show the total rewards and when you click on a bar that bar should become highlighted and stay highlighted until clicked again or until another bar is clicked. When highlighted the graph should show that bars info and that info should match the history list - In the chart, we do not skip zero amount time periods - In the list we do skip tailing zero amount time period but not any that are in between time periods with amounts - Clicking each time period in the top of the chart should switch the data to that time period and unselect any selected bar - The chart should be fairly quick to load and use and there should be no lagging actions ## **Screenshots/Recordings** ### **Before** No chart or button n/a ### **After** https://github.com/user-attachments/assets/750e6dc3-7055-48a2-a579-d76242e10c3e ## **Pre-merge author checklist** - [x] 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). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] 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: Matthew Grainger <46547583+Matt561@users.noreply.github.com> --- .../UI/AssetOverview/Balance/Balance.tsx | 13 +- .../StakeEarningsHistoryView.styles.ts | 19 + .../StakeEarningsHistoryView.test.tsx | 107 ++ .../StakeEarningsHistoryView.tsx | 44 + .../StakeEarningsHistoryView.types.ts | 9 + .../StakeEarningsHistoryView.test.tsx.snap | 980 ++++++++++++++++++ app/components/UI/Stake/__mocks__/mockData.ts | 17 +- .../Stake/components/GasImpactModal/index.tsx | 2 +- .../StakingBalance/StakingBalance.tsx | 9 +- .../StakingBalance.test.tsx.snap | 4 +- .../StakingEarnings/StakingEarnings.test.tsx | 18 +- .../StakingEarningsHistory.constants.ts | 9 + .../StakingEarningsHistory.test.tsx | 332 ++++++ .../StakingEarningsHistory.tsx | 307 ++++++ .../StakingEarningsHistory.types.ts | 25 + .../StakingEarningsHistory.utils.test.ts | 158 +++ .../StakingEarningsHistory.utils.ts | 177 ++++ .../StakingEarningsHistoryChart.styles.ts | 25 + .../StakingEarningsHistoryChart.test.tsx | 202 ++++ .../StakingEarningsHistoryChart.tsx | 279 +++++ .../StakingEarningsHistoryChart.types.ts | 26 + .../StakingEarningsHistoryChart.test.tsx.snap | 265 +++++ .../StakingEarningsHistoryList.styles.ts | 40 + .../StakingEarningsHistoryList.test.tsx | 47 + .../StakingEarningsHistoryList.tsx | 107 ++ .../StakingEarningsHistoryList.types.ts | 13 + .../StakingEarningsTimePeriod.styles.ts | 43 + .../StakingEarningsTimePeriod.test.tsx | 39 + .../StakingEarningsTimePeriod.tsx | 85 ++ .../StakingEarningsTimePeriod.types.ts | 10 + .../StakingEarningsHistoryButton.test.tsx | 52 + .../StakingEarningsHistoryButton.tsx | 42 + .../StakingEarnings.test.tsx.snap | 41 + .../components/StakingEarnings/index.tsx | 2 + .../hooks/useStakingEarningsHistory.test.tsx | 98 ++ .../Stake/hooks/useStakingEarningsHistory.ts | 67 ++ app/components/UI/Stake/routes/index.tsx | 5 + .../UI/Stake/sdk/stakeSdkProvider.tsx | 9 +- .../UI/Stake/utils/date/index.test.ts | 33 + app/components/UI/Stake/utils/date/index.ts | 14 + .../Tokens/TokenList/TokenListItem/index.tsx | 8 +- app/constants/navigation/Routes.ts | 1 + app/util/testUtils/react-native-svg-charts.ts | 56 + e2e/selectors/wallet/WalletView.selectors.js | 1 + locales/languages/en.json | 5 +- package.json | 2 +- yarn.lock | 8 +- 47 files changed, 3831 insertions(+), 24 deletions(-) create mode 100644 app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.styles.ts create mode 100644 app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.test.tsx create mode 100644 app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.tsx create mode 100644 app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.types.ts create mode 100644 app/components/UI/Stake/Views/StakeEarningsHistoryView/__snapshots__/StakeEarningsHistoryView.test.tsx.snap create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.constants.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.test.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.types.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.test.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.styles.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.test.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.types.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/__snapshots__/StakingEarningsHistoryChart.test.tsx.snap create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.styles.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.test.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.types.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.styles.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.test.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.types.ts create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.test.tsx create mode 100644 app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.tsx create mode 100644 app/components/UI/Stake/hooks/useStakingEarningsHistory.test.tsx create mode 100644 app/components/UI/Stake/hooks/useStakingEarningsHistory.ts create mode 100644 app/components/UI/Stake/utils/date/index.test.ts create mode 100644 app/components/UI/Stake/utils/date/index.ts create mode 100644 app/util/testUtils/react-native-svg-charts.ts diff --git a/app/components/UI/AssetOverview/Balance/Balance.tsx b/app/components/UI/AssetOverview/Balance/Balance.tsx index 8dc96b67932..dd0efd0032b 100644 --- a/app/components/UI/AssetOverview/Balance/Balance.tsx +++ b/app/components/UI/AssetOverview/Balance/Balance.tsx @@ -6,8 +6,10 @@ import { useStyles } from '../../../../component-library/hooks'; import styleSheet from './Balance.styles'; import AssetElement from '../../AssetElement'; import { useSelector } from 'react-redux'; -import { selectNetworkName } from '../../../../selectors/networkInfos'; -import { selectChainId } from '../../../../selectors/networkController'; +import { + selectChainId, + selectNetworkConfigurationByChainId, +} from '../../../../selectors/networkController'; import { getTestNetImageByChainId, getDefaultNetworkByChainId, @@ -35,6 +37,7 @@ import { UnpopularNetworkList, CustomNetworkImgMapping, } from '../../../../util/networks/customNetworks'; +import { RootState } from '../../../../reducers'; interface BalanceProps { asset: TokenI; @@ -91,7 +94,9 @@ export const NetworkBadgeSource = (chainId: Hex, ticker: string) => { const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { const { styles } = useStyles(styleSheet, {}); const navigation = useNavigation(); - const networkName = useSelector(selectNetworkName); + const networkConfigurationByChainId = useSelector((state: RootState) => + selectNetworkConfigurationByChainId(state, asset.chainId as Hex), + ); const chainId = useSelector(selectChainId); const tokenChainId = isPortfolioViewEnabled() ? asset.chainId : chainId; @@ -156,7 +161,7 @@ const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { } > diff --git a/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.styles.ts b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.styles.ts new file mode 100644 index 00000000000..0bbc2abee27 --- /dev/null +++ b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.styles.ts @@ -0,0 +1,19 @@ +import type { Theme } from '../../../../../util/theme/models'; +import { StyleSheet } from 'react-native'; + +const stylesSheet = (params: { theme: Theme }) => { + const { theme } = params; + const { colors } = theme; + + return StyleSheet.create({ + mainContainer: { + flexGrow: 1, + paddingTop: 8, + paddingHorizontal: 16, + backgroundColor: colors.background.default, + justifyContent: 'space-between', + }, + }); +}; + +export default stylesSheet; diff --git a/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.test.tsx b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.test.tsx new file mode 100644 index 00000000000..fa1854612e7 --- /dev/null +++ b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.test.tsx @@ -0,0 +1,107 @@ +import React from 'react'; +import StakeEarningsHistoryView from './StakeEarningsHistoryView'; +import useStakingEarningsHistory from '../../hooks/useStakingEarningsHistory'; +import { MOCK_STAKED_ETH_ASSET } from '../../__mocks__/mockData'; +import { fireLayoutEvent } from '../../../../../util/testUtils/react-native-svg-charts'; +import { getStakingNavbar } from '../../../Navbar'; +import renderWithProvider from '../../../../../util/test/renderWithProvider'; +import { backgroundState } from '../../../../../util/test/initial-root-state'; +import { Hex } from '@metamask/utils'; + +jest.mock('../../../Navbar'); +jest.mock('../../hooks/useStakingEarningsHistory'); + +const mockNavigation = { + navigate: jest.fn(), + setOptions: jest.fn(), +}; + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useNavigation: () => mockNavigation, + useRoute: () => ({ + key: '1', + name: 'params', + params: { asset: MOCK_STAKED_ETH_ASSET }, + }), + }; +}); +jest.mock('react-native-svg-charts', () => { + const reactNativeSvgCharts = jest.requireActual('react-native-svg-charts'); // Get the actual Grid component + return { + ...reactNativeSvgCharts, + Grid: () => <>, + }; +}); + +(useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2023-01-01', + dailyRewards: '1000000000000000000', + sumRewards: '1000000000000000000', + }, + { + dateStr: '2023-01-02', + dailyRewards: '1000000000000000000', + sumRewards: '2000000000000000000', + }, + ], + isLoading: false, + error: null, +}); + +const mockInitialState = { + settings: {}, + engine: { + backgroundState: { + ...backgroundState, + CurrencyRateController: { + currentCurrency: 'usd', + currencyRates: { + ETH: { + conversionRate: 3363.79, + }, + }, + }, + NetworkController: { + selectedNetworkClientId: 'selectedNetworkClientId', + networkConfigurationsByChainId: { + '0x1': { + nativeCurrency: 'ETH', + chainId: '0x1' as Hex, + rpcEndpoints: [ + { + networkClientId: 'selectedNetworkClientId', + }, + ], + defaultRpcEndpointIndex: 0, + }, + }, + }, + }, + }, +}; + +const earningsHistoryView = ; + +describe('StakeEarningsHistoryView', () => { + it('renders correctly and matches snapshot', () => { + const renderedView = renderWithProvider(earningsHistoryView, { + state: mockInitialState, + }); + fireLayoutEvent(renderedView.root); + expect(renderedView.toJSON()).toMatchSnapshot(); + }); + + it('calls navigation setOptions to get staking navigation bar', () => { + const renderedView = renderWithProvider(earningsHistoryView, { + state: mockInitialState, + }); + fireLayoutEvent(renderedView.root); + expect(mockNavigation.setOptions).toHaveBeenCalled(); + expect(getStakingNavbar).toHaveBeenCalled(); + }); +}); diff --git a/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.tsx b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.tsx new file mode 100644 index 00000000000..7be8d6485c5 --- /dev/null +++ b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.tsx @@ -0,0 +1,44 @@ +import { useNavigation, useRoute } from '@react-navigation/native'; +import React, { useEffect } from 'react'; +import { View } from 'react-native'; +import { ScrollView } from 'react-native-gesture-handler'; +import { strings } from '../../../../../../locales/i18n'; +import { useStyles } from '../../../../hooks/useStyles'; +import { getStakingNavbar } from '../../../Navbar'; +import StakingEarningsHistory from '../../components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory'; +import styleSheet from './StakeEarningsHistoryView.styles'; +import { StakeEarningsHistoryViewRouteParams } from './StakeEarningsHistoryView.types'; + +const StakeEarningsHistoryView = () => { + const navigation = useNavigation(); + const route = useRoute(); + const { styles, theme } = useStyles(styleSheet, {}); + const { asset } = route.params; + + useEffect(() => { + navigation.setOptions( + getStakingNavbar( + strings('stake.earnings_history_title', { + ticker: asset.ticker, + }), + navigation, + theme.colors, + { + backgroundColor: theme.colors.background.default, + hasCancelButton: false, + hasBackButton: true, + }, + ), + ); + }, [navigation, theme.colors, asset.ticker]); + + return ( + + + + + + ); +}; + +export default StakeEarningsHistoryView; diff --git a/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.types.ts b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.types.ts new file mode 100644 index 00000000000..106bb6ead4e --- /dev/null +++ b/app/components/UI/Stake/Views/StakeEarningsHistoryView/StakeEarningsHistoryView.types.ts @@ -0,0 +1,9 @@ +import { TokenI } from '../../../Tokens/types'; + +export interface StakeEarningsHistoryViewRouteParams { + key: string; + name: string; + params: { + asset: TokenI; + }; +} diff --git a/app/components/UI/Stake/Views/StakeEarningsHistoryView/__snapshots__/StakeEarningsHistoryView.test.tsx.snap b/app/components/UI/Stake/Views/StakeEarningsHistoryView/__snapshots__/StakeEarningsHistoryView.test.tsx.snap new file mode 100644 index 00000000000..6469b6b7eda --- /dev/null +++ b/app/components/UI/Stake/Views/StakeEarningsHistoryView/__snapshots__/StakeEarningsHistoryView.test.tsx.snap @@ -0,0 +1,980 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StakeEarningsHistoryView renders correctly and matches snapshot 1`] = ` + + + + + + + + + + 7D + + + + + + + + + M + + + + + + + + + Y + + + + + + + + + + 2 + + ETH + + + Lifetime earnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Payout history + + + + + 2023 + + + + + + January + + + + + + + + 2 + + ETH + + + + + $6727.58 + + + + + + + + + + +`; diff --git a/app/components/UI/Stake/__mocks__/mockData.ts b/app/components/UI/Stake/__mocks__/mockData.ts index ab3e2b9ff3e..f0fcabbca3d 100644 --- a/app/components/UI/Stake/__mocks__/mockData.ts +++ b/app/components/UI/Stake/__mocks__/mockData.ts @@ -10,14 +10,29 @@ import { Contract } from 'ethers'; import { Stake } from '../sdk/stakeSdkProvider'; export const MOCK_STAKED_ETH_ASSET = { + decimals: 18, + address: '0x0000000000000000000000000000000000000000', chainId: '0x1', balance: '4.9999 ETH', balanceFiat: '$13,292.20', name: 'Staked Ethereum', - symbol: 'ETH', + symbol: 'Ethereum', + ticker: 'ETH', isETH: true, } as TokenI; +export const MOCK_USDC_ASSET = { + decimals: 6, + address: '0xUSDC000000000000000000000000000000000000', + chainId: '0x1', + balance: '200.9999 USDC', + balanceFiat: '$200.98', + name: 'USD Coin', + symbol: 'USD Coin', + ticker: 'USDC', + isETH: false, +} as TokenI; + export const MOCK_GET_POOLED_STAKES_API_RESPONSE: PooledStakes = { accounts: [ { diff --git a/app/components/UI/Stake/components/GasImpactModal/index.tsx b/app/components/UI/Stake/components/GasImpactModal/index.tsx index dabbaca7c5d..c2872241556 100644 --- a/app/components/UI/Stake/components/GasImpactModal/index.tsx +++ b/app/components/UI/Stake/components/GasImpactModal/index.tsx @@ -126,7 +126,7 @@ const GasImpactModal = ({ route }: GasImpactModalProps) => { - {strings('stake.gas_cost_impact_warning')} + {strings('stake.gas_cost_impact_warning', { percentOverDeposit: 30 })} { setHasSentViewingStakingRewardsMetric, ] = useState(false); - const networkName = useSelector(selectNetworkName); + const networkConfigurationByChainId = useSelector((state: RootState) => + selectNetworkConfigurationByChainId(state, asset.chainId as Hex), + ); const { isEligible: isEligibleForPooledStaking } = useStakingEligibility(); @@ -216,7 +219,7 @@ const StakingBalanceContent = ({ asset }: StakingBalanceProps) => { asset.chainId as Hex, asset.ticker ?? asset.symbol, )} - name={networkName} + name={networkConfigurationByChainId?.name} /> } > diff --git a/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap b/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap index a3a8efd1247..1ae10dfbaae 100644 --- a/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap +++ b/app/components/UI/Stake/components/StakingBalance/__snapshots__/StakingBalance.test.tsx.snap @@ -16,7 +16,7 @@ exports[`StakingBalance render matches snapshot 1`] = ` "paddingVertical": 10, } } - testID="asset-ETH" + testID="asset-Ethereum" > ({ describe('Staking Earnings', () => { it('should render correctly', () => { const { toJSON, getByText } = renderWithProvider( - , + , { state: STATE_MOCK, }, @@ -78,6 +91,7 @@ describe('Staking Earnings', () => { expect(getByText(strings('stake.annual_rate'))).toBeDefined(); expect(getByText(strings('stake.lifetime_rewards'))).toBeDefined(); expect(getByText(strings('stake.estimated_annual_earnings'))).toBeDefined(); + expect(getByText(strings('stake.view_earnings_history'))).toBeDefined(); expect(toJSON()).toMatchSnapshot(); }); }); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.constants.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.constants.ts new file mode 100644 index 00000000000..f39dd555f4d --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.constants.ts @@ -0,0 +1,9 @@ +import { DateRange } from './StakingEarningsTimePeriod/StakingEarningsTimePeriod.types'; + +export const EARNINGS_HISTORY_TIME_PERIOD_DEFAULT = DateRange.MONTHLY; +export const EARNINGS_HISTORY_DAYS_LIMIT = 730; +export const EARNINGS_HISTORY_CHART_BAR_LIMIT = { + [DateRange.DAILY]: 7, + [DateRange.MONTHLY]: 12, + [DateRange.YEARLY]: 2, +}; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.test.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.test.tsx new file mode 100644 index 00000000000..f2bf3bd0a50 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.test.tsx @@ -0,0 +1,332 @@ +import React from 'react'; +import { fireEvent } from '@testing-library/react-native'; +import StakingEarningsHistory from './StakingEarningsHistory'; +import useStakingEarningsHistory from '../../../hooks/useStakingEarningsHistory'; +import { MOCK_STAKED_ETH_ASSET } from '../../../__mocks__/mockData'; +import renderWithProvider from '../../../../../../util/test/renderWithProvider'; +import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../../../../util/test/accountsControllerTestUtils'; +import { backgroundState } from '../../../../../../util/test/initial-root-state'; +import { Hex } from '@metamask/smart-transactions-controller/dist/types'; +import { TokenI } from '../../../../Tokens/types'; + +jest.mock('../../../hooks/useStakingEarningsHistory'); +jest.mock('react-native-svg-charts', () => { + const reactNativeSvgCharts = jest.requireActual('react-native-svg-charts'); + return { + ...reactNativeSvgCharts, + Grid: () => <>, + }; +}); + +const mockInitialState = { + settings: {}, + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + CurrencyRateController: { + currentCurrency: 'usd', + currencyRates: { + ETH: { + conversionRate: 3363.79, + }, + }, + }, + TokenRatesController: { + marketData: { + '0x1': { + '0xUSDC000000000000000000000000000000000000': { + price: 0.0002990514020561363, + }, + }, + }, + }, + NetworkController: { + selectedNetworkClientId: 'selectedNetworkClientId', + networkConfigurationsByChainId: { + '0x1': { + nativeCurrency: 'ETH', + chainId: '0x1' as Hex, + rpcEndpoints: [ + { + networkClientId: 'selectedNetworkClientId', + }, + ], + defaultRpcEndpointIndex: 0, + }, + }, + }, + }, + }, +}; + +describe('StakingEarningsHistory', () => { + beforeEach(() => { + (useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2022-12-31', + dailyRewards: '442219562575615', + sumRewards: '442219562575615', + }, + { + dateStr: '2023-01-01', + dailyRewards: '542219562575615', + sumRewards: '984439125151230', + }, + ], + isLoading: false, + error: null, + }); + }); + + it('renders correctly with earnings history', () => { + const { getByText } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(getByText('7D')).toBeTruthy(); + expect(getByText('M')).toBeTruthy(); + expect(getByText('Y')).toBeTruthy(); + expect(getByText('Lifetime earnings')).toBeTruthy(); + expect(getByText('0.00098 ETH')).toBeTruthy(); + expect(getByText('December')).toBeTruthy(); + expect(getByText('$1.49')).toBeTruthy(); + expect(getByText('+ 0.00044 ETH')).toBeTruthy(); + expect(getByText('January')).toBeTruthy(); + expect(getByText('$1.82')).toBeTruthy(); + expect(getByText('+ 0.00054 ETH')).toBeTruthy(); + }); + + it('renders correctly with trailing zero values', () => { + (useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2022-11-02', + dailyRewards: '0', + sumRewards: '0', + }, + { + dateStr: '2022-12-31', + dailyRewards: '442219562575615', + sumRewards: '442219562575615', + }, + { + dateStr: '2023-01-01', + dailyRewards: '542219562575615', + sumRewards: '984439125151230', + }, + ], + isLoading: false, + error: null, + }); + + const { getByText, queryByText } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(getByText('Lifetime earnings')).toBeTruthy(); + expect(getByText('0.00098 ETH')).toBeTruthy(); + expect(getByText('December')).toBeTruthy(); + expect(getByText('$1.49')).toBeTruthy(); + expect(getByText('+ 0.00044 ETH')).toBeTruthy(); + expect(getByText('January')).toBeTruthy(); + expect(getByText('$1.82')).toBeTruthy(); + expect(getByText('+ 0.00054 ETH')).toBeTruthy(); + expect(queryByText('November')).toBeFalsy(); + }); + + it('should render correctly with an erc20 token asset', () => { + (useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2022-12-31', + dailyRewards: '100000000', + sumRewards: '100000000', + }, + { + dateStr: '2023-01-01', + dailyRewards: '300000000', + sumRewards: '400000000', + }, + ], + isLoading: false, + error: null, + }); + + const erc20Asset = { + address: '0xUSDC000000000000000000000000000000000000', + chainId: '0x1', + name: 'USD Coin', + symbol: 'USD Coin', + ticker: 'USDC', + isETH: false, + decimals: 6, + } as TokenI; + + const { getByText, queryByText } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(getByText('Lifetime earnings')).toBeTruthy(); + expect(getByText('400 USDC')).toBeTruthy(); + expect(getByText('December')).toBeTruthy(); + expect(getByText('$100.59')).toBeTruthy(); + expect(getByText('+ 100 USDC')).toBeTruthy(); + expect(getByText('January')).toBeTruthy(); + expect(getByText('$301.78')).toBeTruthy(); + expect(getByText('+ 300 USDC')).toBeTruthy(); + expect(queryByText('November')).toBeFalsy(); + }); + + it('should render correctly when switching currency setting', () => { + (useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2022-12-31', + dailyRewards: '100000000', + sumRewards: '100000000', + }, + { + dateStr: '2023-01-01', + dailyRewards: '300000000', + sumRewards: '400000000', + }, + ], + isLoading: false, + error: null, + }); + + const erc20Asset = { + address: '0xUSDC000000000000000000000000000000000000', + chainId: '0x1', + name: 'USD Coin', + symbol: 'USD Coin', + ticker: 'USDC', + isETH: false, + decimals: 6, + } as TokenI; + + const { getByText, queryByText } = renderWithProvider( + , + { + state: { + ...mockInitialState, + engine: { + ...mockInitialState.engine, + backgroundState: { + ...mockInitialState.engine.backgroundState, + CurrencyRateController: { + ...mockInitialState.engine.backgroundState + .CurrencyRateController, + currentCurrency: 'xlm', + currencyRates: { + ETH: { + conversionRate: 7683.22, + }, + }, + }, + }, + }, + }, + }, + ); + + expect(getByText('Lifetime earnings')).toBeTruthy(); + expect(getByText('400 USDC')).toBeTruthy(); + expect(getByText('December')).toBeTruthy(); + expect(getByText('229.77 XLM')).toBeTruthy(); + expect(getByText('+ 100 USDC')).toBeTruthy(); + expect(getByText('January')).toBeTruthy(); + expect(getByText('689.3 XLM')).toBeTruthy(); + expect(getByText('+ 300 USDC')).toBeTruthy(); + expect(queryByText('November')).toBeFalsy(); + }); + + it('renders correctly with inner and trailing zero values', () => { + (useStakingEarningsHistory as jest.Mock).mockReturnValue({ + earningsHistory: [ + { + dateStr: '2022-10-02', + dailyRewards: '0', + sumRewards: '0', + }, + { + dateStr: '2022-11-30', + dailyRewards: '442219562575615', + sumRewards: '442219562575615', + }, + { + dateStr: '2022-12-31', + dailyRewards: '0', + sumRewards: '442219562575615', + }, + { + dateStr: '2023-01-01', + dailyRewards: '542219562575615', + sumRewards: '984439125151230', + }, + ], + isLoading: false, + error: null, + }); + + const { getByText, queryByText } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(getByText('Lifetime earnings')).toBeTruthy(); + expect(getByText('0.00098 ETH')).toBeTruthy(); + expect(getByText('November')).toBeTruthy(); + expect(getByText('$1.49')).toBeTruthy(); + expect(getByText('+ 0.00044 ETH')).toBeTruthy(); + expect(getByText('December')).toBeTruthy(); + expect(getByText('+ 0 ETH')).toBeTruthy(); + expect(getByText('$0')).toBeTruthy(); + expect(getByText('January')).toBeTruthy(); + expect(getByText('$1.82')).toBeTruthy(); + expect(getByText('+ 0.00054 ETH')).toBeTruthy(); + expect(queryByText('October')).toBeFalsy(); + }); + + it('calls onTimePeriodChange and updates the selected time period', () => { + const { getByText } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + const timePeriodButton7D = getByText('7D'); + fireEvent.press(timePeriodButton7D); + + expect(getByText('December 31')).toBeTruthy(); + expect(getByText('$1.49')).toBeTruthy(); + expect(getByText('+ 0.00044 ETH')).toBeTruthy(); + expect(getByText('January 1')).toBeTruthy(); + expect(getByText('$1.82')).toBeTruthy(); + expect(getByText('+ 0.00054 ETH')).toBeTruthy(); + + const timePeriodButtonY = getByText('Y'); + fireEvent.press(timePeriodButtonY); + + expect(getByText('2022')).toBeTruthy(); + expect(getByText('$1.49')).toBeTruthy(); + expect(getByText('+ 0.00044 ETH')).toBeTruthy(); + expect(getByText('2023')).toBeTruthy(); + expect(getByText('$1.82')).toBeTruthy(); + expect(getByText('+ 0.00054 ETH')).toBeTruthy(); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.tsx new file mode 100644 index 00000000000..edd467066ca --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.tsx @@ -0,0 +1,307 @@ +import { BN } from 'ethereumjs-util'; +import React, { useMemo, useState } from 'react'; +import { View } from 'react-native'; +import useStakingEarningsHistory, { + EarningHistory, +} from '../../../hooks/useStakingEarningsHistory'; +import { StakingEarningsHistoryChart } from './StakingEarningsHistoryChart/StakingEarningsHistoryChart'; +import { ChainId } from '@metamask/controller-utils'; +import { useSelector } from 'react-redux'; +import { + selectCurrencyRates, + selectCurrentCurrency, +} from '../../../../../../selectors/currencyRateController'; +import { selectNetworkConfigurations } from '../../../../../../selectors/networkController'; +import { selectTokenMarketData } from '../../../../../../selectors/tokenRatesController'; +import { Hex } from '../../../../../../util/smart-transactions/smart-publish-hook'; +import { + EarningsHistoryData, + StakingEarningsHistoryProps, + TimePeriodGroupInfo, +} from './StakingEarningsHistory.types'; +import StakingEarningsHistoryList from './StakingEarningsHistoryList/StakingEarningsHistoryList'; +import TimePeriodButtonGroup from './StakingEarningsTimePeriod/StakingEarningsTimePeriod'; +import { + EARNINGS_HISTORY_CHART_BAR_LIMIT, + EARNINGS_HISTORY_DAYS_LIMIT, + EARNINGS_HISTORY_TIME_PERIOD_DEFAULT, +} from './StakingEarningsHistory.constants'; +import { DateRange } from './StakingEarningsTimePeriod/StakingEarningsTimePeriod.types'; +import { + fillGapsInEarningsHistory, + formatRewardsFiat, + formatRewardsNumber, + formatRewardsWei, + getEntryTimePeriodGroupInfo, +} from './StakingEarningsHistory.utils'; + +const StakingEarningsHistory = ({ asset }: StakingEarningsHistoryProps) => { + const [selectedTimePeriod, setSelectedTimePeriod] = useState( + EARNINGS_HISTORY_TIME_PERIOD_DEFAULT, + ); + const currentCurrency: string = useSelector(selectCurrentCurrency); + const multiChainMarketData = useSelector(selectTokenMarketData); + const multiChainCurrencyRates = useSelector(selectCurrencyRates); + const networkConfigurations = useSelector(selectNetworkConfigurations); + const { + earningsHistory, + isLoading: isLoadingEarningsHistory, + error: errorEarningsHistory, + } = useStakingEarningsHistory({ + chainId: asset.chainId as ChainId, + limitDays: EARNINGS_HISTORY_DAYS_LIMIT, + }); + + const ticker = asset.ticker ?? asset.symbol; + // get exchange rates for asset chainId + const exchangeRates = multiChainMarketData[asset.chainId as Hex]; + let exchangeRate = 0; + if (exchangeRates) { + exchangeRate = exchangeRates[asset.address as Hex]?.price; + } + // attempt to find native currency for asset chainId + const nativeCurrency = + networkConfigurations[asset.chainId as Hex]?.nativeCurrency; + let conversionRate = 0; + // if native currency is found, use it to get conversion rate + if (nativeCurrency) { + conversionRate = + multiChainCurrencyRates[nativeCurrency]?.conversionRate ?? conversionRate; + } + + const transformedEarningsHistory = useMemo( + () => + fillGapsInEarningsHistory(earningsHistory, EARNINGS_HISTORY_DAYS_LIMIT), + [earningsHistory], + ); + + const { earningsHistoryChartData, earningsHistoryListData } = useMemo(() => { + const historyData: EarningsHistoryData = { + earningsHistoryChartData: { + earnings: [], + earningsTotal: '0', + ticker, + }, + earningsHistoryListData: [], + }; + + if ( + isLoadingEarningsHistory || + errorEarningsHistory || + !transformedEarningsHistory || + transformedEarningsHistory.length === 0 + ) + return historyData; + + const barLimit = EARNINGS_HISTORY_CHART_BAR_LIMIT[selectedTimePeriod]; + let rewardsTotalForChartTimePeriodBN = new BN(0); + let rewardsTotalForListTimePeriodBN = new BN(0); + let trailingZeroHistoryListValues = 0; + let currentTimePeriodChartGroup: string | null = null; + let currentTimePeriodListGroup: string | null = null; + let lastEntryTimePeriodGroupInfo: TimePeriodGroupInfo = { + dateStr: '', + chartGroup: '', + chartGroupLabel: '', + listGroup: '', + listGroupLabel: '', + listGroupHeader: '', + }; + let prevLastEntryTimePeriodGroupInfo: TimePeriodGroupInfo = { + dateStr: '', + chartGroup: '', + chartGroupLabel: '', + listGroup: '', + listGroupLabel: '', + listGroupHeader: '', + }; + + // update earnings total from last sumRewards key + const updateEarningsTotal = (entry: EarningHistory) => { + historyData.earningsHistoryChartData.earningsTotal = formatRewardsWei( + entry.sumRewards, + asset, + ); + }; + + // handles chart specific data per entry + const handleChartData = (entry: EarningHistory) => { + const rewardsBN = new BN(entry.dailyRewards); + const { chartGroup: newChartGroup } = lastEntryTimePeriodGroupInfo; + // add rewards to total for time period + if (currentTimePeriodChartGroup === newChartGroup) { + rewardsTotalForChartTimePeriodBN = + rewardsTotalForChartTimePeriodBN.add(rewardsBN); + } else { + historyData.earningsHistoryChartData.earnings.unshift({ + value: parseFloat( + formatRewardsWei( + rewardsTotalForChartTimePeriodBN.toString(), + asset, + true, + ), + ), + label: prevLastEntryTimePeriodGroupInfo.chartGroupLabel, + }); + // update current time period group + currentTimePeriodChartGroup = newChartGroup; + // reset for next time period + rewardsTotalForChartTimePeriodBN = new BN(rewardsBN); + } + }; + + // handles list specific data per entry + const handleListData = (entry: EarningHistory) => { + const rewardsBN = new BN(entry.dailyRewards); + const { listGroup: newListGroup } = lastEntryTimePeriodGroupInfo; + if (currentTimePeriodListGroup === newListGroup) { + rewardsTotalForListTimePeriodBN = + rewardsTotalForListTimePeriodBN.add(rewardsBN); + } else { + if (!rewardsTotalForListTimePeriodBN.gt(new BN(0))) { + trailingZeroHistoryListValues++; + } else { + trailingZeroHistoryListValues = 0; + } + historyData.earningsHistoryListData.push({ + label: prevLastEntryTimePeriodGroupInfo.listGroupLabel, + groupLabel: prevLastEntryTimePeriodGroupInfo.chartGroupLabel, + groupHeader: prevLastEntryTimePeriodGroupInfo.listGroupHeader, + amount: formatRewardsWei(rewardsTotalForListTimePeriodBN, asset), + amountSecondaryText: formatRewardsFiat( + rewardsTotalForListTimePeriodBN, + asset, + currentCurrency, + conversionRate, + exchangeRate, + ), + ticker, + }); + + // reset for next time period + currentTimePeriodListGroup = newListGroup; + rewardsTotalForListTimePeriodBN = new BN(rewardsBN); + } + }; + + const handleListTrailingZeros = () => { + if (trailingZeroHistoryListValues > 0) { + historyData.earningsHistoryListData.splice( + historyData.earningsHistoryListData.length - + trailingZeroHistoryListValues, + trailingZeroHistoryListValues, + ); + } + }; + + const finalizeListData = () => { + if (historyData.earningsHistoryChartData.earnings.length < barLimit) { + if (!rewardsTotalForListTimePeriodBN.gt(new BN(0))) { + trailingZeroHistoryListValues++; + } else { + trailingZeroHistoryListValues = 0; + } + historyData.earningsHistoryListData.push({ + label: lastEntryTimePeriodGroupInfo.listGroupLabel, + groupLabel: lastEntryTimePeriodGroupInfo.chartGroupLabel, + groupHeader: lastEntryTimePeriodGroupInfo.listGroupHeader, + amount: formatRewardsWei(rewardsTotalForListTimePeriodBN, asset), + amountSecondaryText: formatRewardsFiat( + rewardsTotalForListTimePeriodBN, + asset, + currentCurrency, + conversionRate, + exchangeRate, + ), + ticker, + }); + } + // removes trailing zeros from history list + handleListTrailingZeros(); + }; + + const finalizeChartData = () => { + if (historyData.earningsHistoryChartData.earnings.length < barLimit) { + historyData.earningsHistoryChartData.earnings.unshift({ + value: parseFloat( + formatRewardsWei( + rewardsTotalForChartTimePeriodBN.toString(), + asset, + true, + ), + ), + label: lastEntryTimePeriodGroupInfo.chartGroupLabel, + }); + } + }; + + const finalizeProcessing = () => { + finalizeListData(); + finalizeChartData(); + }; + + const processEntry = (entry: EarningHistory, i: number) => { + if (i === transformedEarningsHistory.length - 1) { + updateEarningsTotal(entry); + } + prevLastEntryTimePeriodGroupInfo = { + ...lastEntryTimePeriodGroupInfo, + }; + lastEntryTimePeriodGroupInfo = getEntryTimePeriodGroupInfo( + entry.dateStr, + selectedTimePeriod, + ); + if (!currentTimePeriodChartGroup) { + currentTimePeriodChartGroup = lastEntryTimePeriodGroupInfo.chartGroup; + currentTimePeriodListGroup = lastEntryTimePeriodGroupInfo.listGroup; + } + if (historyData.earningsHistoryChartData.earnings.length < barLimit) { + handleChartData(entry); + handleListData(entry); + } + }; + + const processEntries = () => { + for (let i = transformedEarningsHistory.length - 1; i >= 0; i--) { + processEntry(transformedEarningsHistory[i], i); + } + finalizeProcessing(); + }; + + processEntries(); + + return historyData; + }, [ + selectedTimePeriod, + isLoadingEarningsHistory, + errorEarningsHistory, + transformedEarningsHistory, + asset, + ticker, + currentCurrency, + conversionRate, + exchangeRate, + ]); + + const onTimePeriodChange = (newTimePeriod: DateRange) => { + setSelectedTimePeriod(newTimePeriod); + }; + + return isLoadingEarningsHistory ? null : ( + + + formatRewardsNumber(value, asset)} + /> + + + ); +}; + +export default StakingEarningsHistory; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.types.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.types.ts new file mode 100644 index 00000000000..ac7b345c38c --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.types.ts @@ -0,0 +1,25 @@ +import { TokenI } from '../../../../Tokens/types'; +import { StakingEarningsHistoryChartData } from './StakingEarningsHistoryChart/StakingEarningsHistoryChart.types'; +import { StakingEarningsHistoryListData } from './StakingEarningsHistoryList/StakingEarningsHistoryList.types'; + +export interface StakingEarningsHistoryProps { + asset: TokenI; +} + +export interface TimePeriodGroupInfo { + dateStr: string; + chartGroup: string; + chartGroupLabel: string; + listGroup: string; + listGroupLabel: string; + listGroupHeader: string; +} + +export interface EarningsHistoryData { + earningsHistoryChartData: { + earnings: StakingEarningsHistoryChartData[]; + earningsTotal: string; + ticker: string; + }; + earningsHistoryListData: StakingEarningsHistoryListData[]; +} diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.test.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.test.ts new file mode 100644 index 00000000000..5bba1a3c256 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.test.ts @@ -0,0 +1,158 @@ +import { + MOCK_STAKED_ETH_ASSET, + MOCK_USDC_ASSET, +} from '../../../__mocks__/mockData'; +import { + getEntryTimePeriodGroupInfo, + fillGapsInEarningsHistory, + formatRewardsWei, + formatRewardsNumber, + formatRewardsFiat, +} from './StakingEarningsHistory.utils'; +import { DateRange } from './StakingEarningsTimePeriod/StakingEarningsTimePeriod.types'; + +const mockChartGroupDaily = { + dateStr: '2023-10-01', + chartGroup: '2023-10-01', + chartGroupLabel: 'October 1', + listGroup: '2023-10-01', + listGroupLabel: 'October 1', + listGroupHeader: '', +}; + +const mockChartGroupMonthly = { + dateStr: '2023-10-01', + chartGroup: '2023-10', + chartGroupLabel: 'October', + listGroup: '2023-10', + listGroupLabel: 'October', + listGroupHeader: '2023', +}; + +const mockChartGroupYearly = { + dateStr: '2023-10-01', + chartGroup: '2023', + chartGroupLabel: '2023', + listGroup: '2023', + listGroupLabel: '2023', + listGroupHeader: '', +}; + +describe('StakingEarningsHistory Utils', () => { + describe('getEntryTimePeriodGroupInfo', () => { + it('should return correct time period group info for daily', () => { + const result = getEntryTimePeriodGroupInfo( + mockChartGroupDaily.dateStr, + DateRange.DAILY, + ); + expect(result).toEqual(mockChartGroupDaily); + }); + + it('should return correct time period group info for monthly', () => { + const result = getEntryTimePeriodGroupInfo( + mockChartGroupMonthly.dateStr, + DateRange.MONTHLY, + ); + expect(result).toEqual(mockChartGroupMonthly); + }); + + it('should return correct time period group info for yearly', () => { + const result = getEntryTimePeriodGroupInfo( + mockChartGroupYearly.dateStr, + DateRange.YEARLY, + ); + expect(result).toEqual(mockChartGroupYearly); + }); + + it('should throw an error for unsupported time period', () => { + expect(() => + getEntryTimePeriodGroupInfo('2023-10-01', 'unsupported' as DateRange), + ).toThrow('Unsupported time period'); + }); + }); + + describe('fillGapsInEarningsHistory', () => { + it('should fill gaps in earnings history', () => { + const earningsHistory = [ + { dateStr: '2023-10-01', dailyRewards: '10', sumRewards: '10' }, + { dateStr: '2023-10-02', dailyRewards: '20', sumRewards: '30' }, + ]; + const result = fillGapsInEarningsHistory(earningsHistory, 5); + expect(result.length).toBe(5); + expect(result[0].dateStr).toBe('2023-09-28'); + expect(result[1].dateStr).toBe('2023-09-29'); + expect(result[2].dateStr).toBe('2023-09-30'); + }); + + it('should return an empty array if earnings history is null', () => { + const result = fillGapsInEarningsHistory(null, 5); + expect(result).toEqual([]); + }); + + it('should return an empty array if earnings history is empty', () => { + const result = fillGapsInEarningsHistory([], 5); + expect(result).toEqual([]); + }); + }); + + describe('formatRewardsWei', () => { + it('should format rewards value with special characters', () => { + const result = formatRewardsWei('1', MOCK_STAKED_ETH_ASSET); + expect(result).toBe('< 0.00001'); + }); + + it('should format rewards value with special characters when asset.isETH is false', () => { + const result = formatRewardsWei('1', MOCK_USDC_ASSET); + expect(result).toBe('< 0.00001'); + }); + + it('should format rewards value without special characters', () => { + const result = formatRewardsWei('1', MOCK_STAKED_ETH_ASSET, true); + expect(result).toBe('0.000000000000000001'); + }); + + it('should format rewards value without special characters when asset.isETH is false', () => { + const result = formatRewardsWei('1', MOCK_USDC_ASSET, true); + expect(result).toBe('0.000001'); + }); + }); + + describe('formatRewardsNumber', () => { + it('should format short rewards number correctly', () => { + const result = formatRewardsNumber(1.456, MOCK_STAKED_ETH_ASSET); + expect(result).toBe('1.456'); + }); + + it('should format long rewards number with 5 decimals', () => { + const result = formatRewardsNumber( + 1.456234265436536, + MOCK_STAKED_ETH_ASSET, + ); + expect(result).toBe('1.45623'); + }); + }); + + describe('formatRewardsFiat', () => { + it('should format rewards to fiat currency', () => { + const result = formatRewardsFiat( + '1000000000000000000', + MOCK_STAKED_ETH_ASSET, + 'usd', + 2000, + 1, + ); + expect(result).toBe('$2000'); + }); + + it('should format rewards to fiat currency when asset.isETH is false', () => { + const result = formatRewardsFiat( + '1000000', + MOCK_USDC_ASSET, + 'usd', + 2000, + 1, + ); + expect(result).toBe('$2000'); + }); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.ts new file mode 100644 index 00000000000..0c305cca66b --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistory.utils.ts @@ -0,0 +1,177 @@ +import { + balanceToFiatNumber, + renderFromTokenMinimalUnit, + renderFiat, + fromTokenMinimalUnit, + weiToFiatNumber, + renderFromWei, + fromWei, +} from '../../../../../../util/number'; +import { BN } from 'ethereumjs-util'; +import { TimePeriodGroupInfo } from './StakingEarningsHistory.types'; +import { DateRange } from './StakingEarningsTimePeriod/StakingEarningsTimePeriod.types'; +import BigNumber from 'bignumber.js'; +import { EarningHistory } from '../../../hooks/useStakingEarningsHistory'; +import { TokenI } from '../../../../Tokens/types'; + +/** + * Formats the date string into a time period group info object + * + * @param {string} dateStr - The date string YYYY-MM-DD to format. + * @param {DateRange} selectedTimePeriod - The selected time period. + * @returns {TimePeriodGroupInfo} The formatted time period group info object. + */ +export const getEntryTimePeriodGroupInfo = ( + dateStr: string, + selectedTimePeriod: DateRange, +): TimePeriodGroupInfo => { + const [newYear, newMonth] = dateStr.split('-'); + const date = new Date(dateStr); + date.setUTCHours(0, 0, 0, 0); + const timePeriodInfo: TimePeriodGroupInfo = { + dateStr, + chartGroup: '', + chartGroupLabel: '', + listGroup: '', + listGroupLabel: '', + listGroupHeader: '', + }; + const dayLabel = date.toLocaleString('fullwide', { + month: 'long', + day: 'numeric', + timeZone: 'UTC', + }); + const monthLabel = date.toLocaleString('fullwide', { + month: 'long', + timeZone: 'UTC', + }); + const yearLabel = date.toLocaleString('fullwide', { + year: 'numeric', + timeZone: 'UTC', + }); + switch (selectedTimePeriod) { + case DateRange.DAILY: + timePeriodInfo.chartGroup = dateStr; + timePeriodInfo.chartGroupLabel = dayLabel; + timePeriodInfo.listGroup = dateStr; + timePeriodInfo.listGroupLabel = dayLabel; + break; + case DateRange.MONTHLY: + timePeriodInfo.chartGroup = `${newYear}-${newMonth}`; + timePeriodInfo.chartGroupLabel = monthLabel; + timePeriodInfo.listGroup = `${newYear}-${newMonth}`; + timePeriodInfo.listGroupLabel = monthLabel; + timePeriodInfo.listGroupHeader = newYear; + break; + case DateRange.YEARLY: + timePeriodInfo.chartGroup = newYear; + timePeriodInfo.chartGroupLabel = yearLabel; + timePeriodInfo.listGroup = newYear; + timePeriodInfo.listGroupLabel = yearLabel; + break; + default: + throw new Error('Unsupported time period'); + } + return timePeriodInfo; +}; + +/** + * Fills gaps in earnings history by adding zero values for days missing out of the limitDays + * + * @param {EarningHistory[] | null} earningsHistory - The earnings history to fill gaps in. + * @param {number} limitDays - The number of days to fill gaps for. + * @returns {EarningHistory[]} The filled earnings history. + */ +export const fillGapsInEarningsHistory = ( + earningsHistory: EarningHistory[] | null, + limitDays: number, +): EarningHistory[] => { + if (!earningsHistory?.length) return []; + const gapFilledEarningsHistory = [...earningsHistory]; + const earliestDate = new Date(earningsHistory[0].dateStr); + const daysToFill = limitDays - earningsHistory.length; + const gapDate = new Date(earliestDate); + gapDate.setUTCHours(0, 0, 0, 0); + for (let i = 0; i < daysToFill; i++) { + gapDate.setDate(gapDate.getDate() - 1); + gapFilledEarningsHistory.unshift({ + dateStr: gapDate.toISOString().split('T')[0], + dailyRewards: '0', + sumRewards: '0', + }); + } + return gapFilledEarningsHistory; +}; + +/** + * Formats the rewards value from minimal unit to string representation + * + * @param {number | string | BN} rewardsValue - The rewards value in minimal units. + * @param {TokenI} asset - The asset to format the rewards value for. + * @param {boolean} [isRemoveSpecialCharacters=false] - A flag indicating whether to remove special characters from the formatted output. + * @returns {string} The formatted rewards value as a string. + */ +export const formatRewardsWei = ( + rewardsValue: number | string | BN, + asset: TokenI, + isRemoveSpecialCharacters: boolean = false, +): string => { + if (!isRemoveSpecialCharacters) { + // return a string with possible special characters in display formatting + return asset.isETH + ? renderFromWei(rewardsValue) + : renderFromTokenMinimalUnit(rewardsValue, asset.decimals); + } + // return a string without special characters + return asset.isETH + ? fromWei(rewardsValue) + : fromTokenMinimalUnit(rewardsValue, asset.decimals); +}; + +/** + * Formats floating point number rewards value into a string representation + * + * @param {number} rewardsValue - The raw rewards value to format. + * @param {TokenI} asset - The asset to format the rewards value for. + * @returns {string} The formatted rewards value string. + */ +export const formatRewardsNumber = ( + rewardsValue: number, + asset: TokenI, +): string => { + const weiValue = new BN( + new BigNumber(rewardsValue) + .multipliedBy(new BigNumber(10).pow(asset.decimals)) + .toString(), + ); + return formatRewardsWei(weiValue, asset); +}; + +/** + * Formats the rewards amount into a fiat currency representation. + * + * @param {string | BN} rewardsValue - The amount of rewards to format in minimal units, which can be a string or a BigNumber (BN). + * @param {TokenI} asset - The asset to format the rewards value for. + * @param {string} currency - The currency symbol to convert to. + * @param {number} conversionRate - ETH to current currency conversion rate + * @param {number} exchangeRate - Asset to ETH conversion rate. + * @returns {string} The formatted fiat currency string. + */ +export const formatRewardsFiat = ( + rewardsValue: string | BN, + asset: TokenI, + currency: string, + conversionRate: number, + exchangeRate: number = 0, +): string => { + if (asset.isETH) { + const weiFiatNumber = weiToFiatNumber(new BN(rewardsValue), conversionRate); + return renderFiat(weiFiatNumber, currency, 2); + } + const balanceFiatNumber = balanceToFiatNumber( + renderFromTokenMinimalUnit(rewardsValue, asset.decimals), + conversionRate, + exchangeRate, + ); + return renderFiat(balanceFiatNumber, currency, 2); +}; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.styles.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.styles.ts new file mode 100644 index 00000000000..2c46ad4d0aa --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.styles.ts @@ -0,0 +1,25 @@ +import { StyleSheet } from 'react-native'; + +const styleSheet = () => + StyleSheet.create({ + stakingEarningsHistoryChart: { + height: 75, + flex: 1, + paddingTop: 16, + paddingBottom: 16, + marginBottom: 4, + }, + stakingEarningsHistoryChartHeaderContainer: { + flex: 1, // Use flex to fill the available space + justifyContent: 'center', // Center vertically + alignItems: 'center', // Center horizontally + paddingTop: 16, + paddingBottom: 16, + }, + stakingEarningsHistoryChartContainer: { + flex: 1, + width: '100%', + }, + }); + +export default styleSheet; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.test.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.test.tsx new file mode 100644 index 00000000000..36cb7e84c9f --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.test.tsx @@ -0,0 +1,202 @@ +import React from 'react'; +import { fireEvent, render, RenderResult } from '@testing-library/react-native'; +import { StakingEarningsHistoryChart } from './StakingEarningsHistoryChart'; +import { fireLayoutEvent } from '../../../../../../../util/testUtils/react-native-svg-charts'; + +jest.mock('react-native-svg-charts', () => { + const reactNativeSvgCharts = jest.requireActual('react-native-svg-charts'); // Get the actual Grid component + return { + ...reactNativeSvgCharts, + Grid: () => <>, + }; +}); + +const mockEarningsData = { + earnings: [ + { value: 1.0, label: 'Day 1' }, + { value: 3.0, label: 'Day 2' }, + { value: 2.0, label: 'Day 3' }, + ], + earningsTotal: '6.00000', + ticker: 'ETH', +}; + +const barChartComponent = ( + +); + +const renderChart = () => { + const chartContainer = render(barChartComponent); + fireLayoutEvent(chartContainer.root, { width: 500, height: 200 }); + const chart = chartContainer.getByTestId('earnings-history-chart-container') + .props.children.props.children[1].props.children.props; + return { + chartContainer, + chart, + }; +}; + +describe('StakingEarningsHistoryChart', () => { + let chartContainer: RenderResult; + let chart: RenderResult['root']; + + beforeEach(() => { + jest.clearAllMocks(); + ({ chartContainer, chart } = renderChart()); + }); + + it('renders correct initial state', async () => { + expect(chartContainer.getByText('Lifetime earnings')).toBeTruthy(); + expect(chartContainer.getByText('6.00000 ETH')).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-bar-0'), + ).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-bar-1'), + ).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-bar-2'), + ).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-line-0'), + ).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-line-1'), + ).toBeTruthy(); + expect( + chartContainer.getByTestId('earning-history-chart-line-2'), + ).toBeTruthy(); + expect(chart.data.length).toBe(mockEarningsData.earnings.length); + }); + + it('updates chart state when bar 1 is clicked', () => { + // click bar 1 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchStart', + { + nativeEvent: { locationX: 50 }, + }, + ); + // expect bar 1 to be selected and highlighted on touch + expect(chartContainer.getByText('Day 1')).toBeTruthy(); + expect(chartContainer.getByText('1.00000 ETH')).toBeTruthy(); + expect(chart.data[0].svg.fill).toBe('#1c8234'); + // end touch bar 1 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchEnd', + { + nativeEvent: { pageX: 50, pageY: 50 }, + }, + ); + // expect bar 1 to be selected and highlighted after touch end + expect(chartContainer.getByText('Day 1')).toBeTruthy(); + expect(chartContainer.getByText('1.00000 ETH')).toBeTruthy(); + expect(chart.data[0].svg.fill).toBe('#1c8234'); + }); + + it('updates chart state when bar 2 is clicked', async () => { + // click bar 2 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchStart', + { + nativeEvent: { locationX: 250 }, + }, + ); + // expect bar 2 to be selected and highlighted on touch + expect(chartContainer.getByText('Day 2')).toBeTruthy(); + expect(chartContainer.getByText('3.00000 ETH')).toBeTruthy(); + expect(chart.data[1].svg.fill).toBe('#1c8234'); + // end touch bar 2 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchEnd', + { + nativeEvent: { locationX: 250 }, + }, + ); + // expect bar 2 to be selected and highlighted after touch end + expect(chartContainer.getByText('Day 2')).toBeTruthy(); + expect(chartContainer.getByText('3.00000 ETH')).toBeTruthy(); + expect(chart.data[1].svg.fill).toBe('#1c8234'); + }); + + it('updates chart state when bar 3 is clicked', async () => { + // click bar 3 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchStart', + { + nativeEvent: { locationX: 450 }, + }, + ); + expect(chartContainer.getByText('Day 3')).toBeTruthy(); + expect(chartContainer.getByText('2.00000 ETH')).toBeTruthy(); + expect(chart.data[2].svg.fill).toBe('#1c8234'); + // end touch bar 3 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchEnd', + { + nativeEvent: { locationX: 450 }, + }, + ); + expect(chartContainer.getByText('Day 3')).toBeTruthy(); + expect(chartContainer.getByText('2.00000 ETH')).toBeTruthy(); + expect(chart.data[2].svg.fill).toBe('#1c8234'); + }); + + it('updates chart to initial state when selected bar is set unselected', async () => { + // click bar 3 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchStart', + { + nativeEvent: { locationX: 450 }, + }, + ); + // end touch bar 3 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchEnd', + { + nativeEvent: { locationX: 450 }, + }, + ); + // expect bar 3 to be selected and highlighted + expect(chart.data[2].svg.fill).toBe('#1c8234'); + // click again + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchStart', + { + nativeEvent: { locationX: 450 }, + }, + ); + // end touch bar 3 + fireEvent( + chartContainer.getByTestId('earnings-history-chart'), + 'onTouchEnd', + { + nativeEvent: { locationX: 450 }, + }, + ); + // expect bar 3 to be unselected and not highlighted + expect(chart.data[0].svg.fill).toBe('url(#bar-gradient)'); + expect(chart.data[1].svg.fill).toBe('url(#bar-gradient)'); + expect(chart.data[2].svg.fill).toBe('url(#bar-gradient)'); + // expect chart to be in initial state + expect(chartContainer.getByText('Lifetime earnings')).toBeTruthy(); + expect(chartContainer.getByText('6.00000 ETH')).toBeTruthy(); + }); + + it('renders to match snapshot', () => { + expect(chartContainer.toJSON()).toMatchSnapshot(); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.tsx new file mode 100644 index 00000000000..1bc98f34392 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.tsx @@ -0,0 +1,279 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import { GestureResponderEvent, View, LayoutChangeEvent } from 'react-native'; +import { Defs, Line, LinearGradient, Stop } from 'react-native-svg'; +import { BarChart, Grid } from 'react-native-svg-charts'; +import { useStyles } from '../../../../../../../component-library/hooks'; +import { useTheme } from '../../../../../../../util/theme'; +import styleSheet from './StakingEarningsHistoryChart.styles'; +import Text, { + TextVariant, +} from '../../../../../../../component-library/components/Texts/Text'; +import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; +import { + HorizontalLinesProps, + StakingEarningsHistoryChartProps, +} from './StakingEarningsHistoryChart.types'; + +const HorizontalLines = ({ + x, + y, + height, + bandwidth: bandWidth, + data, + onBandWidthChange, + strokeColor, +}: HorizontalLinesProps) => { + useEffect(() => { + onBandWidthChange && onBandWidthChange(bandWidth ?? 0); + }, [bandWidth, onBandWidthChange]); + + const renderBarTopLines = useCallback(() => { + if (!x || !y || !height || !data || !bandWidth) return null; + + return data.map((item, index) => ( + + )); + }, [data, x, y, height, bandWidth, strokeColor]); + + return <>{renderBarTopLines()}; +}; + +export function StakingEarningsHistoryChart({ + earnings, + ticker, + earningsTotal, + formatValue = (value) => value.toFixed(5), + onSelectedEarning, +}: StakingEarningsHistoryChartProps): React.ReactElement { + //hooks + const { colors } = useTheme(); + const { styles } = useStyles(styleSheet, {}); + + // constants + const animate = false; + const barGradientId = 'bar-gradient'; + const barGradientStop1 = { + offset: '0%', + stopColor: colors.success.muted, + stopOpacity: 0, + }; + const barGradientStop2 = { + offset: '100%', + stopColor: colors.success.muted, + stopOpacity: 0.1, + }; + const spacingDefault = 0; + + //states + const [selectedBarAmount, setSelectedBarAmount] = useState( + null, + ); + const [lastOnSelectedEarningBarIndex, setLastOnSelectedEarningBarIndex] = + useState(-1); + const [lastToggledBarIndex, setLastToggledBarIndex] = useState(-1); + const [barToggle, setBarToggle] = useState(false); + const [selectedBarIndex, setSelectedBarIndex] = useState(-1); + const [selectedBarLabel, setSelectedBarLabel] = useState(null); + const [bandWidth, setBandWidth] = useState(0); + const [spacing, setSpacing] = useState(spacingDefault); + const [chartWidth, setChartWidth] = useState(0); + const [hoveredBarIndex, setHoveredBarIndex] = useState(-1); + const [transformedData, setTransformedData] = useState< + { + value: number; + label: string; + svg: { fill: string; testID: string }; + }[] + >([]); + + // functions + const updateBarHoveredBarIndex = useCallback( + (xHover: number) => { + if (!bandWidth || !chartWidth || !earnings.length) return; + const barWidthTotal = bandWidth * earnings.length; + const spacingTotal = chartWidth - barWidthTotal; + const estimateGapSize = spacingTotal + ? spacingTotal / (earnings.length - 1) + : 0; + const barSegment = Math.floor(xHover / (bandWidth + estimateGapSize)); + if (barSegment >= 0 && barSegment < earnings.length) { + setHoveredBarIndex(barSegment); + } else { + setHoveredBarIndex(-1); + } + }, + [bandWidth, chartWidth, earnings.length], + ); + const handleTouchEnd = () => { + setHoveredBarIndex(-1); + let overrideBarToggle = !!barToggle; + if (lastToggledBarIndex !== selectedBarIndex) { + overrideBarToggle = false; + } + if (!overrideBarToggle) { + setBarToggle(true); + setLastToggledBarIndex(selectedBarIndex); + } else { + setBarToggle(false); + if ( + lastToggledBarIndex !== -1 && + lastToggledBarIndex === selectedBarIndex + ) { + setSelectedBarIndex(-1); + setLastToggledBarIndex(-1); + } + } + }; + const handleTouch = (evt: GestureResponderEvent) => { + updateBarHoveredBarIndex(evt.nativeEvent.locationX); + }; + + // update bar fill color on index change + useEffect(() => { + setTransformedData((prev) => { + const newTransformedData = [...prev]; + newTransformedData.forEach((data, index) => { + if (index === selectedBarIndex) { + data.svg.fill = colors.success.default; + } else { + data.svg.fill = `url(#${barGradientId})`; + } + }); + return newTransformedData; + }); + }, [selectedBarIndex, colors.success.default]); + // if there is graph data or width change update all state + useEffect(() => { + if (earnings && earnings.length > 0) { + let newSpacing = spacingDefault; + if (earnings.length > 1) { + newSpacing = 0.1; + } + setSpacing(newSpacing); + const newTransformedData = earnings.map((value, index) => ({ + value: value.value, + label: value.label, + svg: { + fill: `url(#${barGradientId})`, + testID: `earning-history-chart-bar-${index}`, + }, + })); + setTransformedData(newTransformedData); + } + }, [earnings, chartWidth]); + // select what is hovered over + useEffect(() => { + if (hoveredBarIndex !== -1) { + setSelectedBarIndex(hoveredBarIndex); + } + }, [hoveredBarIndex]); + // main updates, time period earnings change, selected bar change + useEffect(() => { + if (selectedBarIndex !== -1 && selectedBarIndex < earnings.length) { + const newSelectedBarAmount = formatValue( + earnings[selectedBarIndex].value, + ); + const newSelectedBarLabel = earnings[selectedBarIndex].label; + setSelectedBarAmount(newSelectedBarAmount); + setSelectedBarLabel(newSelectedBarLabel); + } else { + setSelectedBarAmount(null); + setSelectedBarLabel(null); + } + if ( + onSelectedEarning && + lastOnSelectedEarningBarIndex !== selectedBarIndex + ) { + onSelectedEarning(earnings[selectedBarIndex]); + setLastOnSelectedEarningBarIndex(selectedBarIndex); + } + }, [ + selectedBarIndex, + earnings, + formatValue, + colors.success.default, + onSelectedEarning, + lastToggledBarIndex, + lastOnSelectedEarningBarIndex, + ]); + // reset bar toggle state when earnings array changes + useEffect(() => { + // deselect all bars each change + setSelectedBarIndex(-1); + setLastToggledBarIndex(-1); + setBarToggle(false); + }, [earnings]); + + return earnings ? ( + { + const { width } = event.nativeEvent.layout; + setChartWidth(width); + }} + testID={'earnings-history-chart-container'} + > + + + + {selectedBarAmount ?? earningsTotal} {ticker} + + + {selectedBarLabel ?? `Lifetime earnings`} + + + + item.value} + spacingInner={spacing} + spacingOuter={0} + > + + + + + + + + + + + + + ) : ( + + + + ); +} diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.types.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.types.ts new file mode 100644 index 00000000000..62ee051d95b --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/StakingEarningsHistoryChart.types.ts @@ -0,0 +1,26 @@ +export interface StakingEarningsHistoryChartData { + value: number; + label: string; +} + +export interface StakingEarningsHistoryChartProps { + earnings: StakingEarningsHistoryChartData[]; + ticker: string; + earningsTotal: string; + // callback to handle selected earning + onSelectedEarning?: (earning?: { value: number; label: string }) => void; + // format the graph value from parent + formatValue?: (value: number) => string; +} + +export interface HorizontalLinesProps { + // sends bandwidth to parent + onBandWidthChange?: (bandWidth: number) => void; + strokeColor: string; + // BarChart component props are passed into all children + x?: (number: number) => number; + y?: (number: number) => number; + height?: number; + bandwidth?: number; + data?: StakingEarningsHistoryChartProps['earnings']; +} diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/__snapshots__/StakingEarningsHistoryChart.test.tsx.snap b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/__snapshots__/StakingEarningsHistoryChart.test.tsx.snap new file mode 100644 index 00000000000..0f1c7f2cf19 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryChart/__snapshots__/StakingEarningsHistoryChart.test.tsx.snap @@ -0,0 +1,265 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StakingEarningsHistoryChart renders to match snapshot 1`] = ` + + + + + 6.00000 + + ETH + + + Lifetime earnings + + + + + + + + + + + + + + + + + + + + + + + +`; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.styles.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.styles.ts new file mode 100644 index 00000000000..50277e0c15c --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.styles.ts @@ -0,0 +1,40 @@ +import { StyleSheet } from 'react-native'; + +const styleSheet = () => + StyleSheet.create({ + stakingEarningsHistoryListContainer: { + flex: 1, + paddingTop: 24, + paddingBottom: 35, + }, + lineItemContainer: { + flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'flex-start', + paddingVertical: 8, + }, + rightLineItemContainer: { + flex: 1, + width: '50%', + justifyContent: 'space-between', + alignItems: 'flex-end', + }, + rightLineItemBox: { + flex: 1, + }, + leftLineItemBox: { + width: '50%', + justifyContent: 'center', + alignItems: 'flex-start', + flex: 1, + paddingTop: 10, + paddingBottom: 10, + }, + lineItemGroupHeaderContainer: { + paddingTop: 10, + paddingBottom: 10, + }, + }); + +export default styleSheet; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.test.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.test.tsx new file mode 100644 index 00000000000..7b32c416bf8 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.test.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; +import StakingEarningsHistoryList from './StakingEarningsHistoryList'; + +describe('StakingEarningsHistoryList', () => { + const mockEarnings = [ + { + label: 'Reward 1', + amount: '1.0', + amountSecondaryText: '$3000.00', + groupLabel: 'Daily', + groupHeader: '2024', + ticker: 'ETH', + }, + { + label: 'Reward 2', + amount: '3.0', + amountSecondaryText: '$5000.00', + groupLabel: 'Daily', + groupHeader: '2024', + ticker: 'ETH', + }, + { + label: 'Reward 3', + amount: '2.0', + amountSecondaryText: '$6000.00', + groupLabel: 'Daily', + groupHeader: '2025', + ticker: 'ETH', + }, + ]; + + it('renders correctly with earnings data', () => { + const { getByText, getAllByText } = render( + , + ); + + // Check if each earning is displayed + mockEarnings.forEach((earning) => { + expect(getByText(earning.label)).toBeTruthy(); + expect(getByText(`+ ${earning.amount} ETH`)).toBeTruthy(); + expect(getByText(earning.amountSecondaryText)).toBeTruthy(); + expect(getAllByText(`2024`)).toHaveLength(1); + expect(getAllByText(`2025`)).toHaveLength(1); + }); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.tsx new file mode 100644 index 00000000000..14617fccf6d --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.tsx @@ -0,0 +1,107 @@ +import React, { useCallback } from 'react'; +import { View } from 'react-native'; +import Label from '../../../../../../../component-library/components/Form/Label'; +import Text from '../../../../../../../component-library/components/Texts/Text'; +import { TextVariant } from '../../../../../../../component-library/components/Texts/Text/Text.types'; +import { useTheme } from '../../../../../../../util/theme'; +import styleSheet from './StakingEarningsHistoryList.styles'; +import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; +import { strings } from '../../../../../../../../locales/i18n'; +import { StakingEarningsHistoryListProps } from './StakingEarningsHistoryList.types'; + +const StakingEarningsHistoryList = ({ + earnings, + filterByGroupLabel, +}: StakingEarningsHistoryListProps) => { + const { colors } = useTheme(); + const styles = styleSheet(); + + const renderEarningsList = useCallback(() => { + let lastGroupHeader: string | null = null; + return earnings.map((earning, index) => { + const isFirstEarningInGroup = earning.groupHeader !== lastGroupHeader; + lastGroupHeader = earning.groupHeader; + const isGroupHeaderVisible = + earning.groupHeader.length > 0 && isFirstEarningInGroup; + if (!filterByGroupLabel || earning.groupLabel === filterByGroupLabel) { + return ( + + {isGroupHeaderVisible && ( + + + + )} + + + + + + + + + + + {earning.amountSecondaryText} + + + + + + ); + } + return null; + }); + }, [earnings, filterByGroupLabel, styles, colors]); + + const renderLoadingSkeleton = useCallback( + () => ( + + {Array.from({ length: 7 }).map((_, index) => ( + + ))} + + ), + [], + ); + + return ( + + {earnings ? ( + <> + + {renderEarningsList()} + + ) : ( + renderLoadingSkeleton() + )} + + ); +}; + +export default StakingEarningsHistoryList; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.types.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.types.ts new file mode 100644 index 00000000000..acea05cbbe7 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsHistoryList/StakingEarningsHistoryList.types.ts @@ -0,0 +1,13 @@ +export interface StakingEarningsHistoryListProps { + earnings: StakingEarningsHistoryListData[]; + filterByGroupLabel?: string; +} + +export interface StakingEarningsHistoryListData { + label: string; + amount: string; + amountSecondaryText: string; + groupLabel: string; + groupHeader: string; + ticker: string; +} diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.styles.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.styles.ts new file mode 100644 index 00000000000..0c46050b59c --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.styles.ts @@ -0,0 +1,43 @@ +import { StyleSheet } from 'react-native'; +import { Theme } from '../../../../../../../util/theme/models'; + +const styleSheet = (params: { theme: Theme }) => { + const { theme } = params; + const { colors } = theme; + + return StyleSheet.create({ + timePeriodButtonGroupContainer: { + flexDirection: 'row', + justifyContent: 'center', + paddingTop: 32, + paddingBottom: 32, + }, + unselectedButtonLabel: { + color: colors.text.alternative, + }, + selectedButtonLabel: { + color: colors.text.alternative, + }, + buttonContainer: { + marginLeft: 8, + marginRight: 8, + }, + button: { + backgroundColor: colors.background.default, + width: '100%', + borderRadius: 32, + paddingHorizontal: 14, + paddingVertical: 7, + }, + selectedButton: { + backgroundColor: colors.background.muted, + }, + buttonLabel: { + letterSpacing: 3, + textAlign: 'center', + color: colors.text.default, + }, + }); +}; + +export default styleSheet; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.test.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.test.tsx new file mode 100644 index 00000000000..4c490eec6e3 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.test.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react-native'; +import TimePeriodButtonGroup from './StakingEarningsTimePeriod'; +import { DateRange } from './StakingEarningsTimePeriod.types'; +describe('TimePeriodButtonGroup', () => { + const mockOnTimePeriodChange = jest.fn(); + + it('renders correctly and allows time period selection', () => { + const { getByText } = render( + , + ); + + // Check if the initial time period button is rendered + expect(getByText('M')).toBeTruthy(); + + // Simulate selecting a different time period + fireEvent.press(getByText('7D')); + + // Check if the onTimePeriodChange function is called with the correct argument + expect(mockOnTimePeriodChange).toHaveBeenCalledWith(DateRange.DAILY); + }); + + it('renders all time period options', () => { + const { getByText } = render( + , + ); + + // Check if all time period buttons are rendered + expect(getByText('7D')).toBeTruthy(); + expect(getByText('M')).toBeTruthy(); + expect(getByText('Y')).toBeTruthy(); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.tsx new file mode 100644 index 00000000000..972e11870b2 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.tsx @@ -0,0 +1,85 @@ +import React, { useState } from 'react'; +import { TouchableOpacity, View } from 'react-native'; +import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; +import Text, { + TextVariant, +} from '../../../../../../../component-library/components/Texts/Text'; +import { useStyles } from '../../../../../../../component-library/hooks'; +import styleSheet from './StakingEarningsTimePeriod.styles'; +import { + DateRange, + TimePeriodButtonGroupProps, +} from './StakingEarningsTimePeriod.types'; + +const TimePeriodButtonGroup: React.FC = ({ + onTimePeriodChange = () => undefined, + initialTimePeriod, +}) => { + const [selectedButton, setSelectedButton] = useState( + () => initialTimePeriod, + ); + const [pressedButton, setPressedButton] = useState(null); + + const { styles } = useStyles(styleSheet, {}); + + const renderButton = (dateRange: DateRange, width: number) => { + const handlePress = () => { + setSelectedButton(dateRange); + onTimePeriodChange(dateRange); + }; + const handlePressIn = () => { + setPressedButton(dateRange); + }; + const handlePressOut = () => { + setPressedButton(null); + }; + + const isSelected = selectedButton === dateRange; + const isPressed = pressedButton === dateRange; + const labelStyle = + !isSelected && !isPressed + ? styles.unselectedButtonLabel + : styles.selectedButtonLabel; + const labelElement = ( + + {dateRange} + + ); + + const buttonSelectedStyle = !isSelected ? {} : styles.selectedButton; + const buttonStyle = { ...styles.button, ...buttonSelectedStyle }; + + return ( + + + + {labelElement} + + + + ); + }; + + return ( + + {initialTimePeriod ? ( + <> + {renderButton(DateRange.DAILY, 50)} + {renderButton(DateRange.MONTHLY, 45)} + {renderButton(DateRange.YEARLY, 42)} + + ) : ( + + + + )} + + ); +}; + +export default TimePeriodButtonGroup; diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.types.ts b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.types.ts new file mode 100644 index 00000000000..216fcddfd32 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistory/StakingEarningsTimePeriod/StakingEarningsTimePeriod.types.ts @@ -0,0 +1,10 @@ +export enum DateRange { + DAILY = '7D', + MONTHLY = 'M', + YEARLY = 'Y', +} + +export interface TimePeriodButtonGroupProps { + onTimePeriodChange?: (timePeriod: DateRange) => void; + initialTimePeriod: DateRange; +} diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.test.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.test.tsx new file mode 100644 index 00000000000..abeeb275305 --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.test.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { fireEvent, waitFor } from '@testing-library/react-native'; +import { WalletViewSelectorsIDs } from '../../../../../../../e2e/selectors/wallet/WalletView.selectors'; +import Routes from '../../../../../../constants/navigation/Routes'; +import renderWithProvider from '../../../../../../util/test/renderWithProvider'; +import { MOCK_STAKED_ETH_ASSET } from '../../../__mocks__/mockData'; +import StakingEarningsHistoryButton from './StakingEarningsHistoryButton'; + +const mockNavigate = jest.fn(); + +jest.mock('@react-navigation/native', () => { + const actualReactNavigation = jest.requireActual('@react-navigation/native'); + return { + ...actualReactNavigation, + useNavigation: () => ({ + navigate: mockNavigate, + }), + }; +}); + +const renderComponent = () => + renderWithProvider( + , + ); + +describe('StakingEarningsHistoryButton', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders correctly', () => { + const { getByTestId } = renderComponent(); + expect( + getByTestId(WalletViewSelectorsIDs.STAKE_EARNINGS_HISTORY_BUTTON), + ).toBeDefined(); + }); + + it('navigates to Stake Rewards History screen when stake history button is pressed', async () => { + const { getByTestId } = renderComponent(); + + fireEvent.press( + getByTestId(WalletViewSelectorsIDs.STAKE_EARNINGS_HISTORY_BUTTON), + ); + + await waitFor(() => { + expect(mockNavigate).toHaveBeenCalledWith('StakeScreens', { + screen: Routes.STAKING.EARNINGS_HISTORY, + params: { asset: MOCK_STAKED_ETH_ASSET }, + }); + }); + }); +}); diff --git a/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.tsx b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.tsx new file mode 100644 index 00000000000..f8fe909fc8a --- /dev/null +++ b/app/components/UI/Stake/components/StakingEarnings/StakingEarningsHistoryButton/StakingEarningsHistoryButton.tsx @@ -0,0 +1,42 @@ +import { useNavigation } from '@react-navigation/native'; +import React from 'react'; +import { View } from 'react-native'; +import { strings } from '../../../../../../../locales/i18n'; +import Button, { + ButtonVariants, + ButtonWidthTypes, +} from '../../../../../../component-library/components/Buttons/Button'; +import Routes from '../../../../../../constants/navigation/Routes'; +import { TokenI } from '../../../../Tokens/types'; +import { WalletViewSelectorsIDs } from '../../../../../../../e2e/selectors/wallet/WalletView.selectors'; + +interface StakingEarningsHistoryButtonProps { + asset: TokenI; +} + +const StakingEarningsHistoryButton = ({ + asset, +}: StakingEarningsHistoryButtonProps) => { + const { navigate } = useNavigation(); + + const onViewEarningsHistoryPress = () => { + navigate('StakeScreens', { + screen: Routes.STAKING.EARNINGS_HISTORY, + params: { asset }, + }); + }; + + return ( + +