From 158285921187253f02c1e52bb8219844e00cc7fb Mon Sep 17 00:00:00 2001
From: Brendan Kirby <124314512+bkirb@users.noreply.github.com>
Date: Tue, 22 Oct 2024 07:03:12 -0700
Subject: [PATCH 1/3] test: initial off-ramp test to show build quote screen
(#11573)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## **Description**
This is the initial test and foundation for Off-Ramp testing. It should
go through the onboarding screen, select region, select payment method,
and show the screen to build a Sell quote.
## **Related issues**
https://consensyssoftware.atlassian.net/browse/RAMPS-1869
## **Manual testing steps**
This test is consistently passing:
```
PASS e2e/specs/ramps/offramp.spec.js (36.081 s)
smokeAssets OffRamp
✓ should select Region and Payment Method to see the Build Sell Quote screen (16087 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 36.139 s
```
## **Screenshots/Recordings**
## **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: legobeat <109787230+legobeat@users.noreply.github.com>
---
e2e/pages/Ramps/BuildQuoteView.js | 5 ++
e2e/pages/Ramps/SellGetStartedView.js | 15 +++++
e2e/pages/modals/WalletActionsModal.js | 8 +++
e2e/selectors/Ramps/BuildQuote.selectors.js | 1 +
e2e/specs/ramps/offramp.spec.js | 75 +++++++++++++++++++++
e2e/specs/ramps/onramp.spec.js | 2 +-
6 files changed, 105 insertions(+), 1 deletion(-)
create mode 100644 e2e/pages/Ramps/SellGetStartedView.js
create mode 100644 e2e/specs/ramps/offramp.spec.js
diff --git a/e2e/pages/Ramps/BuildQuoteView.js b/e2e/pages/Ramps/BuildQuoteView.js
index dbdc2e524ed..63c916c0833 100644
--- a/e2e/pages/Ramps/BuildQuoteView.js
+++ b/e2e/pages/Ramps/BuildQuoteView.js
@@ -5,6 +5,11 @@ class BuildQuoteView {
get amountToBuyLabel() {
return Matchers.getElementByText(BuildQuoteSelectors.AMOUNT_TO_BUY_LABEL);
}
+
+ get amountToSellLabel() {
+ return Matchers.getElementByText(BuildQuoteSelectors.AMOUNT_TO_SELL_LABEL);
+ }
+
get getQuotesButton() {
return Matchers.getElementByText(BuildQuoteSelectors.GET_QUOTES_BUTTON);
}
diff --git a/e2e/pages/Ramps/SellGetStartedView.js b/e2e/pages/Ramps/SellGetStartedView.js
new file mode 100644
index 00000000000..5644df74339
--- /dev/null
+++ b/e2e/pages/Ramps/SellGetStartedView.js
@@ -0,0 +1,15 @@
+import Matchers from '../../utils/Matchers';
+import Gestures from '../../utils/Gestures';
+import { GetStartedSelectors } from '../../selectors/Ramps/GetStarted.selectors';
+
+class SellGetStartedView {
+ get getStartedButton() {
+ return Matchers.getElementByText(GetStartedSelectors.GET_STARTED);
+ }
+
+ async tapGetStartedButton() {
+ await Gestures.waitAndTap(this.getStartedButton);
+ }
+}
+
+export default new SellGetStartedView();
diff --git a/e2e/pages/modals/WalletActionsModal.js b/e2e/pages/modals/WalletActionsModal.js
index 1b8ac8b3fc6..d6d3aadb49b 100644
--- a/e2e/pages/modals/WalletActionsModal.js
+++ b/e2e/pages/modals/WalletActionsModal.js
@@ -21,6 +21,10 @@ class WalletActionsModal {
return Matchers.getElementByID(WalletActionsModalSelectorsIDs.BUY_BUTTON);
}
+ get sellButton() {
+ return Matchers.getElementByID(WalletActionsModalSelectorsIDs.SELL_BUTTON);
+ }
+
async tapSendButton() {
await Gestures.waitAndTap(this.sendButton);
}
@@ -36,6 +40,10 @@ class WalletActionsModal {
async tapBuyButton() {
await Gestures.waitAndTap(this.buyButton);
}
+
+ async tapSellButton() {
+ await Gestures.waitAndTap(this.sellButton);
+ }
}
export default new WalletActionsModal();
diff --git a/e2e/selectors/Ramps/BuildQuote.selectors.js b/e2e/selectors/Ramps/BuildQuote.selectors.js
index 6f31cad907d..1c3a116b9f8 100644
--- a/e2e/selectors/Ramps/BuildQuote.selectors.js
+++ b/e2e/selectors/Ramps/BuildQuote.selectors.js
@@ -2,5 +2,6 @@ import enContent from '../../../locales/languages/en.json';
export const BuildQuoteSelectors = {
AMOUNT_TO_BUY_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_buy,
+ AMOUNT_TO_SELL_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_sell,
GET_QUOTES_BUTTON: enContent.fiat_on_ramp_aggregator.get_quotes,
};
diff --git a/e2e/specs/ramps/offramp.spec.js b/e2e/specs/ramps/offramp.spec.js
new file mode 100644
index 00000000000..d990ed0993b
--- /dev/null
+++ b/e2e/specs/ramps/offramp.spec.js
@@ -0,0 +1,75 @@
+'use strict';
+import { loginToApp } from '../../viewHelper';
+import TabBarComponent from '../../pages/TabBarComponent';
+import WalletActionsModal from '../../pages/modals/WalletActionsModal';
+import FixtureBuilder from '../../fixtures/fixture-builder';
+import {
+ loadFixture,
+ startFixtureServer,
+ stopFixtureServer,
+} from '../../fixtures/fixture-helper';
+import { CustomNetworks } from '../../resources/networks.e2e';
+import TestHelpers from '../../helpers';
+import FixtureServer from '../../fixtures/fixture-server';
+import { getFixturesServerPort } from '../../fixtures/utils';
+import { SmokeAssets } from '../../tags';
+import Assertions from '../../utils/Assertions';
+import SellGetStartedView from '../../pages/Ramps/SellGetStartedView';
+import SelectRegionView from '../../pages/Ramps/SelectRegionView';
+import SelectPaymentMethodView from '../../pages/Ramps/SelectPaymentMethodView';
+import BuildQuoteView from '../../pages/Ramps/BuildQuoteView';
+
+const fixtureServer = new FixtureServer();
+
+const Regions = {
+ USA: 'United States of America',
+ CALIFORNIA: 'California',
+ FRANCE: 'France',
+ UK: 'United Kingdom',
+};
+
+const PaymentMethods = {
+ DEBIT_OR_CREDIT: 'Debit or Credit',
+ INSTANT_ACH_BANK_TRANSFER: 'Insant ACH Bank Transfer',
+ ACH_BANK_TRANSFER: 'ACH Bank Transfer',
+}
+
+describe(SmokeAssets('Off-Ramp'), () => {
+ beforeAll(async () => {
+ await TestHelpers.reverseServerPort();
+ const fixture = new FixtureBuilder()
+ .withNetworkController(CustomNetworks.Tenderly)
+ .build();
+ await startFixtureServer(fixtureServer);
+ await loadFixture(fixtureServer, { fixture });
+ await device.launchApp({
+ permissions: { notifications: 'YES' },
+ launchArgs: { fixtureServerPort: `${getFixturesServerPort()}` },
+ });
+ await loginToApp();
+ });
+
+ afterAll(async () => {
+ await stopFixtureServer(fixtureServer);
+ });
+
+ beforeEach(async () => {
+ jest.setTimeout(150000);
+ });
+
+ it('should display Build Sell Quote based on selected Region and Payment', async () => {
+ await TabBarComponent.tapWallet();
+ await TabBarComponent.tapActions();
+ await WalletActionsModal.tapSellButton();
+ await SellGetStartedView.tapGetStartedButton();
+ await SelectRegionView.tapSelectRegionDropdown();
+ await SelectRegionView.tapRegionOption(Regions.USA);
+ await SelectRegionView.tapRegionOption(Regions.CALIFORNIA);
+ await SelectRegionView.tapContinueButton();
+ await SelectPaymentMethodView.tapPaymentMethodOption(PaymentMethods.DEBIT_OR_CREDIT);
+ await SelectPaymentMethodView.tapContinueButton();
+ await Assertions.checkIfVisible(BuildQuoteView.amountToSellLabel);
+ await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton);
+ });
+
+});
diff --git a/e2e/specs/ramps/onramp.spec.js b/e2e/specs/ramps/onramp.spec.js
index 2b43bfaf803..e426e34e828 100644
--- a/e2e/specs/ramps/onramp.spec.js
+++ b/e2e/specs/ramps/onramp.spec.js
@@ -41,7 +41,7 @@ describe(SmokeAssets('Buy Crypto'), () => {
jest.setTimeout(150000);
});
- it('should select Region and Payment Method to see the Build Quote screen', async () => {
+ it('should select Region and Payment Method to see the Build Buy Quote screen', async () => {
await TabBarComponent.tapWallet();
await TabBarComponent.tapActions();
await WalletActionsModal.tapBuyButton();
From f2f84ed9c7214d32a5e4e50be724bc4a1c4f1996 Mon Sep 17 00:00:00 2001
From: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Date: Tue, 22 Oct 2024 10:45:05 -0400
Subject: [PATCH 2/3] feat: STAKE-805 integrate stake method (#11845)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## **Description**
This PR enables staking on both Ethereum mainnet and Holesky.
## **Related issues**
Ticket: [STAKE-805: [FE] [Stake flow] Integrate stake sdk
method](https://consensyssoftware.atlassian.net/browse/STAKE-805)
## **Manual testing steps**
1. Add `export MM_POOLED_STAKING_UI_ENABLED=true` to your .js.env file.
2. Select Ethereum in the asset list
3. Scroll down a bit and click "Stake More"
4. Enter an amount to stake and click "review"
5. On the review screen, click "Continue"
6. You should see the transaction confirmation screen appear. Click
"Confirm".
7. The transaction should be submitted and you should be redirected to
the Ethereum asset details page
## **Screenshots/Recordings**
### **Before**
https://github.com/user-attachments/assets/f90dfc78-b51a-4a6d-aa93-e48cc4146d30
### **After**
**Update:** On transaction submission, the user is now redirected to the
Transactions View.
https://github.com/user-attachments/assets/61752a3b-6a7d-4bec-ae3b-a2060ddc257a
## **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.
---
.../StakeConfirmationView.test.tsx | 9 +
.../StakeConfirmationView.tsx | 6 +-
.../StakeInputView/StakeInputView.test.tsx | 27 +-
.../Views/StakeInputView/StakeInputView.tsx | 7 +-
.../ConfirmationFooter.test.tsx | 44 +-
.../ConfirmationFooter/ConfirmationFooter.tsx | 5 +-
.../ConfirmationFooter.types.ts | 6 +
.../FooterButtonGroup.test.tsx | 60 +-
.../FooterButtonGroup/FooterButtonGroup.tsx | 58 +-
.../FooterButtonGroup.types.ts | 9 +
.../FooterButtonGroup.test.tsx.snap | 2 +-
.../Stake/hooks/usePoolStakedDeposit/index.ts | 85 +
.../usePoolStakedDeposit.test.tsx | 127 +
.../stakeSdkProvider.test.tsx.snap | 2229 +----------------
.../UI/Stake/sdk/stakeSdkProvider.test.tsx | 68 +-
.../UI/Stake/sdk/stakeSdkProvider.tsx | 75 +-
package.json | 2 +-
yarn.lock | 12 +-
18 files changed, 513 insertions(+), 2318 deletions(-)
create mode 100644 app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/ConfirmationFooter.types.ts
create mode 100644 app/components/UI/Stake/components/StakingConfirmation/ConfirmationFooter/FooterButtonGroup/FooterButtonGroup.types.ts
create mode 100644 app/components/UI/Stake/hooks/usePoolStakedDeposit/index.ts
create mode 100644 app/components/UI/Stake/hooks/usePoolStakedDeposit/usePoolStakedDeposit.test.tsx
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')}
/>