diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 311e2dfda..017103ecd 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -2810,6 +2810,9 @@
"openSeaNew": {
"message": "OpenSea"
},
+ "operationFailed": {
+ "message": "Operation Failed"
+ },
"optional": {
"message": "Optional"
},
@@ -4478,6 +4481,10 @@
"transactionErrored": {
"message": "Transaction encountered an error."
},
+ "transactionFailed": {
+ "message": "Transaction Failed"
+ },
+
"transactionFee": {
"message": "Transaction fee"
},
diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss
index 0fb69b866..b646641ba 100644
--- a/ui/components/app/app-components.scss
+++ b/ui/components/app/app-components.scss
@@ -104,3 +104,6 @@
@import 'network-account-balance-header/index';
@import 'approve-content-card/index';
@import 'transaction-alerts/transaction-alerts';
+///: BEGIN:ONLY_INCLUDE_IN(mmi)
+@import '../institutional/transaction-failed-modal/index';
+///: END:ONLY_INCLUDE_IN
diff --git a/ui/components/institutional/transaction-failed-modal/index.js b/ui/components/institutional/transaction-failed-modal/index.js
new file mode 100644
index 000000000..2f120e825
--- /dev/null
+++ b/ui/components/institutional/transaction-failed-modal/index.js
@@ -0,0 +1 @@
+export { default } from './transaction-failed';
diff --git a/ui/components/institutional/transaction-failed-modal/index.scss b/ui/components/institutional/transaction-failed-modal/index.scss
new file mode 100644
index 000000000..c36a45fed
--- /dev/null
+++ b/ui/components/institutional/transaction-failed-modal/index.scss
@@ -0,0 +1,7 @@
+.transaction-failed {
+ &__description {
+ border: 1px solid var(--color-border-muted);
+ max-width: 100%;
+ overflow-wrap: anywhere;
+ }
+}
diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.js
new file mode 100644
index 000000000..24f566fed
--- /dev/null
+++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.js
@@ -0,0 +1,79 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import withModalProps from '../../../helpers/higher-order-components/with-modal-props';
+import { useI18nContext } from '../../../hooks/useI18nContext';
+import Modal from '../../app/modal';
+import Box from '../../ui/box/box';
+import {
+ AlignItems,
+ BorderRadius,
+ DISPLAY,
+ FLEX_DIRECTION,
+ FONT_WEIGHT,
+ TEXT_ALIGN,
+ TextVariant,
+} from '../../../helpers/constants/design-system';
+import { Text, Icon, IconName, IconSize } from '../../component-library';
+
+const TransactionFailedModal = ({
+ hideModal,
+ closeNotification,
+ operationFailed,
+ errorMessage,
+}) => {
+ const t = useI18nContext();
+ const handleSubmit = () => {
+ if (closeNotification) {
+ global.platform.closeCurrentWindow();
+ }
+ hideModal();
+ };
+
+ return (
+
+
+
+
+ {operationFailed
+ ? `${t('operationFailed')}!`
+ : `${t('transactionFailed')}!`}
+
+
+ {errorMessage}
+
+
+
+ );
+};
+
+TransactionFailedModal.propTypes = {
+ hideModal: PropTypes.func,
+ errorMessage: PropTypes.string,
+ closeNotification: PropTypes.bool,
+ operationFailed: PropTypes.bool,
+};
+
+export default withModalProps(TransactionFailedModal);
diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js
new file mode 100644
index 000000000..256b1c59e
--- /dev/null
+++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import TransactionFailedModal from '.';
+
+export default {
+ title: 'Components/Institutional/TransactionFailedModal',
+ argTypes: {},
+ args: {
+ errorMessage: 'test',
+ operationFailed: false,
+ },
+};
+
+export const DefaultStory = (args) => {
+ return ;
+};
+
+DefaultStory.storyName = 'TransactionFailedModal';
diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js
new file mode 100644
index 000000000..ccff04111
--- /dev/null
+++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js
@@ -0,0 +1,63 @@
+import React from 'react';
+import { screen, fireEvent } from '@testing-library/react';
+import configureMockStore from 'redux-mock-store';
+import { renderWithProvider } from '../../../../test/lib/render-helpers';
+import testData from '../../../../.storybook/test-data';
+import TransactionFailed from '.';
+
+const mockErrorMessage = 'Something went wrong';
+
+describe('Transaction Failed', () => {
+ const mockStore = {
+ ...testData,
+ };
+
+ const store = configureMockStore()(mockStore);
+
+ it('renders the error message', () => {
+ renderWithProvider(
+ ,
+ store,
+ );
+ const errorMessageElement = screen.getByText(mockErrorMessage);
+ expect(errorMessageElement).toBeInTheDocument();
+ });
+
+ it('renders the correct title when operation fails', () => {
+ const operationFailed = true;
+ const title = 'Operation Failed!';
+ renderWithProvider(
+ ,
+ store,
+ );
+ const titleElement = screen.getByText(title);
+ expect(titleElement).toBeInTheDocument();
+ });
+
+ it('renders the correct title when transaction fails', () => {
+ const operationFailed = false;
+ const title = 'Transaction Failed!';
+ renderWithProvider(
+ ,
+ store,
+ );
+ const titleElement = screen.getByText(title);
+ expect(titleElement).toBeInTheDocument();
+ });
+
+ it('closes window when closeNotification is true', () => {
+ global.platform = {
+ closeCurrentWindow: jest.fn(),
+ };
+ renderWithProvider(, store);
+ const okButton = screen.getByText('Ok');
+ fireEvent.click(okButton);
+ expect(global.platform.closeCurrentWindow).toHaveBeenCalledTimes(1);
+ });
+});