Skip to content

Commit

Permalink
cherry pick: fix: smart transactions in redesigned confirmations (#28353
Browse files Browse the repository at this point in the history
)

## **Description**
Cherry pick of:
#28273

[![Open in GitHub

Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/28273?quickstart=1)

## **Related issues**

## **Manual testing steps**

1. Install fresh extension.
2. Create transaction using redesigned confirmation.
3. Ensure smart transaction is performed.

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding

Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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.


<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/28353?quickstart=1)

## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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 Walsh <[email protected]>
  • Loading branch information
dan437 and matthewwalsh0 authored Nov 7, 2024
1 parent 7798ef4 commit 18f97b8
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/data/confirmations/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export const getMockConfirmState = (args: RootState = { metamask: {} }) => ({
...args.metamask,
preferences: {
...mockState.metamask.preferences,
...(args.metamask?.preferences as Record<string, unknown>),
redesignedTransactionsEnabled: true,
redesignedConfirmationsEnabled: true,
isRedesignedConfirmationsDeveloperEnabled: true,
Expand Down
4 changes: 4 additions & 0 deletions ui/pages/confirmations/components/confirm/info/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TransactionType } from '@metamask/transaction-controller';
import React, { useMemo } from 'react';
import { useConfirmContext } from '../../../context/confirm';
import { SignatureRequestType } from '../../../types/confirm';
import { useSmartTransactionFeatureFlags } from '../../../hooks/useSmartTransactionFeatureFlags';
import ApproveInfo from './approve/approve';
import BaseTransactionInfo from './base-transaction-info/base-transaction-info';
import NativeTransferInfo from './native-transfer/native-transfer';
Expand All @@ -15,6 +16,9 @@ import TypedSignInfo from './typed-sign/typed-sign';
const Info = () => {
const { currentConfirmation } = useConfirmContext();

// TODO: Create TransactionInfo and SignatureInfo components.
useSmartTransactionFeatureFlags();

const ConfirmationInfoComponentMap = useMemo(
() => ({
[TransactionType.contractInteraction]: () => BaseTransactionInfo,
Expand Down
119 changes: 119 additions & 0 deletions ui/pages/confirmations/hooks/useSmartTransactionFeatureFlags.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { act } from 'react-dom/test-utils';
import { useDispatch } from 'react-redux';
import { CHAIN_IDS, TransactionMeta } from '@metamask/transaction-controller';
import { Hex } from '@metamask/utils';
import {
fetchSmartTransactionsLiveness,
setSwapsFeatureFlags,
} from '../../../store/actions';
import { renderHookWithConfirmContextProvider } from '../../../../test/lib/confirmations/render-helpers';
import { genUnapprovedContractInteractionConfirmation } from '../../../../test/data/confirmations/contract-interaction';
import { getMockConfirmStateForTransaction } from '../../../../test/data/confirmations/helper';
import { mockNetworkState } from '../../../../test/stub/networks';
import { fetchSwapsFeatureFlags } from '../../swaps/swaps.util';
import { useSmartTransactionFeatureFlags } from './useSmartTransactionFeatureFlags';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: jest.fn(),
}));

jest.mock('../../../store/actions', () => ({
...jest.requireActual('../../../store/actions'),
setSwapsFeatureFlags: jest.fn(),
fetchSmartTransactionsLiveness: jest.fn(),
}));

jest.mock('../../swaps/swaps.util', () => ({
...jest.requireActual('../../swaps/swaps.util'),
fetchSwapsFeatureFlags: jest.fn(),
}));

async function runHook({
smartTransactionsOptInStatus,
chainId,
confirmation,
}: {
smartTransactionsOptInStatus: boolean;
chainId: Hex;
confirmation?: Partial<TransactionMeta>;
}) {
const transaction =
(confirmation as TransactionMeta) ??
genUnapprovedContractInteractionConfirmation({
chainId,
});

const state = getMockConfirmStateForTransaction(transaction, {
metamask: {
...mockNetworkState({ chainId, id: 'Test' }),
selectedNetworkClientId: 'Test',
preferences: {
smartTransactionsOptInStatus,
},
},
});

renderHookWithConfirmContextProvider(
() => useSmartTransactionFeatureFlags(),
state,
);

await act(async () => {
// Intentionally empty
});
}

describe('useSmartTransactionFeatureFlags', () => {
const setSwapsFeatureFlagsMock = jest.mocked(setSwapsFeatureFlags);
const fetchSwapsFeatureFlagsMock = jest.mocked(fetchSwapsFeatureFlags);
const fetchSmartTransactionsLivenessMock = jest.mocked(
fetchSmartTransactionsLiveness,
);
const useDispatchMock = jest.mocked(useDispatch);

beforeEach(() => {
jest.resetAllMocks();
useDispatchMock.mockReturnValue(jest.fn());
fetchSwapsFeatureFlagsMock.mockResolvedValue({});
fetchSmartTransactionsLivenessMock.mockReturnValue(() => Promise.resolve());
});

it('updates feature flags', async () => {
await runHook({
smartTransactionsOptInStatus: true,
chainId: CHAIN_IDS.MAINNET,
});

expect(setSwapsFeatureFlagsMock).toHaveBeenCalledTimes(1);
expect(setSwapsFeatureFlagsMock).toHaveBeenCalledWith({});
});

it('does not update feature flags if smart transactions disabled', async () => {
await runHook({
smartTransactionsOptInStatus: false,
chainId: CHAIN_IDS.MAINNET,
});

expect(setSwapsFeatureFlagsMock).not.toHaveBeenCalled();
});

it('does not update feature flags if chain not supported', async () => {
await runHook({
smartTransactionsOptInStatus: true,
chainId: CHAIN_IDS.ARBITRUM,
});

expect(setSwapsFeatureFlagsMock).not.toHaveBeenCalled();
});

it('does not update feature flags if confirmation is not transaction', async () => {
await runHook({
smartTransactionsOptInStatus: true,
chainId: CHAIN_IDS.MAINNET,
confirmation: {},
});

expect(setSwapsFeatureFlagsMock).not.toHaveBeenCalled();
});
});
53 changes: 53 additions & 0 deletions ui/pages/confirmations/hooks/useSmartTransactionFeatureFlags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useDispatch, useSelector } from 'react-redux';
import { useEffect } from 'react';
import { TransactionMeta } from '@metamask/transaction-controller';
import log from 'loglevel';
import {
getCurrentChainSupportsSmartTransactions,
getSmartTransactionsPreferenceEnabled,
} from '../../../../shared/modules/selectors';
import { fetchSwapsFeatureFlags } from '../../swaps/swaps.util';
import {
fetchSmartTransactionsLiveness,
setSwapsFeatureFlags,
} from '../../../store/actions';
import { useConfirmContext } from '../context/confirm';

export function useSmartTransactionFeatureFlags() {
const dispatch = useDispatch();
const { currentConfirmation } = useConfirmContext<TransactionMeta>();
const { id: transactionId, txParams } = currentConfirmation ?? {};
const isTransaction = Boolean(txParams);

const smartTransactionsPreferenceEnabled = useSelector(
getSmartTransactionsPreferenceEnabled,
);

const currentChainSupportsSmartTransactions = useSelector(
getCurrentChainSupportsSmartTransactions,
);

useEffect(() => {
if (
!isTransaction ||
!transactionId ||
!smartTransactionsPreferenceEnabled ||
!currentChainSupportsSmartTransactions
) {
return;
}

Promise.all([fetchSwapsFeatureFlags(), fetchSmartTransactionsLiveness()()])
.then(([swapsFeatureFlags]) => {
dispatch(setSwapsFeatureFlags(swapsFeatureFlags));
})
.catch((error) => {
log.debug('Error updating smart transaction feature flags', error);
});
}, [
isTransaction,
transactionId,
smartTransactionsPreferenceEnabled,
currentChainSupportsSmartTransactions,
]);
}

0 comments on commit 18f97b8

Please sign in to comment.