From a0c4febfcef2368df6a2afb963e57b2b64a15116 Mon Sep 17 00:00:00 2001
From: dragana8 <92531782+dragana8@users.noreply.github.com>
Date: Mon, 16 May 2022 20:36:19 +0200
Subject: [PATCH] "Cancel/reject all" for signature requests #13201 (#13786)
---
.../app/signature-request-original/index.scss | 4 +
.../signature-request-original.component.js | 36 ++++++++
.../signature-request-original.container.js | 28 +++++-
ui/selectors/confirm-transaction.js | 23 +++++
ui/selectors/selectors.js | 18 ++++
ui/store/actions.js | 91 +++++++++++++++++++
ui/store/actions.test.js | 54 +++++++++++
7 files changed, 251 insertions(+), 3 deletions(-)
diff --git a/ui/components/app/signature-request-original/index.scss b/ui/components/app/signature-request-original/index.scss
index 2e2aca65f..dd1e5e05c 100644
--- a/ui/components/app/signature-request-original/index.scss
+++ b/ui/components/app/signature-request-original/index.scss
@@ -20,6 +20,10 @@
@media screen and (min-width: $break-large) {
height: 620px;
}
+
+ &__reject {
+ padding-bottom: 20px;
+ }
}
&__typed-container {
diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js
index 80954ce93..a3eef4ec0 100644
--- a/ui/components/app/signature-request-original/signature-request-original.component.js
+++ b/ui/components/app/signature-request-original/signature-request-original.component.js
@@ -38,6 +38,9 @@ export default class SignatureRequestOriginal extends Component {
hardwareWalletRequiresConnection: PropTypes.bool,
isLedgerWallet: PropTypes.bool,
nativeCurrency: PropTypes.string.isRequired,
+ messagesCount: PropTypes.number,
+ showRejectTransactionsConfirmationModal: PropTypes.func.isRequired,
+ cancelAll: PropTypes.func.isRequired,
};
state = {
@@ -315,7 +318,31 @@ export default class SignatureRequestOriginal extends Component {
);
};
+ handleCancelAll = () => {
+ const {
+ cancelAll,
+ clearConfirmTransaction,
+ history,
+ mostRecentOverviewPage,
+ showRejectTransactionsConfirmationModal,
+ messagesCount,
+ } = this.props;
+ const unapprovedTxCount = messagesCount;
+
+ showRejectTransactionsConfirmationModal({
+ unapprovedTxCount,
+ onSubmit: async () => {
+ await cancelAll();
+ clearConfirmTransaction();
+ history.push(mostRecentOverviewPage);
+ },
+ });
+ };
+
render = () => {
+ const { messagesCount } = this.props;
+ const { t } = this.context;
+ const rejectNText = t('rejectTxsN', [messagesCount]);
return (
{this.renderHeader()}
@@ -326,6 +353,15 @@ export default class SignatureRequestOriginal extends Component {
) : null}
{this.renderFooter()}
+ {messagesCount > 1 ? (
+
+ ) : null}
);
};
diff --git a/ui/components/app/signature-request-original/signature-request-original.container.js b/ui/components/app/signature-request-original/signature-request-original.container.js
index 8031d92ed..f30310358 100644
--- a/ui/components/app/signature-request-original/signature-request-original.container.js
+++ b/ui/components/app/signature-request-original/signature-request-original.container.js
@@ -3,14 +3,16 @@ import { compose } from 'redux';
import { withRouter } from 'react-router-dom';
import { MESSAGE_TYPE } from '../../../../shared/constants/app';
-import { goHome } from '../../../store/actions';
+import { goHome, cancelMsgs, showModal } from '../../../store/actions';
import {
accountsWithSendEtherInfoSelector,
conversionRateSelector,
getSubjectMetadata,
doesAddressRequireLedgerHidConnection,
+ unconfirmedMessagesHashSelector,
+ getTotalUnapprovedMessagesCount,
} from '../../../selectors';
-import { getAccountByAddress } from '../../../helpers/utils/util';
+import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util';
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck';
import { getMostRecentOverviewPage } from '../../../ducks/history/history';
import {
@@ -29,6 +31,8 @@ function mapStateToProps(state, ownProps) {
from,
);
const isLedgerWallet = isAddressLedger(state, from);
+ const messagesList = unconfirmedMessagesHashSelector(state);
+ const messagesCount = getTotalUnapprovedMessagesCount(state);
return {
requester: null,
@@ -41,6 +45,8 @@ function mapStateToProps(state, ownProps) {
// not passed to component
allAccounts: accountsWithSendEtherInfoSelector(state),
subjectMetadata: getSubjectMetadata(state),
+ messagesList,
+ messagesCount,
};
}
@@ -48,6 +54,19 @@ function mapDispatchToProps(dispatch) {
return {
goHome: () => dispatch(goHome()),
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
+ showRejectTransactionsConfirmationModal: ({
+ onSubmit,
+ unapprovedTxCount: messagesCount,
+ }) => {
+ return dispatch(
+ showModal({
+ name: 'REJECT_TRANSACTIONS',
+ onSubmit,
+ unapprovedTxCount: messagesCount,
+ }),
+ );
+ },
+ cancelAll: (messagesList) => dispatch(cancelMsgs(messagesList)),
};
}
@@ -62,7 +81,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
txData,
} = ownProps;
- const { allAccounts, ...otherStateProps } = stateProps;
+ const { allAccounts, messagesList, ...otherStateProps } = stateProps;
const {
type,
@@ -71,6 +90,8 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
const fromAccount = getAccountByAddress(allAccounts, from);
+ const { cancelAll: dispatchCancelAll } = dispatchProps;
+
let cancel;
let sign;
if (type === MESSAGE_TYPE.PERSONAL_SIGN) {
@@ -92,6 +113,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
txData,
cancel,
sign,
+ cancelAll: () => dispatchCancelAll(valuesFor(messagesList)),
};
}
diff --git a/ui/selectors/confirm-transaction.js b/ui/selectors/confirm-transaction.js
index e3e8f6efb..e502d473c 100644
--- a/ui/selectors/confirm-transaction.js
+++ b/ui/selectors/confirm-transaction.js
@@ -117,6 +117,29 @@ export const unconfirmedTransactionsHashSelector = createSelector(
},
);
+export const unconfirmedMessagesHashSelector = createSelector(
+ unapprovedMsgsSelector,
+ unapprovedPersonalMsgsSelector,
+ unapprovedDecryptMsgsSelector,
+ unapprovedEncryptionPublicKeyMsgsSelector,
+ unapprovedTypedMessagesSelector,
+ (
+ unapprovedMsgs = {},
+ unapprovedPersonalMsgs = {},
+ unapprovedDecryptMsgs = {},
+ unapprovedEncryptionPublicKeyMsgs = {},
+ unapprovedTypedMessages = {},
+ ) => {
+ return {
+ ...unapprovedMsgs,
+ ...unapprovedPersonalMsgs,
+ ...unapprovedDecryptMsgs,
+ ...unapprovedEncryptionPublicKeyMsgs,
+ ...unapprovedTypedMessages,
+ };
+ },
+);
+
const unapprovedMsgCountSelector = (state) => state.metamask.unapprovedMsgCount;
const unapprovedPersonalMsgCountSelector = (state) =>
state.metamask.unapprovedPersonalMsgCount;
diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js
index 50ee18dbd..e1db5e2cf 100644
--- a/ui/selectors/selectors.js
+++ b/ui/selectors/selectors.js
@@ -470,6 +470,24 @@ export function getTotalUnapprovedCount(state) {
);
}
+export function getTotalUnapprovedMessagesCount(state) {
+ const {
+ unapprovedMsgCount = 0,
+ unapprovedPersonalMsgCount = 0,
+ unapprovedDecryptMsgCount = 0,
+ unapprovedEncryptionPublicKeyMsgCount = 0,
+ unapprovedTypedMessagesCount = 0,
+ } = state.metamask;
+
+ return (
+ unapprovedMsgCount +
+ unapprovedPersonalMsgCount +
+ unapprovedDecryptMsgCount +
+ unapprovedEncryptionPublicKeyMsgCount +
+ unapprovedTypedMessagesCount
+ );
+}
+
function getUnapprovedTxCount(state) {
const { unapprovedTxs = {} } = state.metamask;
return Object.keys(unapprovedTxs).length;
diff --git a/ui/store/actions.js b/ui/store/actions.js
index db0e1cddb..262b715d6 100644
--- a/ui/store/actions.js
+++ b/ui/store/actions.js
@@ -13,6 +13,7 @@ import {
ENVIRONMENT_TYPE_NOTIFICATION,
ORIGIN_METAMASK,
POLLING_TOKEN_ENVIRONMENT_TYPES,
+ MESSAGE_TYPE,
} from '../../shared/constants/app';
import { hasUnconfirmedTransactions } from '../helpers/utils/confirm-tx.util';
import txHelper from '../helpers/utils/tx-helper';
@@ -1021,6 +1022,96 @@ export function cancelMsg(msgData) {
};
}
+/**
+ * Cancels all of the given messages
+ *
+ * @param {Array