mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Signature-Request refactor (#19104)
* refactoring signature-request and adding test coverage * adding storybook and removing the reduntant files: * adding new components from * replacing <SiteOrigin/> with <TagUrl/> * updating review comments from Jyoti and George * adding the hook * refactoring in the changes from #18770 MMI PR * adding new hook for the MMISign changes * updating lavamoat * updating lavamoat * removing a commeted line * updating the sign check with accountType conditional * fixing build issues * updating the review comments on the hooks * updating signatureRequestHeader * lint fix * fixing test failure * lint fix * updating review comments * adding the renamed hook * updating the origin url * fixing test failure * migrating changes from #19184 * updating snapshot * fixing e2e failure * fixing e2e failure * addressing review comments from Joao * migrating chnages from #19892 * moving shallowEqual inside of mmi build * migrating changes from #19881 * fixing build failure * migrating changes from #19949 * migrating changes from #19468 * updating snapshot * updating snapshot * updating QA review comments * fixing full screen height issue from develop * migrating changes from #20083 * fixing snapshot
This commit is contained in:
parent
6ce80fe997
commit
0c203d0518
@ -136,7 +136,7 @@ describe('Eth sign', function () {
|
|||||||
|
|
||||||
await driver.waitForSelector({
|
await driver.waitForSelector({
|
||||||
text: 'Reject 2 requests',
|
text: 'Reject 2 requests',
|
||||||
tag: 'a',
|
tag: 'button',
|
||||||
});
|
});
|
||||||
|
|
||||||
await verifyAndAssertEthSign(driver, DAPP_URL, expectedEthSignMessage);
|
await verifyAndAssertEthSign(driver, DAPP_URL, expectedEthSignMessage);
|
||||||
|
@ -102,7 +102,7 @@ describe('Personal sign', function () {
|
|||||||
|
|
||||||
await driver.waitForSelector({
|
await driver.waitForSelector({
|
||||||
text: 'Reject 2 requests',
|
text: 'Reject 2 requests',
|
||||||
tag: 'a',
|
tag: 'button',
|
||||||
});
|
});
|
||||||
|
|
||||||
const personalMessageRow = await driver.findElement(
|
const personalMessageRow = await driver.findElement(
|
||||||
|
@ -160,7 +160,7 @@ describe('Sign Typed Data Signature Request', function () {
|
|||||||
|
|
||||||
await driver.waitForSelector({
|
await driver.waitForSelector({
|
||||||
text: 'Reject 2 requests',
|
text: 'Reject 2 requests',
|
||||||
tag: 'a',
|
tag: 'button',
|
||||||
});
|
});
|
||||||
|
|
||||||
await verifyAndAssertSignTypedData(
|
await verifyAndAssertSignTypedData(
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
} from '../../../helpers/utils/util';
|
} from '../../../helpers/utils/util';
|
||||||
import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils';
|
import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils';
|
||||||
import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils';
|
import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils';
|
||||||
import Button from '../../ui/button';
|
|
||||||
import SiteOrigin from '../../ui/site-origin';
|
import SiteOrigin from '../../ui/site-origin';
|
||||||
import Typography from '../../ui/typography/typography';
|
import Typography from '../../ui/typography/typography';
|
||||||
import { PageContainerFooter } from '../../ui/page-container';
|
import { PageContainerFooter } from '../../ui/page-container';
|
||||||
@ -23,6 +22,7 @@ import {
|
|||||||
FontWeight,
|
FontWeight,
|
||||||
TextAlign,
|
TextAlign,
|
||||||
TextColor,
|
TextColor,
|
||||||
|
Size,
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
IconColor,
|
IconColor,
|
||||||
DISPLAY,
|
DISPLAY,
|
||||||
@ -31,12 +31,20 @@ import {
|
|||||||
BackgroundColor,
|
BackgroundColor,
|
||||||
///: END:ONLY_INCLUDE_IN
|
///: END:ONLY_INCLUDE_IN
|
||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
|
import {
|
||||||
import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message';
|
ButtonLink,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
Icon,
|
||||||
|
IconName,
|
||||||
|
Text,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../component-library';
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
import { Icon, IconName, Text } from '../../component-library';
|
|
||||||
import Box from '../../ui/box/box';
|
import Box from '../../ui/box/box';
|
||||||
///: END:ONLY_INCLUDE_IN
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
|
||||||
|
import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message';
|
||||||
|
|
||||||
import SignatureRequestHeader from '../signature-request-header';
|
import SignatureRequestHeader from '../signature-request-header';
|
||||||
import SignatureRequestOriginalWarning from './signature-request-original-warning';
|
import SignatureRequestOriginalWarning from './signature-request-original-warning';
|
||||||
|
|
||||||
@ -366,13 +374,13 @@ export default class SignatureRequestOriginal extends Component {
|
|||||||
)}
|
)}
|
||||||
{this.renderFooter()}
|
{this.renderFooter()}
|
||||||
{messagesCount > 1 ? (
|
{messagesCount > 1 ? (
|
||||||
<Button
|
<ButtonLink
|
||||||
type="link"
|
size={Size.inherit}
|
||||||
className="request-signature__container__reject"
|
className="request-signature__container__reject"
|
||||||
onClick={() => this.handleCancelAll()}
|
onClick={() => this.handleCancelAll()}
|
||||||
>
|
>
|
||||||
{rejectNText}
|
{rejectNText}
|
||||||
</Button>
|
</ButtonLink>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -50,7 +50,6 @@ export default function SignatureRequestSIWE({ txData }) {
|
|||||||
const t = useContext(I18nContext);
|
const t = useContext(I18nContext);
|
||||||
const allAccounts = useSelector(accountsWithSendEtherInfoSelector);
|
const allAccounts = useSelector(accountsWithSendEtherInfoSelector);
|
||||||
const subjectMetadata = useSelector(getSubjectMetadata);
|
const subjectMetadata = useSelector(getSubjectMetadata);
|
||||||
|
|
||||||
const messagesCount = useSelector(getTotalUnapprovedMessagesCount);
|
const messagesCount = useSelector(getTotalUnapprovedMessagesCount);
|
||||||
const messagesList = useSelector(unconfirmedMessagesHashSelector);
|
const messagesList = useSelector(unconfirmedMessagesHashSelector);
|
||||||
const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage);
|
const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage);
|
||||||
|
@ -41,7 +41,7 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
|
|
||||||
of
|
of
|
||||||
|
|
||||||
1
|
0
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="confirm-page-container-navigation__longtext"
|
class="confirm-page-container-navigation__longtext"
|
||||||
@ -51,7 +51,7 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="confirm-page-container-navigation__container"
|
class="confirm-page-container-navigation__container"
|
||||||
style="visibility: initial;"
|
style="visibility: hidden;"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="confirm-page-container-navigation__arrow"
|
class="confirm-page-container-navigation__arrow"
|
||||||
@ -92,7 +92,7 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
style="height: 32px; width: 32px; border-radius: 16px;"
|
style="height: 32px; width: 32px; border-radius: 16px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 32px; height: 32px; display: inline-block; background: rgb(245, 228, 0);"
|
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 32px; height: 32px; display: inline-block; background: rgb(24, 151, 242);"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
height="32"
|
height="32"
|
||||||
@ -101,25 +101,25 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
y="0"
|
y="0"
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
fill="#F2BE02"
|
fill="#FA7900"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(5.482725134273373 -5.1953603353074) rotate(387.1 16 16)"
|
transform="translate(-0.4291965340260923 -4.589212785086649) rotate(266.5 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
/>
|
/>
|
||||||
<rect
|
<rect
|
||||||
fill="#01778E"
|
fill="#F2A202"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(-2.6054559418209475 16.704606255523125) rotate(227.4 16 16)"
|
transform="translate(2.4067447047270143 13.767950912205709) rotate(242.5 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
/>
|
/>
|
||||||
<rect
|
<rect
|
||||||
fill="#C81435"
|
fill="#C8144A"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(17.969690840904306 -12.592649051897114) rotate(422.3 16 16)"
|
transform="translate(-19.808734531871874 -18.328897166120687) rotate(396.2 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
@ -134,7 +134,7 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
<span
|
<span
|
||||||
class="icon-with-fallback__fallback"
|
class="icon-with-fallback__fallback"
|
||||||
>
|
>
|
||||||
U
|
L
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -144,12 +144,12 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
|
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
|
||||||
>
|
>
|
||||||
Unknown private network
|
Localhost 8545
|
||||||
</h6>
|
</h6>
|
||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
||||||
>
|
>
|
||||||
Antonio
|
John Doe
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -165,9 +165,9 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
align="end"
|
align="end"
|
||||||
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
||||||
>
|
>
|
||||||
966.987986
|
0
|
||||||
|
|
||||||
ABC
|
ETH
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -179,56 +179,48 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
class="signature-request__origin"
|
class="signature-request__origin"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="site-origin"
|
class="box mm-tag-url box--padding-right-4 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--align-items-center box--background-color-background-default box--rounded-pill box--border-color-border-default box--border-width-1 box--border-style-solid"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="chip chip--with-left-icon chip--border-color-border-muted chip--background-color-undefined"
|
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-favicon mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="chip__left-icon"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class=""
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon-with-fallback__fallback"
|
class="box mm-icon mm-icon--size-md box--display-inline-block box--flex-direction-row box--color-icon-default"
|
||||||
>
|
style="mask-image: url('./images/icons/global.svg');"
|
||||||
T
|
/>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<p
|
||||||
<span
|
class="mm-box mm-text mm-text--body-md mm-text--ellipsis mm-box--color-text-alternative"
|
||||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
test
|
test
|
||||||
</span>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h2
|
||||||
<h3
|
class="mm-box mm-text signature-request__content__title mm-text--heading-lg mm-box--margin-top-4 mm-box--color-text-default"
|
||||||
class="mm-box mm-text signature-request__content__title mm-text--heading-md mm-box--margin-top-4 mm-box--color-text-default"
|
|
||||||
>
|
>
|
||||||
Signature request
|
Signature request
|
||||||
</h3>
|
</h2>
|
||||||
<h6
|
<h6
|
||||||
align="center"
|
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-text--text-align-center mm-box--margin-top-4 mm-box--margin-right-12 mm-box--margin-left-12 mm-box--color-text-alternative"
|
||||||
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-box--margin-12 mm-box--margin-top-3 mm-box--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
Only sign this message if you fully understand the content and trust the requesting site.
|
Only sign this message if you fully understand the content and trust the requesting site.
|
||||||
</h6>
|
</h6>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<button
|
||||||
class="button btn-link signature-request-content__verify-contract-details"
|
class="mm-box mm-text mm-button-base signature-request-content__verify-contract-details mm-button-link mm-button-link--size-auto mm-text--body-md-medium mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
|
||||||
data-testid="verify-contract-details"
|
data-testid="verify-contract-details"
|
||||||
role="button"
|
>
|
||||||
tabindex="0"
|
<span
|
||||||
|
class="mm-box mm-text mm-text--inherit mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
Verify third-party details
|
Verify third-party details
|
||||||
</h6>
|
</h6>
|
||||||
</a>
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -773,6 +765,12 @@ exports[`Signature Request Component render should match snapshot when we are us
|
|||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
class="mm-box mm-text mm-button-base signature-request__reject-all-button mm-button-link mm-button-link--size-inherit mm-text--body-md-medium mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
|
||||||
|
data-testid="signature-request-reject-all"
|
||||||
|
>
|
||||||
|
Reject 2 requests
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -818,7 +816,7 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
|
|
||||||
of
|
of
|
||||||
|
|
||||||
1
|
0
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="confirm-page-container-navigation__longtext"
|
class="confirm-page-container-navigation__longtext"
|
||||||
@ -828,7 +826,7 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="confirm-page-container-navigation__container"
|
class="confirm-page-container-navigation__container"
|
||||||
style="visibility: initial;"
|
style="visibility: hidden;"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="confirm-page-container-navigation__arrow"
|
class="confirm-page-container-navigation__arrow"
|
||||||
@ -869,7 +867,7 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
style="height: 32px; width: 32px; border-radius: 16px;"
|
style="height: 32px; width: 32px; border-radius: 16px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 32px; height: 32px; display: inline-block; background: rgb(245, 228, 0);"
|
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 32px; height: 32px; display: inline-block; background: rgb(24, 151, 242);"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
height="32"
|
height="32"
|
||||||
@ -878,25 +876,25 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
y="0"
|
y="0"
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
fill="#F2BE02"
|
fill="#FA7900"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(5.482725134273373 -5.1953603353074) rotate(387.1 16 16)"
|
transform="translate(-0.4291965340260923 -4.589212785086649) rotate(266.5 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
/>
|
/>
|
||||||
<rect
|
<rect
|
||||||
fill="#01778E"
|
fill="#F2A202"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(-2.6054559418209475 16.704606255523125) rotate(227.4 16 16)"
|
transform="translate(2.4067447047270143 13.767950912205709) rotate(242.5 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
/>
|
/>
|
||||||
<rect
|
<rect
|
||||||
fill="#C81435"
|
fill="#C8144A"
|
||||||
height="32"
|
height="32"
|
||||||
transform="translate(17.969690840904306 -12.592649051897114) rotate(422.3 16 16)"
|
transform="translate(-19.808734531871874 -18.328897166120687) rotate(396.2 16 16)"
|
||||||
width="32"
|
width="32"
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
@ -911,7 +909,7 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
<span
|
<span
|
||||||
class="icon-with-fallback__fallback"
|
class="icon-with-fallback__fallback"
|
||||||
>
|
>
|
||||||
U
|
L
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -921,12 +919,12 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
|
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
|
||||||
>
|
>
|
||||||
Unknown private network
|
Localhost 8545
|
||||||
</h6>
|
</h6>
|
||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
||||||
>
|
>
|
||||||
Antonio
|
John Doe
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -942,9 +940,9 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
align="end"
|
align="end"
|
||||||
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"
|
||||||
>
|
>
|
||||||
1515270.174798
|
0
|
||||||
|
|
||||||
DEF
|
ETH
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -956,56 +954,48 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
class="signature-request__origin"
|
class="signature-request__origin"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="site-origin"
|
class="box mm-tag-url box--padding-right-4 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--align-items-center box--background-color-background-default box--rounded-pill box--border-color-border-default box--border-width-1 box--border-style-solid"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="chip chip--with-left-icon chip--border-color-border-muted chip--background-color-undefined"
|
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-favicon mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="chip__left-icon"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class=""
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon-with-fallback__fallback"
|
class="box mm-icon mm-icon--size-md box--display-inline-block box--flex-direction-row box--color-icon-default"
|
||||||
>
|
style="mask-image: url('./images/icons/global.svg');"
|
||||||
T
|
/>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<p
|
||||||
<span
|
class="mm-box mm-text mm-text--body-md mm-text--ellipsis mm-box--color-text-alternative"
|
||||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
test
|
test
|
||||||
</span>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h2
|
||||||
<h3
|
class="mm-box mm-text signature-request__content__title mm-text--heading-lg mm-box--margin-top-4 mm-box--color-text-default"
|
||||||
class="mm-box mm-text signature-request__content__title mm-text--heading-md mm-box--margin-top-4 mm-box--color-text-default"
|
|
||||||
>
|
>
|
||||||
Signature request
|
Signature request
|
||||||
</h3>
|
</h2>
|
||||||
<h6
|
<h6
|
||||||
align="center"
|
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-text--text-align-center mm-box--margin-top-4 mm-box--margin-right-12 mm-box--margin-left-12 mm-box--color-text-alternative"
|
||||||
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-box--margin-12 mm-box--margin-top-3 mm-box--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
Only sign this message if you fully understand the content and trust the requesting site.
|
Only sign this message if you fully understand the content and trust the requesting site.
|
||||||
</h6>
|
</h6>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<button
|
||||||
class="button btn-link signature-request-content__verify-contract-details"
|
class="mm-box mm-text mm-button-base signature-request-content__verify-contract-details mm-button-link mm-button-link--size-auto mm-text--body-md-medium mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
|
||||||
data-testid="verify-contract-details"
|
data-testid="verify-contract-details"
|
||||||
role="button"
|
>
|
||||||
tabindex="0"
|
<span
|
||||||
|
class="mm-box mm-text mm-text--inherit mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
Verify third-party details
|
Verify third-party details
|
||||||
</h6>
|
</h6>
|
||||||
</a>
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -1550,6 +1540,12 @@ exports[`Signature Request Component render should match snapshot when we want t
|
|||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
class="mm-box mm-text mm-button-base signature-request__reject-all-button mm-button-link mm-button-link--size-inherit mm-text--body-md-medium mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
|
||||||
|
data-testid="signature-request-reject-all"
|
||||||
|
>
|
||||||
|
Reject 2 requests
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
@ -1 +1 @@
|
|||||||
export { default } from './signature-request.container';
|
export { default } from './signature-request';
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
||||||
@include screen-sm-min {
|
@include screen-sm-min {
|
||||||
max-height: 80vh;
|
max-height: max-content;
|
||||||
min-height: 570px;
|
min-height: 570px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__reject-all-button {
|
&__reject-all-button {
|
||||||
margin-top: -15px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__origin {
|
&__origin {
|
||||||
@ -58,12 +58,6 @@
|
|||||||
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
@include H6;
|
|
||||||
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.signature-request-content__verify-contract-details {
|
a.signature-request-content__verify-contract-details {
|
||||||
|
@ -1,427 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import { memoize } from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { ethErrors, serializeError } from 'eth-rpc-errors';
|
|
||||||
import LedgerInstructionField from '../ledger-instruction-field';
|
|
||||||
import {
|
|
||||||
sanitizeMessage,
|
|
||||||
getURLHostName,
|
|
||||||
getNetworkNameFromProviderType,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
shortenAddress,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../helpers/utils/util';
|
|
||||||
import {
|
|
||||||
MetaMetricsEventCategory,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
MetaMetricsEventName,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../../shared/constants/metametrics';
|
|
||||||
import SiteOrigin from '../../ui/site-origin';
|
|
||||||
import Button from '../../ui/button';
|
|
||||||
import ContractDetailsModal from '../modals/contract-details-modal/contract-details-modal';
|
|
||||||
import {
|
|
||||||
TextAlign,
|
|
||||||
TextColor,
|
|
||||||
TextVariant,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
IconColor,
|
|
||||||
Display,
|
|
||||||
BlockSize,
|
|
||||||
BackgroundColor,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../helpers/constants/design-system';
|
|
||||||
import NetworkAccountBalanceHeader from '../network-account-balance-header';
|
|
||||||
import { Numeric } from '../../../../shared/modules/Numeric';
|
|
||||||
import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils';
|
|
||||||
import { EtherDenomination } from '../../../../shared/constants/common';
|
|
||||||
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
|
|
||||||
import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message';
|
|
||||||
import { formatCurrency } from '../../../helpers/utils/confirm-tx.util';
|
|
||||||
import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils';
|
|
||||||
|
|
||||||
import {
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
Box,
|
|
||||||
Icon,
|
|
||||||
IconName,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
Text,
|
|
||||||
} from '../../component-library';
|
|
||||||
import Footer from './signature-request-footer';
|
|
||||||
import Message from './signature-request-message';
|
|
||||||
|
|
||||||
export default class SignatureRequest extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
/**
|
|
||||||
* The display content of transaction data
|
|
||||||
*/
|
|
||||||
txData: PropTypes.object.isRequired,
|
|
||||||
/**
|
|
||||||
* The display content of sender account
|
|
||||||
*/
|
|
||||||
fromAccount: PropTypes.shape({
|
|
||||||
address: PropTypes.string.isRequired,
|
|
||||||
balance: PropTypes.string,
|
|
||||||
name: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
/**
|
|
||||||
* Check if the wallet is ledget wallet or not
|
|
||||||
*/
|
|
||||||
isLedgerWallet: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the hardware wallet requires a connection disables the sign button if true.
|
|
||||||
*/
|
|
||||||
hardwareWalletRequiresConnection: PropTypes.bool.isRequired,
|
|
||||||
/**
|
|
||||||
* Current network chainId
|
|
||||||
*/
|
|
||||||
chainId: PropTypes.string,
|
|
||||||
/**
|
|
||||||
* RPC prefs of the current network
|
|
||||||
*/
|
|
||||||
rpcPrefs: PropTypes.object,
|
|
||||||
nativeCurrency: PropTypes.string,
|
|
||||||
currentCurrency: PropTypes.string.isRequired,
|
|
||||||
conversionRate: PropTypes.number,
|
|
||||||
providerConfig: PropTypes.object,
|
|
||||||
subjectMetadata: PropTypes.object,
|
|
||||||
unapprovedMessagesCount: PropTypes.number,
|
|
||||||
clearConfirmTransaction: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object,
|
|
||||||
mostRecentOverviewPage: PropTypes.string,
|
|
||||||
showRejectTransactionsConfirmationModal: PropTypes.func.isRequired,
|
|
||||||
cancelAllApprovals: PropTypes.func.isRequired,
|
|
||||||
resolvePendingApproval: PropTypes.func.isRequired,
|
|
||||||
rejectPendingApproval: PropTypes.func.isRequired,
|
|
||||||
completedTx: PropTypes.func.isRequired,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
showCustodianDeepLink: PropTypes.func,
|
|
||||||
isNotification: PropTypes.bool,
|
|
||||||
mmiOnSignCallback: PropTypes.func,
|
|
||||||
// Used to show a warning if the signing account is not the selected account
|
|
||||||
// Largely relevant for contract wallet custodians
|
|
||||||
selectedAccount: PropTypes.object,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
trackEvent: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
hasScrolledMessage: false,
|
|
||||||
showContractDetails: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.txData.custodyId) {
|
|
||||||
this.props.showCustodianDeepLink({
|
|
||||||
custodyId: this.props.txData.custodyId,
|
|
||||||
fromAddress: this.props.fromAccount.address,
|
|
||||||
closeNotification: this.props.isNotification,
|
|
||||||
onDeepLinkFetched: () => undefined,
|
|
||||||
onDeepLinkShown: () => {
|
|
||||||
this.context.trackEvent({
|
|
||||||
category: MetaMetricsEventCategory.MMI,
|
|
||||||
event: MetaMetricsEventName.SignatureDeeplinkDisplayed,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
|
|
||||||
setMessageRootRef(ref) {
|
|
||||||
this.messageRootRef = ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
formatWallet(wallet) {
|
|
||||||
return `${wallet.slice(0, 8)}...${wallet.slice(
|
|
||||||
wallet.length - 8,
|
|
||||||
wallet.length,
|
|
||||||
)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
memoizedParseMessage = memoize((data) => {
|
|
||||||
const { message, domain = {}, primaryType, types } = JSON.parse(data);
|
|
||||||
const sanitizedMessage = sanitizeMessage(message, primaryType, types);
|
|
||||||
return { sanitizedMessage, domain, primaryType };
|
|
||||||
});
|
|
||||||
|
|
||||||
handleCancelAll = () => {
|
|
||||||
const {
|
|
||||||
clearConfirmTransaction,
|
|
||||||
history,
|
|
||||||
mostRecentOverviewPage,
|
|
||||||
showRejectTransactionsConfirmationModal,
|
|
||||||
unapprovedMessagesCount,
|
|
||||||
cancelAllApprovals,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
showRejectTransactionsConfirmationModal({
|
|
||||||
unapprovedTxCount: unapprovedMessagesCount,
|
|
||||||
onSubmit: async () => {
|
|
||||||
await cancelAllApprovals();
|
|
||||||
clearConfirmTransaction();
|
|
||||||
history.push(mostRecentOverviewPage);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
providerConfig,
|
|
||||||
txData: {
|
|
||||||
msgParams: { data, origin, version },
|
|
||||||
type,
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
fromAccount: { address, balance, name },
|
|
||||||
isLedgerWallet,
|
|
||||||
hardwareWalletRequiresConnection,
|
|
||||||
chainId,
|
|
||||||
rpcPrefs,
|
|
||||||
txData,
|
|
||||||
subjectMetadata,
|
|
||||||
nativeCurrency,
|
|
||||||
currentCurrency,
|
|
||||||
conversionRate,
|
|
||||||
unapprovedMessagesCount,
|
|
||||||
resolvePendingApproval,
|
|
||||||
rejectPendingApproval,
|
|
||||||
completedTx,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const { t, trackEvent } = this.context;
|
|
||||||
const {
|
|
||||||
sanitizedMessage,
|
|
||||||
domain: { verifyingContract },
|
|
||||||
primaryType,
|
|
||||||
} = this.memoizedParseMessage(data);
|
|
||||||
const rejectNText = t('rejectRequestsN', [unapprovedMessagesCount]);
|
|
||||||
const networkName = getNetworkNameFromProviderType(providerConfig.type);
|
|
||||||
const currentNetwork =
|
|
||||||
networkName === ''
|
|
||||||
? providerConfig.nickname || t('unknownNetwork')
|
|
||||||
: t(networkName);
|
|
||||||
|
|
||||||
const balanceInBaseAsset = conversionRate
|
|
||||||
? formatCurrency(
|
|
||||||
getValueFromWeiHex({
|
|
||||||
value: balance,
|
|
||||||
fromCurrency: nativeCurrency,
|
|
||||||
toCurrency: currentCurrency,
|
|
||||||
conversionRate,
|
|
||||||
numberOfDecimals: 6,
|
|
||||||
toDenomination: EtherDenomination.ETH,
|
|
||||||
}),
|
|
||||||
currentCurrency,
|
|
||||||
)
|
|
||||||
: new Numeric(balance, 16, EtherDenomination.WEI)
|
|
||||||
.toDenomination(EtherDenomination.ETH)
|
|
||||||
.round(6)
|
|
||||||
.toBase(10)
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
const onSign = async () => {
|
|
||||||
///: 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',
|
|
||||||
properties: {
|
|
||||||
action: 'Sign Request',
|
|
||||||
legacy_event: true,
|
|
||||||
type,
|
|
||||||
version,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancel = async () => {
|
|
||||||
await rejectPendingApproval(
|
|
||||||
id,
|
|
||||||
serializeError(ethErrors.provider.userRejectedRequest()),
|
|
||||||
);
|
|
||||||
trackEvent({
|
|
||||||
category: MetaMetricsEventCategory.Transactions,
|
|
||||||
event: 'Cancel',
|
|
||||||
properties: {
|
|
||||||
action: 'Sign Request',
|
|
||||||
legacy_event: true,
|
|
||||||
type,
|
|
||||||
version,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const messageIsScrollable =
|
|
||||||
this.messageRootRef?.scrollHeight > this.messageRootRef?.clientHeight;
|
|
||||||
|
|
||||||
const targetSubjectMetadata = txData.msgParams.origin
|
|
||||||
? subjectMetadata?.[txData.msgParams.origin]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="signature-request">
|
|
||||||
<ConfirmPageContainerNavigation />
|
|
||||||
<div
|
|
||||||
className="request-signature__account"
|
|
||||||
data-testid="request-signature-account"
|
|
||||||
>
|
|
||||||
<NetworkAccountBalanceHeader
|
|
||||||
networkName={currentNetwork}
|
|
||||||
accountName={name}
|
|
||||||
accountBalance={balanceInBaseAsset}
|
|
||||||
tokenName={
|
|
||||||
conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency
|
|
||||||
}
|
|
||||||
accountAddress={address}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="signature-request-content">
|
|
||||||
{isSuspiciousResponse(txData?.securityProviderResponse) && (
|
|
||||||
<SecurityProviderBannerMessage
|
|
||||||
securityProviderResponse={txData.securityProviderResponse}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
this.props.selectedAccount.address === address ? null : (
|
|
||||||
<Box
|
|
||||||
className="request-signature__mismatch-info"
|
|
||||||
display={Display.Flex}
|
|
||||||
width={BlockSize.Full}
|
|
||||||
padding={4}
|
|
||||||
marginBottom={4}
|
|
||||||
backgroundColor={BackgroundColor.primaryMuted}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name={IconName.Info}
|
|
||||||
color={IconColor.infoDefault}
|
|
||||||
marginRight={2}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
variant={TextVariant.bodyXs}
|
|
||||||
color={TextColor.textDefault}
|
|
||||||
>
|
|
||||||
{this.context.t('mismatchAccount', [
|
|
||||||
shortenAddress(this.props.selectedAccount.address),
|
|
||||||
shortenAddress(address),
|
|
||||||
])}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
}
|
|
||||||
|
|
||||||
<div className="signature-request__origin">
|
|
||||||
<SiteOrigin
|
|
||||||
siteOrigin={origin}
|
|
||||||
iconSrc={targetSubjectMetadata?.iconUrl}
|
|
||||||
iconName={getURLHostName(origin) || origin}
|
|
||||||
chip
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
className="signature-request__content__title"
|
|
||||||
variant={TextVariant.headingMd}
|
|
||||||
as="h3"
|
|
||||||
marginTop={4}
|
|
||||||
>
|
|
||||||
{this.context.t('sigRequest')}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
className="request-signature__content__subtitle"
|
|
||||||
variant={TextVariant.bodySm}
|
|
||||||
as="h6"
|
|
||||||
color={TextColor.textAlternative}
|
|
||||||
align={TextAlign.Center}
|
|
||||||
margin={12}
|
|
||||||
marginTop={3}
|
|
||||||
>
|
|
||||||
{this.context.t('signatureRequestGuidance')}
|
|
||||||
</Text>
|
|
||||||
{verifyingContract ? (
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => this.setState({ showContractDetails: true })}
|
|
||||||
className="signature-request-content__verify-contract-details"
|
|
||||||
data-testid="verify-contract-details"
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
variant={TextVariant.bodySm}
|
|
||||||
as="h6"
|
|
||||||
color={TextColor.primaryDefault}
|
|
||||||
>
|
|
||||||
{this.context.t('verifyContractDetails')}
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
{isLedgerWallet ? (
|
|
||||||
<div className="confirm-approve-content__ledger-instruction-wrapper">
|
|
||||||
<LedgerInstructionField showDataInstruction />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Message
|
|
||||||
data={sanitizedMessage}
|
|
||||||
onMessageScrolled={() => this.setState({ hasScrolledMessage: true })}
|
|
||||||
setMessageRootRef={this.setMessageRootRef.bind(this)}
|
|
||||||
messageRootRef={this.messageRootRef}
|
|
||||||
messageIsScrollable={messageIsScrollable}
|
|
||||||
primaryType={primaryType}
|
|
||||||
/>
|
|
||||||
<Footer
|
|
||||||
cancelAction={onCancel}
|
|
||||||
signAction={onSign}
|
|
||||||
disabled={
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
Boolean(this.props.txData?.custodyId) ||
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
hardwareWalletRequiresConnection ||
|
|
||||||
(messageIsScrollable && !this.state.hasScrolledMessage)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{this.state.showContractDetails && (
|
|
||||||
<ContractDetailsModal
|
|
||||||
toAddress={verifyingContract}
|
|
||||||
chainId={chainId}
|
|
||||||
rpcPrefs={rpcPrefs}
|
|
||||||
onClose={() => this.setState({ showContractDetails: false })}
|
|
||||||
isContractRequestingSignature
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{unapprovedMessagesCount > 1 ? (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
className="signature-request__reject-all-button"
|
|
||||||
data-testid="signature-request-reject-all"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.handleCancelAll();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{rejectNText}
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app';
|
|
||||||
|
|
||||||
export { ENVIRONMENT_TYPE_NOTIFICATION };
|
|
@ -1,298 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import {
|
|
||||||
accountsWithSendEtherInfoSelector,
|
|
||||||
doesAddressRequireLedgerHidConnection,
|
|
||||||
getCurrentChainId,
|
|
||||||
getRpcPrefsForCurrentProvider,
|
|
||||||
getSubjectMetadata,
|
|
||||||
unconfirmedMessagesHashSelector,
|
|
||||||
getTotalUnapprovedMessagesCount,
|
|
||||||
getCurrentCurrency,
|
|
||||||
getPreferences,
|
|
||||||
conversionRateSelector,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
getAccountType,
|
|
||||||
getSelectedAccount,
|
|
||||||
unapprovedTypedMessagesSelector,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../selectors';
|
|
||||||
import {
|
|
||||||
isAddressLedger,
|
|
||||||
getNativeCurrency,
|
|
||||||
getProviderConfig,
|
|
||||||
} from '../../../ducks/metamask/metamask';
|
|
||||||
import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util';
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
// eslint-disable-next-line import/order
|
|
||||||
import { showCustodianDeepLink } from '@metamask-institutional/extension';
|
|
||||||
import {
|
|
||||||
mmiActionsFactory,
|
|
||||||
setTypedMessageInProgress,
|
|
||||||
} from '../../../store/institutional/institution-background';
|
|
||||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
|
||||||
import {
|
|
||||||
showCustodyConfirmLink,
|
|
||||||
checkForUnapprovedMessages,
|
|
||||||
} from '../../../store/institutional/institution-actions';
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
import {
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../../shared/constants/app';
|
|
||||||
|
|
||||||
import {
|
|
||||||
showModal,
|
|
||||||
resolvePendingApproval,
|
|
||||||
rejectPendingApproval,
|
|
||||||
rejectAllMessages,
|
|
||||||
completedTx,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
goHome,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} from '../../../store/actions';
|
|
||||||
import { getMostRecentOverviewPage } from '../../../ducks/history/history';
|
|
||||||
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck';
|
|
||||||
import SignatureRequest from './signature-request.component';
|
|
||||||
|
|
||||||
function mapStateToProps(state, ownProps) {
|
|
||||||
const { txData } = ownProps;
|
|
||||||
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
const envType = getEnvironmentType();
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
|
|
||||||
const {
|
|
||||||
msgParams: { from },
|
|
||||||
} = txData;
|
|
||||||
const providerConfig = getProviderConfig(state);
|
|
||||||
|
|
||||||
const hardwareWalletRequiresConnection =
|
|
||||||
doesAddressRequireLedgerHidConnection(state, from);
|
|
||||||
const isLedgerWallet = isAddressLedger(state, from);
|
|
||||||
const chainId = getCurrentChainId(state);
|
|
||||||
const rpcPrefs = getRpcPrefsForCurrentProvider(state);
|
|
||||||
const unconfirmedMessagesList = unconfirmedMessagesHashSelector(state);
|
|
||||||
const unapprovedMessagesCount = getTotalUnapprovedMessagesCount(state);
|
|
||||||
const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
|
|
||||||
|
|
||||||
return {
|
|
||||||
providerConfig,
|
|
||||||
isLedgerWallet,
|
|
||||||
hardwareWalletRequiresConnection,
|
|
||||||
chainId,
|
|
||||||
rpcPrefs,
|
|
||||||
unconfirmedMessagesList,
|
|
||||||
unapprovedMessagesCount,
|
|
||||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
|
||||||
nativeCurrency: getNativeCurrency(state),
|
|
||||||
currentCurrency: getCurrentCurrency(state),
|
|
||||||
conversionRate: useNativeCurrencyAsPrimaryCurrency
|
|
||||||
? null
|
|
||||||
: conversionRateSelector(state),
|
|
||||||
subjectMetadata: getSubjectMetadata(state),
|
|
||||||
// not forwarded to component
|
|
||||||
allAccounts: accountsWithSendEtherInfoSelector(state),
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
accountType: getAccountType(state),
|
|
||||||
isNotification: envType === ENVIRONMENT_TYPE_NOTIFICATION,
|
|
||||||
selectedAccount: getSelectedAccount(state),
|
|
||||||
unapprovedTypedMessages: unapprovedTypedMessagesSelector(state),
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mapDispatchToProps = null;
|
|
||||||
|
|
||||||
mapDispatchToProps = function (dispatch) {
|
|
||||||
return {
|
|
||||||
resolvePendingApproval: (id) => dispatch(resolvePendingApproval(id)),
|
|
||||||
completedTx: (id) => dispatch(completedTx(id)),
|
|
||||||
rejectPendingApproval: (id, error) =>
|
|
||||||
dispatch(rejectPendingApproval(id, error)),
|
|
||||||
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
|
|
||||||
showRejectTransactionsConfirmationModal: ({
|
|
||||||
onSubmit,
|
|
||||||
unapprovedTxCount: unapprovedMessagesCount,
|
|
||||||
}) => {
|
|
||||||
return dispatch(
|
|
||||||
showModal({
|
|
||||||
name: 'REJECT_TRANSACTIONS',
|
|
||||||
onSubmit,
|
|
||||||
unapprovedTxCount: unapprovedMessagesCount,
|
|
||||||
isRequestType: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cancelAllApprovals: (unconfirmedMessagesList) => {
|
|
||||||
dispatch(rejectAllMessages(unconfirmedMessagesList));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
function mmiMapDispatchToProps(dispatch) {
|
|
||||||
const mmiActions = mmiActionsFactory();
|
|
||||||
return {
|
|
||||||
setMsgInProgress: (msgId) => dispatch(setTypedMessageInProgress(msgId)),
|
|
||||||
showCustodianDeepLink: ({
|
|
||||||
custodyId,
|
|
||||||
fromAddress,
|
|
||||||
closeNotification,
|
|
||||||
onDeepLinkFetched,
|
|
||||||
onDeepLinkShown,
|
|
||||||
}) =>
|
|
||||||
showCustodianDeepLink({
|
|
||||||
dispatch,
|
|
||||||
mmiActions,
|
|
||||||
txId: undefined,
|
|
||||||
fromAddress,
|
|
||||||
custodyId,
|
|
||||||
isSignature: true,
|
|
||||||
closeNotification,
|
|
||||||
onDeepLinkFetched,
|
|
||||||
onDeepLinkShown,
|
|
||||||
showCustodyConfirmLink,
|
|
||||||
}),
|
|
||||||
showTransactionsFailedModal: ({
|
|
||||||
errorMessage,
|
|
||||||
closeNotification,
|
|
||||||
operationFailed,
|
|
||||||
}) =>
|
|
||||||
dispatch(
|
|
||||||
showModal({
|
|
||||||
name: 'TRANSACTION_FAILED',
|
|
||||||
errorMessage,
|
|
||||||
closeNotification,
|
|
||||||
operationFailed,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
setWaitForConfirmDeepLinkDialog: (wait) =>
|
|
||||||
dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)),
|
|
||||||
goHome: () => dispatch(goHome()),
|
|
||||||
resolvePendingApproval: (id) => dispatch(resolvePendingApproval(id)),
|
|
||||||
completedTx: (id) => dispatch(completedTx(id)),
|
|
||||||
rejectPendingApproval: (id, error) =>
|
|
||||||
dispatch(rejectPendingApproval(id, error)),
|
|
||||||
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
|
|
||||||
showRejectTransactionsConfirmationModal: ({
|
|
||||||
onSubmit,
|
|
||||||
unapprovedTxCount: unapprovedMessagesCount,
|
|
||||||
}) => {
|
|
||||||
return dispatch(
|
|
||||||
showModal({
|
|
||||||
name: 'REJECT_TRANSACTIONS',
|
|
||||||
onSubmit,
|
|
||||||
unapprovedTxCount: unapprovedMessagesCount,
|
|
||||||
isRequestType: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cancelAllApprovals: (unconfirmedMessagesList) => {
|
|
||||||
dispatch(rejectAllMessages(unconfirmedMessagesList));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
mapDispatchToProps = mmiMapDispatchToProps;
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
|
|
||||||
function mergeProps(stateProps, dispatchProps, ownProps) {
|
|
||||||
const {
|
|
||||||
allAccounts,
|
|
||||||
isLedgerWallet,
|
|
||||||
hardwareWalletRequiresConnection,
|
|
||||||
chainId,
|
|
||||||
rpcPrefs,
|
|
||||||
nativeCurrency,
|
|
||||||
currentCurrency,
|
|
||||||
conversionRate,
|
|
||||||
providerConfig,
|
|
||||||
subjectMetadata,
|
|
||||||
unconfirmedMessagesList,
|
|
||||||
unapprovedMessagesCount,
|
|
||||||
mostRecentOverviewPage,
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
accountType,
|
|
||||||
isNotification,
|
|
||||||
unapprovedTypedMessages,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
} = stateProps;
|
|
||||||
const { txData } = ownProps;
|
|
||||||
|
|
||||||
const {
|
|
||||||
cancelAll: dispatchCancelAll,
|
|
||||||
cancelAllApprovals: dispatchCancelAllApprovals,
|
|
||||||
} = dispatchProps;
|
|
||||||
|
|
||||||
const {
|
|
||||||
msgParams: { from },
|
|
||||||
} = txData;
|
|
||||||
|
|
||||||
const fromAccount = getAccountByAddress(allAccounts, from);
|
|
||||||
|
|
||||||
///: 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,
|
|
||||||
unapprovedTypedMessages,
|
|
||||||
);
|
|
||||||
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,
|
|
||||||
...dispatchProps,
|
|
||||||
fromAccount,
|
|
||||||
txData,
|
|
||||||
isLedgerWallet,
|
|
||||||
hardwareWalletRequiresConnection,
|
|
||||||
chainId,
|
|
||||||
rpcPrefs,
|
|
||||||
nativeCurrency,
|
|
||||||
currentCurrency,
|
|
||||||
conversionRate,
|
|
||||||
providerConfig,
|
|
||||||
subjectMetadata,
|
|
||||||
unapprovedMessagesCount,
|
|
||||||
mostRecentOverviewPage,
|
|
||||||
cancelAll: () => dispatchCancelAll(valuesFor(unconfirmedMessagesList)),
|
|
||||||
cancelAllApprovals: () =>
|
|
||||||
dispatchCancelAllApprovals(valuesFor(unconfirmedMessagesList)),
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
||||||
mmiOnSignCallback,
|
|
||||||
///: END:ONLY_INCLUDE_IN
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps,
|
|
||||||
mergeProps,
|
|
||||||
)(SignatureRequest);
|
|
@ -1,237 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import sinon from 'sinon';
|
|
||||||
import { fireEvent, screen, act } from '@testing-library/react';
|
|
||||||
import configureMockStore from 'redux-mock-store';
|
|
||||||
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
|
||||||
import SignatureRequest from './signature-request.container';
|
|
||||||
|
|
||||||
const mockStoreWithEth = {
|
|
||||||
metamask: {
|
|
||||||
tokenList: {
|
|
||||||
'0x514910771af9ca656af840dff83e8264ecf986ca': {
|
|
||||||
address: '0x514910771af9ca656af840dff83e8264ecf986ca',
|
|
||||||
symbol: 'LINK',
|
|
||||||
decimals: 18,
|
|
||||||
name: 'ChainLink Token',
|
|
||||||
iconUrl: 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png',
|
|
||||||
aggregators: [
|
|
||||||
'Aave',
|
|
||||||
'Bancor',
|
|
||||||
'CMC',
|
|
||||||
'Crypto.com',
|
|
||||||
'CoinGecko',
|
|
||||||
'1inch',
|
|
||||||
'Paraswap',
|
|
||||||
'PMM',
|
|
||||||
'Zapper',
|
|
||||||
'Zerion',
|
|
||||||
'0x',
|
|
||||||
],
|
|
||||||
occurrences: 12,
|
|
||||||
unlisted: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
identities: {
|
|
||||||
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
|
|
||||||
name: 'Account 2',
|
|
||||||
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
addressBook: {
|
|
||||||
undefined: {
|
|
||||||
0: {
|
|
||||||
address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0',
|
|
||||||
name: '',
|
|
||||||
isEns: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
providerConfig: {
|
|
||||||
type: 'rpc',
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
useNativeCurrencyAsPrimaryCurrency: true,
|
|
||||||
},
|
|
||||||
accounts: {
|
|
||||||
'0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': {
|
|
||||||
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
|
||||||
balance: '0x03',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cachedBalances: {},
|
|
||||||
unapprovedDecryptMsgs: {},
|
|
||||||
unapprovedEncryptionPublicKeyMsgs: {},
|
|
||||||
unconfirmedTransactions: {},
|
|
||||||
selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
|
||||||
nativeCurrency: 'ETH',
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockStoreWithFiat = {
|
|
||||||
...mockStoreWithEth,
|
|
||||||
preferences: {
|
|
||||||
useNativeCurrencyAsPrimaryCurrency: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
describe('Signature Request', () => {
|
|
||||||
const propsWithEth = {
|
|
||||||
fromAccount: {
|
|
||||||
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
|
||||||
balance: '0x346ba7725f412cbfdb',
|
|
||||||
name: 'John Doe',
|
|
||||||
},
|
|
||||||
history: {
|
|
||||||
push: sinon.spy(),
|
|
||||||
},
|
|
||||||
hardwareWalletRequiresConnection: false,
|
|
||||||
mostRecentOverviewPage: '/',
|
|
||||||
clearConfirmTransaction: sinon.spy(),
|
|
||||||
cancelMessage: sinon.spy(),
|
|
||||||
cancel: sinon.stub().resolves(),
|
|
||||||
rejectPendingApproval: sinon.stub().resolves(),
|
|
||||||
showRejectTransactionsConfirmationModal: sinon.stub().resolves(),
|
|
||||||
cancelAll: sinon.stub().resolves(),
|
|
||||||
providerConfig: {
|
|
||||||
type: 'rpc',
|
|
||||||
},
|
|
||||||
unapprovedMessagesCount: 2,
|
|
||||||
sign: sinon.stub().resolves(),
|
|
||||||
cancelAllApprovals: sinon.stub().resolves(),
|
|
||||||
resolvePendingApproval: sinon.stub().resolves(),
|
|
||||||
completedTx: sinon.stub().resolves(),
|
|
||||||
txData: {
|
|
||||||
msgParams: {
|
|
||||||
id: 1,
|
|
||||||
data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"4","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}',
|
|
||||||
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
|
||||||
origin: 'test.domain',
|
|
||||||
},
|
|
||||||
status: 'unapproved',
|
|
||||||
time: 1,
|
|
||||||
type: 'eth_sign',
|
|
||||||
},
|
|
||||||
nativeCurrency: 'ETH',
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: null,
|
|
||||||
selectedAccount: {
|
|
||||||
address: '0x123456789abcdef',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const propsWithFiat = {
|
|
||||||
...propsWithEth,
|
|
||||||
conversionRate: 156.72,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Render with different currencies', () => {
|
|
||||||
it('should render balance with ETH when conversionRate is not provided', () => {
|
|
||||||
const store = configureMockStore()(mockStoreWithEth);
|
|
||||||
renderWithProvider(
|
|
||||||
<SignatureRequest.WrappedComponent {...propsWithEth} />,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
screen.getByTestId('request-signature-account').textContent,
|
|
||||||
).toMatchInlineSnapshot(
|
|
||||||
`"UUnknown private networkJohn DoeBalance966.987986 ETH"`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render balance with fiat when conversionRate not provided', () => {
|
|
||||||
const store = configureMockStore()(mockStoreWithFiat);
|
|
||||||
renderWithProvider(
|
|
||||||
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
screen.getByTestId('request-signature-account').textContent,
|
|
||||||
).toMatchInlineSnapshot(
|
|
||||||
`"UUnknown private networkJohn DoeBalance$151,546.36 USD"`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('functionality check', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
const store = configureMockStore()(mockStoreWithFiat);
|
|
||||||
renderWithProvider(
|
|
||||||
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
propsWithFiat.clearConfirmTransaction.resetHistory();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('cancel', async () => {
|
|
||||||
const cancelButton = screen.getByTestId('page-container-footer-cancel');
|
|
||||||
await act(() => {
|
|
||||||
fireEvent.click(cancelButton);
|
|
||||||
});
|
|
||||||
expect(propsWithFiat.rejectPendingApproval.calledOnce).toStrictEqual(
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign', async () => {
|
|
||||||
const signButton = screen.getByTestId('page-container-footer-next');
|
|
||||||
await act(() => {
|
|
||||||
fireEvent.click(signButton);
|
|
||||||
});
|
|
||||||
expect(propsWithFiat.resolvePendingApproval.calledOnce).toStrictEqual(
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('have user warning', () => {
|
|
||||||
const warningText = screen.getByText(
|
|
||||||
'Only sign this message if you fully understand the content and trust the requesting site.',
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(warningText).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('contract details', () => {
|
|
||||||
let store;
|
|
||||||
beforeEach(() => {
|
|
||||||
store = configureMockStore()(mockStoreWithFiat);
|
|
||||||
});
|
|
||||||
it('shows verify contract details link when verifyingContract is set', () => {
|
|
||||||
renderWithProvider(
|
|
||||||
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
const verifyingContractLink = screen.getByTestId(
|
|
||||||
'verify-contract-details',
|
|
||||||
);
|
|
||||||
expect(verifyingContractLink).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show verify contract details link when verifyingContract is not set', () => {
|
|
||||||
const newData = JSON.parse(propsWithFiat.txData.msgParams.data);
|
|
||||||
delete newData.domain.verifyingContract;
|
|
||||||
|
|
||||||
const newProps = {
|
|
||||||
...propsWithFiat,
|
|
||||||
txData: {
|
|
||||||
...propsWithFiat.txData,
|
|
||||||
msgParams: {
|
|
||||||
...propsWithFiat.txData.msgParams,
|
|
||||||
data: JSON.stringify(newData),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
renderWithProvider(
|
|
||||||
<SignatureRequest.WrappedComponent {...newProps} />,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.queryByTestId('verify-contract-details')).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
380
ui/components/app/signature-request/signature-request.js
Normal file
380
ui/components/app/signature-request/signature-request.js
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
import React, { useContext, useState, useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
useDispatch,
|
||||||
|
useSelector,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
shallowEqual,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { memoize } from 'lodash';
|
||||||
|
import { ethErrors, serializeError } from 'eth-rpc-errors';
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
import { showCustodianDeepLink } from '@metamask-institutional/extension';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
import {
|
||||||
|
resolvePendingApproval,
|
||||||
|
rejectPendingApproval,
|
||||||
|
completedTx,
|
||||||
|
} from '../../../store/actions';
|
||||||
|
import {
|
||||||
|
doesAddressRequireLedgerHidConnection,
|
||||||
|
getSubjectMetadata,
|
||||||
|
getTotalUnapprovedMessagesCount,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
accountsWithSendEtherInfoSelector,
|
||||||
|
getSelectedAccount,
|
||||||
|
getAccountType,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../selectors';
|
||||||
|
import {
|
||||||
|
getProviderConfig,
|
||||||
|
isAddressLedger,
|
||||||
|
} from '../../../ducks/metamask/metamask';
|
||||||
|
import {
|
||||||
|
sanitizeMessage,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
getAccountByAddress,
|
||||||
|
shortenAddress,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../helpers/utils/util';
|
||||||
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
|
import { useRejectTransactionModal } from '../../../hooks/useRejectTransactionModal';
|
||||||
|
|
||||||
|
import { ConfirmPageContainerNavigation } from '../confirm-page-container';
|
||||||
|
import SignatureRequestHeader from '../signature-request-header/signature-request-header';
|
||||||
|
import SecurityProviderBannerMessage from '../security-provider-banner-message';
|
||||||
|
import LedgerInstructionField from '../ledger-instruction-field';
|
||||||
|
import ContractDetailsModal from '../modals/contract-details-modal';
|
||||||
|
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||||
|
import {
|
||||||
|
MetaMetricsEventCategory,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
MetaMetricsEventName,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../../shared/constants/metametrics';
|
||||||
|
import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider';
|
||||||
|
|
||||||
|
import {
|
||||||
|
TextAlign,
|
||||||
|
TextColor,
|
||||||
|
TextVariant,
|
||||||
|
Size,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
IconColor,
|
||||||
|
BackgroundColor,
|
||||||
|
Display,
|
||||||
|
BlockSize,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import {
|
||||||
|
BUTTON_VARIANT,
|
||||||
|
Button,
|
||||||
|
ButtonLink,
|
||||||
|
TagUrl,
|
||||||
|
Text,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
Icon,
|
||||||
|
IconName,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
// eslint-disable-next-line import/order
|
||||||
|
import Box from '../../ui/box/box';
|
||||||
|
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app';
|
||||||
|
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||||
|
import { mmiActionsFactory } from '../../../store/institutional/institution-background';
|
||||||
|
import { showCustodyConfirmLink } from '../../../store/institutional/institution-actions';
|
||||||
|
import { useMMICustodySignMessage } from '../../../hooks/useMMICustodySignMessage';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
import Message from './signature-request-message';
|
||||||
|
import Footer from './signature-request-footer';
|
||||||
|
|
||||||
|
const SignatureRequest = ({ txData }) => {
|
||||||
|
const trackEvent = useContext(MetaMetricsContext);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const t = useI18nContext();
|
||||||
|
|
||||||
|
const [hasScrolledMessage, setHasScrolledMessage] = useState(false);
|
||||||
|
const [showContractDetails, setShowContractDetails] = useState(false);
|
||||||
|
const [messageRootRef, setMessageRootRef] = useState(null);
|
||||||
|
const [messageIsScrollable, setMessageIsScrollable] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
msgParams: { from, data, origin, version },
|
||||||
|
} = txData;
|
||||||
|
|
||||||
|
// not forwarded to component
|
||||||
|
const hardwareWalletRequiresConnection = useSelector((state) =>
|
||||||
|
doesAddressRequireLedgerHidConnection(state, from),
|
||||||
|
);
|
||||||
|
const { chainId, rpcPrefs } = useSelector(getProviderConfig);
|
||||||
|
const unapprovedMessagesCount = useSelector(getTotalUnapprovedMessagesCount);
|
||||||
|
const subjectMetadata = useSelector(getSubjectMetadata);
|
||||||
|
const isLedgerWallet = useSelector((state) => isAddressLedger(state, from));
|
||||||
|
const { handleCancelAll } = useRejectTransactionModal();
|
||||||
|
|
||||||
|
///: 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
|
||||||
|
const selectedAccount = useSelector(getSelectedAccount);
|
||||||
|
const mmiActions = mmiActionsFactory();
|
||||||
|
const accountType = useSelector(getAccountType);
|
||||||
|
const isNotification = getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION;
|
||||||
|
const allAccounts = useSelector(
|
||||||
|
accountsWithSendEtherInfoSelector,
|
||||||
|
shallowEqual,
|
||||||
|
);
|
||||||
|
const { address } = getAccountByAddress(allAccounts, from) || {};
|
||||||
|
const { custodySignFn } = useMMICustodySignMessage();
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMessageIsScrollable(
|
||||||
|
messageRootRef?.scrollHeight > messageRootRef?.clientHeight,
|
||||||
|
);
|
||||||
|
}, [messageRootRef]);
|
||||||
|
|
||||||
|
const targetSubjectMetadata = subjectMetadata?.[origin] || null;
|
||||||
|
|
||||||
|
const parseMessage = memoize((dataToParse) => {
|
||||||
|
const {
|
||||||
|
message,
|
||||||
|
domain = {},
|
||||||
|
primaryType,
|
||||||
|
types,
|
||||||
|
} = JSON.parse(dataToParse);
|
||||||
|
const sanitizedMessage = sanitizeMessage(message, primaryType, types);
|
||||||
|
return { sanitizedMessage, domain, primaryType };
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSign = async () => {
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
if (accountType === 'custody') {
|
||||||
|
await custodySignFn(txData);
|
||||||
|
}
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
await dispatch(resolvePendingApproval(id));
|
||||||
|
completedTx(id);
|
||||||
|
|
||||||
|
trackEvent({
|
||||||
|
category: MetaMetricsEventCategory.Transactions,
|
||||||
|
event: 'Confirm',
|
||||||
|
properties: {
|
||||||
|
action: 'Sign Request',
|
||||||
|
legacy_event: true,
|
||||||
|
type,
|
||||||
|
version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = async () => {
|
||||||
|
await dispatch(
|
||||||
|
rejectPendingApproval(
|
||||||
|
id,
|
||||||
|
serializeError(ethErrors.provider.userRejectedRequest()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
trackEvent({
|
||||||
|
category: MetaMetricsEventCategory.Transactions,
|
||||||
|
event: 'Cancel',
|
||||||
|
properties: {
|
||||||
|
action: 'Sign Request',
|
||||||
|
legacy_event: true,
|
||||||
|
type,
|
||||||
|
version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
sanitizedMessage,
|
||||||
|
domain: { verifyingContract },
|
||||||
|
primaryType,
|
||||||
|
} = parseMessage(data);
|
||||||
|
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
useEffect(() => {
|
||||||
|
if (txData.custodyId) {
|
||||||
|
showCustodianDeepLink({
|
||||||
|
dispatch,
|
||||||
|
mmiActions,
|
||||||
|
txId: undefined,
|
||||||
|
custodyId: txData.custodyId,
|
||||||
|
fromAddress: address,
|
||||||
|
isSignature: true,
|
||||||
|
closeNotification: isNotification,
|
||||||
|
onDeepLinkFetched: () => undefined,
|
||||||
|
onDeepLinkShown: () => {
|
||||||
|
trackEvent({
|
||||||
|
category: MetaMetricsEventCategory.MMI,
|
||||||
|
event: MetaMetricsEventName.SignatureDeeplinkDisplayed,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showCustodyConfirmLink,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
dispatch,
|
||||||
|
mmiActions,
|
||||||
|
txData.custodyId,
|
||||||
|
address,
|
||||||
|
isNotification,
|
||||||
|
trackEvent,
|
||||||
|
]);
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="signature-request">
|
||||||
|
<ConfirmPageContainerNavigation />
|
||||||
|
<div
|
||||||
|
className="request-signature__account"
|
||||||
|
data-testid="request-signature-account"
|
||||||
|
>
|
||||||
|
<SignatureRequestHeader txData={txData} />
|
||||||
|
</div>
|
||||||
|
<div className="signature-request-content">
|
||||||
|
{(txData?.securityProviderResponse?.flagAsDangerous !== undefined &&
|
||||||
|
txData?.securityProviderResponse?.flagAsDangerous !==
|
||||||
|
SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS) ||
|
||||||
|
(txData?.securityProviderResponse &&
|
||||||
|
Object.keys(txData.securityProviderResponse).length === 0) ? (
|
||||||
|
<SecurityProviderBannerMessage
|
||||||
|
securityProviderResponse={txData.securityProviderResponse}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
selectedAccount.address === address ? null : (
|
||||||
|
<Box
|
||||||
|
className="request-signature__mismatch-info"
|
||||||
|
display={Display.Flex}
|
||||||
|
width={BlockSize.Full}
|
||||||
|
padding={4}
|
||||||
|
marginBottom={4}
|
||||||
|
backgroundColor={BackgroundColor.primaryMuted}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={IconName.Info}
|
||||||
|
color={IconColor.infoDefault}
|
||||||
|
marginRight={2}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
variant={TextVariant.bodyXs}
|
||||||
|
color={TextColor.textDefault}
|
||||||
|
as="h6"
|
||||||
|
>
|
||||||
|
{t('mismatchAccount', [
|
||||||
|
shortenAddress(selectedAccount.address),
|
||||||
|
shortenAddress(address),
|
||||||
|
])}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
}
|
||||||
|
<div className="signature-request__origin">
|
||||||
|
<TagUrl
|
||||||
|
label={origin}
|
||||||
|
labelProps={{
|
||||||
|
color: TextColor.textAlternative,
|
||||||
|
}}
|
||||||
|
src={targetSubjectMetadata?.iconUrl}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Text
|
||||||
|
className="signature-request__content__title"
|
||||||
|
variant={TextVariant.headingLg}
|
||||||
|
marginTop={4}
|
||||||
|
>
|
||||||
|
{t('sigRequest')}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
className="request-signature__content__subtitle"
|
||||||
|
variant={TextVariant.bodySm}
|
||||||
|
color={TextColor.textAlternative}
|
||||||
|
textAlign={TextAlign.Center}
|
||||||
|
marginLeft={12}
|
||||||
|
marginRight={12}
|
||||||
|
marginTop={4}
|
||||||
|
as="h6"
|
||||||
|
>
|
||||||
|
{t('signatureRequestGuidance')}
|
||||||
|
</Text>
|
||||||
|
{verifyingContract ? (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
variant={BUTTON_VARIANT.LINK}
|
||||||
|
onClick={() => setShowContractDetails(true)}
|
||||||
|
className="signature-request-content__verify-contract-details"
|
||||||
|
data-testid="verify-contract-details"
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
variant={TextVariant.bodySm}
|
||||||
|
color={TextColor.primaryDefault}
|
||||||
|
as="h6"
|
||||||
|
>
|
||||||
|
{t('verifyContractDetails')}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
{isLedgerWallet ? (
|
||||||
|
<div className="confirm-approve-content__ledger-instruction-wrapper">
|
||||||
|
<LedgerInstructionField showDataInstruction />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<Message
|
||||||
|
data={sanitizedMessage}
|
||||||
|
onMessageScrolled={() => setHasScrolledMessage(true)}
|
||||||
|
setMessageRootRef={setMessageRootRef}
|
||||||
|
messageRootRef={messageRootRef}
|
||||||
|
messageIsScrollable={messageIsScrollable}
|
||||||
|
primaryType={primaryType}
|
||||||
|
/>
|
||||||
|
<Footer
|
||||||
|
cancelAction={onCancel}
|
||||||
|
signAction={onSign}
|
||||||
|
disabled={
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
Boolean(txData?.custodyId) ||
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
hardwareWalletRequiresConnection ||
|
||||||
|
(messageIsScrollable && !hasScrolledMessage)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{showContractDetails && (
|
||||||
|
<ContractDetailsModal
|
||||||
|
toAddress={verifyingContract}
|
||||||
|
chainId={chainId}
|
||||||
|
rpcPrefs={rpcPrefs}
|
||||||
|
onClose={() => setShowContractDetails(false)}
|
||||||
|
isContractRequestingSignature
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{unapprovedMessagesCount > 1 ? (
|
||||||
|
<ButtonLink
|
||||||
|
size={Size.inherit}
|
||||||
|
className="signature-request__reject-all-button"
|
||||||
|
data-testid="signature-request-reject-all"
|
||||||
|
onClick={handleCancelAll}
|
||||||
|
>
|
||||||
|
{t('rejectRequestsN', [unapprovedMessagesCount])}
|
||||||
|
</ButtonLink>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SignatureRequest.propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SignatureRequest;
|
@ -1,14 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import configureStore from '../../../store/store';
|
||||||
import testData from '../../../../.storybook/test-data';
|
import testData from '../../../../.storybook/test-data';
|
||||||
import README from './README.mdx';
|
import README from './README.mdx';
|
||||||
import SignatureRequest from './signature-request.component';
|
import SignatureRequest from './signature-request';
|
||||||
|
|
||||||
const [MOCK_PRIMARY_IDENTITY, MOCK_SECONDARY_IDENTITY] = Object.values(
|
const store = configureStore({
|
||||||
testData.metamask.identities,
|
...testData,
|
||||||
);
|
metamask: {
|
||||||
|
...testData.metamask,
|
||||||
|
selectedAddress: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Components/App/SignatureRequest',
|
title: 'Components/App/SignatureRequest',
|
||||||
|
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
|
||||||
|
|
||||||
component: SignatureRequest,
|
component: SignatureRequest,
|
||||||
parameters: {
|
parameters: {
|
||||||
docs: {
|
docs: {
|
||||||
@ -17,22 +25,6 @@ export default {
|
|||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
txData: { control: 'object' },
|
txData: { control: 'object' },
|
||||||
fromAccount: {
|
|
||||||
table: {
|
|
||||||
address: { control: 'text' },
|
|
||||||
balance: { control: 'text' },
|
|
||||||
name: { control: 'text' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hardwareWalletRequiresConnection: { control: 'boolean' },
|
|
||||||
isLedgerWallet: { control: 'boolean' },
|
|
||||||
clearConfirmTransaction: { action: 'Clean Confirm' },
|
|
||||||
cancel: { action: 'Cancel' },
|
|
||||||
sign: { action: 'Sign' },
|
|
||||||
showRejectTransactionsConfirmationModal: {
|
|
||||||
action: 'showRejectTransactionsConfirmationModal',
|
|
||||||
},
|
|
||||||
cancelAll: { action: 'cancelAll' },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,6 +37,7 @@ DefaultStory.storyName = 'Default';
|
|||||||
DefaultStory.args = {
|
DefaultStory.args = {
|
||||||
txData: {
|
txData: {
|
||||||
msgParams: {
|
msgParams: {
|
||||||
|
from: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
domain: {
|
domain: {
|
||||||
name: 'happydapp.website',
|
name: 'happydapp.website',
|
||||||
@ -79,11 +72,6 @@ DefaultStory.args = {
|
|||||||
origin: 'https://happydapp.website/',
|
origin: 'https://happydapp.website/',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fromAccount: MOCK_PRIMARY_IDENTITY,
|
|
||||||
providerConfig: { name: 'Goerli ETH' },
|
|
||||||
selectedAccount: MOCK_PRIMARY_IDENTITY,
|
|
||||||
hardwareWalletRequiresConnection: false,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AccountMismatchStory = (args) => {
|
export const AccountMismatchStory = (args) => {
|
||||||
@ -94,5 +82,10 @@ AccountMismatchStory.storyName = 'AccountMismatch';
|
|||||||
|
|
||||||
AccountMismatchStory.args = {
|
AccountMismatchStory.args = {
|
||||||
...DefaultStory.args,
|
...DefaultStory.args,
|
||||||
selectedAccount: MOCK_SECONDARY_IDENTITY,
|
txData: {
|
||||||
|
msgParams: {
|
||||||
|
...DefaultStory.args.txData.msgParams,
|
||||||
|
from: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,33 +1,98 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { fireEvent } from '@testing-library/react';
|
import { fireEvent } from '@testing-library/react';
|
||||||
import configureMockStore from 'redux-mock-store';
|
import configureMockStore from 'redux-mock-store';
|
||||||
import mockState from '../../../../test/data/mock-state.json';
|
import mockState from '../../../../test/data/mock-state.json';
|
||||||
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
||||||
import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider';
|
import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider';
|
||||||
import SignatureRequest from './signature-request.component';
|
import {
|
||||||
|
getNativeCurrency,
|
||||||
|
getProviderConfig,
|
||||||
|
} from '../../../ducks/metamask/metamask';
|
||||||
|
import {
|
||||||
|
accountsWithSendEtherInfoSelector,
|
||||||
|
conversionRateSelector,
|
||||||
|
getCurrentCurrency,
|
||||||
|
getMemoizedAddressBook,
|
||||||
|
getMemoizedMetaMaskIdentities,
|
||||||
|
getPreferences,
|
||||||
|
getSelectedAccount,
|
||||||
|
getTotalUnapprovedMessagesCount,
|
||||||
|
unconfirmedTransactionsHashSelector,
|
||||||
|
} from '../../../selectors';
|
||||||
|
import SignatureRequest from './signature-request';
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
hardwareWalletRequiresConnection: false,
|
clearConfirmTransaction: () => jest.fn(),
|
||||||
clearConfirmTransaction: () => undefined,
|
cancel: () => jest.fn(),
|
||||||
cancel: () => undefined,
|
cancelAll: () => jest.fn(),
|
||||||
cancelAll: () => undefined,
|
showRejectTransactionsConfirmationModal: () => jest.fn(),
|
||||||
mostRecentOverviewPage: '/',
|
sign: () => jest.fn(),
|
||||||
showRejectTransactionsConfirmationModal: () => undefined,
|
};
|
||||||
sign: () => undefined,
|
const mockStore = {
|
||||||
history: { push: '/' },
|
metamask: {
|
||||||
providerConfig: { type: 'rpc' },
|
providerConfig: {
|
||||||
nativeCurrency: 'ABC',
|
chainId: '0x539',
|
||||||
currentCurrency: 'def',
|
nickname: 'Localhost 8545',
|
||||||
fromAccount: {
|
rpcPrefs: {},
|
||||||
address: '0x123456789abcdef',
|
rpcUrl: 'http://localhost:8545',
|
||||||
balance: '0x346ba7725f412cbfdb',
|
ticker: 'ETH',
|
||||||
name: 'Antonio',
|
type: 'rpc',
|
||||||
},
|
},
|
||||||
selectedAccount: {
|
preferences: {
|
||||||
address: '0x123456789abcdef',
|
useNativeCurrencyAsPrimaryCurrency: true,
|
||||||
|
},
|
||||||
|
accounts: {
|
||||||
|
'0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': {
|
||||||
|
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
|
balance: '0x03',
|
||||||
|
name: 'John Doe',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
|
currentCurrency: 'usd',
|
||||||
|
conversionRate: null,
|
||||||
|
unapprovedTypedMessagesCount: 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
jest.mock('react-redux', () => {
|
||||||
|
const actual = jest.requireActual('react-redux');
|
||||||
|
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
useSelector: jest.fn(),
|
||||||
|
useDispatch: () => jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateUseSelectorRouter = (opts) => (selector) => {
|
||||||
|
switch (selector) {
|
||||||
|
case getProviderConfig:
|
||||||
|
return opts.metamask.providerConfig;
|
||||||
|
case getCurrentCurrency:
|
||||||
|
return opts.metamask.currentCurrency;
|
||||||
|
case getNativeCurrency:
|
||||||
|
return opts.metamask.nativeCurrency;
|
||||||
|
case getTotalUnapprovedMessagesCount:
|
||||||
|
return opts.metamask.unapprovedTypedMessagesCount;
|
||||||
|
case getPreferences:
|
||||||
|
return opts.metamask.preferences;
|
||||||
|
case conversionRateSelector:
|
||||||
|
return opts.metamask.conversionRate;
|
||||||
|
case getSelectedAccount:
|
||||||
|
return opts.metamask.accounts[opts.metamask.selectedAddress];
|
||||||
|
case getMemoizedAddressBook:
|
||||||
|
return [];
|
||||||
|
case accountsWithSendEtherInfoSelector:
|
||||||
|
return Object.values(opts.metamask.accounts);
|
||||||
|
case unconfirmedTransactionsHashSelector:
|
||||||
|
case getMemoizedMetaMaskIdentities:
|
||||||
|
return {};
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
describe('Signature Request Component', () => {
|
describe('Signature Request Component', () => {
|
||||||
const store = configureMockStore()(mockState);
|
const store = configureMockStore()(mockState);
|
||||||
|
|
||||||
@ -35,6 +100,7 @@ describe('Signature Request Component', () => {
|
|||||||
let messageData;
|
let messageData;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
useSelector.mockImplementation(generateUseSelectorRouter(mockStore));
|
||||||
messageData = {
|
messageData = {
|
||||||
domain: {
|
domain: {
|
||||||
chainId: 97,
|
chainId: 97,
|
||||||
@ -84,7 +150,17 @@ describe('Signature Request Component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should match snapshot when we want to switch to fiat', () => {
|
it('should match snapshot when we want to switch to fiat', () => {
|
||||||
|
useSelector.mockImplementation(
|
||||||
|
generateUseSelectorRouter({
|
||||||
|
...mockStore,
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
conversionRate: 231.06,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -95,7 +171,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={1567}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -105,6 +180,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should match snapshot when we are using eth', () => {
|
it('should match snapshot when we are using eth', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -115,7 +191,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -125,6 +200,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should render navigation', () => {
|
it('should render navigation', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -135,7 +211,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -149,6 +224,7 @@ describe('Signature Request Component', () => {
|
|||||||
do_not_display: 'two',
|
do_not_display: 'two',
|
||||||
};
|
};
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -159,7 +235,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -171,7 +246,17 @@ describe('Signature Request Component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not render a reject multiple requests link if there is not multiple requests', () => {
|
it('should not render a reject multiple requests link if there is not multiple requests', () => {
|
||||||
|
useSelector.mockImplementation(
|
||||||
|
generateUseSelectorRouter({
|
||||||
|
...mockStore,
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
unapprovedTypedMessagesCount: 0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -182,7 +267,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -194,6 +278,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should render a reject multiple requests link if there is multiple requests (greater than 1)', () => {
|
it('should render a reject multiple requests link if there is multiple requests (greater than 1)', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -204,8 +289,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -217,6 +300,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should call reject all button when button is clicked', () => {
|
it('should call reject all button when button is clicked', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -227,8 +311,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -242,6 +324,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should render text of reject all button', () => {
|
it('should render text of reject all button', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -252,8 +335,6 @@ describe('Signature Request Component', () => {
|
|||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
}}
|
}}
|
||||||
conversionRate={null}
|
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -263,6 +344,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should render SecurityProviderBannerMessage component properly', () => {
|
it('should render SecurityProviderBannerMessage component properly', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -271,7 +353,6 @@ describe('Signature Request Component', () => {
|
|||||||
const { queryByText } = renderWithProvider(
|
const { queryByText } = renderWithProvider(
|
||||||
<SignatureRequest
|
<SignatureRequest
|
||||||
{...baseProps}
|
{...baseProps}
|
||||||
conversionRate={null}
|
|
||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
securityProviderResponse: {
|
securityProviderResponse: {
|
||||||
@ -280,7 +361,6 @@ describe('Signature Request Component', () => {
|
|||||||
reason_header: 'Some reason header...',
|
reason_header: 'Some reason header...',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -296,6 +376,7 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should not render SecurityProviderBannerMessage component when flagAsDangerous is not malicious', () => {
|
it('should not render SecurityProviderBannerMessage component when flagAsDangerous is not malicious', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
@ -304,14 +385,12 @@ describe('Signature Request Component', () => {
|
|||||||
const { queryByText } = renderWithProvider(
|
const { queryByText } = renderWithProvider(
|
||||||
<SignatureRequest
|
<SignatureRequest
|
||||||
{...baseProps}
|
{...baseProps}
|
||||||
conversionRate={null}
|
|
||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
securityProviderResponse: {
|
securityProviderResponse: {
|
||||||
flagAsDangerous: SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS,
|
flagAsDangerous: SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
@ -327,27 +406,39 @@ describe('Signature Request Component', () => {
|
|||||||
|
|
||||||
it('should render a warning when the selected account is not the one being used to sign', () => {
|
it('should render a warning when the selected account is not the one being used to sign', () => {
|
||||||
const msgParams = {
|
const msgParams = {
|
||||||
|
from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
|
||||||
data: JSON.stringify(messageData),
|
data: JSON.stringify(messageData),
|
||||||
version: 'V4',
|
version: 'V4',
|
||||||
origin: 'test',
|
origin: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = renderWithProvider(
|
useSelector.mockImplementation(
|
||||||
<SignatureRequest
|
generateUseSelectorRouter({
|
||||||
{...baseProps}
|
...mockStore,
|
||||||
selectedAccount={{
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
||||||
|
accounts: {
|
||||||
|
...mockStore.metamask.accounts,
|
||||||
|
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
|
||||||
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
||||||
balance: '0x0',
|
balance: '0x0',
|
||||||
name: 'Account 1',
|
name: 'Account 1',
|
||||||
}}
|
},
|
||||||
conversionRate={null}
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { container } = renderWithProvider(
|
||||||
|
<SignatureRequest
|
||||||
|
{...baseProps}
|
||||||
txData={{
|
txData={{
|
||||||
msgParams,
|
msgParams,
|
||||||
securityProviderResponse: {
|
securityProviderResponse: {
|
||||||
flagAsDangerous: SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS,
|
flagAsDangerous: SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
unapprovedMessagesCount={2}
|
|
||||||
/>,
|
/>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
77
ui/hooks/useMMICustodySignMessage.js
Normal file
77
ui/hooks/useMMICustodySignMessage.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { showCustodianDeepLink } from '@metamask-institutional/extension';
|
||||||
|
import {
|
||||||
|
showCustodyConfirmLink,
|
||||||
|
checkForUnapprovedMessages,
|
||||||
|
} from '../store/institutional/institution-actions';
|
||||||
|
import {
|
||||||
|
mmiActionsFactory,
|
||||||
|
setTypedMessageInProgress,
|
||||||
|
} from '../store/institutional/institution-background';
|
||||||
|
import {
|
||||||
|
accountsWithSendEtherInfoSelector,
|
||||||
|
getAccountType,
|
||||||
|
unapprovedTypedMessagesSelector,
|
||||||
|
} from '../selectors';
|
||||||
|
import { getAccountByAddress } from '../helpers/utils/util';
|
||||||
|
import { getEnvironmentType } from '../../app/scripts/lib/util';
|
||||||
|
import { goHome, showModal } from '../store/actions';
|
||||||
|
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../shared/constants/app';
|
||||||
|
|
||||||
|
export function useMMICustodySignMessage() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const mmiActions = mmiActionsFactory();
|
||||||
|
const envType = getEnvironmentType();
|
||||||
|
const accountType = useSelector(getAccountType);
|
||||||
|
const isNotification = envType === ENVIRONMENT_TYPE_NOTIFICATION;
|
||||||
|
const allAccounts = useSelector(
|
||||||
|
accountsWithSendEtherInfoSelector,
|
||||||
|
shallowEqual,
|
||||||
|
);
|
||||||
|
const unapprovedTypedMessages = useSelector(unapprovedTypedMessagesSelector);
|
||||||
|
|
||||||
|
const custodySignFn = async (_msgData) => {
|
||||||
|
if (accountType === 'custody') {
|
||||||
|
const { address: fromAddress } =
|
||||||
|
getAccountByAddress(allAccounts, _msgData.msgParams.from) || {};
|
||||||
|
try {
|
||||||
|
let msgData = _msgData;
|
||||||
|
let id = _msgData.custodyId;
|
||||||
|
if (!_msgData.custodyId) {
|
||||||
|
msgData = checkForUnapprovedMessages(
|
||||||
|
_msgData,
|
||||||
|
unapprovedTypedMessages,
|
||||||
|
);
|
||||||
|
id = msgData.custodyId;
|
||||||
|
}
|
||||||
|
showCustodianDeepLink({
|
||||||
|
dispatch,
|
||||||
|
mmiActions,
|
||||||
|
txId: undefined,
|
||||||
|
custodyId: id,
|
||||||
|
fromAddress,
|
||||||
|
isSignature: true,
|
||||||
|
closeNotification: isNotification,
|
||||||
|
onDeepLinkFetched: () => undefined,
|
||||||
|
onDeepLinkShown: () => undefined,
|
||||||
|
showCustodyConfirmLink,
|
||||||
|
});
|
||||||
|
await dispatch(setTypedMessageInProgress(msgData.metamaskId));
|
||||||
|
await dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(true));
|
||||||
|
await dispatch(goHome());
|
||||||
|
} catch (err) {
|
||||||
|
await dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(true));
|
||||||
|
await dispatch(
|
||||||
|
showModal({
|
||||||
|
name: 'TRANSACTION_FAILED',
|
||||||
|
errorMessage: err.message,
|
||||||
|
closeNotification: true,
|
||||||
|
operationFailed: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { custodySignFn };
|
||||||
|
}
|
35
ui/hooks/useRejectTransactionModal.js
Normal file
35
ui/hooks/useRejectTransactionModal.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { valuesFor } from '../helpers/utils/util';
|
||||||
|
import { showModal, rejectAllMessages } from '../store/actions';
|
||||||
|
import { clearConfirmTransaction } from '../ducks/confirm-transaction/confirm-transaction.duck';
|
||||||
|
import { getMostRecentOverviewPage } from '../ducks/history/history';
|
||||||
|
import {
|
||||||
|
getTotalUnapprovedMessagesCount,
|
||||||
|
unconfirmedMessagesHashSelector,
|
||||||
|
} from '../selectors';
|
||||||
|
|
||||||
|
export function useRejectTransactionModal() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const history = useHistory();
|
||||||
|
const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage);
|
||||||
|
const unapprovedMessagesCount = useSelector(getTotalUnapprovedMessagesCount);
|
||||||
|
const unconfirmedMessagesList = useSelector(unconfirmedMessagesHashSelector);
|
||||||
|
|
||||||
|
const handleCancelAll = () => {
|
||||||
|
dispatch(
|
||||||
|
showModal({
|
||||||
|
name: 'REJECT_TRANSACTIONS',
|
||||||
|
onSubmit: async () => {
|
||||||
|
await dispatch(rejectAllMessages(valuesFor(unconfirmedMessagesList)));
|
||||||
|
dispatch(clearConfirmTransaction());
|
||||||
|
history.push(mostRecentOverviewPage);
|
||||||
|
},
|
||||||
|
unapprovedTxCount: unapprovedMessagesCount,
|
||||||
|
isRequestType: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { handleCancelAll };
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Signature Request Component render should match snapshot 1`] = `
|
exports[`Confirm Signature Request Component render should match snapshot 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="signature-request"
|
class="signature-request"
|
||||||
@ -178,56 +178,48 @@ exports[`Signature Request Component render should match snapshot 1`] = `
|
|||||||
class="signature-request__origin"
|
class="signature-request__origin"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="site-origin"
|
class="box mm-tag-url box--padding-right-4 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--align-items-center box--background-color-background-default box--rounded-pill box--border-color-border-default box--border-width-1 box--border-style-solid"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="chip chip--with-left-icon chip--border-color-border-muted chip--background-color-undefined"
|
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-favicon mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="chip__left-icon"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class=""
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon-with-fallback__fallback"
|
class="box mm-icon mm-icon--size-md box--display-inline-block box--flex-direction-row box--color-icon-default"
|
||||||
>
|
style="mask-image: url('./images/icons/global.svg');"
|
||||||
M
|
/>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<p
|
||||||
<span
|
class="mm-box mm-text mm-text--body-md mm-text--ellipsis mm-box--color-text-alternative"
|
||||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
https://metamask.github.io
|
https://metamask.github.io
|
||||||
</span>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h2
|
||||||
<h3
|
class="mm-box mm-text signature-request__content__title mm-text--heading-lg mm-box--margin-top-4 mm-box--color-text-default"
|
||||||
class="mm-box mm-text signature-request__content__title mm-text--heading-md mm-box--margin-top-4 mm-box--color-text-default"
|
|
||||||
>
|
>
|
||||||
Signature request
|
Signature request
|
||||||
</h3>
|
</h2>
|
||||||
<h6
|
<h6
|
||||||
align="center"
|
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-text--text-align-center mm-box--margin-top-4 mm-box--margin-right-12 mm-box--margin-left-12 mm-box--color-text-alternative"
|
||||||
class="mm-box mm-text request-signature__content__subtitle mm-text--body-sm mm-box--margin-12 mm-box--margin-top-3 mm-box--color-text-alternative"
|
|
||||||
>
|
>
|
||||||
Only sign this message if you fully understand the content and trust the requesting site.
|
Only sign this message if you fully understand the content and trust the requesting site.
|
||||||
</h6>
|
</h6>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<button
|
||||||
class="button btn-link signature-request-content__verify-contract-details"
|
class="mm-box mm-text mm-button-base signature-request-content__verify-contract-details mm-button-link mm-button-link--size-auto mm-text--body-md-medium mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
|
||||||
data-testid="verify-contract-details"
|
data-testid="verify-contract-details"
|
||||||
role="button"
|
>
|
||||||
tabindex="0"
|
<span
|
||||||
|
class="mm-box mm-text mm-text--inherit mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
<h6
|
<h6
|
||||||
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
class="mm-box mm-text mm-text--body-sm mm-box--color-primary-default"
|
||||||
>
|
>
|
||||||
Verify third-party details
|
Verify third-party details
|
||||||
</h6>
|
</h6>
|
||||||
</a>
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -57,7 +57,7 @@ const mockState = {
|
|||||||
send: { draftTransactions: {} },
|
send: { draftTransactions: {} },
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Signature Request Component', () => {
|
describe('Confirm Signature Request Component', () => {
|
||||||
const store = configureMockStore()(mockState);
|
const store = configureMockStore()(mockState);
|
||||||
|
|
||||||
describe('render', () => {
|
describe('render', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user