1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 11:22:43 +02:00

[MMI] personal sign and sign typed logic (#19892)

* adds missing logic

* lint fixes
This commit is contained in:
António Regadas 2023-07-06 16:10:03 +01:00 committed by GitHub
parent 5d3690aa24
commit 2c22e85947
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 183 additions and 24 deletions

View File

@ -1467,6 +1467,18 @@ export default class MetamaskController extends EventEmitter {
this.signatureController.newUnsignedPersonalMessage.bind( this.signatureController.newUnsignedPersonalMessage.bind(
this.signatureController, this.signatureController,
), ),
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
setTypedMessageInProgress:
this.signatureController.setTypedMessageInProgress.bind(
this.signatureController,
),
setPersonalMessageInProgress:
this.signatureController.setPersonalMessageInProgress.bind(
this.signatureController,
),
///: END:ONLY_INCLUDE_IN
processEncryptionPublicKey: processEncryptionPublicKey:
this.encryptionPublicKeyController.newRequestEncryptionPublicKey.bind( this.encryptionPublicKeyController.newRequestEncryptionPublicKey.bind(
this.encryptionPublicKeyController, this.encryptionPublicKeyController,

View File

@ -64,7 +64,10 @@ export default class SignatureRequestOriginal extends Component {
resolvePendingApproval: PropTypes.func.isRequired, resolvePendingApproval: PropTypes.func.isRequired,
completedTx: PropTypes.func.isRequired, completedTx: PropTypes.func.isRequired,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
// Used to show a warning if the signing account is not the selected account
// Largely relevant for contract wallet custodians
selectedAccount: PropTypes.object, selectedAccount: PropTypes.object,
mmiOnSignCallback: PropTypes.func,
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
}; };
@ -262,7 +265,7 @@ export default class SignatureRequestOriginal extends Component {
clearConfirmTransaction, clearConfirmTransaction,
history, history,
mostRecentOverviewPage, mostRecentOverviewPage,
txData: { type, id }, txData,
hardwareWalletRequiresConnection, hardwareWalletRequiresConnection,
rejectPendingApproval, rejectPendingApproval,
resolvePendingApproval, resolvePendingApproval,
@ -275,22 +278,34 @@ export default class SignatureRequestOriginal extends Component {
submitText={t('sign')} submitText={t('sign')}
onCancel={async () => { onCancel={async () => {
await rejectPendingApproval( await rejectPendingApproval(
id, txData.id,
serializeError(ethErrors.provider.userRejectedRequest()), serializeError(ethErrors.provider.userRejectedRequest()),
); );
clearConfirmTransaction(); clearConfirmTransaction();
history.push(mostRecentOverviewPage); history.push(mostRecentOverviewPage);
}} }}
onSubmit={async () => { onSubmit={async () => {
if (type === MESSAGE_TYPE.ETH_SIGN) { if (txData.type === MESSAGE_TYPE.ETH_SIGN) {
this.setState({ showSignatureRequestWarning: true }); this.setState({ showSignatureRequestWarning: true });
} else { } else {
await resolvePendingApproval(id); ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
if (this.props.mmiOnSignCallback) {
await this.props.mmiOnSignCallback(txData);
return;
}
///: END:ONLY_INCLUDE_IN
await resolvePendingApproval(txData.id);
clearConfirmTransaction(); clearConfirmTransaction();
history.push(mostRecentOverviewPage); history.push(mostRecentOverviewPage);
} }
}} }}
disabled={hardwareWalletRequiresConnection} disabled={
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
Boolean(txData?.custodyId) ||
///: END:ONLY_INCLUDE_IN
hardwareWalletRequiresConnection
}
/> />
); );
}; };

View File

@ -9,6 +9,17 @@ import {
rejectAllMessages, rejectAllMessages,
completedTx, completedTx,
} from '../../../store/actions'; } from '../../../store/actions';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
// eslint-disable-next-line import/order
import { showCustodianDeepLink } from '@metamask-institutional/extension';
import {
mmiActionsFactory,
setPersonalMessageInProgress,
} from '../../../store/institutional/institution-background';
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
import { checkForUnapprovedMessages } from '../../../store/institutional/institution-actions';
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app';
///: END:ONLY_INCLUDE_IN
import { import {
accountsWithSendEtherInfoSelector, accountsWithSendEtherInfoSelector,
getSubjectMetadata, getSubjectMetadata,
@ -16,6 +27,8 @@ import {
unconfirmedMessagesHashSelector, unconfirmedMessagesHashSelector,
getTotalUnapprovedMessagesCount, getTotalUnapprovedMessagesCount,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
unapprovedPersonalMsgsSelector,
getAccountType,
getSelectedAccount, getSelectedAccount,
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
} from '../../../selectors'; } from '../../../selectors';
@ -30,6 +43,10 @@ function mapStateToProps(state, ownProps) {
msgParams: { from }, msgParams: { from },
} = ownProps.txData; } = ownProps.txData;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const envType = getEnvironmentType();
///: END:ONLY_INCLUDE_IN
const hardwareWalletRequiresConnection = const hardwareWalletRequiresConnection =
doesAddressRequireLedgerHidConnection(state, from); doesAddressRequireLedgerHidConnection(state, from);
const isLedgerWallet = isAddressLedger(state, from); const isLedgerWallet = isAddressLedger(state, from);
@ -48,12 +65,63 @@ function mapStateToProps(state, ownProps) {
messagesList, messagesList,
messagesCount, messagesCount,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType: getAccountType(state),
isNotification: envType === ENVIRONMENT_TYPE_NOTIFICATION,
selectedAccount: getSelectedAccount(state), selectedAccount: getSelectedAccount(state),
unapprovedPersonalMessages: unapprovedPersonalMsgsSelector(state),
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
}; };
} }
function mapDispatchToProps(dispatch) { let mapDispatchToProps = null;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
function mmiMapDispatchToProps(dispatch) {
const mmiActions = mmiActionsFactory();
return {
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
setMsgInProgress: (msgId) => dispatch(setPersonalMessageInProgress(msgId)),
showCustodianDeepLink: ({
custodyId,
fromAddress,
closeNotification,
onDeepLinkFetched,
onDeepLinkShown,
}) =>
showCustodianDeepLink({
dispatch,
mmiActions,
txId: undefined,
fromAddress,
custodyId,
isSignature: true,
closeNotification,
onDeepLinkFetched,
onDeepLinkShown,
}),
showTransactionsFailedModal: ({
errorMessage,
closeNotification,
operationFailed,
}) =>
dispatch(
showModal({
name: 'TRANSACTION_FAILED',
errorMessage,
closeNotification,
operationFailed,
}),
),
setWaitForConfirmDeepLinkDialog: (wait) =>
dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)),
goHome: () => dispatch(goHome()),
};
}
mapDispatchToProps = mmiMapDispatchToProps;
///: END:ONLY_INCLUDE_IN
mapDispatchToProps = function (dispatch) {
return { return {
goHome: () => dispatch(goHome()), goHome: () => dispatch(goHome()),
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
@ -80,12 +148,21 @@ function mapDispatchToProps(dispatch) {
dispatch(rejectAllMessages(messagesList)); dispatch(rejectAllMessages(messagesList));
}, },
}; };
} };
function mergeProps(stateProps, dispatchProps, ownProps) { function mergeProps(stateProps, dispatchProps, ownProps) {
const { txData } = ownProps; const { txData } = ownProps;
const { allAccounts, messagesList, ...otherStateProps } = stateProps; const {
allAccounts,
messagesList,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType,
isNotification,
unapprovedPersonalMessages,
///: END:ONLY_INCLUDE_IN
...otherStateProps
} = stateProps;
const { const {
msgParams: { from }, msgParams: { from },
@ -95,6 +172,41 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
const { cancelAllApprovals: dispatchCancelAllApprovals } = dispatchProps; const { cancelAllApprovals: dispatchCancelAllApprovals } = dispatchProps;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const mmiOnSignCallback = async (_msgData) => {
if (accountType === 'custody') {
try {
let msgData = _msgData;
let id = _msgData.custodyId;
if (!_msgData.custodyId) {
msgData = checkForUnapprovedMessages(
_msgData,
unapprovedPersonalMessages,
);
id = msgData.custodyId;
}
dispatchProps.showCustodianDeepLink({
custodyId: id,
fromAddress: fromAccount.address,
closeNotification: isNotification,
onDeepLinkFetched: () => undefined,
onDeepLinkShown: () => undefined,
});
await dispatchProps.setMsgInProgress(msgData.metamaskId);
await dispatchProps.setWaitForConfirmDeepLinkDialog(true);
await goHome();
} catch (err) {
await dispatchProps.setWaitForConfirmDeepLinkDialog(true);
await dispatchProps.showTransactionsFailedModal({
errorMessage: err.message,
closeNotification: true,
operationFailed: true,
});
}
}
};
///: END:ONLY_INCLUDE_IN
return { return {
...ownProps, ...ownProps,
...otherStateProps, ...otherStateProps,
@ -103,6 +215,9 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
txData, txData,
cancelAllApprovals: () => cancelAllApprovals: () =>
dispatchCancelAllApprovals(valuesFor(messagesList)), dispatchCancelAllApprovals(valuesFor(messagesList)),
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
mmiOnSignCallback,
///: END:ONLY_INCLUDE_IN
}; };
} }

View File

@ -223,14 +223,16 @@ export default class SignatureRequest extends PureComponent {
.toString(); .toString();
const onSign = async () => { const onSign = async () => {
await resolvePendingApproval(id);
completedTx(id);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
if (this.props.mmiOnSignCallback) { if (this.props.mmiOnSignCallback) {
await this.props.mmiOnSignCallback(txData); await this.props.mmiOnSignCallback(txData);
return;
} }
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
await resolvePendingApproval(id);
completedTx(id);
trackEvent({ trackEvent({
category: MetaMetricsEventCategory.Transactions, category: MetaMetricsEventCategory.Transactions,
event: 'Confirm', event: 'Confirm',

View File

@ -30,7 +30,7 @@ import {
setTypedMessageInProgress, setTypedMessageInProgress,
} from '../../../store/institutional/institution-background'; } from '../../../store/institutional/institution-background';
import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import { getEnvironmentType } from '../../../../app/scripts/lib/util';
import { checkForUnapprovedTypedMessages } from '../../../store/institutional/institution-actions'; import { checkForUnapprovedMessages } from '../../../store/institutional/institution-actions';
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
import { import {
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
@ -214,7 +214,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
let msgData = _msgData; let msgData = _msgData;
let id = _msgData.custodyId; let id = _msgData.custodyId;
if (!_msgData.custodyId) { if (!_msgData.custodyId) {
msgData = checkForUnapprovedTypedMessages( msgData = checkForUnapprovedMessages(
_msgData, _msgData,
unapprovedTypedMessages, unapprovedTypedMessages,
); );

View File

@ -6,7 +6,7 @@ import { _setBackgroundConnection } from '../action-queue';
import { import {
showInteractiveReplacementTokenModal, showInteractiveReplacementTokenModal,
showCustodyConfirmLink, showCustodyConfirmLink,
checkForUnapprovedTypedMessages, checkForUnapprovedMessages,
updateCustodyState, updateCustodyState,
} from './institution-actions'; } from './institution-actions';
@ -153,8 +153,8 @@ describe('#InstitutionActions', () => {
}); });
}); });
describe('#checkForUnapprovedTypedMessages', () => { describe('#checkForUnapprovedMessages', () => {
it('calls checkForUnapprovedTypedMessages and returns the messageData', async () => { it('calls checkForUnapprovedMessages and returns the messageData', async () => {
const messageData = { const messageData = {
id: 1, id: 1,
type: 'tx', type: 'tx',
@ -166,7 +166,7 @@ describe('#checkForUnapprovedTypedMessages', () => {
status: 'unapproved', status: 'unapproved',
}; };
expect(checkForUnapprovedTypedMessages(messageData, { msg: 'msg' })).toBe( expect(checkForUnapprovedMessages(messageData, { msg: 'msg' })).toBe(
messageData, messageData,
); );
}); });

View File

@ -109,18 +109,18 @@ export function updateCustodyState(
} }
} }
export function checkForUnapprovedTypedMessages( export function checkForUnapprovedMessages(
msgData: TemporaryMessageDataType['msgParams'], msgData: TemporaryMessageDataType['msgParams'],
unapprovedTypedMessages: MessagesIndexedById, unapprovedMessages: MessagesIndexedById,
) { ) {
const custodianUnapprovedMessages = Object.keys(unapprovedTypedMessages) const custodianUnapprovedMessages = Object.keys(unapprovedMessages)
.map((key) => unapprovedTypedMessages[key]) .map((key) => unapprovedMessages[key])
.filter((message) => message.custodyId && message.status === 'unapproved'); .filter((message) => message.custodyId && message.status === 'unapproved');
if (custodianUnapprovedMessages && custodianUnapprovedMessages.length > 0) { if (custodianUnapprovedMessages && custodianUnapprovedMessages.length > 0) {
return { return {
...msgData, ...msgData,
custodyId: unapprovedTypedMessages[msgData.metamaskId]?.custodyId, custodyId: unapprovedMessages[msgData.metamaskId]?.custodyId,
}; };
} }

View File

@ -11,7 +11,7 @@ import {
callBackgroundMethod, callBackgroundMethod,
submitRequestToBackground, submitRequestToBackground,
} from '../action-queue'; } from '../action-queue';
import { MetaMaskReduxState } from '../store'; import { MetaMaskReduxDispatch, MetaMaskReduxState } from '../store';
import { isErrorWithMessage } from '../../../shared/modules/error'; import { isErrorWithMessage } from '../../../shared/modules/error';
export function showInteractiveReplacementTokenBanner({ export function showInteractiveReplacementTokenBanner({
@ -21,7 +21,7 @@ export function showInteractiveReplacementTokenBanner({
url: string; url: string;
oldRefreshToken: string; oldRefreshToken: string;
}): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> { }): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return async (dispatch) => { return async (dispatch: MetaMaskReduxDispatch) => {
try { try {
await submitRequestToBackground('showInteractiveReplacementTokenBanner', [ await submitRequestToBackground('showInteractiveReplacementTokenBanner', [
url, url,
@ -37,7 +37,7 @@ export function showInteractiveReplacementTokenBanner({
} }
export function setTypedMessageInProgress(msgId: string) { export function setTypedMessageInProgress(msgId: string) {
return async (dispatch: any) => { return async (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication()); dispatch(showLoadingIndication());
try { try {
await submitRequestToBackground('setTypedMessageInProgress', [msgId]); await submitRequestToBackground('setTypedMessageInProgress', [msgId]);
@ -51,6 +51,21 @@ export function setTypedMessageInProgress(msgId: string) {
}; };
} }
export function setPersonalMessageInProgress(msgId: string) {
return async (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication());
try {
await submitRequestToBackground('setPersonalMessageInProgress', [msgId]);
} catch (error: any) {
log.error(error);
dispatch(displayWarning(error.message));
} finally {
await forceUpdateMetamaskState(dispatch);
dispatch(hideLoadingIndication());
}
};
}
/** /**
* A factory that contains all MMI actions ready to use * A factory that contains all MMI actions ready to use
* Example usage: * Example usage: