1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/ui/components/app/signature-request-original/signature-request-original.component.js
amerkadicE 80e4a1fef4
Update signature request screens (#15776)
Fix e2e test

Update siteicon for v4 signature type

Code refactor

Code refactor

Remove origin and address in signatrue request

Update e2e tests

Use getNetworkName function

Move header component inline jsx

Update snaps
2022-11-30 19:11:36 +01:00

359 lines
10 KiB
JavaScript

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { ObjectInspector } from 'react-inspector';
import LedgerInstructionField from '../ledger-instruction-field';
import { MESSAGE_TYPE } from '../../../../shared/constants/app';
import { EVENT } from '../../../../shared/constants/metametrics';
import { getURLHostName } from '../../../helpers/utils/util';
import { conversionUtil } from '../../../../shared/modules/conversion.utils';
import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils';
import Button from '../../ui/button';
import SiteOrigin from '../../ui/site-origin';
import NetworkAccountBalanceHeader from '../network-account-balance-header';
import Typography from '../../ui/typography/typography';
import {
TYPOGRAPHY,
FONT_WEIGHT,
} from '../../../helpers/constants/design-system';
import { NETWORK_TYPES } from '../../../../shared/constants/network';
import SignatureRequestOriginalWarning from './signature-request-original-warning';
export default class SignatureRequestOriginal extends Component {
static contextTypes = {
t: PropTypes.func.isRequired,
trackEvent: PropTypes.func.isRequired,
};
static propTypes = {
fromAccount: PropTypes.shape({
address: PropTypes.string.isRequired,
balance: PropTypes.string,
name: PropTypes.string,
}).isRequired,
cancel: PropTypes.func.isRequired,
clearConfirmTransaction: PropTypes.func.isRequired,
conversionRate: PropTypes.number,
history: PropTypes.object.isRequired,
mostRecentOverviewPage: PropTypes.string.isRequired,
sign: PropTypes.func.isRequired,
txData: PropTypes.object.isRequired,
subjectMetadata: PropTypes.object,
hardwareWalletRequiresConnection: PropTypes.bool,
isLedgerWallet: PropTypes.bool,
nativeCurrency: PropTypes.string.isRequired,
messagesCount: PropTypes.number,
showRejectTransactionsConfirmationModal: PropTypes.func.isRequired,
cancelAll: PropTypes.func.isRequired,
provider: PropTypes.object,
};
state = {
fromAccount: this.props.fromAccount,
showSignatureRequestWarning: false,
};
getNetworkName() {
const { provider } = this.props;
const providerName = provider.type;
const { t } = this.context;
switch (providerName) {
case NETWORK_TYPES.MAINNET:
return t('mainnet');
case NETWORK_TYPES.GOERLI:
return t('goerli');
case NETWORK_TYPES.SEPOLIA:
return t('sepolia');
case NETWORK_TYPES.LOCALHOST:
return t('localhost');
default:
return provider.nickname || t('unknownNetwork');
}
}
msgHexToText = (hex) => {
try {
const stripped = stripHexPrefix(hex);
const buff = Buffer.from(stripped, 'hex');
return buff.length === 32 ? hex : buff.toString('utf8');
} catch (e) {
return hex;
}
};
renderTypedData = (data) => {
const { t } = this.context;
const { domain, message } = JSON.parse(data);
return (
<div className="request-signature__typed-container">
{domain ? (
<div>
<h1>{t('domain')}</h1>
<ObjectInspector data={domain} expandLevel={1} name="domain" />
</div>
) : (
''
)}
{message ? (
<div>
<h1>{t('message')}</h1>
<ObjectInspector data={message} expandLevel={1} name="message" />
</div>
) : (
''
)}
</div>
);
};
renderBody = () => {
let rows;
const notice = `${this.context.t('youSign')}:`;
const { txData, subjectMetadata } = this.props;
const {
type,
msgParams: { data },
} = txData;
if (type === MESSAGE_TYPE.PERSONAL_SIGN) {
rows = [
{ name: this.context.t('message'), value: this.msgHexToText(data) },
];
} else if (type === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA) {
rows = data;
} else if (type === MESSAGE_TYPE.ETH_SIGN) {
rows = [{ name: this.context.t('message'), value: data }];
}
const targetSubjectMetadata = txData.msgParams.origin
? subjectMetadata?.[txData.msgParams.origin]
: null;
return (
<div className="request-signature__body">
<div className="request-signature__origin">
<SiteOrigin
siteOrigin={txData.msgParams.origin}
iconSrc={targetSubjectMetadata?.iconUrl}
iconName={
getURLHostName(targetSubjectMetadata?.origin) ||
targetSubjectMetadata?.origin
}
chip
/>
</div>
<Typography
className="request-signature__content__title"
variant={TYPOGRAPHY.H3}
fontWeight={FONT_WEIGHT.BOLD}
>
{this.context.t('sigRequest')}
</Typography>
<div className={classnames('request-signature__notice')}>{notice}</div>
<div className="request-signature__rows">
{rows.map(({ name, value }, index) => {
if (typeof value === 'boolean') {
// eslint-disable-next-line no-param-reassign
value = value.toString();
}
return (
<div
className="request-signature__row"
key={`request-signature-row-${index}`}
>
<div className="request-signature__row-title">{`${name}:`}</div>
<div className="request-signature__row-value">{value}</div>
</div>
);
})}
</div>
</div>
);
};
onSubmit = async (event) => {
const { clearConfirmTransaction, history, mostRecentOverviewPage, sign } =
this.props;
const { trackEvent, type } = this.context;
await sign(event);
trackEvent({
category: EVENT.CATEGORIES.TRANSACTIONS,
event: 'Confirm',
properties: {
action: 'Sign Request',
legacy_event: true,
type,
},
});
clearConfirmTransaction();
history.push(mostRecentOverviewPage);
};
onCancel = async (event) => {
const { clearConfirmTransaction, history, mostRecentOverviewPage, cancel } =
this.props;
const { trackEvent, type } = this.context;
await cancel(event);
trackEvent({
category: EVENT.CATEGORIES.TRANSACTIONS,
event: 'Cancel',
properties: {
action: 'Sign Request',
legacy_event: true,
type,
},
});
clearConfirmTransaction();
history.push(mostRecentOverviewPage);
};
renderFooter = () => {
const {
cancel,
sign,
clearConfirmTransaction,
history,
mostRecentOverviewPage,
txData: { type },
hardwareWalletRequiresConnection,
} = this.props;
const { trackEvent, t } = this.context;
return (
<div className="request-signature__footer">
<Button
type="secondary"
large
className="request-signature__footer__cancel-button"
onClick={async (event) => {
await cancel(event);
trackEvent({
category: EVENT.CATEGORIES.TRANSACTIONS,
event: 'Cancel',
properties: {
action: 'Sign Request',
legacy_event: true,
type,
},
});
clearConfirmTransaction();
history.push(mostRecentOverviewPage);
}}
>
{t('reject')}
</Button>
<Button
data-testid="request-signature__sign"
type="primary"
large
className="request-signature__footer__sign-button"
disabled={hardwareWalletRequiresConnection}
onClick={async (event) => {
if (type === MESSAGE_TYPE.ETH_SIGN) {
this.setState({ showSignatureRequestWarning: true });
} else {
await sign(event);
trackEvent({
category: EVENT.CATEGORIES.TRANSACTIONS,
event: 'Confirm',
properties: {
action: 'Sign Request',
legacy_event: true,
type,
},
});
clearConfirmTransaction();
history.push(mostRecentOverviewPage);
}
}}
>
{t('sign')}
</Button>
</div>
);
};
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, conversionRate, nativeCurrency } = this.props;
const { fromAccount, showSignatureRequestWarning } = this.state;
const { t } = this.context;
const rejectNText = t('rejectRequestsN', [messagesCount]);
const currentNetwork = this.getNetworkName();
const balanceInBaseAsset = conversionUtil(fromAccount.balance, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
fromDenomination: 'WEI',
numberOfDecimals: 6,
conversionRate,
});
return (
<div className="request-signature__container">
<div className="request-signature__account">
<NetworkAccountBalanceHeader
networkName={currentNetwork}
accountName={fromAccount.name}
accountBalance={balanceInBaseAsset}
tokenName={nativeCurrency}
accountAddress={fromAccount.address}
/>
</div>
{this.renderBody()}
{this.props.isLedgerWallet ? (
<div className="confirm-approve-content__ledger-instruction-wrapper">
<LedgerInstructionField showDataInstruction />
</div>
) : null}
{showSignatureRequestWarning && (
<SignatureRequestOriginalWarning
senderAddress={fromAccount.address}
name={fromAccount.name}
onSubmit={async (event) => await this.onSubmit(event)}
onCancel={async (event) => await this.onCancel(event)}
/>
)}
{this.renderFooter()}
{messagesCount > 1 ? (
<Button
type="link"
className="request-signature__container__reject"
onClick={() => this.handleCancelAll()}
>
{rejectNText}
</Button>
) : null}
</div>
);
};
}