Skip to content

Commit

Permalink
Merge branch 'main' into brian/multichain-token-rates
Browse files Browse the repository at this point in the history
  • Loading branch information
bergeron authored Nov 14, 2024
2 parents 14281c1 + 3af74fb commit 4a77428
Show file tree
Hide file tree
Showing 29 changed files with 1,158 additions and 405 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ jobs:
- uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 #v1
with:
ruby-version: '3.1.6'
bundler-cache: true
env:
BUNDLE_GEMFILE: ios/Gemfile
- run: yarn setup
Expand Down Expand Up @@ -181,7 +180,6 @@ jobs:
name: ios-bundle
path: ios/main.jsbundle


- name: Push bundle size to mobile_bundlesize_stats repo
run: ./scripts/push-bundle-size.sh
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { ChainId, PooledStakingContract } from '@metamask/stake-sdk';
import { Contract } from 'ethers';
import { MOCK_GET_VAULT_RESPONSE } from '../../__mocks__/mockData';
import { toWei } from '../../../../../util/number';
import { strings } from '../../../../../../locales/i18n';
// eslint-disable-next-line import/no-namespace
import * as useStakingGasFee from '../../hooks/useStakingGasFee';

function render(Component: React.ComponentType) {
return renderScreen(
Expand Down Expand Up @@ -96,7 +99,6 @@ jest.mock('../../hooks/useStakingGasFee', () => ({
__esModule: true,
default: () => ({
estimatedGasFeeWei: mockGasFee,
gasLimit: 70122,
isLoadingStakingGasFee: false,
isStakingGasFeeError: false,
refreshGasValues: jest.fn(),
Expand Down Expand Up @@ -203,5 +205,31 @@ describe('StakeInputView', () => {
screen: Routes.STAKING.MODALS.LEARN_MORE,
});
});

it('navigates to gas impact modal when gas cost is 30% or more of deposit amount', () => {
jest.spyOn(useStakingGasFee, 'default').mockReturnValue({
estimatedGasFeeWei: toWei('0.25'),
isLoadingStakingGasFee: false,
isStakingGasFeeError: false,
refreshGasValues: jest.fn(),
});

render(StakeInputView);

fireEvent.press(screen.getByText('25%'));

fireEvent.press(screen.getByText(strings('stake.review')));

expect(mockNavigate).toHaveBeenLastCalledWith('StakeModals', {
screen: Routes.STAKING.MODALS.GAS_IMPACT,
params: {
amountFiat: '750',
amountWei: '375000000000000000',
annualRewardRate: '2.5%',
annualRewardsETH: '0.00938 ETH',
annualRewardsFiat: '18.75 USD',
},
});
});
});
});
49 changes: 34 additions & 15 deletions app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const StakeInputView = () => {
isLoadingVaultData,
handleMax,
balanceValue,
isHighGasCostImpact,
isLoadingStakingGasFee,
} = useStakingInputHandlers();

const navigateToLearnMoreModal = () => {
Expand All @@ -55,16 +57,30 @@ const StakeInputView = () => {
});
trackEvent(
createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED)
.addProperties({
selected_provider: 'consensys',
text: 'Tooltip Question Mark Trigger',
location: 'Stake Input View'
})
.build()
.addProperties({
selected_provider: 'consensys',
text: 'Tooltip Question Mark Trigger',
location: 'Stake Input View',
})
.build(),
);
};

const handleStakePress = useCallback(() => {
if (isHighGasCostImpact()) {
navigation.navigate('StakeModals', {
screen: Routes.STAKING.MODALS.GAS_IMPACT,
params: {
amountWei: amountWei.toString(),
amountFiat: fiatAmount,
annualRewardsETH,
annualRewardsFiat,
annualRewardRate,
},
});
return;
}

navigation.navigate('StakeScreens', {
screen: Routes.STAKING.STAKE_CONFIRMATION,
params: {
Expand All @@ -77,23 +93,24 @@ const StakeInputView = () => {
});
trackEvent(
createEventBuilder(MetaMetricsEvents.REVIEW_STAKE_BUTTON_CLICKED)
.addProperties({
selected_provider: 'consensys',
tokens_to_stake_native_value: amountEth,
tokens_to_stake_usd_value: fiatAmount,
})
.build(),
.addProperties({
selected_provider: 'consensys',
tokens_to_stake_native_value: amountEth,
tokens_to_stake_usd_value: fiatAmount,
})
.build(),
);
}, [
amountEth,
isHighGasCostImpact,
navigation,
amountWei,
fiatAmount,
annualRewardsETH,
annualRewardsFiat,
annualRewardRate,
trackEvent,
createEventBuilder
createEventBuilder,
amountEth,
]);

const handleMaxButtonPress = () => {
Expand Down Expand Up @@ -164,7 +181,9 @@ const StakeInputView = () => {
size={ButtonSize.Lg}
labelTextVariant={TextVariant.BodyMDMedium}
variant={ButtonVariants.Primary}
isDisabled={isOverMaximum || !isNonZeroAmount}
isDisabled={
isOverMaximum || !isNonZeroAmount || isLoadingStakingGasFee
}
width={ButtonWidthTypes.Full}
onPress={handleStakePress}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { StyleSheet } from 'react-native';

const styleSheet = () =>
StyleSheet.create({
container: {
paddingHorizontal: 16,
},
content: {
paddingBottom: 16,
},
footer: {
paddingBottom: 16,
},
});

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import renderWithProvider from '../../../../../util/test/renderWithProvider';
import { GasImpactModalProps } from './GasImpactModal.types';
import GasImpactModal from './index';
import { Metrics, SafeAreaProvider } from 'react-native-safe-area-context';
import { fireEvent } from '@testing-library/react-native';
import { strings } from '../../../../../../locales/i18n';

const mockNavigate = jest.fn();
const mockGoBack = jest.fn();

jest.mock('@react-navigation/native', () => {
const actualReactNavigation = jest.requireActual('@react-navigation/native');
return {
...actualReactNavigation,
useNavigation: () => ({
navigate: mockNavigate,
goBack: mockGoBack,
}),
};
});

const props: GasImpactModalProps = {
route: {
key: '1',
params: {
amountWei: '3210000000000000',
amountFiat: '7.46',
annualRewardRate: '2.5%',
annualRewardsETH: '2.5 ETH',
annualRewardsFiat: '$5000',
},
name: 'params',
},
};

const initialMetrics: Metrics = {
frame: { x: 0, y: 0, width: 320, height: 640 },
insets: { top: 0, left: 0, right: 0, bottom: 0 },
};

const renderGasImpactModal = () =>
renderWithProvider(
<SafeAreaProvider initialMetrics={initialMetrics}>
<GasImpactModal {...props} />,
</SafeAreaProvider>,
);

describe('GasImpactModal', () => {
it('render matches snapshot', () => {
const { toJSON } = renderGasImpactModal();

expect(toJSON()).toMatchSnapshot();
});

it('navigates to StakeConfirmationView on approval', () => {
const { getByText } = renderGasImpactModal();

const proceedAnywayButton = getByText(strings('stake.proceed_anyway'));

fireEvent.press(proceedAnywayButton);

expect(mockNavigate).toHaveBeenCalledTimes(1);
});

it('closes gas impact modal on cancel', () => {
const { getByText } = renderGasImpactModal();

const proceedAnywayButton = getByText(strings('stake.cancel'));

fireEvent.press(proceedAnywayButton);

expect(mockGoBack).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RouteProp } from '@react-navigation/native';

interface GasImpactModalRouteParams {
amountWei: string;
amountFiat: string;
annualRewardsETH: string;
annualRewardsFiat: string;
annualRewardRate: string;
}

export interface GasImpactModalProps {
route: RouteProp<{ params: GasImpactModalRouteParams }, 'params'>;
}
Loading

0 comments on commit 4a77428

Please sign in to comment.