diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx index 109fe3e7fac..a0c36a05079 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.test.tsx @@ -53,6 +53,15 @@ jest.mock('@react-navigation/native', () => { }; }); +jest.mock('../../hooks/usePoolStakedDeposit', () => ({ + __esModule: true, + default: () => ({ + poolStakingContract: {}, + estimateDepositGas: jest.fn(), + attemptDepositTransaction: jest.fn(), + }), +})); + describe('StakeConfirmationView', () => { it('render matches snapshot', () => { const props: StakeConfirmationViewProps = { diff --git a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx index 2f1a4890286..857752feafb 100644 --- a/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx +++ b/app/components/UI/Stake/Views/StakeConfirmationView/StakeConfirmationView.tsx @@ -11,6 +11,7 @@ import ConfirmationFooter from '../../components/StakingConfirmation/Confirmatio import { StakeConfirmationViewProps } from './StakeConfirmationView.types'; import { MOCK_GET_VAULT_RESPONSE } from '../../components/StakingBalance/mockData'; import { strings } from '../../../../../../locales/i18n'; +import { FooterButtonGroupActions } from '../../components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.types'; const MOCK_REWARD_DATA = { REWARDS: { @@ -52,7 +53,10 @@ const StakeConfirmationView = ({ route }: StakeConfirmationViewProps) => { /> - + ); }; diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx index 9648fba601e..a44c0971a53 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.test.tsx @@ -6,6 +6,8 @@ import Routes from '../../../../../constants/navigation/Routes'; import { backgroundState } from '../../../../../util/test/initial-root-state'; import { BN } from 'ethereumjs-util'; import { Stake } from '../../sdk/stakeSdkProvider'; +import { ChainId, PooledStakingContract } from '@metamask/stake-sdk'; +import { Contract } from 'ethers'; function render(Component: React.ComponentType) { return renderScreen( @@ -53,15 +55,30 @@ jest.mock('../../../../../selectors/currencyRateController.ts', () => ({ const mockBalanceBN = new BN('1500000000000000000'); +const mockPooledStakingContractService: PooledStakingContract = { + chainId: ChainId.ETHEREUM, + connectSignerOrProvider: jest.fn(), + contract: new Contract('0x0000000000000000000000000000000000000000', []), + convertToShares: jest.fn(), + encodeClaimExitedAssetsTransactionData: jest.fn(), + encodeDepositTransactionData: jest.fn(), + encodeEnterExitQueueTransactionData: jest.fn(), + encodeMulticallTransactionData: jest.fn(), + estimateClaimExitedAssetsGas: jest.fn(), + estimateDepositGas: jest.fn(), + estimateEnterExitQueueGas: jest.fn(), + estimateMulticallGas: jest.fn(), +}; + jest.mock('../../hooks/useStakeContext.ts', () => ({ useStakeContext: jest.fn(() => { const stakeContext: Stake = { setSdkType: jest.fn(), - sdkService: undefined - } - return stakeContext - }) -})) + stakingContract: mockPooledStakingContractService, + }; + return stakeContext; + }), +})); jest.mock('../../hooks/useBalance', () => ({ __esModule: true, diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx index 782e4d5ab3c..0431e67a77f 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx @@ -19,7 +19,6 @@ import styleSheet from './StakeInputView.styles'; import useStakingInputHandlers from '../../hooks/useStakingInput'; import useBalance from '../../hooks/useBalance'; import InputDisplay from '../../components/InputDisplay'; -import { useStakeContext } from '../../hooks/useStakeContext'; const StakeInputView = () => { const title = strings('stake.stake_eth'); @@ -44,9 +43,6 @@ const StakeInputView = () => { estimatedAnnualRewards, } = useStakingInputHandlers(balanceWei); - - const { sdkService } = useStakeContext(); - const navigateToLearnMoreModal = () => { navigation.navigate('StakeModals', { screen: Routes.STAKING.MODALS.LEARN_MORE, @@ -61,8 +57,7 @@ const StakeInputView = () => { amountFiat: fiatAmount, }, }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [amountWei, fiatAmount, navigation, sdkService]); + }, [amountWei, fiatAmount, navigation]); const balanceText = strings('stake.balance'); diff --git a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.test.tsx b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.test.tsx index 36db2a000b1..011c63bfbf7 100644 --- a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.test.tsx +++ b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.test.tsx @@ -1,18 +1,58 @@ import React from 'react'; import renderWithProvider from '../../../../../../util/test/renderWithProvider'; import ConfirmationFooter from './ConfirmationFooter'; +import { ConfirmationFooterProps } from './ConfirmationFooter.types'; +import { createMockAccountsControllerState } from '../../../../../../util/test/accountsControllerTestUtils'; +import { backgroundState } from '../../../../../../util/test/initial-root-state'; +import { FooterButtonGroupActions } from './FooterButtonGroup/FooterButtonGroup.types'; + +const MOCK_ADDRESS_1 = '0x0'; +const MOCK_ADDRESS_2 = '0x1'; + +const MOCK_ACCOUNTS_CONTROLLER_STATE = createMockAccountsControllerState([ + MOCK_ADDRESS_1, + MOCK_ADDRESS_2, +]); + +const mockInitialState = { + settings: {}, + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + }, + }, +}; jest.mock('@react-navigation/native', () => { const actualReactNavigation = jest.requireActual('@react-navigation/native'); return { ...actualReactNavigation, - useNavigation: jest.fn(), + useNavigation: () => ({ + navigate: jest.fn(), + }), }; }); +jest.mock('../../../hooks/usePoolStakedDeposit', () => ({ + __esModule: true, + default: () => ({ + poolStakingContract: {}, + estimateDepositGas: jest.fn(), + attemptDepositTransaction: jest.fn(), + }), +})); + describe('ConfirmationFooter', () => { it('render matches snapshot', () => { - const { toJSON } = renderWithProvider(); + const props: ConfirmationFooterProps = { + valueWei: '3210000000000000', + action: FooterButtonGroupActions.STAKE, + }; + + const { toJSON } = renderWithProvider(, { + state: mockInitialState, + }); expect(toJSON()).toMatchSnapshot(); }); diff --git a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.tsx b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.tsx index 6505cef13f7..acf580af357 100644 --- a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.tsx +++ b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.tsx @@ -4,14 +4,15 @@ import styleSheet from './ConfirmationFooter.styles'; import { View } from 'react-native'; import FooterLegalLinks from './LegalLinks/LegalLinks'; import FooterButtonGroup from './FooterButtonGroup/FooterButtonGroup'; +import { ConfirmationFooterProps } from './ConfirmationFooter.types'; -const ConfirmationFooter = () => { +const ConfirmationFooter = ({ valueWei, action }: ConfirmationFooterProps) => { const { styles } = useStyles(styleSheet, {}); return ( - + ); }; diff --git a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.types.ts b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.types.ts new file mode 100644 index 00000000000..a2d10bc09eb --- /dev/null +++ b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.types.ts @@ -0,0 +1,6 @@ +import { FooterButtonGroupActions } from './FooterButtonGroup/FooterButtonGroup.types'; + +export interface ConfirmationFooterProps { + valueWei: string; // deposit, unstake, and claim value + action: FooterButtonGroupActions; +} diff --git a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.test.tsx b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.test.tsx index 9f756063fa6..ffaec56ae87 100644 --- a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.test.tsx +++ b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.test.tsx @@ -3,9 +3,34 @@ import renderWithProvider from '../../../../../../../util/test/renderWithProvide import { strings } from '../../../../../../../../locales/i18n'; import FooterButtonGroup from './FooterButtonGroup'; import { fireEvent } from '@testing-library/react-native'; +import { + FooterButtonGroupActions, + FooterButtonGroupProps, +} from './FooterButtonGroup.types'; +import { createMockAccountsControllerState } from '../../../../../../../util/test/accountsControllerTestUtils'; +import { backgroundState } from '../../../../../../../util/test/initial-root-state'; + +const MOCK_ADDRESS_1 = '0x0'; +const MOCK_ADDRESS_2 = '0x1'; + +const MOCK_ACCOUNTS_CONTROLLER_STATE = createMockAccountsControllerState([ + MOCK_ADDRESS_1, + MOCK_ADDRESS_2, +]); + +const mockInitialState = { + settings: {}, + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + }, + }, +}; const mockCanGoBack = jest.fn(); const mockGoBack = jest.fn(); +const mockNavigate = jest.fn(); jest.mock('@react-navigation/native', () => { const actualReactNavigation = jest.requireActual('@react-navigation/native'); @@ -14,17 +39,35 @@ jest.mock('@react-navigation/native', () => { useNavigation: () => ({ canGoBack: mockCanGoBack, goBack: mockGoBack, + navigate: mockNavigate, }), }; }); +jest.mock('../../../../hooks/usePoolStakedDeposit', () => ({ + __esModule: true, + default: () => ({ + poolStakingContract: {}, + estimateDepositGas: jest.fn(), + attemptDepositTransaction: jest.fn(), + }), +})); + describe('FooterButtonGroup', () => { beforeEach(() => { jest.resetAllMocks(); }); it('render matches snapshot', () => { - const { getByText, toJSON } = renderWithProvider(); + const props: FooterButtonGroupProps = { + valueWei: '3210000000000000', + action: FooterButtonGroupActions.STAKE, + }; + + const { getByText, toJSON } = renderWithProvider( + , + { state: mockInitialState }, + ); expect(getByText(strings('stake.cancel'))).toBeDefined(); expect(getByText(strings('stake.confirm'))).toBeDefined(); @@ -32,15 +75,22 @@ describe('FooterButtonGroup', () => { expect(toJSON()).toMatchSnapshot(); }); - it('navigates to previous page when cancel button is pressed', () => { + it('navigates to Asset page when cancel is pressed', () => { mockCanGoBack.mockImplementationOnce(() => true); + const props: FooterButtonGroupProps = { + valueWei: '3210000000000000', + action: FooterButtonGroupActions.STAKE, + }; - const { getByText, toJSON } = renderWithProvider(); + const { getByText, toJSON } = renderWithProvider( + , + { state: mockInitialState }, + ); fireEvent.press(getByText(strings('stake.cancel'))); - expect(mockCanGoBack).toHaveBeenCalledTimes(1); - expect(mockGoBack).toHaveBeenCalledTimes(1); + expect(mockNavigate).toHaveBeenCalledTimes(1); + expect(mockNavigate).toHaveBeenCalledWith('Asset'); expect(toJSON()).toMatchSnapshot(); }); diff --git a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.tsx b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.tsx index bd781bfc9a8..00464468daa 100644 --- a/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.tsx +++ b/app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.tsx @@ -13,16 +13,57 @@ import Text, { } from '../../../../../../../component-library/components/Texts/Text'; import { useStyles } from '../../../../../../hooks/useStyles'; import styleSheet from './FooterButtonGroup.styles'; +import { useSelector } from 'react-redux'; +import { selectSelectedInternalAccount } from '../../../../../../../selectors/accountsController'; +import usePoolStakedDeposit from '../../../../hooks/usePoolStakedDeposit'; +import Engine from '../../../../../../../core/Engine'; +import { + FooterButtonGroupActions, + FooterButtonGroupProps, +} from './FooterButtonGroup.types'; +import Routes from '../../../../../../../constants/navigation/Routes'; -const FooterButtonGroup = () => { +const FooterButtonGroup = ({ valueWei, action }: FooterButtonGroupProps) => { const { styles } = useStyles(styleSheet, {}); - const navigation = useNavigation(); + const { navigate } = useNavigation(); - const handleGoBack = () => { - if (navigation.canGoBack()) { - navigation.goBack(); - } + const activeAccount = useSelector(selectSelectedInternalAccount); + + const { attemptDepositTransaction } = usePoolStakedDeposit(); + + const handleStake = async () => { + if (!activeAccount?.address) return; + + const txRes = await attemptDepositTransaction( + valueWei, + activeAccount.address, + ); + + const transactionId = txRes?.transactionMeta?.id; + + // Listening for confirmation + Engine.controllerMessenger.subscribeOnceIf( + 'TransactionController:transactionSubmitted', + () => { + navigate(Routes.TRANSACTIONS_VIEW); + }, + ({ transactionMeta }) => transactionMeta.id === transactionId, + ); + + // Engine.controllerMessenger.subscribeOnceIf( + // 'TransactionController:transactionConfirmed', + // () => { + // TODO: Call refreshPooledStakes(); + // refreshPooledStakes(); + // }, + // (transactionMeta) => transactionMeta.id === transactionId, + // ); + }; + + const handleConfirmation = () => { + if (action === FooterButtonGroupActions.STAKE) return handleStake(); + // TODO: Add handler (STAKE-803) }; return ( @@ -37,7 +78,7 @@ const FooterButtonGroup = () => { variant={ButtonVariants.Secondary} width={ButtonWidthTypes.Full} size={ButtonSize.Lg} - onPress={handleGoBack} + onPress={() => navigate('Asset')} />