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,
),
///: 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:
this.encryptionPublicKeyController.newRequestEncryptionPublicKey.bind(
this.encryptionPublicKeyController,

View File

@ -64,7 +64,10 @@ export default class SignatureRequestOriginal extends Component {
resolvePendingApproval: PropTypes.func.isRequired,
completedTx: PropTypes.func.isRequired,
///: 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,
mmiOnSignCallback: PropTypes.func,
///: END:ONLY_INCLUDE_IN
};
@ -262,7 +265,7 @@ export default class SignatureRequestOriginal extends Component {
clearConfirmTransaction,
history,
mostRecentOverviewPage,
txData: { type, id },
txData,
hardwareWalletRequiresConnection,
rejectPendingApproval,
resolvePendingApproval,
@ -275,22 +278,34 @@ export default class SignatureRequestOriginal extends Component {
submitText={t('sign')}
onCancel={async () => {
await rejectPendingApproval(
id,
txData.id,
serializeError(ethErrors.provider.userRejectedRequest()),
);
clearConfirmTransaction();
history.push(mostRecentOverviewPage);
}}
onSubmit={async () => {
if (type === MESSAGE_TYPE.ETH_SIGN) {
if (txData.type === MESSAGE_TYPE.ETH_SIGN) {
this.setState({ showSignatureRequestWarning: true });
} 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();
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,
completedTx,
} 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 {
accountsWithSendEtherInfoSelector,
getSubjectMetadata,
@ -16,6 +27,8 @@ import {
unconfirmedMessagesHashSelector,
getTotalUnapprovedMessagesCount,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
unapprovedPersonalMsgsSelector,
getAccountType,
getSelectedAccount,
///: END:ONLY_INCLUDE_IN
} from '../../../selectors';
@ -30,6 +43,10 @@ function mapStateToProps(state, ownProps) {
msgParams: { from },
} = ownProps.txData;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const envType = getEnvironmentType();
///: END:ONLY_INCLUDE_IN
const hardwareWalletRequiresConnection =
doesAddressRequireLedgerHidConnection(state, from);
const isLedgerWallet = isAddressLedger(state, from);
@ -48,12 +65,63 @@ function mapStateToProps(state, ownProps) {
messagesList,
messagesCount,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType: getAccountType(state),
isNotification: envType === ENVIRONMENT_TYPE_NOTIFICATION,
selectedAccount: getSelectedAccount(state),
unapprovedPersonalMessages: unapprovedPersonalMsgsSelector(state),
///: 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 {
goHome: () => dispatch(goHome()),
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
@ -80,12 +148,21 @@ function mapDispatchToProps(dispatch) {
dispatch(rejectAllMessages(messagesList));
},
};
}
};
function mergeProps(stateProps, dispatchProps, 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 {
msgParams: { from },
@ -95,6 +172,41 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
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 {
...ownProps,
...otherStateProps,
@ -103,6 +215,9 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
txData,
cancelAllApprovals: () =>
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();
const onSign = async () => {
await resolvePendingApproval(id);
completedTx(id);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
if (this.props.mmiOnSignCallback) {
await this.props.mmiOnSignCallback(txData);
return;
}
///: END:ONLY_INCLUDE_IN
await resolvePendingApproval(id);
completedTx(id);
trackEvent({
category: MetaMetricsEventCategory.Transactions,
event: 'Confirm',

View File

@ -30,7 +30,7 @@ import {
setTypedMessageInProgress,
} from '../../../store/institutional/institution-background';
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
import {
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
@ -214,7 +214,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
let msgData = _msgData;
let id = _msgData.custodyId;
if (!_msgData.custodyId) {
msgData = checkForUnapprovedTypedMessages(
msgData = checkForUnapprovedMessages(
_msgData,
unapprovedTypedMessages,
);

View File

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

View File

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

View File

@ -11,7 +11,7 @@ import {
callBackgroundMethod,
submitRequestToBackground,
} from '../action-queue';
import { MetaMaskReduxState } from '../store';
import { MetaMaskReduxDispatch, MetaMaskReduxState } from '../store';
import { isErrorWithMessage } from '../../../shared/modules/error';
export function showInteractiveReplacementTokenBanner({
@ -21,7 +21,7 @@ export function showInteractiveReplacementTokenBanner({
url: string;
oldRefreshToken: string;
}): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return async (dispatch) => {
return async (dispatch: MetaMaskReduxDispatch) => {
try {
await submitRequestToBackground('showInteractiveReplacementTokenBanner', [
url,
@ -37,7 +37,7 @@ export function showInteractiveReplacementTokenBanner({
}
export function setTypedMessageInProgress(msgId: string) {
return async (dispatch: any) => {
return async (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication());
try {
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
* Example usage: