From 6fa36d8540c1006e113d3372c2658512821caecc Mon Sep 17 00:00:00 2001 From: Matthew Grainger Date: Tue, 7 Jan 2025 17:14:06 -0500 Subject: [PATCH] feat: removed pooled staking feature flag --- .../UI/AssetOverview/Balance/Balance.tsx | 5 +- .../UI/AssetOverview/Balance/index.test.tsx | 74 +++++++++++++++++-- .../TokenDetails/TokenDetails.tsx | 3 +- .../StakeButton/StakeButton.test.tsx | 4 - .../UI/Stake/components/StakeButton/index.tsx | 7 +- .../StakingBalance/StakingBalance.tsx | 2 +- .../StakingEarnings/StakingEarnings.test.tsx | 4 - .../components/StakingEarnings/index.tsx | 8 +- app/components/UI/Stake/constants/index.ts | 4 - .../UI/Stake/sdk/stakeSdkProvider.test.tsx | 4 - app/components/UI/Tokens/index.test.tsx | 4 - app/core/Engine/Engine.ts | 27 ++++--- bitrise.yml | 21 +++--- 13 files changed, 96 insertions(+), 71 deletions(-) diff --git a/app/components/UI/AssetOverview/Balance/Balance.tsx b/app/components/UI/AssetOverview/Balance/Balance.tsx index 82662417e44..8dc96b67932 100644 --- a/app/components/UI/AssetOverview/Balance/Balance.tsx +++ b/app/components/UI/AssetOverview/Balance/Balance.tsx @@ -29,7 +29,6 @@ import Text, { } from '../../../../component-library/components/Texts/Text'; import { TokenI } from '../../Tokens/types'; import { useNavigation } from '@react-navigation/native'; -import { isPooledStakingFeatureEnabled } from '../../Stake/constants'; import StakingBalance from '../../Stake/components/StakingBalance/StakingBalance'; import { PopularList, @@ -167,9 +166,7 @@ const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { {asset.name || asset.symbol} - {isPooledStakingFeatureEnabled() && asset?.isETH && ( - - )} + {asset?.isETH && } ); }; diff --git a/app/components/UI/AssetOverview/Balance/index.test.tsx b/app/components/UI/AssetOverview/Balance/index.test.tsx index ba5dd5f2fc3..724b02bc1a4 100644 --- a/app/components/UI/AssetOverview/Balance/index.test.tsx +++ b/app/components/UI/AssetOverview/Balance/index.test.tsx @@ -58,11 +58,21 @@ const mockETH = { isNative: true, }; -const mockInitialState = { - engine: { - backgroundState, +jest.mock('../../../../core/Engine', () => ({ + context: { + NetworkController: { + getNetworkClientById: () => ({ + configuration: { + chainId: '0x1', + rpcUrl: 'https://mainnet.infura.io/v3', + ticker: 'ETH', + type: 'custom', + }, + }), + findNetworkClientIdByChainId: () => 'mainnet', + }, }, -}; +})); jest.mock('../../../../util/networks', () => ({ ...jest.requireActual('../../../../util/networks'), @@ -74,6 +84,48 @@ jest.mock('../../../../util/networks', () => ({ isPortfolioViewEnabled: jest.fn(), })); +jest.mock('../../Stake/hooks/usePooledStakes', () => ({ + __esModule: true, + default: () => ({ + pooledStakesData: { + account: '0xabc', + assets: '10000000000000000', + exitRequests: [], + lifetimeRewards: '100000000000000', + }, + exchangeRate: 1.018, + hasStakedPositions: true, + hasEthToUnstake: true, + isLoadingPooledStakesData: false, + }), +})); + +jest.mock('../../Stake/hooks/useVaultData', () => ({ + __esModule: true, + default: () => ({ + vaultData: { + apy: '2.437033146840025387168141592920355', + capacity: '1000000000000000000000000000000000000000000000000000000000000', + feePercent: 1500, + totalAssets: '10000000000000000000000', + vaultAddress: '0xdef', + }, + }), +})); + +jest.mock('../../Stake/hooks/useStakingEligibility', () => ({ + __esModule: true, + default: () => ({ + isEligible: true, + }), +})); + +const mockInitialState = { + engine: { + backgroundState, + }, +}; + describe('Balance', () => { const mockStore = configureMockStore(); const store = mockStore(mockInitialState); @@ -131,13 +183,19 @@ describe('Balance', () => { }); it('should not fire navigation event for native tokens', () => { - const { queryByTestId } = render( + const { queryAllByTestId } = render( - + , , ); - const assetElement = queryByTestId('asset-ETH'); - fireEvent.press(assetElement); + + // Includes native ETH and staked ETH + const ethElements = queryAllByTestId('asset-ETH'); + + ethElements.forEach((ethElement) => { + fireEvent.press(ethElement); + }); + expect(mockNavigate).toHaveBeenCalledTimes(0); }); diff --git a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx index 54df1781873..8b7203262f1 100644 --- a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx +++ b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.tsx @@ -28,7 +28,6 @@ import Logger from '../../../../util/Logger'; import TokenDetailsList from './TokenDetailsList'; import MarketDetailsList from './MarketDetailsList'; import { TokenI } from '../../Tokens/types'; -import { isPooledStakingFeatureEnabled } from '../../Stake/constants'; import StakingEarnings from '../../Stake/components/StakingEarnings'; import { isPortfolioViewEnabled } from '../../../../util/networks'; @@ -147,7 +146,7 @@ const TokenDetails: React.FC = ({ asset }) => { return ( - {asset.isETH && isPooledStakingFeatureEnabled() && } + {asset.isETH && } {(asset.isETH || tokenMetadata) && ( )} diff --git a/app/components/UI/Stake/components/StakeButton/StakeButton.test.tsx b/app/components/UI/Stake/components/StakeButton/StakeButton.test.tsx index 637ae857c92..2d4374e5c4b 100644 --- a/app/components/UI/Stake/components/StakeButton/StakeButton.test.tsx +++ b/app/components/UI/Stake/components/StakeButton/StakeButton.test.tsx @@ -21,10 +21,6 @@ jest.mock('@react-navigation/native', () => { }; }); -jest.mock('../../constants', () => ({ - isPooledStakingFeatureEnabled: jest.fn().mockReturnValue(true), -})); - jest.mock('../../../../hooks/useMetrics'); (useMetrics as jest.MockedFn).mockReturnValue({ diff --git a/app/components/UI/Stake/components/StakeButton/index.tsx b/app/components/UI/Stake/components/StakeButton/index.tsx index ca578bef3bd..14b62a11689 100644 --- a/app/components/UI/Stake/components/StakeButton/index.tsx +++ b/app/components/UI/Stake/components/StakeButton/index.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { TokenI, BrowserTab } from '../../../Tokens/types'; import { useNavigation } from '@react-navigation/native'; -import { isPooledStakingFeatureEnabled } from '../../constants'; import Routes from '../../../../../constants/navigation/Routes'; import { useSelector } from 'react-redux'; import AppConstants from '../../../../../core/AppConstants'; @@ -42,7 +41,7 @@ const StakeButtonContent = ({ asset }: StakeButtonProps) => { const onStakeButtonPress = async () => { const { isEligible } = await refreshPooledStakingEligibility(); - if (isPooledStakingFeatureEnabled() && isEligible) { + if (isEligible) { navigation.navigate('StakeScreens', { screen: Routes.STAKING.STAKE }); } else { const existingStakeTab = browserTabs.find((tab: BrowserTab) => @@ -87,9 +86,7 @@ const StakeButtonContent = ({ asset }: StakeButtonProps) => { {' • '} - {isPooledStakingFeatureEnabled() - ? `${strings('stake.earn')} ` - : `${strings('stake.stake')} `} + {`${strings('stake.earn')} `} { return ( - {hasEthToUnstake && ( + {hasEthToUnstake && !isLoadingPooledStakesData && ( ({ - isPooledStakingFeatureEnabled: jest.fn().mockReturnValue(true), -})); - const mockNavigate = jest.fn(); const STATE_MOCK = { diff --git a/app/components/UI/Stake/components/StakingEarnings/index.tsx b/app/components/UI/Stake/components/StakingEarnings/index.tsx index b5a7d035c02..c16fe9bfee4 100644 --- a/app/components/UI/Stake/components/StakingEarnings/index.tsx +++ b/app/components/UI/Stake/components/StakingEarnings/index.tsx @@ -15,7 +15,6 @@ import ButtonIcon, { } from '../../../../../component-library/components/Buttons/ButtonIcon'; import useTooltipModal from '../../../../../components/hooks/useTooltipModal'; import { strings } from '../../../../../../locales/i18n'; -import { isPooledStakingFeatureEnabled } from '../../../Stake/constants'; import useStakingChain from '../../hooks/useStakingChain'; import { StakeSDKProvider } from '../../sdk/stakeSdkProvider'; import useStakingEarnings from '../../hooks/useStakingEarnings'; @@ -47,12 +46,7 @@ const StakingEarningsContent = () => { const { isStakingSupportedChain } = useStakingChain(); - if ( - !isPooledStakingFeatureEnabled() || - !isStakingSupportedChain || - !hasStakedPositions - ) - return <>; + if (!isStakingSupportedChain || !hasStakedPositions) return <>; return ( diff --git a/app/components/UI/Stake/constants/index.ts b/app/components/UI/Stake/constants/index.ts index 4d59090ccc0..c35f1f017da 100644 --- a/app/components/UI/Stake/constants/index.ts +++ b/app/components/UI/Stake/constants/index.ts @@ -1,6 +1,2 @@ -/* eslint-disable import/prefer-default-export */ -export const isPooledStakingFeatureEnabled = () => - process.env.MM_POOLED_STAKING_UI_ENABLED === 'true'; - export const POOLED_STAKING_FAQ_URL = 'https://support.metamask.io/metamask-portfolio/move-crypto/stake/staking-pool/'; diff --git a/app/components/UI/Stake/sdk/stakeSdkProvider.test.tsx b/app/components/UI/Stake/sdk/stakeSdkProvider.test.tsx index 142dc2d1ad6..3ba6230913e 100644 --- a/app/components/UI/Stake/sdk/stakeSdkProvider.test.tsx +++ b/app/components/UI/Stake/sdk/stakeSdkProvider.test.tsx @@ -8,10 +8,6 @@ import { View } from 'react-native'; import Text from '../../../../component-library/components/Texts/Text'; import { MOCK_POOL_STAKING_SDK } from '../__mocks__/mockData'; -jest.mock('../../Stake/constants', () => ({ - isPooledStakingFeatureEnabled: jest.fn().mockReturnValue(true), -})); - jest.mock('../../../../core/Engine', () => ({ context: { NetworkController: { diff --git a/app/components/UI/Tokens/index.test.tsx b/app/components/UI/Tokens/index.test.tsx index 4928d4368e1..e8a0df5103e 100644 --- a/app/components/UI/Tokens/index.test.tsx +++ b/app/components/UI/Tokens/index.test.tsx @@ -236,10 +236,6 @@ jest.mock('@react-navigation/native', () => { }; }); -jest.mock('../../UI/Stake/constants', () => ({ - isPooledStakingFeatureEnabled: jest.fn().mockReturnValue(true), -})); - jest.mock('../../UI/Stake/hooks/useStakingEligibility', () => ({ __esModule: true, default: jest.fn(() => ({ diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 95c23de7ba2..e7a275f443d 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -197,7 +197,6 @@ import { getSmartTransactionMetricsProperties } from '../../util/smart-transacti import { trace } from '../../util/trace'; import { MetricsEventBuilder } from '../Analytics/MetricsEventBuilder'; import { JsonMap } from '../Analytics/MetaMetrics.types'; -import { isPooledStakingFeatureEnabled } from '../../components/UI/Stake/constants'; import { ControllerMessenger, EngineState, @@ -735,7 +734,7 @@ export class Engine { assetsContractController.getStakedBalanceForChain.bind( assetsContractController, ), - includeStakedAssets: isPooledStakingFeatureEnabled(), + includeStakedAssets: true, }); const permissionController = new PermissionController({ messenger: this.controllerMessenger.getRestricted({ @@ -971,8 +970,8 @@ export class Engine { disableSnaps: !isBasicFunctionalityToggleEnabled(), }), clientCryptography: { - pbkdf2Sha512: pbkdf2 - } + pbkdf2Sha512: pbkdf2, + }, }); const authenticationController = new AuthenticationController.Controller({ @@ -1173,7 +1172,7 @@ export class Engine { return Boolean( hasProperty(showIncomingTransactions, currentChainId) && - showIncomingTransactions?.[currentHexChainId], + showIncomingTransactions?.[currentHexChainId], ); }, updateTransactions: true, @@ -1302,7 +1301,9 @@ export class Engine { .addProperties({ token_standard: 'ERC20', asset_type: 'token', - chain_id: getDecimalChainId(getGlobalChainId(networkController)), + chain_id: getDecimalChainId( + getGlobalChainId(networkController), + ), }) .build(), ), @@ -1518,7 +1519,7 @@ export class Engine { if ( state.networksMetadata[state.selectedNetworkClientId].status === NetworkStatus.Available && - getGlobalChainId(networkController) !== currentChainId + getGlobalChainId(networkController) !== currentChainId ) { // We should add a state or event emitter saying the provider changed setTimeout(() => { @@ -1538,7 +1539,9 @@ export class Engine { } catch (error) { console.error( error, - `Network ID not changed, current chainId: ${getGlobalChainId(networkController)}`, + `Network ID not changed, current chainId: ${getGlobalChainId( + networkController, + )}`, ); } }, @@ -1780,7 +1783,7 @@ export class Engine { const tokenBalances = allTokenBalances?.[selectedInternalAccount.address as Hex]?.[ - chainId + chainId ] ?? {}; tokens.forEach( (item: { address: string; balance?: string; decimals: number }) => { @@ -1791,9 +1794,9 @@ export class Engine { item.balance || (item.address in tokenBalances ? renderFromTokenMinimalUnit( - tokenBalances[item.address as Hex], - item.decimals, - ) + tokenBalances[item.address as Hex], + item.decimals, + ) : undefined); const tokenBalanceFiat = balanceToFiatNumber( // TODO: Fix this by handling or eliminating the undefined case diff --git a/bitrise.yml b/bitrise.yml index e46fa35dea7..b3a397e35ec 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -114,7 +114,7 @@ stages: workflows: - deploy_android_to_store: {} create_build_qa_and_expo: - workflows: + workflows: - build_android_devbuild: {} - build_android_qa: {} - build_ios_devbuild: {} @@ -1247,20 +1247,20 @@ workflows: - content: |- # Define the source path of the generated APK SOURCE_APK_PATH="$PROJECT_LOCATION/app/build/outputs/apk/prod/debug/app-prod-debug.apk" - + # Define the destination path with the new name DEST_APK_PATH="$BITRISE_DEPLOY_DIR/android-expo-dev-build.apk" - + # Copy and rename the APK cp "$SOURCE_APK_PATH" "$DEST_APK_PATH" - + # Optionally, print the new path for verification echo "APK has been copied and renamed to: $DEST_APK_PATH" - deploy-to-bitrise-io@2.2.3: is_always_run: false is_skippable: true inputs: - - deploy_path: "$BITRISE_DEPLOY_DIR/android-expo-dev-build.apk" + - deploy_path: '$BITRISE_DEPLOY_DIR/android-expo-dev-build.apk' title: Bitrise Deploy APK meta: bitrise.io: @@ -1537,13 +1537,13 @@ workflows: - content: |- # Define the source path of the generated IPA SOURCE_IPA_PATH="ios/build/output/MetaMask.ipa" - + # Define the destination path with the new name DEST_IPA_PATH="$BITRISE_DEPLOY_DIR/ios-expo-dev-build.ipa" - + # Copy and rename the IPA cp "$SOURCE_IPA_PATH" "$DEST_IPA_PATH" - + # Optionally, print the new path for verification echo "IPA has been copied and renamed to: $DEST_IPA_PATH" - deploy-to-bitrise-io@2.2.3: @@ -1551,7 +1551,7 @@ workflows: is_skippable: true inputs: - pipeline_intermediate_files: ios/build/output/MetaMask.ipa:BITRISE_APP_STORE_IPA_PATH - - deploy_path: "$BITRISE_DEPLOY_DIR/ios-expo-dev-build.ipa" + - deploy_path: '$BITRISE_DEPLOY_DIR/ios-expo-dev-build.ipa' title: Deploy iOS IPA build_ios_qa: envs: @@ -1755,9 +1755,6 @@ app: - opts: is_expand: false MM_PERMISSIONS_SETTINGS_V1_ENABLED: false - - opts: - is_expand: false - MM_POOLED_STAKING_UI_ENABLED: true - opts: is_expand: false MM_SECURITY_ALERTS_API_ENABLED: true