From 047d664c2eb02baba05a2e70ca85bdf7b0ef1616 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 5 Oct 2022 14:21:55 +0200 Subject: [PATCH 01/33] Lower coverage requirement (#16087) --- jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 1f687bb811b1..bfaddcfa87e8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,7 +11,7 @@ module.exports = { coverageThreshold: { global: { branches: 44, - functions: 46.8, + functions: 46, lines: 52, statements: 52, }, From 3271b812e3bb9b7b7d61ba6b97cea46939f22c52 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 5 Oct 2022 22:47:58 +0530 Subject: [PATCH 02/33] Removing use of window object from sentry code (#16022) --- app/scripts/lib/setupSentry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 5ef0e68b4c17..01b736c63d37 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -226,7 +226,7 @@ function rewriteReportUrls(report) { } function toMetamaskUrl(origUrl) { - const filePath = origUrl.split(window.location.origin)[1]; + const filePath = origUrl.split(globalThis.location.origin)[1]; if (!filePath) { return origUrl; } From ca6701c27e6d2dcc8db89b6aed917a0d21389c63 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Wed, 5 Oct 2022 19:43:44 +0200 Subject: [PATCH 03/33] [FLASK] Fix transaction insight data display (#16023) * stringify content to display * check if data is a string to avoid stringifying it * prettify JSON data --- .../app/confirm-page-container/flask/index.scss | 5 +++++ .../flask/snap-insight.js | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ui/components/app/confirm-page-container/flask/index.scss b/ui/components/app/confirm-page-container/flask/index.scss index cd027f79c5eb..aff8fd2a482c 100644 --- a/ui/components/app/confirm-page-container/flask/index.scss +++ b/ui/components/app/confirm-page-container/flask/index.scss @@ -1,3 +1,8 @@ .snap-insight { word-wrap: break-word; + + &__container__data__json { + word-wrap: break-word; + overflow-x: auto; + } } diff --git a/ui/components/app/confirm-page-container/flask/snap-insight.js b/ui/components/app/confirm-page-container/flask/snap-insight.js index 1567763dd1db..6446d4943b0c 100644 --- a/ui/components/app/confirm-page-container/flask/snap-insight.js +++ b/ui/components/app/confirm-page-container/flask/snap-insight.js @@ -64,7 +64,22 @@ export const SnapInsight = ({ transaction, chainId, selectedSnap }) => { > {key} - {data[key]} + + {typeof data[key] === 'string' ? ( + + {data[key]} + + ) : ( + + +
{JSON.stringify(data[key], null, 2)}
+
+
+ )} ))} From d97b9c7eef9733432c0492455ca60344c96021bc Mon Sep 17 00:00:00 2001 From: ryanml Date: Wed, 5 Oct 2022 10:53:21 -0700 Subject: [PATCH 04/33] Fix typo in French translation for "removeAccount" (#16095) --- app/_locales/fr/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index bd6821004ca5..5818725c7955 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -2799,7 +2799,7 @@ "message": "Supprimer" }, "removeAccount": { - "message": "Suprimer le compte" + "message": "Supprimer le compte" }, "removeAccountDescription": { "message": "Ce compte va être supprimé de votre portefeuille. Veuillez vérifier que vous avez la phrase secrète de récupération originale de ce compte ou la clé privée pour ce compte importé avant de continuer. Vous pouvez importer ou créer à nouveau des comptes à partir du menu des comptes. " From a993509afcc195556e3d02ee62776c47ad4dc80f Mon Sep 17 00:00:00 2001 From: Filip Sekulic Date: Wed, 5 Oct 2022 21:48:35 +0200 Subject: [PATCH 05/33] Review spending cap screen (#15919) --- app/_locales/en/messages.json | 12 + ui/components/app/app-components.scss | 1 + .../approve-content-card.js | 241 ++++++++++ .../app/approve-content-card/index.js | 1 + .../app/approve-content-card/index.scss | 51 ++ .../contract-details-modal.js | 146 +++++- .../contract-details-modal.stories.js | 67 +-- .../modals/contract-details-modal/index.scss | 10 +- .../contract-token-values.js | 29 +- .../ui/review-spending-cap/index.scss | 2 +- .../review-spending-cap.js | 4 +- ui/pages/confirm-approve/confirm-approve.js | 289 +++++++----- ui/pages/pages.scss | 1 + ui/pages/token-allowance/index.js | 1 + ui/pages/token-allowance/index.scss | 41 ++ ui/pages/token-allowance/token-allowance.js | 437 ++++++++++++++++++ .../token-allowance.stories.js | 201 ++++++++ 17 files changed, 1348 insertions(+), 186 deletions(-) create mode 100644 ui/components/app/approve-content-card/approve-content-card.js create mode 100644 ui/components/app/approve-content-card/index.js create mode 100644 ui/components/app/approve-content-card/index.scss create mode 100644 ui/pages/token-allowance/index.js create mode 100644 ui/pages/token-allowance/index.scss create mode 100644 ui/pages/token-allowance/token-allowance.js create mode 100644 ui/pages/token-allowance/token-allowance.stories.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 61552da611b2..04d76f58c37f 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2927,6 +2927,9 @@ "revealTheSeedPhrase": { "message": "Reveal seed phrase" }, + "reviewSpendingCap": { + "message": "Review your spending cap" + }, "revokeAllTokensTitle": { "message": "Revoke permission to access all of your $1?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3122,6 +3125,9 @@ "message": "Approve $1 with no spend limit", "description": "The token symbol that is being approved" }, + "setSpendingCap": { + "message": "Set a spending cap for your" + }, "settings": { "message": "Settings" }, @@ -4230,6 +4236,9 @@ "userName": { "message": "Username" }, + "verifyContractDetails": { + "message": "Verify contract details" + }, "verifyThisTokenDecimalOn": { "message": "Token decimal can be found on $1", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" @@ -4251,6 +4260,9 @@ "viewContact": { "message": "View contact" }, + "viewDetails": { + "message": "View details" + }, "viewFullTransactionDetails": { "message": "View full transaction details" }, diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index aab3eec4985d..fad86dbc3485 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -96,3 +96,4 @@ @import 'detected-token/detected-token-ignored-popover/index'; @import 'detected-token/detected-token-selection-popover/index'; @import 'network-account-balance-header/index'; +@import 'approve-content-card/index'; diff --git a/ui/components/app/approve-content-card/approve-content-card.js b/ui/components/app/approve-content-card/approve-content-card.js new file mode 100644 index 000000000000..34b7e3ee9368 --- /dev/null +++ b/ui/components/app/approve-content-card/approve-content-card.js @@ -0,0 +1,241 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import Box from '../../ui/box/box'; +import Button from '../../ui/button'; +import EditGasFeeButton from '../edit-gas-fee-button/edit-gas-fee-button'; +import Typography from '../../ui/typography/typography'; +import { + ALIGN_ITEMS, + BLOCK_SIZES, + COLORS, + DISPLAY, + FLEX_DIRECTION, + FONT_WEIGHT, + JUSTIFY_CONTENT, + TEXT_ALIGN, + TYPOGRAPHY, +} from '../../../helpers/constants/design-system'; +import { I18nContext } from '../../../../.storybook/i18n'; +import GasDetailsItem from '../gas-details-item/gas-details-item'; +import MultiLayerFeeMessage from '../multilayer-fee-message/multi-layer-fee-message'; +import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; + +export default function ApproveContentCard({ + showHeader = true, + symbol, + title, + showEdit, + showAdvanceGasFeeOptions = false, + onEditClick, + footer, + noBorder, + supportsEIP1559V2, + renderTransactionDetailsContent, + renderDataContent, + isMultiLayerFeeNetwork, + ethTransactionTotal, + nativeCurrency, + fullTxData, + hexTransactionTotal, + fiatTransactionTotal, + currentCurrency, + isSetApproveForAll, + isApprovalOrRejection, + data, +}) { + const t = useContext(I18nContext); + + return ( + + {showHeader && ( + + {supportsEIP1559V2 && title === t('transactionFee') ? null : ( + <> + + {symbol} + + + + {title} + + + + )} + {showEdit && (!showAdvanceGasFeeOptions || !supportsEIP1559V2) && ( + + + + )} + {showEdit && showAdvanceGasFeeOptions && supportsEIP1559V2 && ( + + )} + + )} + + {renderTransactionDetailsContent && + (!isMultiLayerFeeNetwork && supportsEIP1559V2 ? ( + + ) : ( + + {isMultiLayerFeeNetwork ? ( + + + + {t('transactionDetailLayer2GasHeading')} + {`${ethTransactionTotal} ${nativeCurrency}`} + + + + + ) : ( + <> + + + {t('feeAssociatedRequest')} + + + + + + {formatCurrency(fiatTransactionTotal, currentCurrency)} + + + + + {`${ethTransactionTotal} ${nativeCurrency}`} + + + + + )} + + ))} + {renderDataContent && ( + + + + {isSetApproveForAll + ? t('functionSetApprovalForAll') + : t('functionApprove')} + + + {isSetApproveForAll && isApprovalOrRejection !== undefined ? ( + + + {`${t('parameters')}: ${isApprovalOrRejection}`} + + + ) : null} + + + {data} + + + + )} + + {footer} + + ); +} + +ApproveContentCard.propTypes = { + showHeader: PropTypes.bool, + symbol: PropTypes.node, + title: PropTypes.string, + showEdit: PropTypes.bool, + showAdvanceGasFeeOptions: PropTypes.bool, + onEditClick: PropTypes.func, + footer: PropTypes.node, + noBorder: PropTypes.bool, + supportsEIP1559V2: PropTypes.bool, + renderTransactionDetailsContent: PropTypes.bool, + renderDataContent: PropTypes.bool, + isMultiLayerFeeNetwork: PropTypes.bool, + ethTransactionTotal: PropTypes.string, + nativeCurrency: PropTypes.string, + fullTxData: PropTypes.object, + hexTransactionTotal: PropTypes.string, + fiatTransactionTotal: PropTypes.string, + currentCurrency: PropTypes.string, + isSetApproveForAll: PropTypes.bool, + isApprovalOrRejection: PropTypes.bool, + data: PropTypes.string, +}; diff --git a/ui/components/app/approve-content-card/index.js b/ui/components/app/approve-content-card/index.js new file mode 100644 index 000000000000..02838ddb5ab0 --- /dev/null +++ b/ui/components/app/approve-content-card/index.js @@ -0,0 +1 @@ +export { default } from './approve-content-card'; diff --git a/ui/components/app/approve-content-card/index.scss b/ui/components/app/approve-content-card/index.scss new file mode 100644 index 000000000000..8dd9badc1d5d --- /dev/null +++ b/ui/components/app/approve-content-card/index.scss @@ -0,0 +1,51 @@ +.approve-content-card-container { + &__card, + &__card--no-border { + border-bottom: 1px solid var(--color-border-default); + position: relative; + padding-inline-start: 24px; + padding-inline-end: 24px; + } + + &__card--no-border { + border-bottom: none; + } + + &__card-header { + position: relative; + + &__symbol { + width: auto; + } + + &__symbol--aligned { + width: 100%; + } + + &__title { + width: 100%; + } + + &__title--aligned { + margin-inline-start: 27px; + position: absolute; + width: auto; + } + } + + &__card-content--aligned { + margin-inline-start: 42px; + } + + &__transaction-details-extra-content { + width: 100%; + } + + &__data { + width: 100%; + + &__data-block { + overflow-wrap: break-word; + } + } +} diff --git a/ui/components/app/modals/contract-details-modal/contract-details-modal.js b/ui/components/app/modals/contract-details-modal/contract-details-modal.js index 5ac65d8b2511..818920afe2f7 100644 --- a/ui/components/app/modals/contract-details-modal/contract-details-modal.js +++ b/ui/components/app/modals/contract-details-modal/contract-details-modal.js @@ -1,5 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { getAccountLink } from '@metamask/etherscan-link'; +import { useSelector } from 'react-redux'; +import classnames from 'classnames'; import Box from '../../../ui/box'; import IconCopy from '../../../ui/icon/icon-copy'; import IconBlockExplorer from '../../../ui/icon/icon-block-explorer'; @@ -19,9 +22,27 @@ import { SIZES, BORDER_STYLE, } from '../../../../helpers/constants/design-system'; +import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard'; +import UrlIcon from '../../../ui/url-icon/url-icon'; +import { getAddressBookEntry } from '../../../../selectors'; -export default function ContractDetailsModal({ onClose, address, tokenName }) { +export default function ContractDetailsModal({ + onClose, + tokenName, + tokenAddress, + toAddress, + chainId, + rpcPrefs, + origin, + siteImage, +}) { const t = useI18nContext(); + const [copiedTokenAddress, handleCopyTokenAddress] = useCopyToClipboard(); + const [copiedToAddress, handleCopyToAddress] = useCopyToClipboard(); + + const addressBookEntry = useSelector((state) => ({ + data: getAddressBookEntry(state, toAddress), + })); return ( @@ -65,7 +86,7 @@ export default function ContractDetailsModal({ onClose, address, tokenName }) { > @@ -74,7 +95,7 @@ export default function ContractDetailsModal({ onClose, address, tokenName }) { variant={TYPOGRAPHY.H5} marginTop={4} > - {tokenName || ellipsify(address)} + {tokenName || ellipsify(tokenAddress)} {tokenName && ( - {ellipsify(address)} + {ellipsify(tokenAddress)} )} @@ -91,10 +112,20 @@ export default function ContractDetailsModal({ onClose, address, tokenName }) { className="contract-details-modal__content__contract__buttons" > - + @@ -105,6 +136,19 @@ export default function ContractDetailsModal({ onClose, address, tokenName }) { @@ -173,6 +238,19 @@ export default function ContractDetailsModal({ onClose, address, tokenName }) { - ); } ContractDetailsModal.propTypes = { + /** + * Function that should close the modal + */ onClose: PropTypes.func, - address: PropTypes.string, + /** + * Name of the token that is waiting to be allowed + */ tokenName: PropTypes.string, + /** + * Address of the token that is waiting to be allowed + */ + tokenAddress: PropTypes.string, + /** + * Contract address requesting spending cap + */ + toAddress: PropTypes.string, + /** + * Current network chainId + */ + chainId: PropTypes.string, + /** + * RPC prefs of the current network + */ + rpcPrefs: PropTypes.object, + /** + * Dapp URL + */ + origin: PropTypes.string, + /** + * Dapp image + */ + siteImage: PropTypes.string, }; diff --git a/ui/components/app/modals/contract-details-modal/contract-details-modal.stories.js b/ui/components/app/modals/contract-details-modal/contract-details-modal.stories.js index 8cf6272fc1f0..fb022d134ee3 100644 --- a/ui/components/app/modals/contract-details-modal/contract-details-modal.stories.js +++ b/ui/components/app/modals/contract-details-modal/contract-details-modal.stories.js @@ -1,23 +1,44 @@ -import React, { useState } from 'react'; -import Button from '../../../ui/button'; +import React from 'react'; import ContractDetailsModal from './contract-details-modal'; export default { title: 'Components/App/Modals/ContractDetailsModal', id: __filename, argTypes: { - onClosePopover: { - action: 'Close Contract Details', - }, - onOpenPopover: { - action: 'Open Contract Details', + onClose: { + action: 'onClose', }, tokenName: { control: { type: 'text', }, }, - address: { + tokenAddress: { + control: { + type: 'text', + }, + }, + toAddress: { + control: { + type: 'text', + }, + }, + chainId: { + control: { + type: 'text', + }, + }, + rpcPrefs: { + control: { + type: 'object', + }, + }, + origin: { + control: { + type: 'text', + }, + }, + siteImage: { control: { type: 'text', }, @@ -25,33 +46,17 @@ export default { }, args: { tokenName: 'DAI', - address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + toAddress: '0x9bc5baf874d2da8d216ae9f137804184ee5afef4', + chainId: '0x3', + rpcPrefs: {}, + origin: 'https://metamask.github.io', + siteImage: 'https://metamask.github.io/test-dapp/metamask-fox.svg', }, }; export const DefaultStory = (args) => { - const [showContractDetails, setshowContractDetails] = useState(false); - return ( - <> - - {showContractDetails && ( - { - args.onClosePopover(); - setshowContractDetails(false); - }} - {...args} - /> - )} - - ); + return ; }; DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/modals/contract-details-modal/index.scss b/ui/components/app/modals/contract-details-modal/index.scss index b36649fd77d7..52af5a2405e5 100644 --- a/ui/components/app/modals/contract-details-modal/index.scss +++ b/ui/components/app/modals/contract-details-modal/index.scss @@ -9,6 +9,10 @@ margin: 16px 16px 38px 16px; } + &__identicon-for-unknown-contact { + margin: 16px; + } + &__buttons { flex-grow: 1; @@ -22,10 +26,4 @@ } } } - - &__footer { - button + button { - margin-inline-start: 1rem; - } - } } diff --git a/ui/components/ui/contract-token-values/contract-token-values.js b/ui/components/ui/contract-token-values/contract-token-values.js index 1c7f4edb001f..1b2635ad6576 100644 --- a/ui/components/ui/contract-token-values/contract-token-values.js +++ b/ui/components/ui/contract-token-values/contract-token-values.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { getAccountLink } from '@metamask/etherscan-link'; import IconCopy from '../icon/icon-copy'; import IconBlockExplorer from '../icon/icon-block-explorer'; import Box from '../box/box'; @@ -18,7 +19,12 @@ import { import Button from '../button'; import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; -export default function ContractTokenValues({ address, tokenName }) { +export default function ContractTokenValues({ + address, + tokenName, + chainId, + rpcPrefs, +}) { const t = useI18nContext(); const [copied, handleCopy] = useCopyToClipboard(); @@ -62,6 +68,19 @@ export default function ContractTokenValues({ address, tokenName }) { @@ -80,4 +99,12 @@ ContractTokenValues.propTypes = { * Displayed the token name currently tracked in state */ tokenName: PropTypes.string, + /** + * Current network chainId + */ + chainId: PropTypes.string, + /** + * RPC prefs + */ + rpcPrefs: PropTypes.object, }; diff --git a/ui/components/ui/review-spending-cap/index.scss b/ui/components/ui/review-spending-cap/index.scss index 110edfdf4a59..fdcb3d5626c6 100644 --- a/ui/components/ui/review-spending-cap/index.scss +++ b/ui/components/ui/review-spending-cap/index.scss @@ -8,7 +8,7 @@ width: 180px; &__warning-icon { - color: var(--color-warning-default); + color: var(--color-error-default); } &__question-icon { diff --git a/ui/components/ui/review-spending-cap/review-spending-cap.js b/ui/components/ui/review-spending-cap/review-spending-cap.js index 760471628e8b..38761de631c1 100644 --- a/ui/components/ui/review-spending-cap/review-spending-cap.js +++ b/ui/components/ui/review-spending-cap/review-spending-cap.js @@ -70,7 +70,7 @@ export default function ReviewSpendingCap({ key="tooltip-text" variant={TYPOGRAPHY.H7} fontWeight={FONT_WEIGHT.BOLD} - color={COLORS.WARNING_DEFAULT} + color={COLORS.ERROR_DEFAULT} > {' '} {t('beCareful')} @@ -110,7 +110,7 @@ export default function ReviewSpendingCap({ as={TYPOGRAPHY.H6} color={ tokenValue > currentTokenBalance - ? COLORS.WARNING_DEFAULT + ? COLORS.ERROR_DEFAULT : COLORS.TEXT_DEFAULT } variant={TYPOGRAPHY.H6} diff --git a/ui/pages/confirm-approve/confirm-approve.js b/ui/pages/confirm-approve/confirm-approve.js index 5af747801d5b..26c065b4460e 100644 --- a/ui/pages/confirm-approve/confirm-approve.js +++ b/ui/pages/confirm-approve/confirm-approve.js @@ -36,6 +36,7 @@ import Loading from '../../components/ui/loading-screen'; import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils'; import { ERC1155, ERC20, ERC721 } from '../../../shared/constants/transaction'; import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils'; +import TokenAllowance from '../token-allowance/token-allowance'; import { getCustomTxParamsData } from './confirm-approve.util'; import ConfirmApproveContent from './confirm-approve-content'; @@ -157,130 +158,174 @@ export default function ConfirmApprove({ parseStandardTokenTransactionData(transactionData); const isApprovalOrRejection = getTokenApprovedParam(parsedTransactionData); - return tokenSymbol === undefined && assetName === undefined ? ( - - ) : ( - !process.env.TOKEN_ALLOWANCE_IMPROVEMENTS && ( + if (tokenSymbol === undefined && assetName === undefined) { + return ; + } + if (process.env.TOKEN_ALLOWANCE_IMPROVEMENTS && assetStandard === ERC20) { + return ( - - - dispatch( - showModal({ - name: 'EDIT_APPROVAL_PERMISSION', - customTokenAmount, - decimals, - origin, - setCustomAmount, - tokenAmount, - tokenBalance, - tokenSymbol, - tokenId, - assetStandard, - }), - ) - } - data={customData || transactionData} - toAddress={toAddress} - currentCurrency={currentCurrency} - nativeCurrency={nativeCurrency} - ethTransactionTotal={ethTransactionTotal} - fiatTransactionTotal={fiatTransactionTotal} - hexTransactionTotal={hexTransactionTotal} - useNonceField={useNonceField} - nextNonce={nextNonce} - customNonceValue={customNonceValue} - updateCustomNonce={(value) => { - dispatch(updateCustomNonce(value)); - }} - getNextNonce={() => dispatch(getNextNonce())} - showCustomizeNonceModal={({ - /* eslint-disable no-shadow */ - useNonceField, - nextNonce, - customNonceValue, - updateCustomNonce, - getNextNonce, - /* eslint-disable no-shadow */ - }) => - dispatch( - showModal({ - name: 'CUSTOMIZE_NONCE', - useNonceField, - nextNonce, - customNonceValue, - updateCustomNonce, - getNextNonce, - }), - ) - } - warning={submitWarning} - txData={transaction} - fromAddressIsLedger={fromAddressIsLedger} - chainId={chainId} - rpcPrefs={rpcPrefs} - isContract={isContract} - isMultiLayerFeeNetwork={isMultiLayerFeeNetwork} - supportsEIP1559V2={supportsEIP1559V2} - /> - {showCustomizeGasPopover && !supportsEIP1559V2 && ( - - )} - {supportsEIP1559V2 && ( - <> - - - - )} - - } - hideSenderToRecipient - customTxParamsData={customData} - assetStandard={assetStandard} - /> + + + {showCustomizeGasPopover && !supportsEIP1559V2 && ( + + )} + {supportsEIP1559V2 && ( + <> + + + + )} + - ) + ); + } + return ( + + + + dispatch( + showModal({ + name: 'EDIT_APPROVAL_PERMISSION', + customTokenAmount, + decimals, + origin, + setCustomAmount, + tokenAmount, + tokenBalance, + tokenSymbol, + tokenId, + assetStandard, + }), + ) + } + data={customData || transactionData} + toAddress={toAddress} + currentCurrency={currentCurrency} + nativeCurrency={nativeCurrency} + ethTransactionTotal={ethTransactionTotal} + fiatTransactionTotal={fiatTransactionTotal} + hexTransactionTotal={hexTransactionTotal} + useNonceField={useNonceField} + nextNonce={nextNonce} + customNonceValue={customNonceValue} + updateCustomNonce={(value) => { + dispatch(updateCustomNonce(value)); + }} + getNextNonce={() => dispatch(getNextNonce())} + showCustomizeNonceModal={({ + /* eslint-disable no-shadow */ + useNonceField, + nextNonce, + customNonceValue, + updateCustomNonce, + getNextNonce, + /* eslint-disable no-shadow */ + }) => + dispatch( + showModal({ + name: 'CUSTOMIZE_NONCE', + useNonceField, + nextNonce, + customNonceValue, + updateCustomNonce, + getNextNonce, + }), + ) + } + warning={submitWarning} + txData={transaction} + fromAddressIsLedger={fromAddressIsLedger} + chainId={chainId} + rpcPrefs={rpcPrefs} + isContract={isContract} + isMultiLayerFeeNetwork={isMultiLayerFeeNetwork} + supportsEIP1559V2={supportsEIP1559V2} + /> + {showCustomizeGasPopover && !supportsEIP1559V2 && ( + + )} + {supportsEIP1559V2 && ( + <> + + + + )} + + } + hideSenderToRecipient + customTxParamsData={customData} + assetStandard={assetStandard} + /> + ); } diff --git a/ui/pages/pages.scss b/ui/pages/pages.scss index d6160c24f745..ec51b6783b0a 100644 --- a/ui/pages/pages.scss +++ b/ui/pages/pages.scss @@ -21,6 +21,7 @@ @import 'send/send'; @import 'settings/index'; @import 'swaps/index'; +@import 'token-allowance/index'; @import 'token-details/index'; @import 'unlock-page/index'; @import 'onboarding-flow/index'; diff --git a/ui/pages/token-allowance/index.js b/ui/pages/token-allowance/index.js new file mode 100644 index 000000000000..4f7bc6c57add --- /dev/null +++ b/ui/pages/token-allowance/index.js @@ -0,0 +1 @@ +export { default } from './token-allowance'; diff --git a/ui/pages/token-allowance/index.scss b/ui/pages/token-allowance/index.scss new file mode 100644 index 000000000000..057be3d10951 --- /dev/null +++ b/ui/pages/token-allowance/index.scss @@ -0,0 +1,41 @@ +.token-allowance-container { + &__icon-display-content { + width: fit-content; + height: 40px; + box-sizing: border-box; + border-radius: 100px; + position: relative; + + &__siteimage-identicon { + width: 24px; + height: 24px; + box-shadow: none; + background: none; + } + } + + a.token-allowance-container__verify-link { + width: fit-content; + margin-inline-start: 96px; + margin-inline-end: 96px; + padding: 0; + } + + a.token-allowance-container__view-details { + width: fit-content; + margin-inline-start: 108px; + margin-inline-end: 108px; + } + + &__card-wrapper { + width: 100%; + } + + &__data { + width: 100%; + } + + &__full-tx-content { + max-width: 100%; + } +} diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js new file mode 100644 index 000000000000..201c0a36439d --- /dev/null +++ b/ui/pages/token-allowance/token-allowance.js @@ -0,0 +1,437 @@ +import React, { useState, useContext } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import Box from '../../components/ui/box/box'; +import NetworkAccountBalanceHeader from '../../components/app/network-account-balance-header/network-account-balance-header'; +import UrlIcon from '../../components/ui/url-icon/url-icon'; +import Typography from '../../components/ui/typography/typography'; +import { + ALIGN_ITEMS, + BORDER_STYLE, + COLORS, + DISPLAY, + FLEX_DIRECTION, + FONT_WEIGHT, + JUSTIFY_CONTENT, + TEXT_ALIGN, + TYPOGRAPHY, +} from '../../helpers/constants/design-system'; +import { I18nContext } from '../../contexts/i18n'; +import ContractTokenValues from '../../components/ui/contract-token-values/contract-token-values'; +import Button from '../../components/ui/button'; +import ReviewSpendingCap from '../../components/ui/review-spending-cap/review-spending-cap'; +import { PageContainerFooter } from '../../components/ui/page-container'; +import ContractDetailsModal from '../../components/app/modals/contract-details-modal/contract-details-modal'; +import { + getCurrentAccountWithSendEtherInfo, + getNetworkIdentifier, + transactionFeeSelector, + getKnownMethodData, + getRpcPrefsForCurrentProvider, +} from '../../selectors'; +import { NETWORK_TO_NAME_MAP } from '../../../shared/constants/network'; +import { + cancelTx, + updateAndApproveTx, + updateCustomNonce, +} from '../../store/actions'; +import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'; +import { getMostRecentOverviewPage } from '../../ducks/history/history'; +import ApproveContentCard from '../../components/app/approve-content-card/approve-content-card'; + +export default function TokenAllowance({ + origin, + siteImage, + showCustomizeGasModal, + useNonceField, + currentCurrency, + nativeCurrency, + ethTransactionTotal, + fiatTransactionTotal, + hexTransactionTotal, + txData, + isMultiLayerFeeNetwork, + supportsEIP1559V2, + userAddress, + tokenAddress, + data, + isSetApproveForAll, + isApprovalOrRejection, + customTxParamsData, + dappProposedTokenAmount, + currentTokenBalance, + toAddress, + tokenSymbol, +}) { + const t = useContext(I18nContext); + const dispatch = useDispatch(); + const history = useHistory(); + const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); + + const [showContractDetails, setShowContractDetails] = useState(false); + const [showFullTxDetails, setShowFullTxDetails] = useState(false); + const [isFirstPage, setIsFirstPage] = useState(false); + + const currentAccount = useSelector(getCurrentAccountWithSendEtherInfo); + const networkIdentifier = useSelector(getNetworkIdentifier); + const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); + + let fullTxData = { ...txData }; + + if (customTxParamsData) { + fullTxData = { + ...fullTxData, + txParams: { + ...fullTxData.txParams, + data: customTxParamsData, + }, + }; + } + + const fee = useSelector((state) => transactionFeeSelector(state, fullTxData)); + const methodData = useSelector((state) => getKnownMethodData(state, data)); + + const networkName = + NETWORK_TO_NAME_MAP[fullTxData.chainId] || networkIdentifier; + + const customNonceValue = ''; + const customNonceMerge = (transactionData) => + customNonceValue + ? { + ...transactionData, + customNonceValue, + } + : transactionData; + + const handleReject = () => { + dispatch(cancelTx(fullTxData)).then(() => { + dispatch(clearConfirmTransaction()); + dispatch(updateCustomNonce('')); + history.push(mostRecentOverviewPage); + }); + }; + + const handleApprove = () => { + const { name } = methodData; + + if (fee.gasEstimationObject.baseFeePerGas) { + fullTxData.estimatedBaseFee = fee.gasEstimationObject.baseFeePerGas; + } + + if (name) { + fullTxData.contractMethodName = name; + } + + if (dappProposedTokenAmount) { + fullTxData.dappProposedTokenAmount = dappProposedTokenAmount; + fullTxData.originalApprovalAmount = dappProposedTokenAmount; + } + + if (currentTokenBalance) { + fullTxData.currentTokenBalance = currentTokenBalance; + } + + dispatch(updateAndApproveTx(customNonceMerge(fullTxData))).then(() => { + dispatch(clearConfirmTransaction()); + dispatch(updateCustomNonce('')); + history.push(mostRecentOverviewPage); + }); + }; + + return ( + + + + {!isFirstPage && ( + + )} + + + + {isFirstPage ? 1 : 2} {t('ofTextNofM')} 2 + + + + + + + + + {origin} + + + + + + {isFirstPage ? t('setSpendingCap') : t('reviewSpendingCap')} + + + + + + + + + + setIsFirstPage(true)} + /> + + {!isFirstPage && ( + + } + title={t('transactionFee')} + showEdit + showAdvanceGasFeeOptions + onEditClick={showCustomizeGasModal} + renderTransactionDetailsContent + noBorder={useNonceField || !showFullTxDetails} + supportsEIP1559V2={supportsEIP1559V2} + isMultiLayerFeeNetwork={isMultiLayerFeeNetwork} + ethTransactionTotal={ethTransactionTotal} + nativeCurrency={nativeCurrency} + fullTxData={fullTxData} + hexTransactionTotal={hexTransactionTotal} + fiatTransactionTotal={fiatTransactionTotal} + currentCurrency={currentCurrency} + /> + + )} + + + + {showFullTxDetails ? ( + + + } + title={t('data')} + renderDataContent + noBorder + supportsEIP1559V2={supportsEIP1559V2} + isSetApproveForAll={isSetApproveForAll} + isApprovalOrRejection={isApprovalOrRejection} + data={data} + /> + + + ) : null} + handleReject()} + onSubmit={() => (isFirstPage ? setIsFirstPage(false) : handleApprove())} + /> + {showContractDetails && ( + setShowContractDetails(false)} + tokenAddress={tokenAddress} + toAddress={toAddress} + chainId={fullTxData.chainId} + rpcPrefs={rpcPrefs} + origin={origin} + siteImage={siteImage} + /> + )} + + ); +} + +TokenAllowance.propTypes = { + /** + * Dapp URL + */ + origin: PropTypes.string, + /** + * Dapp image + */ + siteImage: PropTypes.string, + /** + * Function that is supposed to open the customized gas modal + */ + showCustomizeGasModal: PropTypes.func, + /** + * Whether nonce field should be used or not + */ + useNonceField: PropTypes.bool, + /** + * Current fiat currency (e.g. USD) + */ + currentCurrency: PropTypes.string, + /** + * Current native currency (e.g. RopstenETH) + */ + nativeCurrency: PropTypes.string, + /** + * Total sum of the transaction in native currency + */ + ethTransactionTotal: PropTypes.string, + /** + * Total sum of the transaction in fiat currency + */ + fiatTransactionTotal: PropTypes.string, + /** + * Total sum of the transaction converted to hex value + */ + hexTransactionTotal: PropTypes.string, + /** + * Current transaction + */ + txData: PropTypes.object, + /** + * Is multi-layer fee network or not + */ + isMultiLayerFeeNetwork: PropTypes.bool, + /** + * Is the enhanced gas fee enabled or not + */ + supportsEIP1559V2: PropTypes.bool, + /** + * User's address + */ + userAddress: PropTypes.string, + /** + * Address of the token that is waiting to be allowed + */ + tokenAddress: PropTypes.string, + /** + * Current transaction data + */ + data: PropTypes.string, + /** + * Is set approve for all or not + */ + isSetApproveForAll: PropTypes.bool, + /** + * Whether a current set approval for all transaction will approve or revoke access + */ + isApprovalOrRejection: PropTypes.bool, + /** + * Custom transaction parameters data made by the user (fees) + */ + customTxParamsData: PropTypes.object, + /** + * Token amount proposed by the Dapp + */ + dappProposedTokenAmount: PropTypes.string, + /** + * Token balance of the current account + */ + currentTokenBalance: PropTypes.string, + /** + * Contract address requesting spending cap + */ + toAddress: PropTypes.string, + /** + * Symbol of the token that is waiting to be allowed + */ + tokenSymbol: PropTypes.string, +}; diff --git a/ui/pages/token-allowance/token-allowance.stories.js b/ui/pages/token-allowance/token-allowance.stories.js new file mode 100644 index 000000000000..39875bfc6da5 --- /dev/null +++ b/ui/pages/token-allowance/token-allowance.stories.js @@ -0,0 +1,201 @@ +import React from 'react'; +import TokenAllowance from './token-allowance'; + +export default { + title: 'Pages/TokenAllowance', + id: __filename, + argTypes: { + origin: { + control: 'text', + }, + siteImage: { + control: 'text', + }, + showCustomizeGasModal: { + action: 'showCustomizeGasModal', + }, + useNonceField: { + control: 'boolean', + }, + currentCurrency: { + control: 'text', + }, + nativeCurrency: { + control: 'text', + }, + ethTransactionTotal: { + control: 'text', + }, + fiatTransactionTotal: { + control: 'text', + }, + hexTransactionTotal: { + control: 'text', + }, + isMultiLayerFeeNetwork: { + control: 'text', + }, + supportsEIP1559V2: { + control: 'boolean', + }, + userAddress: { + control: 'text', + }, + tokenAddress: { + control: 'text', + }, + data: { + control: 'text', + }, + isSetApproveForAll: { + control: 'boolean', + }, + setApproveForAllArg: { + control: 'boolean', + }, + customTxParamsData: { + control: 'object', + }, + dappProposedTokenAmount: { + control: 'text', + }, + currentTokenBalance: { + control: 'text', + }, + toAddress: { + control: 'text', + }, + tokenSymbol: { + control: 'text', + }, + txData: { + control: 'object', + }, + }, + args: { + origin: 'https://metamask.github.io', + siteImage: 'https://metamask.github.io/test-dapp/metamask-fox.svg', + useNonceField: false, + currentCurrency: 'usd', + nativeCurrency: 'RopstenETH', + ethTransactionTotal: '0.0012', + fiatTransactionTotal: '1.6', + hexTransactionTotal: '0x44364c5bb0000', + isMultiLayerFeeNetwork: false, + supportsEIP1559V2: false, + userAddress: '0xdd34b35ca1de17dfcdc07f79ff1f8f94868c40a1', + tokenAddress: '0x55797717b9947b31306f4aac7ad1365c6e3923bd', + data: '0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000011170', + isSetApproveForAll: false, + setApproveForAllArg: false, + customTxParamsData: {}, + dappProposedTokenAmount: '7', + currentTokenBalance: '10', + toAddress: '0x9bc5baf874d2da8d216ae9f137804184ee5afef4', + tokenSymbol: 'TST', + txData: { + id: 3049568294499567, + time: 1664449552289, + status: 'unapproved', + metamaskNetworkId: '3', + originalGasEstimate: '0xea60', + userEditedGasLimit: false, + chainId: '0x3', + loadingDefaults: false, + dappSuggestedGasFees: { + gasPrice: '0x4a817c800', + gas: '0xea60', + }, + sendFlowHistory: [], + txParams: { + from: '0xdd34b35ca1de17dfcdc07f79ff1f8f94868c40a1', + to: '0x55797717b9947b31306f4aac7ad1365c6e3923bd', + value: '0x0', + data: '0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000011170', + gas: '0xea60', + maxFeePerGas: '0x4a817c800', + maxPriorityFeePerGas: '0x4a817c800', + }, + origin: 'https://metamask.github.io', + type: 'approve', + history: [ + { + id: 3049568294499567, + time: 1664449552289, + status: 'unapproved', + metamaskNetworkId: '3', + originalGasEstimate: '0xea60', + userEditedGasLimit: false, + chainId: '0x3', + loadingDefaults: true, + dappSuggestedGasFees: { + gasPrice: '0x4a817c800', + gas: '0xea60', + }, + sendFlowHistory: [], + txParams: { + from: '0xdd34b35ca1de17dfcdc07f79ff1f8f94868c40a1', + to: '0x55797717b9947b31306f4aac7ad1365c6e3923bd', + value: '0x0', + data: '0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000011170', + gas: '0xea60', + gasPrice: '0x4a817c800', + }, + origin: 'https://metamask.github.io', + type: 'approve', + }, + [ + { + op: 'remove', + path: '/txParams/gasPrice', + note: 'Added new unapproved transaction.', + timestamp: 1664449553939, + }, + { + op: 'add', + path: '/txParams/maxFeePerGas', + value: '0x4a817c800', + }, + { + op: 'add', + path: '/txParams/maxPriorityFeePerGas', + value: '0x4a817c800', + }, + { + op: 'replace', + path: '/loadingDefaults', + value: false, + }, + { + op: 'add', + path: '/userFeeLevel', + value: 'custom', + }, + { + op: 'add', + path: '/defaultGasEstimates', + value: { + estimateType: 'custom', + gas: '0xea60', + maxFeePerGas: '0x4a817c800', + maxPriorityFeePerGas: '0x4a817c800', + }, + }, + ], + ], + userFeeLevel: 'custom', + defaultGasEstimates: { + estimateType: 'custom', + gas: '0xea60', + maxFeePerGas: '0x4a817c800', + maxPriorityFeePerGas: '0x4a817c800', + }, + }, + }, +}; + +export const DefaultStory = (args) => { + return ; +}; + +DefaultStory.storyName = 'Default'; From 12aa200ad02e6f35f29883cf73f5a79207d2b2e2 Mon Sep 17 00:00:00 2001 From: Garrett Bear Date: Wed, 5 Oct 2022 21:51:02 -0700 Subject: [PATCH 06/33] 15090: add primary button (#16079) * 15090: add primary button * updates * add button base props * add button base props to primary * remove button base props and improve classname test * update box shadow animation * fix anchor test and update documentation * fix button base iconProps proptype --- .../button-base/button-base.js | 8 +- .../button-base/button-base.test.js | 11 +- .../button-primary/README.mdx | 57 ++++++++ .../button-primary.constants.js | 7 + .../button-primary/button-primary.js | 45 ++++++ .../button-primary/button-primary.scss | 43 ++++++ .../button-primary/button-primary.stories.js | 137 ++++++++++++++++++ .../button-primary/button-primary.test.js | 97 +++++++++++++ .../component-library/button-primary/index.js | 1 + .../component-library-components.scss | 1 + 10 files changed, 401 insertions(+), 6 deletions(-) create mode 100644 ui/components/component-library/button-primary/README.mdx create mode 100644 ui/components/component-library/button-primary/button-primary.constants.js create mode 100644 ui/components/component-library/button-primary/button-primary.js create mode 100644 ui/components/component-library/button-primary/button-primary.scss create mode 100644 ui/components/component-library/button-primary/button-primary.stories.js create mode 100644 ui/components/component-library/button-primary/button-primary.test.js create mode 100644 ui/components/component-library/button-primary/index.js diff --git a/ui/components/component-library/button-base/button-base.js b/ui/components/component-library/button-base/button-base.js index eeb19c1a267d..1f5a1f10f811 100644 --- a/ui/components/component-library/button-base/button-base.js +++ b/ui/components/component-library/button-base/button-base.js @@ -39,9 +39,9 @@ export const ButtonBase = ({ 'mm-button', `mm-button--size-${size}`, { - 'mm-button--loading': Boolean(loading), - 'mm-button--disabled': Boolean(disabled), - 'mm-button--block': Boolean(block), + 'mm-button--loading': loading, + 'mm-button--disabled': disabled, + 'mm-button--block': block, }, className, )} @@ -117,7 +117,7 @@ ButtonBase.propTypes = { /** * iconProps accepts all the props from Icon */ - iconProps: Icon.propTypes, + iconProps: PropTypes.object, /** * Boolean to show loading spinner in button */ diff --git a/ui/components/component-library/button-base/button-base.test.js b/ui/components/component-library/button-base/button-base.test.js index 5c03604334a4..32a7ef94d812 100644 --- a/ui/components/component-library/button-base/button-base.test.js +++ b/ui/components/component-library/button-base/button-base.test.js @@ -18,9 +18,9 @@ describe('ButtonBase', () => { const { getByTestId, container } = render( , ); - expect(getByTestId('button-base')).toBeDefined(); - expect(container.querySelector('a')).toBeDefined(); expect(getByTestId('button-base')).toHaveClass('mm-button'); + const anchor = container.getElementsByTagName('a').length; + expect(anchor).toBe(1); }); it('should render button as block', () => { @@ -51,6 +51,13 @@ describe('ButtonBase', () => { ); }); + it('should render with added classname', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('classname')).toHaveClass('mm-button--test'); + }); + it('should render with different button states', () => { const { getByTestId } = render( <> diff --git a/ui/components/component-library/button-primary/README.mdx b/ui/components/component-library/button-primary/README.mdx new file mode 100644 index 000000000000..69a110540a78 --- /dev/null +++ b/ui/components/component-library/button-primary/README.mdx @@ -0,0 +1,57 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import { ButtonPrimary } from './button-primary'; + +# ButtonPrimary + +The `ButtonPrimary` is an extension of `ButtonBase` to support primary styles. + + + + + +## Props + +The `ButtonPrimary` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) and [ButtonBase](/docs/ui-components-component-library-button-base-button-base-stories-js--default-story#props) component props + + + +### Size + +Use the `size` prop and the `SIZES` object from `./ui/helpers/constants/design-system.js` to change the size of `ButtonPrimary`. Defaults to `SIZES.MD` + +Optional: `BUTTON_SIZES` from `./button-base` object can be used instead of `SIZES`. + +Possible sizes include: + +- `SIZES.SM` 32px +- `SIZES.MD` 40px +- `SIZES.LG` 48px + + + + + +```jsx +import { SIZES } from '../../../helpers/constants/design-system'; +import { ButtonPrimary } from '../ui/component-library/button/button-primary/button-primary'; + + + + +``` + +### Type + +Use the `type` prop and the `BUTTON_TYPES` object from `./ui/helpers/constants/design-system.js` to change the context of `ButtonPrimary`. + + + + + +```jsx +import { ButtonPrimary } from '../ui/component-library/button/button-primary/button-primary'; + +Normal +Danger +``` diff --git a/ui/components/component-library/button-primary/button-primary.constants.js b/ui/components/component-library/button-primary/button-primary.constants.js new file mode 100644 index 000000000000..4fa0915034d8 --- /dev/null +++ b/ui/components/component-library/button-primary/button-primary.constants.js @@ -0,0 +1,7 @@ +import { SIZES } from '../../../helpers/constants/design-system'; + +export const BUTTON_PRIMARY_SIZES = { + SM: SIZES.SM, + MD: SIZES.MD, + LG: SIZES.LG, +}; diff --git a/ui/components/component-library/button-primary/button-primary.js b/ui/components/component-library/button-primary/button-primary.js new file mode 100644 index 000000000000..78dc3e93d4ad --- /dev/null +++ b/ui/components/component-library/button-primary/button-primary.js @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; + +import { ButtonBase } from '../button-base'; +import { BUTTON_PRIMARY_SIZES } from './button-primary.constants'; + +export const ButtonPrimary = ({ + className, + danger, + size = BUTTON_PRIMARY_SIZES.MD, + ...props +}) => { + return ( + + ); +}; + +ButtonPrimary.propTypes = { + /** + * An additional className to apply to the ButtonPrimary. + */ + className: PropTypes.string, + /** + * Boolean to change button type to Danger when true + */ + danger: PropTypes.bool, + /** + * The possible size values for ButtonPrimary: 'SIZES.SM', 'SIZES.MD', 'SIZES.LG', + * Default value is 'SIZES.MD'. + */ + size: PropTypes.oneOf(Object.values(BUTTON_PRIMARY_SIZES)), + /** + * ButtonPrimary accepts all the props from ButtonBase + */ + ...ButtonBase.propTypes, +}; + +export default ButtonPrimary; diff --git a/ui/components/component-library/button-primary/button-primary.scss b/ui/components/component-library/button-primary/button-primary.scss new file mode 100644 index 000000000000..70f0b8bd042c --- /dev/null +++ b/ui/components/component-library/button-primary/button-primary.scss @@ -0,0 +1,43 @@ +.mm-button-primary { + color: var(--color-primary-inverse); + background-color: var(--color-primary-default); + + &:hover { + color: var(--color-primary-inverse); + box-shadow: var(--component-button-primary-shadow); + } + + &:active { + color: var(--color-primary-inverse); + background-color: var(--color-primary-alternative); + } + + &.mm-button--disabled { + &:hover { + box-shadow: none; + } + + &:active { + background-color: var(--color-primary-default); + } + } + + &--type-danger { + color: var(--color-error-inverse); + background-color: var(--color-error-default); + + &:hover { + color: var(--color-error-inverse); + box-shadow: var(--component-button-danger-shadow); + } + + &:active { + color: var(--color-error-inverse); + background-color: var(--color-error-alternative); + } + + &.mm-button--disabled:active { + background-color: var(--color-error-default); + } + } +} diff --git a/ui/components/component-library/button-primary/button-primary.stories.js b/ui/components/component-library/button-primary/button-primary.stories.js new file mode 100644 index 000000000000..fff0966b08e2 --- /dev/null +++ b/ui/components/component-library/button-primary/button-primary.stories.js @@ -0,0 +1,137 @@ +import React from 'react'; +import { ALIGN_ITEMS, DISPLAY } from '../../../helpers/constants/design-system'; +import Box from '../../ui/box/box'; +import { ICON_NAMES } from '../icon'; +import { ButtonPrimary } from './button-primary'; +import { BUTTON_PRIMARY_SIZES } from './button-primary.constants'; +import README from './README.mdx'; + +const marginSizeControlOptions = [ + undefined, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 'auto', +]; + +export default { + title: 'Components/ComponentLibrary/ButtonPrimary', + id: __filename, + component: ButtonPrimary, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + as: { + control: 'select', + options: ['button', 'a'], + table: { category: 'button base props' }, + }, + block: { + control: 'boolean', + table: { category: 'button base props' }, + }, + children: { + control: 'text', + }, + className: { + control: 'text', + }, + danger: { + control: 'boolean', + }, + disabled: { + control: 'boolean', + table: { category: 'button base props' }, + }, + icon: { + control: 'select', + options: Object.values(ICON_NAMES), + table: { category: 'button base props' }, + }, + iconPositionRight: { + control: 'boolean', + table: { category: 'button base props' }, + }, + iconProps: { + control: 'object', + table: { category: 'button base props' }, + }, + + loading: { + control: 'boolean', + table: { category: 'button base props' }, + }, + size: { + control: 'select', + options: Object.values(BUTTON_PRIMARY_SIZES), + }, + marginTop: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginRight: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginBottom: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginLeft: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + }, + args: { + children: 'Button Primary', + }, +}; + +export const DefaultStory = (args) => ( + <> + + +); + +DefaultStory.storyName = 'Default'; + +export const Size = (args) => ( + + + Small Button + + + Medium (Default) Button + + + Large Button + + +); + +export const Type = (args) => ( + + Normal + {/* Test Anchor tag to match exactly as button */} + + Danger + + +); diff --git a/ui/components/component-library/button-primary/button-primary.test.js b/ui/components/component-library/button-primary/button-primary.test.js new file mode 100644 index 000000000000..34751ae7f61d --- /dev/null +++ b/ui/components/component-library/button-primary/button-primary.test.js @@ -0,0 +1,97 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render } from '@testing-library/react'; +import React from 'react'; +import { ButtonPrimary } from './button-primary'; +import { BUTTON_PRIMARY_SIZES } from './button-primary.constants'; + +describe('ButtonPrimary', () => { + it('should render button element correctly', () => { + const { getByText, getByTestId, container } = render( + + Button Primary + , + ); + expect(getByText('Button Primary')).toBeDefined(); + expect(container.querySelector('button')).toBeDefined(); + expect(getByTestId('button-primary')).toHaveClass('mm-button'); + }); + + it('should render anchor element correctly', () => { + const { getByTestId, container } = render( + , + ); + expect(getByTestId('button-primary')).toHaveClass('mm-button'); + const anchor = container.getElementsByTagName('a').length; + expect(anchor).toBe(1); + }); + + it('should render button as block', () => { + const { getByTestId } = render(); + expect(getByTestId('block')).toHaveClass(`mm-button--block`); + }); + + it('should render with added classname', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('classname')).toHaveClass('mm-button--test'); + }); + + it('should render with different size classes', () => { + const { getByTestId } = render( + <> + + + + , + ); + + expect(getByTestId(BUTTON_PRIMARY_SIZES.SM)).toHaveClass( + `mm-button--size-${BUTTON_PRIMARY_SIZES.SM}`, + ); + expect(getByTestId(BUTTON_PRIMARY_SIZES.MD)).toHaveClass( + `mm-button--size-${BUTTON_PRIMARY_SIZES.MD}`, + ); + expect(getByTestId(BUTTON_PRIMARY_SIZES.LG)).toHaveClass( + `mm-button--size-${BUTTON_PRIMARY_SIZES.LG}`, + ); + }); + + it('should render with different types', () => { + const { getByTestId } = render( + <> + + , + ); + + expect(getByTestId('danger')).toHaveClass('mm-button-primary--type-danger'); + }); + + it('should render with different button states', () => { + const { getByTestId } = render( + <> + + + , + ); + expect(getByTestId('loading')).toHaveClass(`mm-button--loading`); + expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`); + }); + it('should render with icon', () => { + const { container } = render( + , + ); + + const icons = container.getElementsByClassName('icon').length; + expect(icons).toBe(1); + }); +}); diff --git a/ui/components/component-library/button-primary/index.js b/ui/components/component-library/button-primary/index.js new file mode 100644 index 000000000000..e6b99af4c02f --- /dev/null +++ b/ui/components/component-library/button-primary/index.js @@ -0,0 +1 @@ +export { ButtonPrimary } from './button-primary'; diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss index 835f1d842a54..97c7320a4cb8 100644 --- a/ui/components/component-library/component-library-components.scss +++ b/ui/components/component-library/component-library-components.scss @@ -3,5 +3,6 @@ @import 'avatar-token/avatar-token'; @import 'base-avatar/base-avatar'; @import 'button-base/button-base'; +@import 'button-primary/button-primary'; @import 'icon/icon'; @import 'text/text'; From 466e7534c532ae9c9aa58f5408e547c77b43cfe0 Mon Sep 17 00:00:00 2001 From: ryanml Date: Thu, 6 Oct 2022 07:43:52 -0700 Subject: [PATCH 07/33] Fixing Identicon import paths (#16101) --- .../app/modals/contract-details-modal/contract-details-modal.js | 2 +- .../network-account-balance-header.js | 2 +- ui/components/ui/contract-token-values/contract-token-values.js | 2 +- ui/components/ui/new-network-info/new-network-info.js | 2 +- ui/pages/token-details/token-details-page.test.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/components/app/modals/contract-details-modal/contract-details-modal.js b/ui/components/app/modals/contract-details-modal/contract-details-modal.js index 818920afe2f7..dd291303f88a 100644 --- a/ui/components/app/modals/contract-details-modal/contract-details-modal.js +++ b/ui/components/app/modals/contract-details-modal/contract-details-modal.js @@ -9,7 +9,7 @@ import IconBlockExplorer from '../../../ui/icon/icon-block-explorer'; import Button from '../../../ui/button/button.component'; import Tooltip from '../../../ui/tooltip/tooltip'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import Identicon from '../../../ui/identicon/identicon.component'; +import Identicon from '../../../ui/identicon'; import { ellipsify } from '../../../../pages/send/send.utils'; import Popover from '../../../ui/popover'; import Typography from '../../../ui/typography'; diff --git a/ui/components/app/network-account-balance-header/network-account-balance-header.js b/ui/components/app/network-account-balance-header/network-account-balance-header.js index a688c9d693cd..217111c16eac 100644 --- a/ui/components/app/network-account-balance-header/network-account-balance-header.js +++ b/ui/components/app/network-account-balance-header/network-account-balance-header.js @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import Identicon from '../../ui/identicon/identicon.component'; +import Identicon from '../../ui/identicon'; import { DISPLAY, FLEX_DIRECTION, diff --git a/ui/components/ui/contract-token-values/contract-token-values.js b/ui/components/ui/contract-token-values/contract-token-values.js index 1b2635ad6576..3288983e84f2 100644 --- a/ui/components/ui/contract-token-values/contract-token-values.js +++ b/ui/components/ui/contract-token-values/contract-token-values.js @@ -6,7 +6,7 @@ import IconBlockExplorer from '../icon/icon-block-explorer'; import Box from '../box/box'; import Tooltip from '../tooltip/tooltip'; import { useI18nContext } from '../../../hooks/useI18nContext'; -import Identicon from '../identicon/identicon.component'; +import Identicon from '../identicon'; import Typography from '../typography/typography'; import { FONT_WEIGHT, diff --git a/ui/components/ui/new-network-info/new-network-info.js b/ui/components/ui/new-network-info/new-network-info.js index 9b9b7e674302..bedddb904da6 100644 --- a/ui/components/ui/new-network-info/new-network-info.js +++ b/ui/components/ui/new-network-info/new-network-info.js @@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom'; import { I18nContext } from '../../../contexts/i18n'; import Popover from '../popover'; import Button from '../button'; -import Identicon from '../identicon/identicon.component'; +import Identicon from '../identicon'; import Box from '../box'; import { ALIGN_ITEMS, diff --git a/ui/pages/token-details/token-details-page.test.js b/ui/pages/token-details/token-details-page.test.js index c4d1ca53c5ba..766a0607b6d6 100644 --- a/ui/pages/token-details/token-details-page.test.js +++ b/ui/pages/token-details/token-details-page.test.js @@ -2,7 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { fireEvent } from '@testing-library/react'; import { renderWithProvider } from '../../../test/lib/render-helpers'; -import Identicon from '../../components/ui/identicon/identicon.component'; +import Identicon from '../../components/ui/identicon'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; import TokenDetailsPage from './token-details-page'; From 6918bff291ead9b2ca2ff1ce9a8e82371d1cf333 Mon Sep 17 00:00:00 2001 From: Adnan Sahovic <63151811+adnansahovic@users.noreply.github.com> Date: Thu, 6 Oct 2022 16:48:08 +0200 Subject: [PATCH 08/33] Created the NFT component for single NFT allowance (#15825) * Created the NFT component for single NFT allowance * modified NftInfo component * added assetName --- app/_locales/en/messages.json | 3 + ui/components/ui/nft-info/index.js | 1 + ui/components/ui/nft-info/index.scss | 9 +++ ui/components/ui/nft-info/nft-info.js | 64 +++++++++++++++++++ ui/components/ui/nft-info/nft-info.stories.js | 29 +++++++++ ui/components/ui/ui-components.scss | 1 + 6 files changed, 107 insertions(+) create mode 100644 ui/components/ui/nft-info/index.js create mode 100644 ui/components/ui/nft-info/index.scss create mode 100644 ui/components/ui/nft-info/nft-info.js create mode 100644 ui/components/ui/nft-info/nft-info.stories.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 04d76f58c37f..2ffc886b6da4 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -4251,6 +4251,9 @@ "message": "Verify this token on $1 and make sure this is the token you want to trade.", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, + "view": { + "message": "View" + }, "viewAccount": { "message": "View account" }, diff --git a/ui/components/ui/nft-info/index.js b/ui/components/ui/nft-info/index.js new file mode 100644 index 000000000000..f78c5a99f449 --- /dev/null +++ b/ui/components/ui/nft-info/index.js @@ -0,0 +1 @@ +export { default } from './nft-info'; diff --git a/ui/components/ui/nft-info/index.scss b/ui/components/ui/nft-info/index.scss new file mode 100644 index 000000000000..8e87ed280585 --- /dev/null +++ b/ui/components/ui/nft-info/index.scss @@ -0,0 +1,9 @@ +.nft-info { + &__content { + width: 100%; + } + + &__button { + padding: 0; + } +} diff --git a/ui/components/ui/nft-info/nft-info.js b/ui/components/ui/nft-info/nft-info.js new file mode 100644 index 000000000000..41c44947d0b8 --- /dev/null +++ b/ui/components/ui/nft-info/nft-info.js @@ -0,0 +1,64 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import { I18nContext } from '../../../contexts/i18n'; +import Box from '../box'; +import Typography from '../typography'; +import { + COLORS, + DISPLAY, + FONT_WEIGHT, + TYPOGRAPHY, +} from '../../../helpers/constants/design-system'; +import Identicon from '../identicon'; +import Button from '../button'; + +export default function NftInfo({ assetName, tokenAddress, tokenId }) { + const t = useContext(I18nContext); + + return ( + + + + + + + + {assetName} + + + {t('tokenId')} #{tokenId} + + + + + + + + ); +} + +NftInfo.propTypes = { + assetName: PropTypes.string, + tokenAddress: PropTypes.string, + tokenId: PropTypes.string, +}; diff --git a/ui/components/ui/nft-info/nft-info.stories.js b/ui/components/ui/nft-info/nft-info.stories.js new file mode 100644 index 000000000000..e13a7415ec9b --- /dev/null +++ b/ui/components/ui/nft-info/nft-info.stories.js @@ -0,0 +1,29 @@ +import React from 'react'; +import NftInfo from './nft-info'; + +export default { + title: 'Components/UI/NftInfo', + id: __filename, + argTypes: { + assetName: { + control: { type: 'text' }, + }, + tokenAddress: { + control: { type: 'text' }, + }, + tokenId: { + control: { type: 'text' }, + }, + }, + args: { + assetName: 'Catnip Spicewight', + tokenAddress: '0xa3aee8bce55beea1951ef834b99f3ac60d1abeeb', + tokenId: '112233', + }, +}; + +export const DefaultStory = (args) => { + return ; +}; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/ui/ui-components.scss b/ui/components/ui/ui-components.scss index 2f004c47e291..8cc0e8a0b5c0 100644 --- a/ui/components/ui/ui-components.scss +++ b/ui/components/ui/ui-components.scss @@ -62,3 +62,4 @@ @import 'disclosure/disclosure'; @import 'deprecated-test-networks/index.scss'; @import 'contract-token-values/index.scss'; +@import 'nft-info/index.scss'; From 055a7c52c00cb3cecda314d99d7dff39f8cb7072 Mon Sep 17 00:00:00 2001 From: George Marshall Date: Thu, 6 Oct 2022 12:41:22 -0700 Subject: [PATCH 09/33] Adding `TextFieldBase` component (#16043) * Adding TextInputBase component * Removing keyup and keydown props, tests and docs * removing showClear from stories * removing unneeded css * simplifying uncontrolled vs controlled to work * Fortifying maxLength test * Lint fix for test * Doc, style and prop updates * Updating constant names with 'base' * Adding a background color * Adding a background color to input --- .../component-library-components.scss | 1 + .../text-field-base/README.mdx | 298 +++++++++++++++ .../text-field-base/index.js | 5 + .../text-field-base.constants.js | 12 + .../text-field-base/text-field-base.js | 250 ++++++++++++ .../text-field-base/text-field-base.scss | 52 +++ .../text-field-base.stories.js | 361 ++++++++++++++++++ .../text-field-base/text-field-base.test.js | 213 +++++++++++ 8 files changed, 1192 insertions(+) create mode 100644 ui/components/component-library/text-field-base/README.mdx create mode 100644 ui/components/component-library/text-field-base/index.js create mode 100644 ui/components/component-library/text-field-base/text-field-base.constants.js create mode 100644 ui/components/component-library/text-field-base/text-field-base.js create mode 100644 ui/components/component-library/text-field-base/text-field-base.scss create mode 100644 ui/components/component-library/text-field-base/text-field-base.stories.js create mode 100644 ui/components/component-library/text-field-base/text-field-base.test.js diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss index 97c7320a4cb8..85c2f84c6fc5 100644 --- a/ui/components/component-library/component-library-components.scss +++ b/ui/components/component-library/component-library-components.scss @@ -6,3 +6,4 @@ @import 'button-primary/button-primary'; @import 'icon/icon'; @import 'text/text'; +@import 'text-field-base/text-field-base'; diff --git a/ui/components/component-library/text-field-base/README.mdx b/ui/components/component-library/text-field-base/README.mdx new file mode 100644 index 000000000000..a19fdbab1d1e --- /dev/null +++ b/ui/components/component-library/text-field-base/README.mdx @@ -0,0 +1,298 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import { TextFieldBase } from './text-field-base'; + +### This is a base component. It should not be used in your feature code directly but as a "base" for other UI components + +# TextFieldBase + +The `TextFieldBase` is the base component for all text fields. It should not be used directly. It functions as both a uncontrolled and controlled input. + + + + + +## Props + +The `TextFieldBase` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props + + + +### Size + +Use the `size` prop to set the height of the `TextFieldBase`. + +Possible sizes include: + +- `sm` 32px +- `md` 40px +- `lg` 48px + +Defaults to `md` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; +import { SIZES } from '../../../helpers/constants/design-system'; + + + + +``` + +### Type + +Use the `type` prop to change the type of input. + +Possible types include: + +- `text` +- `number` +- `password` + +Defaults to `text`. + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + + // (Default) + + +``` + +### Truncate + +Use the `truncate` prop to truncate the text of the the `TextFieldBase` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Left Accessory Right Accessory + +Use the `leftAccessory` and `rightAccessory` props to add components such as icons or buttons to either side of the `TextFieldBase`. + + + + + +```jsx +import { COLORS, SIZES } from '../../../helpers/constants/design-system'; +import { Icon, ICON_NAMES } from '../../ui/component-library/icons'; + +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + + + } +/> + + + + + } +/> + +} + rightAccessory={ + // TODO: replace with ButtonIcon + + } +/> + + + } + rightAccessory={ + // TODO: replace with ButtonLink + + } +/> +``` + +### Input Ref + +Use the `inputRef` prop to access the ref of the `` html element of `TextFieldBase`. This is useful for focusing the input from a button or other component. + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +const inputRef = useRef(null); +const [value, setValue] = useState(''); +const handleOnClick = () => { + inputRef.current.focus(); +}; +const handleOnChange = (e) => { + setValue(e.target.value); +}; + + +// TODO: replace with Button component + + Edit + +``` + +### Auto Complete + +Use the `autoComplete` prop to set the autocomplete html attribute. It allows the browser to predict the value based on earlier typed values. + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Auto Focus + +Use the `autoFocus` prop to focus the `TextFieldBase` during the first mount + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Default Value + +Use the `defaultValue` prop to set the default value of the `TextFieldBase` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Disabled + +Use the `disabled` prop to set the disabled state of the `TextFieldBase` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Error + +Use the `error` prop to set the error state of the `TextFieldBase` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Max Length + +Use the `maxLength` prop to set the maximum allowed input characters for the `TextFieldBase` + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Read Only + +Use the `readOnly` prop to set the `TextFieldBase` to read only + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +; +``` + +### Required + +Use the `required` prop to set the `TextFieldBase` to required. Currently there is no visual difference to the `TextFieldBase` when required. + + + + + +```jsx +import { TextFieldBase } from '../../ui/component-library/text-field-base'; + +// Currently no visual difference +; +``` diff --git a/ui/components/component-library/text-field-base/index.js b/ui/components/component-library/text-field-base/index.js new file mode 100644 index 000000000000..748a4de127e8 --- /dev/null +++ b/ui/components/component-library/text-field-base/index.js @@ -0,0 +1,5 @@ +export { TextFieldBase } from './text-field-base'; +export { + TEXT_FIELD_BASE_SIZES, + TEXT_FIELD_BASE_TYPES, +} from './text-field-base.constants'; diff --git a/ui/components/component-library/text-field-base/text-field-base.constants.js b/ui/components/component-library/text-field-base/text-field-base.constants.js new file mode 100644 index 000000000000..decdb364a11b --- /dev/null +++ b/ui/components/component-library/text-field-base/text-field-base.constants.js @@ -0,0 +1,12 @@ +import { SIZES } from '../../../helpers/constants/design-system'; + +export const TEXT_FIELD_BASE_SIZES = { + SM: SIZES.SM, + MD: SIZES.MD, + LG: SIZES.LG, +}; +export const TEXT_FIELD_BASE_TYPES = { + TEXT: 'text', + NUMBER: 'number', + PASSWORD: 'password', +}; diff --git a/ui/components/component-library/text-field-base/text-field-base.js b/ui/components/component-library/text-field-base/text-field-base.js new file mode 100644 index 000000000000..909dae6592c5 --- /dev/null +++ b/ui/components/component-library/text-field-base/text-field-base.js @@ -0,0 +1,250 @@ +import React, { useState, useRef, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; + +import { + DISPLAY, + SIZES, + ALIGN_ITEMS, + TEXT, + COLORS, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { Text } from '../text'; + +import { + TEXT_FIELD_BASE_SIZES, + TEXT_FIELD_BASE_TYPES, +} from './text-field-base.constants'; + +export const TextFieldBase = ({ + autoComplete, + autoFocus, + className, + defaultValue, + disabled, + error, + id, + inputProps, + inputRef, + leftAccessory, + rightAccessory, + maxLength, + name, + onBlur, + onChange, + onClick, + onFocus, + placeholder, + readOnly, + required, + size = SIZES.MD, + type = 'text', + truncate, + value, + ...props +}) => { + const internalInputRef = useRef(null); + const [focused, setFocused] = useState(false); + + useEffect(() => { + // The blur won't fire when the disabled state is set on a focused input. + // We need to set the focused state manually. + if (disabled) { + setFocused(false); + } + }, [disabled]); + + const handleClick = (event) => { + const { current } = internalInputRef; + + if (current) { + current.focus(); + setFocused(true); + } + + if (onClick) { + onClick(event); + } + }; + + const handleFocus = (event) => { + setFocused(true); + onFocus && onFocus(event); + }; + + const handleBlur = (event) => { + setFocused(false); + onBlur && onBlur(event); + }; + + const handleInputRef = (ref) => { + internalInputRef.current = ref; + if (inputRef && inputRef.current !== undefined) { + inputRef.current = ref; + } else if (typeof inputRef === 'function') { + inputRef(ref); + } + }; + + return ( + + {leftAccessory} + + {rightAccessory} + + ); +}; + +TextFieldBase.propTypes = { + /** + * Autocomplete allows the browser to predict the value based on earlier typed values + */ + autoComplete: PropTypes.string, + /** + * If `true`, the input will be focused during the first mount. + */ + autoFocus: PropTypes.bool, + /** + * An additional className to apply to the text-field-base + */ + className: PropTypes.string, + /** + * The default input value, useful when not controlling the component. + */ + defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + /** + * If `true`, the input will be disabled. + */ + disabled: PropTypes.bool, + /** + * If `true`, the input will indicate an error + */ + error: PropTypes.bool, + /** + * The id of the `input` element. + */ + id: PropTypes.string, + /** + * Attributes applied to the `input` element. + */ + inputProps: PropTypes.object, + /** + * Component to appear on the left side of the input + */ + leftAccessory: PropTypes.node, + /** + * Component to appear on the right side of the input + */ + rightAccessory: PropTypes.node, + /** + * Use inputRef to pass a ref to the html input element. + */ + inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + /** + * Max number of characters to allow + */ + maxLength: PropTypes.number, + /** + * Name attribute of the `input` element. + */ + name: PropTypes.string, + /** + * Callback fired on blur + */ + onBlur: PropTypes.func, + /** + * Callback fired when the value is changed. + */ + onChange: PropTypes.func, + /** + * Callback fired on focus + */ + onFocus: PropTypes.func, + /** + * The short hint displayed in the input before the user enters a value. + */ + placeholder: PropTypes.string, + /** + * It prevents the user from changing the value of the field (not from interacting with the field). + */ + readOnly: PropTypes.bool, + /** + * If `true`, the input will be required. Currently no visual difference is shown. + */ + required: PropTypes.bool, + /** + * The size of the text field. Changes the height of the component + * Accepts SM(32px), MD(40px), LG(48px) + */ + size: PropTypes.oneOf(Object.values(TEXT_FIELD_BASE_SIZES)), + /** + * Type of the input element. Can be TEXT_FIELD_BASE_TYPES.TEXT, TEXT_FIELD_BASE_TYPES.PASSWORD, TEXT_FIELD_BASE_TYPES.NUMBER + * Defaults to TEXT_FIELD_BASE_TYPES.TEXT ('text') + */ + type: PropTypes.oneOf(Object.values(TEXT_FIELD_BASE_TYPES)), + /** + * The input value, required for a controlled component. + */ + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + /** + * TextFieldBase accepts all the props from Box + */ + ...Box.propTypes, +}; + +TextFieldBase.displayName = 'TextFieldBase'; diff --git a/ui/components/component-library/text-field-base/text-field-base.scss b/ui/components/component-library/text-field-base/text-field-base.scss new file mode 100644 index 000000000000..6672506f5f6f --- /dev/null +++ b/ui/components/component-library/text-field-base/text-field-base.scss @@ -0,0 +1,52 @@ +.mm-text-field-base { + --text-field-base-height: var(--size, 40px); + + &--size-sm { + --size: 32px; + } + + &--size-md { + --size: 40px; + } + + &--size-lg { + --size: 48px; + } + + height: var(--text-field-base-height); + border-color: var(--color-border-default); + + &--focused { + border-color: var(--color-primary-default); + } + + &--error { + border-color: var(--color-error-default); + } + + &--disabled { + opacity: 0.5; + border-color: var(--color-border-default); + } + + // truncates text with ellipsis + &--truncate .mm-text-field-base__input { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__input { + border: none; + height: 100%; + flex-grow: 1; + box-sizing: content-box; + margin: 0; + padding: 0; + + &:focus, + &:focus-visible { + outline: none; + } + } +} diff --git a/ui/components/component-library/text-field-base/text-field-base.stories.js b/ui/components/component-library/text-field-base/text-field-base.stories.js new file mode 100644 index 000000000000..f30e5cef5416 --- /dev/null +++ b/ui/components/component-library/text-field-base/text-field-base.stories.js @@ -0,0 +1,361 @@ +import React, { useState, useRef } from 'react'; + +import { + SIZES, + DISPLAY, + COLORS, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; +import Box from '../../ui/box/box'; + +import { Icon, ICON_NAMES } from '../icon'; +import { AvatarToken } from '../avatar-token'; + +import { + TEXT_FIELD_BASE_SIZES, + TEXT_FIELD_BASE_TYPES, +} from './text-field-base.constants'; +import { TextFieldBase } from './text-field-base'; +import README from './README.mdx'; + +const marginSizeControlOptions = [ + undefined, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 'auto', +]; + +export default { + title: 'Components/ComponentLibrary/TextFieldBase', + id: __filename, + component: TextFieldBase, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + autoComplete: { + control: 'boolean', + }, + autoFocus: { + control: 'boolean', + }, + className: { + control: 'text', + }, + defaultValue: { + control: 'text', + }, + disabled: { + control: 'boolean', + }, + error: { + control: 'boolean', + }, + id: { + control: 'text', + }, + inputProps: { + control: 'object', + }, + leftAccessory: { + control: 'text', + }, + maxLength: { + control: 'number', + }, + name: { + control: 'text', + }, + onBlur: { + action: 'onBlur', + }, + onChange: { + action: 'onChange', + }, + onClick: { + action: 'onClick', + }, + onFocus: { + action: 'onFocus', + }, + placeholder: { + control: 'text', + }, + readOnly: { + control: 'boolean', + }, + required: { + control: 'boolean', + }, + rightAccessory: { + control: 'text', + }, + size: { + control: 'select', + options: Object.values(TEXT_FIELD_BASE_SIZES), + }, + type: { + control: 'select', + options: Object.values(TEXT_FIELD_BASE_TYPES), + }, + value: { + control: 'text', + }, + marginTop: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginRight: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginBottom: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginLeft: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + }, + args: { + placeholder: 'Placeholder...', + autoFocus: false, + defaultValue: '', + disabled: false, + error: false, + id: '', + readOnly: false, + required: false, + size: SIZES.MD, + type: 'text', + truncate: false, + }, +}; + +const Template = (args) => ; + +export const DefaultStory = Template.bind({}); +DefaultStory.storyName = 'Default'; + +export const Size = (args) => { + return ( + + + + + + ); +}; + +export const Type = (args) => ( + + + + + +); + +export const Truncate = Template.bind({}); +Truncate.args = { + placeholder: 'Truncate', + value: 'Truncated text when truncate and width is set', + truncate: true, + style: { width: 240 }, +}; + +export const LeftAccessoryRightAccessory = (args) => { + const [value, setValue] = useState({ + search: '', + metaMask: '', + address: '0x514910771af9ca656af840dff83e8264ecf986ca', + amount: 1, + }); + return ( + + setValue({ ...value, search: e.target.value })} + leftAccessory={ + + } + /> + setValue({ ...value, metaMask: e.target.value })} + placeholder="MetaMask" + rightAccessory={ + + } + /> + setValue({ ...value, address: e.target.value })} + truncate + leftAccessory={} + rightAccessory={ + + } + /> + setValue({ ...value, amount: e.target.value })} + type="number" + leftAccessory={ + + } + rightAccessory={ + + } + /> + + ); +}; + +export const InputRef = (args) => { + const inputRef = useRef(null); + const [value, setValue] = useState(''); + const handleOnClick = () => { + inputRef.current.focus(); + }; + const handleOnChange = (e) => { + setValue(e.target.value); + }; + return ( + <> + + + Edit + + + ); +}; + +export const AutoComplete = Template.bind({}); +AutoComplete.args = { + autoComplete: true, + type: 'password', + placeholder: 'Enter password', +}; + +export const AutoFocus = Template.bind({}); +AutoFocus.args = { autoFocus: true }; + +export const DefaultValue = Template.bind({}); +DefaultValue.args = { defaultValue: 'Default value' }; + +export const Disabled = Template.bind({}); +Disabled.args = { disabled: true }; + +export const ErrorStory = Template.bind({}); +ErrorStory.args = { error: true }; +ErrorStory.storyName = 'Error'; + +export const MaxLength = Template.bind({}); +MaxLength.args = { maxLength: 10, placeholder: 'Max length 10' }; + +export const ReadOnly = Template.bind({}); +ReadOnly.args = { readOnly: true, value: 'Read only' }; + +export const Required = Template.bind({}); +Required.args = { required: true, placeholder: 'Required' }; diff --git a/ui/components/component-library/text-field-base/text-field-base.test.js b/ui/components/component-library/text-field-base/text-field-base.test.js new file mode 100644 index 000000000000..37f190cfdc19 --- /dev/null +++ b/ui/components/component-library/text-field-base/text-field-base.test.js @@ -0,0 +1,213 @@ +/* eslint-disable jest/require-top-level-describe */ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { SIZES } from '../../../helpers/constants/design-system'; + +import { TextFieldBase } from './text-field-base'; + +describe('TextFieldBase', () => { + it('should render correctly', () => { + const { getByRole } = render(); + expect(getByRole('textbox')).toBeDefined(); + }); + it('should render and be able to input text', () => { + const { getByTestId } = render( + , + ); + const textFieldBase = getByTestId('text-field-base'); + + expect(textFieldBase.value).toBe(''); // initial value is empty string + fireEvent.change(textFieldBase, { target: { value: 'text value' } }); + expect(textFieldBase.value).toBe('text value'); + fireEvent.change(textFieldBase, { target: { value: '' } }); // reset value + expect(textFieldBase.value).toBe(''); // value is empty string after reset + }); + it('should render and fire onFocus and onBlur events', () => { + const onFocus = jest.fn(); + const onBlur = jest.fn(); + const { getByTestId } = render( + , + ); + const textFieldBase = getByTestId('text-field-base'); + + fireEvent.focus(textFieldBase); + expect(onFocus).toHaveBeenCalledTimes(1); + fireEvent.blur(textFieldBase); + expect(onBlur).toHaveBeenCalledTimes(1); + }); + it('should render and fire onChange event', () => { + const onChange = jest.fn(); + const { getByTestId } = render( + , + ); + const textFieldBase = getByTestId('text-field-base'); + + fireEvent.change(textFieldBase, { target: { value: 'text value' } }); + expect(onChange).toHaveBeenCalledTimes(1); + }); + it('should render and fire onClick event', () => { + const onClick = jest.fn(); + const { getByTestId } = render( + , + ); + const textFieldBase = getByTestId('text-field-base'); + + fireEvent.click(textFieldBase); + expect(onClick).toHaveBeenCalledTimes(1); + }); + it('should render with different size classes', () => { + const { getByTestId } = render( + <> + + + + , + ); + expect(getByTestId('sm')).toHaveClass('mm-text-field-base--size-sm'); + expect(getByTestId('md')).toHaveClass('mm-text-field-base--size-md'); + expect(getByTestId('lg')).toHaveClass('mm-text-field-base--size-lg'); + }); + it('should render with different types', () => { + const { getByTestId } = render( + <> + + + + , + ); + expect(getByTestId('text-field-base-text')).toHaveAttribute('type', 'text'); + expect(getByTestId('text-field-base-number')).toHaveAttribute( + 'type', + 'number', + ); + expect(getByTestId('text-field-base-password')).toHaveAttribute( + 'type', + 'password', + ); + }); + it('should render with truncate class', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('truncate')).toHaveClass('mm-text-field-base--truncate'); + }); + it('should render with right and left accessories', () => { + const { getByRole, getByText } = render( + left accessory} + rightAccessory={
right accessory
} + />, + ); + expect(getByRole('textbox')).toBeDefined(); + expect(getByText('left accessory')).toBeDefined(); + expect(getByText('right accessory')).toBeDefined(); + }); + it('should render with working ref using inputRef prop', () => { + // Because the 'ref' attribute wont flow down to the DOM + // I'm not exactly sure how to test this? + const mockRef = jest.fn(); + const { getByRole } = render(); + expect(getByRole('textbox')).toBeDefined(); + expect(mockRef).toHaveBeenCalledTimes(1); + }); + it('should render with autoComplete', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('text-field-base-auto-complete')).toHaveAttribute( + 'autocomplete', + 'on', + ); + }); + it('should render with autoFocus', () => { + const { getByRole } = render(); + expect(getByRole('textbox')).toHaveFocus(); + }); + it('should render with a defaultValue', () => { + const { getByRole } = render( + , + ); + expect(getByRole('textbox').value).toBe('default value'); + }); + it('should render in disabled state and not focus or be clickable', () => { + const mockOnClick = jest.fn(); + const mockOnFocus = jest.fn(); + const { getByRole } = render( + , + ); + + getByRole('textbox').focus(); + expect(getByRole('textbox')).toBeDisabled(); + expect(mockOnClick).toHaveBeenCalledTimes(0); + expect(mockOnFocus).toHaveBeenCalledTimes(0); + }); + it('should render with error className when error is true', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('text-field-base-error')).toHaveClass( + 'mm-text-field-base--error', + ); + }); + it('should render with maxLength and not allow more than the set characters', async () => { + const { getByRole } = render(); + const textFieldBase = getByRole('textbox'); + await userEvent.type(textFieldBase, '1234567890'); + expect(getByRole('textbox')).toBeDefined(); + expect(textFieldBase.maxLength).toBe(5); + expect(textFieldBase.value).toBe('12345'); + expect(textFieldBase.value).toHaveLength(5); + }); + it('should render with readOnly attr when readOnly is true', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('text-field-base-readonly')).toHaveAttribute( + 'readonly', + '', + ); + }); + it('should render with required attr when required is true', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('text-field-base-required')).toHaveAttribute( + 'required', + '', + ); + }); +}); From db59186ced8f1a0b98587c3207201a528c1e3757 Mon Sep 17 00:00:00 2001 From: George Marshall Date: Thu, 6 Oct 2022 12:42:52 -0700 Subject: [PATCH 10/33] Adding ast-types to resolutions (#16103) --- package.json | 3 ++- yarn.lock | 7 +------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 0a64aad1e9a2..4ba4375ac381 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,8 @@ "pubnub/superagent-proxy": "^3.0.0", "pull-ws": "^3.3.2", "json-schema": "^0.4.0", - "simple-get": "^4.0.1" + "simple-get": "^4.0.1", + "@storybook/**/ast-types": "^0.14.2" }, "dependencies": { "3box": "^1.10.2", diff --git a/yarn.lock b/yarn.lock index 08a73a300e84..7403c438b107 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7129,12 +7129,7 @@ ast-module-types@^2.3.2, ast-module-types@^2.4.0, ast-module-types@^2.7.0, ast-m resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-2.7.1.tgz#3f7989ef8dfa1fdb82dfe0ab02bdfc7c77a57dd3" integrity sha512-Rnnx/4Dus6fn7fTqdeLEAn5vUll5w7/vts0RN608yFa6si/rDOUonlIIiwugHBFWjylHjxm9owoSZn71KwG4gw== -ast-types@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" - integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== - -ast-types@^0.14.2: +ast-types@^0.13.2, ast-types@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== From 7ba0f78a84c2c3a9bbd17b9d921a0700fafa0750 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 7 Oct 2022 10:02:35 +0200 Subject: [PATCH 11/33] [FLASK] `snaps-skunkworks@0.22.0` (#16069) * snaps-skunkworks@0.22.0 * Update LavaMoat policies * Bump execution environment and fix a breaking change * Fix caveat and permissions * Fix test * Exclude keyring endowment for now * Fix test * Fix snap_confirm missing title --- .../permissions/flask/snap-permissions.js | 9 +- .../controllers/permissions/specifications.js | 2 + .../permissions/specifications.test.js | 5 +- app/scripts/metamask-controller.js | 4 +- lavamoat/browserify/beta/policy.json | 28 ++---- lavamoat/browserify/flask/policy.json | 52 +++++------ lavamoat/browserify/main/policy.json | 28 ++---- package.json | 6 +- shared/constants/permissions.test.js | 5 +- shared/constants/permissions.ts | 3 +- .../flask/snap-confirm/snap-confirm.js | 4 +- yarn.lock | 87 ++++++++++--------- 12 files changed, 113 insertions(+), 120 deletions(-) diff --git a/app/scripts/controllers/permissions/flask/snap-permissions.js b/app/scripts/controllers/permissions/flask/snap-permissions.js index 07024c9ae19f..1a1d78c5d2d3 100644 --- a/app/scripts/controllers/permissions/flask/snap-permissions.js +++ b/app/scripts/controllers/permissions/flask/snap-permissions.js @@ -3,7 +3,10 @@ import { restrictedMethodPermissionBuilders, selectHooks, } from '@metamask/rpc-methods'; -import { ExcludedSnapPermissions } from '../../../../../shared/constants/permissions'; +import { + ExcludedSnapEndowments, + ExcludedSnapPermissions, +} from '../../../../../shared/constants/permissions'; /** * @returns {Record>} All endowment permission @@ -12,7 +15,9 @@ import { ExcludedSnapPermissions } from '../../../../../shared/constants/permiss export const buildSnapEndowmentSpecifications = () => Object.values(endowmentPermissionBuilders).reduce( (allSpecifications, { targetKey, specificationBuilder }) => { - allSpecifications[targetKey] = specificationBuilder(); + if (!ExcludedSnapEndowments.has(targetKey)) { + allSpecifications[targetKey] = specificationBuilder(); + } return allSpecifications; }, {}, diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index de6b1bdad89d..1e3fad4a4829 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -1,5 +1,6 @@ import { constructPermission, PermissionType } from '@metamask/controllers'; ///: BEGIN:ONLY_INCLUDE_IN(flask) +import { endowmentCaveatSpecifications as snapsEndowmentCaveatSpecifications } from '@metamask/snap-controllers'; import { caveatSpecifications as snapsCaveatsSpecifications } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN import { @@ -69,6 +70,7 @@ export const getCaveatSpecifications = ({ getIdentities }) => { ///: BEGIN:ONLY_INCLUDE_IN(flask) ...snapsCaveatsSpecifications, + ...snapsEndowmentCaveatSpecifications, ///: END:ONLY_INCLUDE_IN }; }; diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index e874d3aa6107..4d313b12ceb0 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -16,7 +16,7 @@ describe('PermissionController specifications', () => { describe('caveat specifications', () => { it('getCaveatSpecifications returns the expected specifications object', () => { const caveatSpecifications = getCaveatSpecifications({}); - expect(Object.keys(caveatSpecifications)).toHaveLength(3); + expect(Object.keys(caveatSpecifications)).toHaveLength(4); expect( caveatSpecifications[CaveatTypes.restrictReturnedAccounts].type, ).toStrictEqual(CaveatTypes.restrictReturnedAccounts); @@ -27,6 +27,9 @@ describe('PermissionController specifications', () => { expect(caveatSpecifications.permittedCoinTypes.type).toStrictEqual( SnapCaveatType.PermittedCoinTypes, ); + expect(caveatSpecifications.snapKeyring.type).toStrictEqual( + SnapCaveatType.SnapKeyring, + ); }); describe('restrictReturnedAccounts', () => { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 9d24755f7b1d..51b753ac2179 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -654,7 +654,7 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(flask) this.snapExecutionService = new IframeExecutionService({ iframeUrl: new URL( - 'https://metamask.github.io/iframe-execution-environment/0.8.0', + 'https://metamask.github.io/iframe-execution-environment/0.9.0', ), messenger: this.controllerMessenger.getRestricted({ name: 'ExecutionService', @@ -3744,7 +3744,7 @@ export default class MetamaskController extends EventEmitter { ), getSnaps: this.controllerMessenger.call.bind( this.controllerMessenger, - 'SnapController:getSnaps', + 'SnapController:getPermittedSnaps', origin, ), requestPermissions: async (requestedPermissions) => { diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2e1e455bc59c..3f8260c5eafb 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -682,11 +682,11 @@ "3box>ipfs>ipfs-unixfs-importer>async-iterator-batch": true, "3box>ipfs>ipfs-unixfs-importer>async-iterator-first": true, "3box>ipfs>ipfs-unixfs-importer>rabin-wasm": true, + "3box>ipfs>ipfs-unixfs-importer>superstruct": true, "3box>ipfs>ipld-dag-pb": true, "3box>ipfs>ipld-raw>multihashing-async": true, "3box>ipfs>multicodec": true, "3box>ipfs>multihashes": true, - "3box>ipfs>superstruct": true, "browserify>buffer": true, "madge>rc>deep-extend": true } @@ -841,11 +841,11 @@ "3box>ipfs>libp2p>libp2p-floodsub": true, "3box>ipfs>libp2p>libp2p-ping": true, "3box>ipfs>libp2p>libp2p-switch": true, + "3box>ipfs>libp2p>superstruct": true, "3box>ipfs>multiaddr": true, "3box>ipfs>peer-book": true, "3box>ipfs>peer-id": true, "3box>ipfs>peer-info": true, - "3box>ipfs>superstruct": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true, "browserify>process": true, @@ -3068,20 +3068,13 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils": true, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "eth-block-tracker>@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true } }, - "@metamask/eth-json-rpc-infura>@metamask/utils": { - "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils>superstruct": true, - "eslint>fast-deep-equal": true, - "nock>debug": true - } - }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { "globals": { "URL": true, @@ -4494,9 +4487,13 @@ } }, "eth-block-tracker>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { + "@metamask/snap-utils>superstruct": true, "eslint>fast-deep-equal": true, - "eth-block-tracker>@metamask/utils>superstruct": true, "nock>debug": true } }, @@ -4553,7 +4550,7 @@ }, "packages": { "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/utils": true, + "eth-block-tracker>@metamask/utils": true, "eth-json-rpc-middleware>eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, @@ -4563,13 +4560,6 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>@metamask/utils": { - "packages": { - "eslint>fast-deep-equal": true, - "eth-json-rpc-middleware>@metamask/utils>superstruct": true, - "nock>debug": true - } - }, "eth-json-rpc-middleware>eth-sig-util": { "packages": { "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 6ba23b6c3f72..ea5ae2873364 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -682,11 +682,11 @@ "3box>ipfs>ipfs-unixfs-importer>async-iterator-batch": true, "3box>ipfs>ipfs-unixfs-importer>async-iterator-first": true, "3box>ipfs>ipfs-unixfs-importer>rabin-wasm": true, + "3box>ipfs>ipfs-unixfs-importer>superstruct": true, "3box>ipfs>ipld-dag-pb": true, "3box>ipfs>ipld-raw>multihashing-async": true, "3box>ipfs>multicodec": true, "3box>ipfs>multihashes": true, - "3box>ipfs>superstruct": true, "browserify>buffer": true, "madge>rc>deep-extend": true } @@ -841,11 +841,11 @@ "3box>ipfs>libp2p>libp2p-floodsub": true, "3box>ipfs>libp2p>libp2p-ping": true, "3box>ipfs>libp2p>libp2p-switch": true, + "3box>ipfs>libp2p>superstruct": true, "3box>ipfs>multiaddr": true, "3box>ipfs>peer-book": true, "3box>ipfs>peer-id": true, "3box>ipfs>peer-info": true, - "3box>ipfs>superstruct": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true, "browserify>process": true, @@ -3229,20 +3229,13 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils": true, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "eth-block-tracker>@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true } }, - "@metamask/eth-json-rpc-infura>@metamask/utils": { - "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils>superstruct": true, - "eslint>fast-deep-equal": true, - "nock>debug": true - } - }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { "globals": { "URL": true, @@ -3552,11 +3545,15 @@ } }, "@metamask/rpc-methods": { + "globals": { + "console.warn": true + }, "packages": { "@metamask/rpc-methods>@metamask/controllers": true, "@metamask/rpc-methods>@metamask/key-tree": true, "@metamask/snap-utils": true, - "@metamask/snap-utils>@metamask/utils": true, + "@metamask/snap-utils>superstruct": true, + "eth-block-tracker>@metamask/utils": true, "eth-rpc-errors": true } }, @@ -3869,7 +3866,7 @@ "@metamask/snap-controllers>readable-web-to-node-stream": true, "@metamask/snap-controllers>tar-stream": true, "@metamask/snap-utils": true, - "@metamask/snap-utils>@metamask/utils": true, + "eth-block-tracker>@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, "pump": true @@ -4034,8 +4031,13 @@ "removeEventListener": true }, "packages": { - "@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": true, - "@metamask/snap-utils>@metamask/utils": true + "@metamask/snap-controllers>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": true + } + }, + "@metamask/snap-controllers>@metamask/post-message-stream>@metamask/utils": { + "packages": { + "eslint>fast-deep-equal": true } }, "@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": { @@ -4259,20 +4261,17 @@ "@babel/core>@babel/types": true, "@metamask/snap-utils>ajv": true, "@metamask/snap-utils>rfdc": true, + "@metamask/snap-utils>superstruct": true, "browserify": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "browserify>path-browserify": true, "eslint>fast-deep-equal": true, + "eth-block-tracker>@metamask/utils": true, "semver": true } }, - "@metamask/snap-utils>@metamask/utils": { - "packages": { - "eslint>fast-deep-equal": true - } - }, "@metamask/snap-utils>rfdc": { "packages": { "browserify>buffer": true @@ -5314,9 +5313,13 @@ } }, "eth-block-tracker>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { + "@metamask/snap-utils>superstruct": true, "eslint>fast-deep-equal": true, - "eth-block-tracker>@metamask/utils>superstruct": true, "nock>debug": true } }, @@ -5373,7 +5376,7 @@ }, "packages": { "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/utils": true, + "eth-block-tracker>@metamask/utils": true, "eth-json-rpc-middleware>eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, @@ -5383,13 +5386,6 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>@metamask/utils": { - "packages": { - "eslint>fast-deep-equal": true, - "eth-json-rpc-middleware>@metamask/utils>superstruct": true, - "nock>debug": true - } - }, "eth-json-rpc-middleware>eth-sig-util": { "packages": { "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2e1e455bc59c..3f8260c5eafb 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -682,11 +682,11 @@ "3box>ipfs>ipfs-unixfs-importer>async-iterator-batch": true, "3box>ipfs>ipfs-unixfs-importer>async-iterator-first": true, "3box>ipfs>ipfs-unixfs-importer>rabin-wasm": true, + "3box>ipfs>ipfs-unixfs-importer>superstruct": true, "3box>ipfs>ipld-dag-pb": true, "3box>ipfs>ipld-raw>multihashing-async": true, "3box>ipfs>multicodec": true, "3box>ipfs>multihashes": true, - "3box>ipfs>superstruct": true, "browserify>buffer": true, "madge>rc>deep-extend": true } @@ -841,11 +841,11 @@ "3box>ipfs>libp2p>libp2p-floodsub": true, "3box>ipfs>libp2p>libp2p-ping": true, "3box>ipfs>libp2p>libp2p-switch": true, + "3box>ipfs>libp2p>superstruct": true, "3box>ipfs>multiaddr": true, "3box>ipfs>peer-book": true, "3box>ipfs>peer-id": true, "3box>ipfs>peer-info": true, - "3box>ipfs>superstruct": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true, "browserify>process": true, @@ -3068,20 +3068,13 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils": true, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "eth-block-tracker>@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true } }, - "@metamask/eth-json-rpc-infura>@metamask/utils": { - "packages": { - "@metamask/eth-json-rpc-infura>@metamask/utils>superstruct": true, - "eslint>fast-deep-equal": true, - "nock>debug": true - } - }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { "globals": { "URL": true, @@ -4494,9 +4487,13 @@ } }, "eth-block-tracker>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { + "@metamask/snap-utils>superstruct": true, "eslint>fast-deep-equal": true, - "eth-block-tracker>@metamask/utils>superstruct": true, "nock>debug": true } }, @@ -4553,7 +4550,7 @@ }, "packages": { "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/utils": true, + "eth-block-tracker>@metamask/utils": true, "eth-json-rpc-middleware>eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, @@ -4563,13 +4560,6 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>@metamask/utils": { - "packages": { - "eslint>fast-deep-equal": true, - "eth-json-rpc-middleware>@metamask/utils>superstruct": true, - "nock>debug": true - } - }, "eth-json-rpc-middleware>eth-sig-util": { "packages": { "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, diff --git a/package.json b/package.json index 4ba4375ac381..6be08da738d6 100644 --- a/package.json +++ b/package.json @@ -135,11 +135,11 @@ "@metamask/obs-store": "^5.0.0", "@metamask/post-message-stream": "^4.0.0", "@metamask/providers": "^9.0.0", - "@metamask/rpc-methods": "^0.21.0", + "@metamask/rpc-methods": "^0.22.0", "@metamask/slip44": "^2.1.0", "@metamask/smart-transactions-controller": "^2.3.2", - "@metamask/snap-controllers": "^0.21.0", - "@metamask/snap-utils": "^0.21.0", + "@metamask/snap-controllers": "^0.22.0", + "@metamask/snap-utils": "^0.22.0", "@ngraveio/bc-ur": "^1.1.6", "@popperjs/core": "^2.4.0", "@reduxjs/toolkit": "^1.6.2", diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 3637fed5818a..433d6629c3b5 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -2,6 +2,7 @@ import { endowmentPermissionBuilders } from '@metamask/snap-controllers'; import { restrictedMethodPermissionBuilders } from '@metamask/rpc-methods'; import { EndowmentPermissions, + ExcludedSnapEndowments, ExcludedSnapPermissions, RestrictedMethods, } from './permissions'; @@ -9,7 +10,9 @@ import { describe('EndowmentPermissions', () => { it('has the expected permission keys', () => { expect(Object.keys(EndowmentPermissions).sort()).toStrictEqual( - Object.keys(endowmentPermissionBuilders).sort(), + Object.keys(endowmentPermissionBuilders) + .filter((targetKey) => !ExcludedSnapEndowments.has(targetKey)) + .sort(), ); }); }); diff --git a/shared/constants/permissions.ts b/shared/constants/permissions.ts index ced11127fe44..49c281f1355e 100644 --- a/shared/constants/permissions.ts +++ b/shared/constants/permissions.ts @@ -27,5 +27,6 @@ export const EndowmentPermissions = Object.freeze({ } as const); // Methods / permissions in external packages that we are temporarily excluding. -export const ExcludedSnapPermissions = new Set([]); +export const ExcludedSnapPermissions = new Set(['snap_dialog']); +export const ExcludedSnapEndowments = new Set(['endowment:keyring']); ///: END:ONLY_INCLUDE_IN diff --git a/ui/pages/confirmation/templates/flask/snap-confirm/snap-confirm.js b/ui/pages/confirmation/templates/flask/snap-confirm/snap-confirm.js index a5d278450a57..120bea07cdd2 100644 --- a/ui/pages/confirmation/templates/flask/snap-confirm/snap-confirm.js +++ b/ui/pages/confirmation/templates/flask/snap-confirm/snap-confirm.js @@ -5,14 +5,14 @@ import { import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; function getValues(pendingApproval, t, actions) { - const { prompt, description, textAreaContent } = pendingApproval.requestData; + const { title, description, textAreaContent } = pendingApproval.requestData; return { content: [ { element: 'Typography', key: 'title', - children: prompt, + children: title, props: { variant: TYPOGRAPHY.H3, align: 'center', diff --git a/yarn.lock b/yarn.lock index 7403c438b107..e2271e8d68a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3317,17 +3317,17 @@ resolved "https://registry.yarnpkg.com/@metamask/etherscan-link/-/etherscan-link-2.2.0.tgz#76314d0c1405a0669fc4a0a19e0877bd3d0c389f" integrity sha512-xUgehvgU+ZbzeJ44m4sUtsyf6Dwou+SlYhiKfi6lkRcbWh6Jl3TCi0YM9C7XWgxfnLSdQBO1ndvcp0kslKgMsA== -"@metamask/execution-environments@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@metamask/execution-environments/-/execution-environments-0.21.0.tgz#40d5c63215fb98a43f9d7b3b31c371dbed93adba" - integrity sha512-KnQ07SRcht/jpHa4KLHftI034GPZXzz2I1RsWk/0OMxQ3ECGJwDroH92pXNRy0+HTdz31XWhMzdc1GW5rR2CzA== +"@metamask/execution-environments@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@metamask/execution-environments/-/execution-environments-0.22.0.tgz#2dd67add467e64fc6e992cb36461f20959ed87fd" + integrity sha512-mb5O3HX5Nrt0urAPWohiyB9w465Qk12tF1hXz+vjwFZe4LAbTHza7XsbvTzAy1XD99JjhtLMi+IwaHp8GELcDg== dependencies: "@metamask/object-multiplex" "^1.2.0" "@metamask/post-message-stream" "^6.0.0" "@metamask/providers" "^9.0.0" - "@metamask/snap-types" "^0.21.0" - "@metamask/snap-utils" "^0.21.0" - "@metamask/utils" "^2.0.0" + "@metamask/snap-types" "^0.22.0" + "@metamask/snap-utils" "^0.22.0" + "@metamask/utils" "^3.1.0" eth-rpc-errors "^4.0.3" pump "^3.0.0" ses "^0.15.15" @@ -3449,17 +3449,18 @@ pump "^3.0.0" webextension-polyfill-ts "^0.25.0" -"@metamask/rpc-methods@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.21.0.tgz#7d00029aeaa606d5780fb2e7c01069e714822ae4" - integrity sha512-CXYBzIf6hYH8bkqkvGqFHFmsVdjYGznkgw96NpGosQS4vns07wrvBluA45WehAqgHDZHpom1ffQ8r11PksM86Q== +"@metamask/rpc-methods@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.22.0.tgz#17ee8db33deba5152d531123139fd3ea651e49ef" + integrity sha512-FCVbf68zgHHThG2OAOp9u7iBO1hjIMjo8S85bXsGtStUp9KjiGxnuQhyNK7b/Ny+WuHI+GP26abXRIyS2ampfA== dependencies: "@metamask/controllers" "^31.0.0" "@metamask/key-tree" "^5.0.2" - "@metamask/snap-utils" "^0.21.0" + "@metamask/snap-utils" "^0.22.0" "@metamask/types" "^1.1.0" - "@metamask/utils" "^2.1.0" + "@metamask/utils" "^3.1.0" eth-rpc-errors "^4.0.2" + superstruct "^0.16.5" "@metamask/safe-event-emitter@^2.0.0": version "2.0.0" @@ -3486,19 +3487,20 @@ isomorphic-fetch "^3.0.0" lodash "^4.17.21" -"@metamask/snap-controllers@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.21.0.tgz#5fdc2f350c8739b070f1bfdbc9c7ef7409af234d" - integrity sha512-WZyfB+mQMifB7a5tf5WEVrWnLdoSMG/sXL6YQnItC/96SUX//c9IW+iNB6ZZfiP5lJFwafN5hjOExWH3O/fwbw== +"@metamask/snap-controllers@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.22.0.tgz#bb1dfb7551cfca74b17addad2390ad80a6df8b7a" + integrity sha512-k7TgYyzZna54ns3o9GjnLiHJDT3xvkG4i+zSEJSMPzqAy5Su5p2yMiTe/awEwTVFBMsC9xtX9owc0lArkk8NZw== dependencies: "@metamask/browser-passworder" "^3.0.0" "@metamask/controllers" "^31.0.0" - "@metamask/execution-environments" "^0.21.0" + "@metamask/execution-environments" "^0.22.0" "@metamask/object-multiplex" "^1.1.0" "@metamask/post-message-stream" "^6.0.0" - "@metamask/rpc-methods" "^0.21.0" - "@metamask/snap-utils" "^0.21.0" - "@metamask/utils" "^2.0.0" + "@metamask/rpc-methods" "^0.22.0" + "@metamask/snap-types" "^0.22.0" + "@metamask/snap-utils" "^0.22.0" + "@metamask/utils" "^3.1.0" "@xstate/fsm" "^2.0.0" concat-stream "^2.0.0" eth-rpc-errors "^4.0.2" @@ -3511,29 +3513,30 @@ readable-web-to-node-stream "^3.0.2" tar-stream "^2.2.0" -"@metamask/snap-types@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.21.0.tgz#51380240a97a6ef492dca9d5bcb2d7c6f6c8a023" - integrity sha512-wyamdpiZqVfrHjAysnplVQexEisH8b00XTv6F8kTyKd4pbRTBswmOOc1DhBbi2+7Fw2J5a7pdLb9+/MRMwnztg== +"@metamask/snap-types@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.22.0.tgz#4d74e34eea69a7afe0ad9a4d54be83cf5391bf9e" + integrity sha512-XwJNk+Qbtr7xjuh1Iz7wqybp+xB3H6uRJjlOqtgIoOui9V2zfL/At/FzHMMvaLeUsWJhOVSJP5qmEzCYaOEvmQ== dependencies: "@metamask/providers" "^9.0.0" - "@metamask/snap-utils" "^0.21.0" + "@metamask/snap-utils" "^0.22.0" "@metamask/types" "^1.1.0" -"@metamask/snap-utils@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-utils/-/snap-utils-0.21.0.tgz#7ed5df1d0c25f2660ce36dcc436f3608d72e92d5" - integrity sha512-bfGvCIZd1zfuRUFN68F0HrIHfsCmoh/j6/Sm5sj6v7mIGyERbgpu0mYEwKIRjuCtV5GkGimXU6H2Tof+ZWrLtQ== +"@metamask/snap-utils@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@metamask/snap-utils/-/snap-utils-0.22.0.tgz#1815eecfc8a388a4ae6744664ff28f58404730ee" + integrity sha512-mwe72I/sVMVogNU+gxUU1P2Kos4S/4lEX1MUz7Hr79jfYzTgwTfxz/gaMubjD6CF2q0ZvF5JQr6OBk6ZRLHhCw== dependencies: "@babel/core" "^7.18.6" - "@metamask/snap-types" "^0.21.0" - "@metamask/utils" "^2.0.0" + "@metamask/snap-types" "^0.22.0" + "@metamask/utils" "^3.1.0" ajv "^8.11.0" eth-rpc-errors "^4.0.3" fast-deep-equal "^3.1.3" rfdc "^1.3.0" semver "^7.3.7" ses "^0.15.17" + superstruct "^0.16.5" "@metamask/test-dapp@^5.2.1": version "5.2.1" @@ -3545,22 +3548,22 @@ resolved "https://registry.yarnpkg.com/@metamask/types/-/types-1.1.0.tgz#9bd14b33427932833c50c9187298804a18c2e025" integrity sha512-EEV/GjlYkOSfSPnYXfOosxa3TqYtIW3fhg6jdw+cok/OhMgNn4wCfbENFqjytrHMU2f7ZKtBAvtiP5V8H44sSw== -"@metamask/utils@^2.0.0", "@metamask/utils@^2.1.0": +"@metamask/utils@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-2.1.0.tgz#a65eaa0932b863383844ec323e05e293d8e718ab" integrity sha512-4PHdo5B1ifpw6GbsdlDpp8oqA++rddSmt2pWBHtIGGL2tQMvmfHdaDDSns4JP9iC+AbMogVcUpv5Vt8ow1zsRA== dependencies: fast-deep-equal "^3.1.3" -"@metamask/utils@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.0.1.tgz#53ed2b9cbbd12b18c1db6929728446633d6a74c4" - integrity sha512-FDWQ+MeeWQh0b/w2D50+oVPrRqUIvawDlPia+EH9NCOFN0Ty3KkzkQXfO6FgHKMyR4aWuS4SBOrhWFRW8km6lQ== +"@metamask/utils@^3.0.1", "@metamask/utils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.1.0.tgz#ecfabe08e807bfcfb9ed1d7e727779a9382bee2c" + integrity sha512-zBGKgaqdKO9z2CoBSDzeE5KJUr5pM72YsumyUiklSyqMg/xL9vu7Z+E/pkRtwPmyi2YWXvq1rWfjugTt2+38nA== dependencies: "@types/debug" "^4.1.7" debug "^4.3.4" fast-deep-equal "^3.1.3" - superstruct "^0.16.0" + superstruct "^0.16.5" "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -26687,10 +26690,10 @@ superagent@^3.8.1: qs "^6.5.1" readable-stream "^2.3.5" -superstruct@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.16.0.tgz#9af5e059acd08e774789ad8880962427ef68dace" - integrity sha512-IDQtwnnlaan1NhuHqyD/U11lROYvCQ79JyfwlFU9xEVHzqV/Ys/RrwmHPCG0CVH/1g0BuodEjH1msxK2UHxehA== +superstruct@^0.16.5: + version "0.16.5" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.16.5.tgz#7b7e1f1f8bf6ab141c660e501ac57026e42c09c0" + integrity sha512-GBa1VPdCUDAIrsoMVy2lzE/hKQnieUlc1JVoVzJ2YLx47SoPY4AqF85Ht1bPg5r+8I0v54GbaRdNTnYQ0p+T+Q== superstruct@^0.6.0, superstruct@~0.6.0, superstruct@~0.6.1: version "0.6.1" From e755d83def7a5086833eddea9c93aa8442f3b332 Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Fri, 7 Oct 2022 10:24:24 -0500 Subject: [PATCH 12/33] patch ethereumjs-util stripHexPrefix (#16094) --- patches/ethereumjs-util+7.1.5.patch | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 patches/ethereumjs-util+7.1.5.patch diff --git a/patches/ethereumjs-util+7.1.5.patch b/patches/ethereumjs-util+7.1.5.patch new file mode 100644 index 000000000000..d8d4a9142bd7 --- /dev/null +++ b/patches/ethereumjs-util+7.1.5.patch @@ -0,0 +1,48 @@ +diff --git a/node_modules/ethereumjs-util/dist.browser/internal.js b/node_modules/ethereumjs-util/dist.browser/internal.js +index 9f3888b..3803958 100644 +--- a/node_modules/ethereumjs-util/dist.browser/internal.js ++++ b/node_modules/ethereumjs-util/dist.browser/internal.js +@@ -43,8 +43,9 @@ exports.isHexPrefixed = isHexPrefixed; + * @returns the string without 0x prefix + */ + var stripHexPrefix = function (str) { +- if (typeof str !== 'string') +- throw new Error("[stripHexPrefix] input must be type 'string', received ".concat(typeof str)); ++ if (typeof str !== 'string'){ ++ return str; ++ } + return isHexPrefixed(str) ? str.slice(2) : str; + }; + exports.stripHexPrefix = stripHexPrefix; +diff --git a/node_modules/ethereumjs-util/dist/internal.js b/node_modules/ethereumjs-util/dist/internal.js +index 01a90a0..9f1d8cd 100644 +--- a/node_modules/ethereumjs-util/dist/internal.js ++++ b/node_modules/ethereumjs-util/dist/internal.js +@@ -43,8 +43,9 @@ exports.isHexPrefixed = isHexPrefixed; + * @returns the string without 0x prefix + */ + const stripHexPrefix = (str) => { +- if (typeof str !== 'string') +- throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`); ++ if (typeof str !== 'string'){ ++ return str; ++ } + return isHexPrefixed(str) ? str.slice(2) : str; + }; + exports.stripHexPrefix = stripHexPrefix; +diff --git a/node_modules/ethereumjs-util/src/internal.ts b/node_modules/ethereumjs-util/src/internal.ts +index 52032f5..8f6f5f8 100644 +--- a/node_modules/ethereumjs-util/src/internal.ts ++++ b/node_modules/ethereumjs-util/src/internal.ts +@@ -42,8 +42,9 @@ export function isHexPrefixed(str: string): boolean { + * @returns the string without 0x prefix + */ + export const stripHexPrefix = (str: string): string => { +- if (typeof str !== 'string') +- throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`) ++ if (typeof str !== 'string') { ++ return str; ++ } + + return isHexPrefixed(str) ? str.slice(2) : str + } From 90badb2483043ec55ff70df3ccdbf6e40547b564 Mon Sep 17 00:00:00 2001 From: George Marshall Date: Fri, 7 Oct 2022 08:38:23 -0700 Subject: [PATCH 13/33] Adding border radius full to `Box` component (#16118) * Adding border radius full and updating border radius sizes for box * Adding missing XS size * Updating docs and linting issues * Updating name from 'full' to 'pill' --- ui/components/ui/box/README.mdx | 83 +++++++++++++++++---------- ui/components/ui/box/box.js | 6 +- ui/components/ui/box/box.scss | 14 +++-- ui/components/ui/box/box.stories.js | 78 ++++++++++++++++++++++++- ui/components/ui/box/box.test.js | 65 +++++++++++++++++---- ui/helpers/constants/design-system.js | 10 ++++ 6 files changed, 206 insertions(+), 50 deletions(-) diff --git a/ui/components/ui/box/README.mdx b/ui/components/ui/box/README.mdx index c5b2827503a2..ff443c1f6aee 100644 --- a/ui/components/ui/box/README.mdx +++ b/ui/components/ui/box/README.mdx @@ -14,36 +14,36 @@ Box is a utility component that can be used for layout or as a base for other UI ## Props -| Name | Description | Default | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | -| children | The children of the Box component. If `function` type will render the child as the Box node instead of a child of the Box | - | -| className | Additional className of the Box component | - | -| margin | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values [1, 2, 'auto'] for responsive props | - | -| marginTop | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | -| marginBottom | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | -| marginRight | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | -| marginLeft | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | -| padding | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| paddingTop | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| paddingBottom | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| paddingRight | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| paddingLeft | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| display | [DISPLAY](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L200-L210) values or array of [DISPLAY](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L200-L210) values for responsive props | - | -| flexDirection | [FLEX_DIRECTION](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L187-L192) values or array of [FLEX_DIRECTION](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L187-L192) values for responsive props | FLEX_DIRECTION.ROW | -| flexWrap | [FLEX_WRAP](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L194-L198) values or array of [FLEX_WRAP](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L194-L198) values for responsive props | - | -| alignItems | [ALIGN_ITEMS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L170-L176) values or array of [ALIGN_ITEMS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L170-L176) values for responsive props | - | -| justifyContent | [JUSTIFY_CONTENT](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L178-L185) values or array of [JUSTIFY_CONTENT](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L178-L185) values | - | -| gap | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| textAlign | [TEXT_ALIGN](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L249-L255) values or array of [TEXT_ALIGN](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L249-L255) values for responsive props | - | -| width | [BLOCK_SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L241-L247) values or array of [BLOCK_SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L241-L247) values for responsive props | - | -| height | [BLOCK_SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L241-L247) values or array of [BLOCK_SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#LL241-L247) values for responsive props | - | -| color | [COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L117-L133) values or array of [COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L117-L133) values for responsive props | - | -| backgroundColor | [BACKGROUND_COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L62-L88) values or array of [BACKGROUND_COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L62-L88) values for responsive props | - | -| borderColor | [BORDER_COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L90-L115) values or array of [BORDER_COLORS](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L90-L115) values for responsive props | - | -| borderWidth | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | -| borderRadius | [SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L149-L156) values or array of [SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L149-L156) values for responsive props | - | -| borderStyle | [BORDER_STYLE](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L158-L164) values or array of [BORDER_STYLE](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L158-L164) values for responsive props | - | -| as | The polymorphic `as` prop allows you to change the root HTML element of the Box component. Defaults to 'div' | 'div' | +| Name | Description | Default | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| children | The children of the Box component. If `function` type will render the child as the Box node instead of a child of the Box | - | +| className | Additional className of the Box component | - | +| margin | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values [1, 2, 'auto'] for responsive props | - | +| marginTop | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | +| marginBottom | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | +| marginRight | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | +| marginLeft | 0, 1, 2, 4, 6, 8, 9, 10, 12, 'auto' or array of values for responsive props | - | +| padding | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| paddingTop | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| paddingBottom | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| paddingRight | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| paddingLeft | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| display | DISPLAY values or array of DISPLAY values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| flexDirection | FLEX_DIRECTION values or array of FLEX_DIRECTION values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | FLEX_DIRECTION.ROW | +| flexWrap | FLEX_WRAP values or array of FLEX_WRAP values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| alignItems | ALIGN_ITEMS values or array of ALIGN_ITEMS values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| justifyContent | JUSTIFY_CONTENT values or array of JUSTIFY_CONTENT values from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| gap | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| textAlign | TEXT_ALIGN values or array of TEXT_ALIGN values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| width | BLOCK_SIZES values or array of BLOCK_SIZES values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| height | BLOCK_SIZES values or array of BLOCK_SIZES values for responsive props [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| color | COLORS values or array of COLORS values for responsive props [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| backgroundColor | BACKGROUND_COLORS values or array of BACKGROUND_COLORS values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| borderColor | BORDER_COLORS values or array of BORDER_COLORS values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| borderWidth | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] for responsive props | - | +| borderRadius | BORDER_RADIUS values or array of BORDER_RADIUS values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| borderStyle | BORDER_STYLE values or array of BORDER_STYLE values for responsive props from [../ui/helpers/constants/design-system.js](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js) | - | +| as | The polymorphic `as` prop allows you to change the root HTML element of the Box component. Defaults to 'div' | 'div' | ## Usage @@ -188,6 +188,29 @@ import Box from '../ui/box'; ; ``` +### Border Radius + +Use the `borderRadius` prop along with the `BORDER_RADIUS` object from `ui/helpers/constants/design-system.js` to change border radius. The `borderRadius` prop accepts [responsive props](#responsive-props) in the form of array props. + + + + + +Example of importing `BORDER_RADIUS` object with `Box` component + +```jsx +import { BORDER_RADIUS } from '../../../helpers/constants/design-system'; +import Box from '../ui/box'; + +BORDER_RADIUS.NONE 0px +BORDER_RADIUS.XS 2px +BORDER_RADIUS.SM 4px +BORDER_RADIUS.MD 6px +BORDER_RADIUS.LG 8px +BORDER_RADIUS.XL 12px +BORDER_RADIUS.PILL 9999px +``` + ### Responsive Props The box component provides a responsive props api in the form of array props. Array props are inspired by [styled-systems array props](https://styled-system.com/guides/array-props). The responsive props follow a mobile first methodology with the first item in the array applying the style to the base level size e.g. `0px` and up. The second item overwrites the first items styles at the next breakpoint. diff --git a/ui/components/ui/box/box.js b/ui/components/ui/box/box.js index 446f314cd7dd..83795b4537e1 100644 --- a/ui/components/ui/box/box.js +++ b/ui/components/ui/box/box.js @@ -12,11 +12,11 @@ import { ICON_COLORS, DISPLAY, JUSTIFY_CONTENT, - SIZES, TEXT_ALIGN, FLEX_DIRECTION, FLEX_WRAP, BREAKPOINTS, + BORDER_RADIUS, } from '../../../helpers/constants/design-system'; const BASE_CLASS_NAME = 'box'; @@ -288,8 +288,8 @@ Box.propTypes = { PropTypes.arrayOf(PropTypes.number), ]), borderRadius: PropTypes.oneOfType([ - PropTypes.oneOf(Object.values(SIZES)), - PropTypes.arrayOf(PropTypes.oneOf(Object.values(SIZES))), + PropTypes.oneOf(Object.values(BORDER_RADIUS)), + PropTypes.arrayOf(PropTypes.oneOf(Object.values(BORDER_RADIUS))), ]), borderStyle: PropTypes.oneOfType([ PropTypes.oneOf(Object.values(BORDER_STYLE)), diff --git a/ui/components/ui/box/box.scss b/ui/components/ui/box/box.scss index 77a7364bf4f7..63f9fb9fa9c2 100644 --- a/ui/components/ui/box/box.scss +++ b/ui/components/ui/box/box.scss @@ -134,23 +134,27 @@ $attributesToApplyExtraProperties: margin; } &--rounded-xs { - border-radius: 0.125rem; + border-radius: 2px; } &--rounded-sm { - border-radius: 0.25rem; + border-radius: 4px; } &--rounded-md { - border-radius: 0.375rem; + border-radius: 6px; } &--rounded-lg { - border-radius: 0.5rem; + border-radius: 8px; } &--rounded-xl { - border-radius: 0.75rem; + border-radius: 12px; + } + + &--rounded-pill { + border-radius: 9999px; } // breakpoint classes diff --git a/ui/components/ui/box/box.stories.js b/ui/components/ui/box/box.stories.js index 0c0cbaff4fa5..6d63f186edec 100644 --- a/ui/components/ui/box/box.stories.js +++ b/ui/components/ui/box/box.stories.js @@ -9,10 +9,10 @@ import { BACKGROUND_COLORS, DISPLAY, JUSTIFY_CONTENT, - SIZES, TEXT_ALIGN, FLEX_DIRECTION, FLEX_WRAP, + BORDER_RADIUS, } from '../../../helpers/constants/design-system'; import Typography from '../typography'; @@ -115,7 +115,7 @@ export default { table: { category: 'border' }, }, borderRadius: { - options: Object.values(SIZES), + options: Object.values(BORDER_RADIUS), control: 'select', table: { category: 'border' }, }, @@ -480,6 +480,80 @@ export const BorderColor = () => { ); }; +export const BorderRadius = () => { + return ( + + + BORDER_RADIUS.NONE 0px + + + BORDER_RADIUS.XS 2px + + + BORDER_RADIUS.SM 4px + + + BORDER_RADIUS.MD 6px + + + BORDER_RADIUS.LG 8px + + + BORDER_RADIUS.XL 12px + + + BORDER_RADIUS.PILL 9999px + + + ); +}; + export const ResponsiveProps = () => { return ( <> diff --git a/ui/components/ui/box/box.test.js b/ui/components/ui/box/box.test.js index 7fdfe1737629..8e8534589265 100644 --- a/ui/components/ui/box/box.test.js +++ b/ui/components/ui/box/box.test.js @@ -9,8 +9,8 @@ import { ALIGN_ITEMS, JUSTIFY_CONTENT, TEXT_ALIGN, - SIZES, BLOCK_SIZES, + BORDER_RADIUS, } from '../../../helpers/constants/design-system'; import Box from '.'; @@ -280,22 +280,67 @@ describe('Box', () => { }); it('should render the Box with the borderRadius class', () => { const { getByText } = render( - Box content, + <> + border radius xs + border radius sm + border radius md + border radius lg + border radius xl + border radius pill + border radius none + , ); - expect(getByText('Box content')).toHaveClass('box--rounded-xs'); + expect(getByText('border radius xs')).toHaveClass('box--rounded-xs'); + expect(getByText('border radius sm')).toHaveClass('box--rounded-sm'); + expect(getByText('border radius md')).toHaveClass('box--rounded-md'); + expect(getByText('border radius lg')).toHaveClass('box--rounded-lg'); + expect(getByText('border radius xl')).toHaveClass('box--rounded-xl'); + expect(getByText('border radius pill')).toHaveClass('box--rounded-pill'); + expect(getByText('border radius none')).toHaveClass('box--rounded-none'); }); it('should render the Box with the responsive borderRadius classes', () => { const { getByText } = render( - - Box content - , + <> + + Border radius set 1 + + + Border radius set 2 + + , ); - expect(getByText('Box content')).toHaveClass('box--rounded-xs'); - expect(getByText('Box content')).toHaveClass('box--sm:rounded-sm'); - expect(getByText('Box content')).toHaveClass('box--md:rounded-md'); - expect(getByText('Box content')).toHaveClass('box--lg:rounded-lg'); + expect(getByText('Border radius set 1')).toHaveClass('box--rounded-xs'); + expect(getByText('Border radius set 1')).toHaveClass( + 'box--sm:rounded-sm', + ); + expect(getByText('Border radius set 1')).toHaveClass( + 'box--md:rounded-md', + ); + expect(getByText('Border radius set 1')).toHaveClass( + 'box--lg:rounded-lg', + ); + expect(getByText('Border radius set 2')).toHaveClass('box--rounded-xl'); + expect(getByText('Border radius set 2')).toHaveClass( + 'box--sm:rounded-pill', + ); + expect(getByText('Border radius set 2')).toHaveClass( + 'box--md:rounded-none', + ); }); }); describe('display, gap, flexDirection, flexWrap, alignItems, justifyContent', () => { diff --git a/ui/helpers/constants/design-system.js b/ui/helpers/constants/design-system.js index 58c142e113a7..7c8ddb18e140 100644 --- a/ui/helpers/constants/design-system.js +++ b/ui/helpers/constants/design-system.js @@ -185,6 +185,16 @@ export const BORDER_STYLE = { NONE, }; +export const BORDER_RADIUS = { + XS: SIZES.XS, + SM: SIZES.SM, + MD: SIZES.MD, + LG: SIZES.LG, + XL: SIZES.XL, + NONE, + PILL: 'pill', +}; + const FLEX_END = 'flex-end'; const FLEX_START = 'flex-start'; const CENTER = 'center'; From e4dc8ce012bd70fe038f15074e28f47e3ad8dbf2 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 7 Oct 2022 11:38:38 -0400 Subject: [PATCH 14/33] Fix intermittent storybook build failure (#16124) The CI job for building storybook will fail occasionally, presumably due to a Node.js process running out of heap memory. This job is the only build job that runs with default Node.js memory settings. It has been updated to use a larger instance size and to set the heap size to 2GB, matching our other build jobs. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8527946595d9..627394dddf99 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -386,7 +386,7 @@ jobs: - builds-test prep-build-storybook: - executor: node-browsers + executor: node-browsers-medium-plus steps: - checkout - attach_workspace: @@ -644,7 +644,7 @@ jobs: root: . paths: - test-artifacts - + user-actions-benchmark: executor: node-browsers-medium-plus steps: From 958cfe65a0ecf23e0fb74dd10f503902f7870c9e Mon Sep 17 00:00:00 2001 From: Garrett Bear Date: Fri, 7 Oct 2022 08:50:28 -0700 Subject: [PATCH 15/33] Feat/15951/add button secondary (#16097) * add button secondary * revert change to shadow stories * test and docs update * Update ui/components/component-library/button-secondary/README.mdx Co-authored-by: George Marshall * remove unused fragment Co-authored-by: George Marshall --- .../button-primary/button-primary.stories.js | 6 +- .../button-secondary/README.mdx | 57 ++++++++ .../button-secondary.constants.js | 7 + .../button-secondary/button-secondary.js | 45 ++++++ .../button-secondary/button-secondary.scss | 51 +++++++ .../button-secondary.stories.js | 133 ++++++++++++++++++ .../button-secondary/button-secondary.test.js | 101 +++++++++++++ .../button-secondary/index.js | 1 + .../component-library-components.scss | 1 + 9 files changed, 397 insertions(+), 5 deletions(-) create mode 100644 ui/components/component-library/button-secondary/README.mdx create mode 100644 ui/components/component-library/button-secondary/button-secondary.constants.js create mode 100644 ui/components/component-library/button-secondary/button-secondary.js create mode 100644 ui/components/component-library/button-secondary/button-secondary.scss create mode 100644 ui/components/component-library/button-secondary/button-secondary.stories.js create mode 100644 ui/components/component-library/button-secondary/button-secondary.test.js create mode 100644 ui/components/component-library/button-secondary/index.js diff --git a/ui/components/component-library/button-primary/button-primary.stories.js b/ui/components/component-library/button-primary/button-primary.stories.js index fff0966b08e2..8f9c3cafcf28 100644 --- a/ui/components/component-library/button-primary/button-primary.stories.js +++ b/ui/components/component-library/button-primary/button-primary.stories.js @@ -104,11 +104,7 @@ export default { }, }; -export const DefaultStory = (args) => ( - <> - - -); +export const DefaultStory = (args) => ; DefaultStory.storyName = 'Default'; diff --git a/ui/components/component-library/button-secondary/README.mdx b/ui/components/component-library/button-secondary/README.mdx new file mode 100644 index 000000000000..16a5a74a6404 --- /dev/null +++ b/ui/components/component-library/button-secondary/README.mdx @@ -0,0 +1,57 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import { ButtonSecondary } from './button-secondary'; + +# ButtonSecondary + +The `ButtonSecondary` is an extension of `ButtonBase` to support secondary styles. + + + + + +## Props + +The `ButtonSecondary` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) and [ButtonBase](/docs/ui-components-component-library-button-base-button-base-stories-js--default-story#props) component props + + + +### Size + +Use the `size` prop and the `SIZES` object from `./ui/helpers/constants/design-system.js` to change the size of `ButtonSecondary`. Defaults to `SIZES.MD` + +Optional: `BUTTON_SIZES` from `./button-base` object can be used instead of `SIZES`. + +Possible sizes include: + +- `SIZES.SM` 32px +- `SIZES.MD` 40px +- `SIZES.LG` 48px + + + + + +```jsx +import { SIZES } from '../../../helpers/constants/design-system'; +import { ButtonSecondary } from '../ui/component-library/button/button-secondary/button-secondary'; + + + + +``` + +### Type + +Use the `type` prop and the `BUTTON_TYPES` object from `./ui/helpers/constants/design-system.js` to change the context of `ButtonSecondary`. + + + + + +```jsx +import { ButtonSecondary } from '../ui/component-library/button/button-secondary/button-secondary'; + +Normal +Danger +``` diff --git a/ui/components/component-library/button-secondary/button-secondary.constants.js b/ui/components/component-library/button-secondary/button-secondary.constants.js new file mode 100644 index 000000000000..0e8af938efa2 --- /dev/null +++ b/ui/components/component-library/button-secondary/button-secondary.constants.js @@ -0,0 +1,7 @@ +import { SIZES } from '../../../helpers/constants/design-system'; + +export const BUTTON_SECONDARY_SIZES = { + SM: SIZES.SM, + MD: SIZES.MD, + LG: SIZES.LG, +}; diff --git a/ui/components/component-library/button-secondary/button-secondary.js b/ui/components/component-library/button-secondary/button-secondary.js new file mode 100644 index 000000000000..c8d4ed608baf --- /dev/null +++ b/ui/components/component-library/button-secondary/button-secondary.js @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; + +import { ButtonBase } from '../button-base'; +import { BUTTON_SECONDARY_SIZES } from './button-secondary.constants'; + +export const ButtonSecondary = ({ + className, + danger, + size = BUTTON_SECONDARY_SIZES.MD, + ...props +}) => { + return ( + + ); +}; + +ButtonSecondary.propTypes = { + /** + * An additional className to apply to the ButtonSecondary. + */ + className: PropTypes.string, + /** + * Boolean to change button type to Danger when true + */ + danger: PropTypes.bool, + /** + * The possible size values for ButtonSecondary: 'SIZES.SM', 'SIZES.MD', 'SIZES.LG', + * Default value is 'SIZES.MD'. + */ + size: PropTypes.oneOf(Object.values(BUTTON_SECONDARY_SIZES)), + /** + * ButtonSecondary accepts all the props from ButtonBase + */ + ...ButtonBase.propTypes, +}; + +export default ButtonSecondary; diff --git a/ui/components/component-library/button-secondary/button-secondary.scss b/ui/components/component-library/button-secondary/button-secondary.scss new file mode 100644 index 000000000000..7724e5701b91 --- /dev/null +++ b/ui/components/component-library/button-secondary/button-secondary.scss @@ -0,0 +1,51 @@ +.mm-button-secondary { + color: var(--color-primary-default); + border: 1px solid var(--color-primary-default); + background-color: transparent; + + &:hover { + color: var(--color-primary-inverse); + background-color: var(--color-primary-default); + box-shadow: var(--component-button-primary-shadow); + } + + &:active { + color: var(--color-primary-inverse); + background-color: var(--color-primary-alternative); + border-color: var(--color-primary-alternative); + } + + &.mm-button--disabled { + &:hover { + color: var(--color-primary-default); + box-shadow: none; + background-color: transparent; + } + + &:active { + background-color: transparent; + } + } + + &--type-danger { + color: var(--color-error-default); + border: 1px solid var(--color-error-default); + background-color: transparent; + + &:hover { + color: var(--color-error-inverse); + background-color: var(--color-error-default); + box-shadow: var(--component-button-danger-shadow); + } + + &:active { + color: var(--color-error-inverse); + background-color: var(--color-error-alternative); + border-color: var(--color-error-alternative); + } + + &.mm-button--disabled:hover { + color: var(--color-error-default); + } + } +} diff --git a/ui/components/component-library/button-secondary/button-secondary.stories.js b/ui/components/component-library/button-secondary/button-secondary.stories.js new file mode 100644 index 000000000000..399cb412e755 --- /dev/null +++ b/ui/components/component-library/button-secondary/button-secondary.stories.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { ALIGN_ITEMS, DISPLAY } from '../../../helpers/constants/design-system'; +import Box from '../../ui/box/box'; +import { ICON_NAMES } from '../icon'; +import { ButtonSecondary } from './button-secondary'; +import { BUTTON_SECONDARY_SIZES } from './button-secondary.constants'; +import README from './README.mdx'; + +const marginSizeControlOptions = [ + undefined, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 'auto', +]; + +export default { + title: 'Components/ComponentLibrary/ButtonSecondary', + id: __filename, + component: ButtonSecondary, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + as: { + control: 'select', + options: ['button', 'a'], + table: { category: 'button base props' }, + }, + block: { + control: 'boolean', + table: { category: 'button base props' }, + }, + children: { + control: 'text', + }, + className: { + control: 'text', + }, + danger: { + control: 'boolean', + }, + disabled: { + control: 'boolean', + table: { category: 'button base props' }, + }, + icon: { + control: 'select', + options: Object.values(ICON_NAMES), + table: { category: 'button base props' }, + }, + iconPositionRight: { + control: 'boolean', + table: { category: 'button base props' }, + }, + iconProps: { + control: 'object', + table: { category: 'button base props' }, + }, + + loading: { + control: 'boolean', + table: { category: 'button base props' }, + }, + size: { + control: 'select', + options: Object.values(BUTTON_SECONDARY_SIZES), + }, + marginTop: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginRight: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginBottom: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + marginLeft: { + options: marginSizeControlOptions, + control: 'select', + table: { category: 'box props' }, + }, + }, + args: { + children: 'Button Secondary', + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; + +export const Size = (args) => ( + + + Small Button + + + Medium (Default) Button + + + Large Button + + +); + +export const Type = (args) => ( + + Normal + {/* Test Anchor tag to match exactly as button */} + + Danger + + +); diff --git a/ui/components/component-library/button-secondary/button-secondary.test.js b/ui/components/component-library/button-secondary/button-secondary.test.js new file mode 100644 index 000000000000..61f910ab98a8 --- /dev/null +++ b/ui/components/component-library/button-secondary/button-secondary.test.js @@ -0,0 +1,101 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render } from '@testing-library/react'; +import React from 'react'; +import { ButtonSecondary } from './button-secondary'; +import { BUTTON_SECONDARY_SIZES } from './button-secondary.constants'; + +describe('ButtonSecondary', () => { + it('should render button element correctly', () => { + const { getByText, getByTestId, container } = render( + + Button Secondary + , + ); + expect(getByText('Button Secondary')).toBeDefined(); + expect(container.querySelector('button')).toBeDefined(); + expect(getByTestId('button-secondary')).toHaveClass('mm-button'); + }); + + it('should render anchor element correctly', () => { + const { getByTestId, container } = render( + , + ); + expect(getByTestId('button-secondary')).toHaveClass('mm-button'); + const anchor = container.getElementsByTagName('a').length; + expect(anchor).toBe(1); + }); + + it('should render button as block', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('block')).toHaveClass(`mm-button--block`); + }); + + it('should render with added classname', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('classname')).toHaveClass('mm-button--test'); + }); + + it('should render with different size classes', () => { + const { getByTestId } = render( + <> + + + + , + ); + + expect(getByTestId(BUTTON_SECONDARY_SIZES.SM)).toHaveClass( + `mm-button--size-${BUTTON_SECONDARY_SIZES.SM}`, + ); + expect(getByTestId(BUTTON_SECONDARY_SIZES.MD)).toHaveClass( + `mm-button--size-${BUTTON_SECONDARY_SIZES.MD}`, + ); + expect(getByTestId(BUTTON_SECONDARY_SIZES.LG)).toHaveClass( + `mm-button--size-${BUTTON_SECONDARY_SIZES.LG}`, + ); + }); + + it('should render with different types', () => { + const { getByTestId } = render( + <> + + , + ); + + expect(getByTestId('danger')).toHaveClass( + 'mm-button-secondary--type-danger', + ); + }); + + it('should render with different button states', () => { + const { getByTestId } = render( + <> + + + , + ); + expect(getByTestId('loading')).toHaveClass(`mm-button--loading`); + expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`); + }); + it('should render with icon', () => { + const { container } = render( + , + ); + + const icons = container.getElementsByClassName('icon').length; + expect(icons).toBe(1); + }); +}); diff --git a/ui/components/component-library/button-secondary/index.js b/ui/components/component-library/button-secondary/index.js new file mode 100644 index 000000000000..6b1d2869f0dd --- /dev/null +++ b/ui/components/component-library/button-secondary/index.js @@ -0,0 +1 @@ +export { ButtonSecondary } from './button-secondary'; diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss index 85c2f84c6fc5..2a936327203e 100644 --- a/ui/components/component-library/component-library-components.scss +++ b/ui/components/component-library/component-library-components.scss @@ -4,6 +4,7 @@ @import 'base-avatar/base-avatar'; @import 'button-base/button-base'; @import 'button-primary/button-primary'; +@import 'button-secondary/button-secondary'; @import 'icon/icon'; @import 'text/text'; @import 'text-field-base/text-field-base'; From e72dfad21a2034e66cff93e19e2a3e8d47448a85 Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Fri, 7 Oct 2022 21:23:40 +0530 Subject: [PATCH 16/33] added AvatarAccount component (#15795) * added AvatarAccount component * updated avatar account component and README * updated lint errors * updated avatar account with types * updated Jazzicon lint errors * removed unused imports * updated type prop and Blockie * removed unused exports * updated jazzicon styles * fixed overflow in jazzicon * updated avatar account component * updated avatar account stories with types and size stories * updated test for avatar account * updated tests for avatar account * Adding `TextFieldBase` component (#16043) * Adding TextInputBase component * Removing keyup and keydown props, tests and docs * removing showClear from stories * removing unneeded css * simplifying uncontrolled vs controlled to work * Fortifying maxLength test * Lint fix for test * Doc, style and prop updates * Updating constant names with 'base' * Adding a background color * Adding a background color to input * Adding ast-types to resolutions (#16103) Co-authored-by: George Marshall --- .../avatar-account/README.mdx | 43 ++++++++++++++ .../avatar-account.constants.js | 12 ++++ .../avatar-account/avatar-account.js | 54 +++++++++++++++++ .../avatar-account/avatar-account.scss | 5 ++ .../avatar-account/avatar-account.stories.js | 59 +++++++++++++++++++ .../avatar-account/avatar-account.test.js | 23 ++++++++ .../component-library/avatar-account/index.js | 1 + .../component-library-components.scss | 1 + 8 files changed, 198 insertions(+) create mode 100644 ui/components/component-library/avatar-account/README.mdx create mode 100644 ui/components/component-library/avatar-account/avatar-account.constants.js create mode 100644 ui/components/component-library/avatar-account/avatar-account.js create mode 100644 ui/components/component-library/avatar-account/avatar-account.scss create mode 100644 ui/components/component-library/avatar-account/avatar-account.stories.js create mode 100644 ui/components/component-library/avatar-account/avatar-account.test.js create mode 100644 ui/components/component-library/avatar-account/index.js diff --git a/ui/components/component-library/avatar-account/README.mdx b/ui/components/component-library/avatar-account/README.mdx new file mode 100644 index 000000000000..da8be813c5c9 --- /dev/null +++ b/ui/components/component-library/avatar-account/README.mdx @@ -0,0 +1,43 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import { AvatarAccount } from './avatar-account'; + +# AvatarAccount + +The `AvatarAccount` is a type of avatar reserved for representing accounts. + + + + + +## Props + +The `AvatarAccount` accepts all props below + + + +### Size + +Use the `size` prop to set the size of the `AvatarAccount`. + +Possible sizes include: + +- `xs` 16px +- `sm` 24px +- `md` 32px +- `lg` 40px +- `xl` 48px + +Defaults to `md` + + + + + +### type + +Use the `type` prop for the avatar to be rendered, it can either be a Jazzicon or a Blockie + + + + \ No newline at end of file diff --git a/ui/components/component-library/avatar-account/avatar-account.constants.js b/ui/components/component-library/avatar-account/avatar-account.constants.js new file mode 100644 index 000000000000..fd4e7e7cd1a5 --- /dev/null +++ b/ui/components/component-library/avatar-account/avatar-account.constants.js @@ -0,0 +1,12 @@ +export const DIAMETERS = { + xs: '16', + sm: '24', + md: '32', + lg: '40', + xl: '48', +}; + +export const TYPES = { + JAZZICON: 'Jazzicon', + BLOCKIES: 'Blockie', +}; diff --git a/ui/components/component-library/avatar-account/avatar-account.js b/ui/components/component-library/avatar-account/avatar-account.js new file mode 100644 index 000000000000..032703718fdf --- /dev/null +++ b/ui/components/component-library/avatar-account/avatar-account.js @@ -0,0 +1,54 @@ +import React from 'react'; +import classnames from 'classnames'; +import PropTypes from 'prop-types'; +import Jazzicon from '../../ui/jazzicon/jazzicon.component'; +import BlockieIdenticon from '../../ui/identicon/blockieIdenticon/blockieIdenticon.component'; +import { BaseAvatar } from '../base-avatar'; + +import { SIZES } from '../../../helpers/constants/design-system'; +import { DIAMETERS, TYPES } from './avatar-account.constants'; + +export const AvatarAccount = ({ size, address, className, type, ...props }) => { + return ( + + {type === 'Jazzicon' ? ( + + ) : ( + + )} + + ); +}; + +AvatarAccount.propTypes = { + /** + * The size of the AvatarAccount. + * Possible values could be 'SIZES.XS', 'SIZES.SM', 'SIZES.MD', 'SIZES.LG', 'SIZES.XL' + * Defaults to SIZES.MD + */ + size: PropTypes.oneOf(Object.values(SIZES)), + /** + * The type of the avatar to be rendered, it can render either a Jazzicon or a Blockie + */ + type: PropTypes.oneOf(Object.values(TYPES)), + /** + * Address used for generating random image + */ + address: PropTypes.string, + /** + * Add custom css class + */ + className: PropTypes.string, +}; diff --git a/ui/components/component-library/avatar-account/avatar-account.scss b/ui/components/component-library/avatar-account/avatar-account.scss new file mode 100644 index 000000000000..72d32de8aaf0 --- /dev/null +++ b/ui/components/component-library/avatar-account/avatar-account.scss @@ -0,0 +1,5 @@ +.avatar-account { + &__jazzicon { + display: flex; + } +} diff --git a/ui/components/component-library/avatar-account/avatar-account.stories.js b/ui/components/component-library/avatar-account/avatar-account.stories.js new file mode 100644 index 000000000000..f3fb9ce31e14 --- /dev/null +++ b/ui/components/component-library/avatar-account/avatar-account.stories.js @@ -0,0 +1,59 @@ +import React from 'react'; +import Box from '../../ui/box/box'; +import { + ALIGN_ITEMS, + DISPLAY, + SIZES, +} from '../../../helpers/constants/design-system'; +import { AvatarAccount } from './avatar-account'; +import { TYPES } from './avatar-account.constants'; + +import README from './README.mdx'; + +export default { + title: 'Components/ComponentLibrary/AvatarAccount', + id: __filename, + component: AvatarAccount, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + size: { + control: 'select', + options: Object.values(SIZES), + }, + address: { control: 'text' }, + type: { + control: 'select', + options: Object.values(TYPES), + }, + }, + args: { + address: '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1', + size: SIZES.MD, + type: TYPES.JAZZICON, + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; + +export const Size = (args) => ( + + + + + + + +); + +export const Type = (args) => ( + + + + +); diff --git a/ui/components/component-library/avatar-account/avatar-account.test.js b/ui/components/component-library/avatar-account/avatar-account.test.js new file mode 100644 index 000000000000..94cf2783d5c1 --- /dev/null +++ b/ui/components/component-library/avatar-account/avatar-account.test.js @@ -0,0 +1,23 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render } from '@testing-library/react'; +import React from 'react'; +import { AvatarAccount } from './avatar-account'; +import 'jest-canvas-mock'; + +describe('AvatarAccount', () => { + const args = { + address: '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1', + }; + it('should render Jazzicon correctly', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('avatar-account')).toBeDefined(); + }); + it('should render Blockie correctly', () => { + const { getByTestId } = render( + , + ); + expect(getByTestId('avatar-account')).toBeDefined(); + }); +}); diff --git a/ui/components/component-library/avatar-account/index.js b/ui/components/component-library/avatar-account/index.js new file mode 100644 index 000000000000..f314e744d501 --- /dev/null +++ b/ui/components/component-library/avatar-account/index.js @@ -0,0 +1 @@ +export { AvatarAccount } from './avatar-account'; diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss index 2a936327203e..d15655bb059e 100644 --- a/ui/components/component-library/component-library-components.scss +++ b/ui/components/component-library/component-library-components.scss @@ -1,4 +1,5 @@ /** Please import your files in alphabetical order **/ +@import 'avatar-account/avatar-account'; @import 'avatar-network/avatar-network'; @import 'avatar-token/avatar-token'; @import 'base-avatar/base-avatar'; From 7279ea5b404f39857b1a43df5171058d7b37ffbf Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 7 Oct 2022 12:49:20 -0400 Subject: [PATCH 17/33] Use current version of the phishing warning page (#16123) We now use the `latest` tag for the phishing warning page, we now use the version that matches what we have in our manifest. This ensures that our phishing warning e2e tests match the behaviour of the production build, and it ensures that breaking changes to the phishing warning page don't impact users in production. --- development/build/scripts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/development/build/scripts.js b/development/build/scripts.js index 3ccaace8e10d..1e2ec7957d66 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -30,6 +30,7 @@ const bifyModuleGroups = require('bify-module-groups'); const { streamFlatMap } = require('../stream-flat-map'); const { BuildType } = require('../lib/build-type'); const { generateIconNames } = require('../generate-icon-names'); +const phishingWarningManifest = require('../../node_modules/@metamask/phishing-warning/package.json'); const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); const { getConfig, getProductionConfig } = require('./config'); const { @@ -112,7 +113,7 @@ function getPhishingWarningPageUrl({ config, testing }) { if (!phishingWarningPageUrl) { phishingWarningPageUrl = testing ? 'http://localhost:9999/' - : 'https://metamask.github.io/phishing-warning/latest/'; + : `https://metamask.github.io/phishing-warning/v${phishingWarningManifest.version}/`; } // We add a hash/fragment to the URL dynamically, so we need to ensure it From 7604009405f03dead8460a3b1794e5018f5796eb Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 7 Oct 2022 20:35:53 +0200 Subject: [PATCH 18/33] [FLASK] Fix wrong action name for `wallet_getSnaps` hook (#16125) --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 51b753ac2179..54bb1ae570f9 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3744,7 +3744,7 @@ export default class MetamaskController extends EventEmitter { ), getSnaps: this.controllerMessenger.call.bind( this.controllerMessenger, - 'SnapController:getPermittedSnaps', + 'SnapController:getPermitted', origin, ), requestPermissions: async (requestedPermissions) => { From dc775b598e3be43f6aebf703a911b08c03549dc3 Mon Sep 17 00:00:00 2001 From: PeterYinusa <53189696+PeterYinusa@users.noreply.github.com> Date: Mon, 10 Oct 2022 12:43:18 +0100 Subject: [PATCH 19/33] add decrypt e2e (#16122) --- test/e2e/tests/encrypt-decrypt.spec.js | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 test/e2e/tests/encrypt-decrypt.spec.js diff --git a/test/e2e/tests/encrypt-decrypt.spec.js b/test/e2e/tests/encrypt-decrypt.spec.js new file mode 100644 index 000000000000..059d93ca9ee2 --- /dev/null +++ b/test/e2e/tests/encrypt-decrypt.spec.js @@ -0,0 +1,89 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); + +describe('Encrypt Decrypt', function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + const encryptionKey = 'fxYXfCbun026g5zcCQh7Ia+O0urAEVZWLG8H4Jzu7Xs='; + const message = 'Hello, Bob!'; + it('should decrypt an encrypted message', async function () { + await withFixtures( + { + dapp: true, + fixtures: 'connected-state', + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage('http://127.0.0.1:8080'); + + // Get Encryption key + await driver.clickElement('#getEncryptionKeyButton'); + await driver.waitUntilXWindowHandles(3); + let windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.waitForSelector({ + css: '.request-encryption-public-key__header__text', + text: 'Request encryption public key', + }); + await driver.clickElement({ text: 'Provide', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + const encryptionKeyLabel = await driver.findElement( + '#encryptionKeyDisplay', + ); + assert.equal(await encryptionKeyLabel.getText(), encryptionKey); + + // Encrypt + await driver.fill('#encryptMessageInput', message); + await driver.clickElement('#encryptButton'); + await driver.waitForSelector({ + css: '#ciphertextDisplay', + text: '0x', + }); + + // Decrypt + await driver.clickElement('#decryptButton'); + await driver.waitUntilXWindowHandles(3); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.waitForSelector({ + css: '.request-decrypt-message__header__text', + text: 'Decrypt request', + }); + + // Verify message in MetaMask Notification + await driver.clickElement({ text: 'Decrypt message', tag: 'div' }); + const notificationMessage = await driver.findElement( + '.request-decrypt-message__message-text', + ); + assert.equal(await notificationMessage.getText(), message); + await driver.clickElement({ text: 'Decrypt', tag: 'button' }); + + // Verify message in Test Dapp + await driver.waitUntilXWindowHandles(2); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + const clearTextLabel = await driver.findElement('#cleartextDisplay'); + assert.equal(await clearTextLabel.getText(), message); + }, + ); + }); +}); From 1b3dc0db546645d6a2fe0252dd0eead08156faae Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Mon, 10 Oct 2022 14:33:13 +0200 Subject: [PATCH 20/33] [MV3] Add e2e chrome test job for MV3 build (#15991) * Add filter tag * Fix tag * test tag * fix * Changed tag * Add test-e2e-chrome * Filter by branch instead of tag * Move tests to correct mv3 folder * Remove ignore from e2e regular chrome job * Remove filter, so it's run on all PRs * Handling red X for MV3 e2e failures Co-authored-by: Mark Stacey Co-authored-by: Mark Stacey --- .circleci/config.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 627394dddf99..85b19febda7c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -90,6 +90,9 @@ workflows: - test-e2e-firefox-snaps: requires: - prep-build-test-flask + - test-e2e-chrome-mv3: + requires: + - prep-build-test-mv3 - test-unit: requires: - prep-deps @@ -537,6 +540,33 @@ jobs: - store_artifacts: path: test-artifacts destination: test-artifacts + + test-e2e-chrome-mv3: + executor: node-browsers + steps: + - checkout + - run: + name: Re-Install Chrome + command: ./.circleci/scripts/chrome-install.sh + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test-mv3 ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test-mv3 ./builds + - run: + name: test:e2e:chrome + command: | + if .circleci/scripts/test-run-e2e.sh + then + yarn test:e2e:chrome --retries 2 || echo "Temporarily suppressing MV3 e2e test failures" + fi + no_output_timeout: 20m + - store_artifacts: + path: test-artifacts + destination: test-artifacts test-e2e-firefox-snaps: executor: node-browsers From f6f8edfd15dc6f28f86a30600049b36f9febfbf8 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 10 Oct 2022 11:46:58 -0400 Subject: [PATCH 21/33] Update `eth-json-rpc-middleware` to v9.0.1 (#16096) This update includes fixes for our `block-ref` and `retry-on-empty` middleware. The `block-ref` middleware resolves the block reference `latest` to a specific block number, the latest one we are aware of. This is meant to protect against situations where the network gives inconsistent answers for what the latest block number is due to some nodes being out-of-sync with each other (this was a frequent problem years ago with Infura). It was broken in that the `latest` resolution was failing, and we were submitting an additional redundant request to Infura for each request. The `retry-on-empty` middleware is meant to retry certain methods when they return an empty response. This was also meant to deal with network synchronization issues that were more common years ago. This middleware works by making a "child" request over and over until either a retry limit is reached, or a non-empty response is received. It was broken in that the final response recieved was thrown away, so it's as though the middleware was not used. Except that it did result in additional redundant network requests. As a result of this update we should see that the extension is more resilient to certain network synchronization issues. But this is difficult to test, and these issues may not happen in production anymore today. We should see a reduction in requests to Infura as well. This should be easier to test. --- .../provider-api-tests/shared-tests.js | 115 ++---------------- lavamoat/browserify/beta/policy.json | 47 +++---- lavamoat/browserify/flask/policy.json | 47 +++---- lavamoat/browserify/main/policy.json | 47 +++---- lavamoat/build-system/policy.json | 30 ++--- package.json | 2 +- yarn.lock | 31 +++-- 7 files changed, 99 insertions(+), 220 deletions(-) diff --git a/app/scripts/controllers/network/provider-api-tests/shared-tests.js b/app/scripts/controllers/network/provider-api-tests/shared-tests.js index c28855435a55..30d02170c0e4 100644 --- a/app/scripts/controllers/network/provider-api-tests/shared-tests.js +++ b/app/scripts/controllers/network/provider-api-tests/shared-tests.js @@ -673,12 +673,6 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[0] }, }); - // Note that the block-ref middleware will still allow the original - // request to go through. - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[0] }, - }); const results = await withInfuraClient(({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests), @@ -713,31 +707,15 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[0] }, }); - // Note that the block-ref middleware will still allow the original - // request to go through. - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[0] }, - }); comms.mockNextBlockTrackerRequest({ blockNumber: '0x200' }); - comms.mockInfuraRpcCall({ - request: requests[1], - response: { result: mockResults[1] }, - }); - // The previous two requests will happen again, with a different block - // number, in the same order. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( - requests[0], + requests[1], blockParamIndex, '0x200', ), response: { result: mockResults[1] }, }); - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[1] }, - }); const results = await withInfuraClient(async (client) => { const firstResult = await client.makeRpcCall(requests[0]); @@ -780,25 +758,14 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[0] }, }); - // Note that the block-ref middleware will still allow the original - // request to go through. - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[0] }, - }); - // The previous two requests will happen again, in the same order. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( - requests[0], + requests[1], blockParamIndex, '0x100', ), response: { result: mockResults[1] }, }); - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[1] }, - }); const results = await withInfuraClient(({ makeRpcCallsInSeries }) => makeRpcCallsInSeries(requests), @@ -823,8 +790,9 @@ export function testsForRpcMethodSupportingBlockParam( comms.mockNextBlockTrackerRequest({ blockNumber: '0x100' }); // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block - // number. + // number, and we delay it. comms.mockInfuraRpcCall({ + delay: 100, request: buildRequestWithReplacedBlockParam( requests[0], blockParamIndex, @@ -832,13 +800,6 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[0] }, }); - // This is the original request as below, which the block-ref - // middleware will allow through, except that we delay it. - comms.mockInfuraRpcCall({ - request: requests[0], - response: { result: mockResults[0] }, - delay: 100, - }); // The previous two requests will happen again, in the same order. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( @@ -848,10 +809,6 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[1] }, }); - comms.mockInfuraRpcCall({ - request: requests[1], - response: { result: mockResults[1] }, - }); comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( requests[2], @@ -860,10 +817,6 @@ export function testsForRpcMethodSupportingBlockParam( ), response: { result: mockResults[2] }, }); - comms.mockInfuraRpcCall({ - request: requests[2], - response: { result: mockResults[2] }, - }); const results = await withInfuraClient(async (client) => { const resultPromises = [ @@ -902,10 +855,6 @@ export function testsForRpcMethodSupportingBlockParam( // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block // number. - // - // Note, however, that the block-ref middleware doesn't run the - // original request, as it fails before it gets to that point, so - // there is no need to mock the request again. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( request, @@ -940,10 +889,6 @@ export function testsForRpcMethodSupportingBlockParam( // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block // number. - // - // Note, however, that the block-ref middleware doesn't run the - // original request, as it fails before it gets to that point, so - // there is no need to mock the request again. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( request, @@ -978,10 +923,6 @@ export function testsForRpcMethodSupportingBlockParam( // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block // number. - // - // Note, however, that the block-ref middleware doesn't run the - // original request, as it fails before it gets to that point, so - // there is no need to mock the request again. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( request, @@ -1046,15 +987,6 @@ export function testsForRpcMethodSupportingBlockParam( httpStatus: 200, }, }); - // Note that the block-ref middleware will still allow the original - // request to go through. - comms.mockInfuraRpcCall({ - request, - response: { - result: 'the result', - httpStatus: 200, - }, - }); const result = await withInfuraClient( async ({ makeRpcCall, clock }) => { return await waitForPromiseToBeFulfilledAfterRunningAllTimers( @@ -1082,10 +1014,6 @@ export function testsForRpcMethodSupportingBlockParam( // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block // number. - // - // Note, however, that the block-ref middleware doesn't run the - // original request, as it fails before it gets to that point, so - // there is no need to mock the request again. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( request, @@ -1153,15 +1081,6 @@ export function testsForRpcMethodSupportingBlockParam( httpStatus: 200, }, }); - // Note that the block-ref middleware will still allow the - // original request to go through. - comms.mockInfuraRpcCall({ - request, - response: { - result: 'the result', - httpStatus: 200, - }, - }); const result = await withInfuraClient( async ({ makeRpcCall, clock }) => { return await waitForPromiseToBeFulfilledAfterRunningAllTimers( @@ -1189,10 +1108,6 @@ export function testsForRpcMethodSupportingBlockParam( // The block-ref middleware will make the request as specified // except that the block param is replaced with the latest block // number. - // - // Note, however, that the block-ref middleware doesn't run the - // original request, as it fails before it gets to that point, so - // there is no need to mock the request again. comms.mockInfuraRpcCall({ request: buildRequestWithReplacedBlockParam( request, @@ -1408,23 +1323,16 @@ export function testsForRpcMethodSupportingBlockParam( // also happens within the retry-on-empty middleware (although the // latest block is cached by now). comms.mockNextBlockTrackerRequest({ blockNumber: '0x100' }); - // The retry-on-empty middleware will make an explicit request. - comms.mockInfuraRpcCall({ - request, - response: { result: 'this result gets overwritten' }, - }); - // Note that the retry-on-empty middleware will still allow the - // original request to go through. comms.mockInfuraRpcCall({ request, - response: { result: 'the actual result' }, + response: { result: 'the result' }, }); const result = await withInfuraClient(({ makeRpcCall }) => makeRpcCall(request), ); - expect(result).toStrictEqual('the actual result'); + expect(result).toStrictEqual('the result'); }); }); @@ -1440,23 +1348,16 @@ export function testsForRpcMethodSupportingBlockParam( // also happens within the retry-on-empty middleware (although the // latest block is cached by now). comms.mockNextBlockTrackerRequest({ blockNumber: '0x100' }); - // The retry-on-empty middleware will make an explicit request. - comms.mockInfuraRpcCall({ - request, - response: { result: 'this result gets overwritten' }, - }); - // Note that the retry-on-empty middleware will still allow the - // original request to go through. comms.mockInfuraRpcCall({ request, - response: { result: 'the actual result' }, + response: { result: 'the result' }, }); const result = await withInfuraClient(({ makeRpcCall }) => makeRpcCall(request), ); - expect(result).toStrictEqual('the actual result'); + expect(result).toStrictEqual('the result'); }); }); } diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 3f8260c5eafb..3270beda279d 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -4551,7 +4551,7 @@ "packages": { "browserify>browser-resolve": true, "eth-block-tracker>@metamask/utils": true, - "eth-json-rpc-middleware>eth-sig-util": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, "json-rpc-engine": true, @@ -4560,45 +4560,32 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>eth-sig-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": true - } - }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": { - "packages": { - "bn.js": true, + "3box>tweetnacl": true, + "3box>tweetnacl-util": true, "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, + "eth-lattice-keyring>@ethereumjs/util": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": { "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true + "browserify>browser-resolve": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "ethereumjs-wallet>safe-buffer": true + "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ea5ae2873364..2302a924e8eb 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -5377,7 +5377,7 @@ "packages": { "browserify>browser-resolve": true, "eth-block-tracker>@metamask/utils": true, - "eth-json-rpc-middleware>eth-sig-util": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, "json-rpc-engine": true, @@ -5386,45 +5386,32 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>eth-sig-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": true - } - }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": { - "packages": { - "bn.js": true, + "3box>tweetnacl": true, + "3box>tweetnacl-util": true, "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, + "eth-lattice-keyring>@ethereumjs/util": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": { "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true + "browserify>browser-resolve": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "ethereumjs-wallet>safe-buffer": true + "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 3f8260c5eafb..3270beda279d 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -4551,7 +4551,7 @@ "packages": { "browserify>browser-resolve": true, "eth-block-tracker>@metamask/utils": true, - "eth-json-rpc-middleware>eth-sig-util": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-json-rpc-middleware>pify": true, "eth-rpc-errors": true, "json-rpc-engine": true, @@ -4560,45 +4560,32 @@ "vinyl>clone": true } }, - "eth-json-rpc-middleware>eth-sig-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": true - } - }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi": { - "packages": { - "bn.js": true, + "3box>tweetnacl": true, + "3box>tweetnacl-util": true, "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, + "eth-lattice-keyring>@ethereumjs/util": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-abi>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>bn.js": { "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true + "browserify>browser-resolve": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, "packages": { - "3box>ethers>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "ethereumjs-wallet>safe-buffer": true + "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true } }, - "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>ethjs-util": { + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index d05fa519b195..8ef7fd2736ed 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -2873,7 +2873,21 @@ }, "packages": { "eslint>file-entry-cache>flat-cache>flatted": true, - "nyc>rimraf": true + "eslint>file-entry-cache>flat-cache>rimraf": true + } + }, + "eslint>file-entry-cache>flat-cache>rimraf": { + "builtin": { + "assert": true, + "fs": true, + "path.join": true + }, + "globals": { + "process.platform": true, + "setTimeout": true + }, + "packages": { + "nyc>glob": true } }, "eslint>glob-parent": { @@ -5857,20 +5871,6 @@ "path.resolve": true } }, - "nyc>rimraf": { - "builtin": { - "assert": true, - "fs": true, - "path.join": true - }, - "globals": { - "process.platform": true, - "setTimeout": true - }, - "packages": { - "nyc>glob": true - } - }, "nyc>signal-exit": { "builtin": { "assert.equal": true, diff --git a/package.json b/package.json index 6be08da738d6..f31176b51850 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "eth-block-tracker": "^6.0.0", "eth-ens-namehash": "^2.0.8", "eth-json-rpc-filters": "^4.2.1", - "eth-json-rpc-middleware": "^9.0.0", + "eth-json-rpc-middleware": "^9.0.1", "eth-keyring-controller": "^7.0.2", "eth-lattice-keyring": "^0.12.3", "eth-method-registry": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index e2271e8d68a4..d04837698113 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3299,6 +3299,18 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@metamask/eth-sig-util@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-5.0.0.tgz#106364008029d30a231668a7133d6d0dae60adf6" + integrity sha512-wBOfkmPJoQG3c6kfxxJxQKfzxqSVtMxRjMD4C6xNtGU+TEuBacC3jIgjUUPlC5MTWu4XFo1Y8VWrmc1AlwAitA== + dependencies: + "@ethereumjs/util" "^8.0.0" + bn.js "4.11.8" + ethereum-cryptography "^1.1.2" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + "@metamask/eth-token-tracker@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@metamask/eth-token-tracker/-/eth-token-tracker-4.0.0.tgz#f3129855873a857ef675d4c28f532be684241b61" @@ -3555,7 +3567,7 @@ dependencies: fast-deep-equal "^3.1.3" -"@metamask/utils@^3.0.1", "@metamask/utils@^3.1.0": +"@metamask/utils@^3.0.1", "@metamask/utils@^3.0.3", "@metamask/utils@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.1.0.tgz#ecfabe08e807bfcfb9ed1d7e727779a9382bee2c" integrity sha512-zBGKgaqdKO9z2CoBSDzeE5KJUr5pM72YsumyUiklSyqMg/xL9vu7Z+E/pkRtwPmyi2YWXvq1rWfjugTt2+38nA== @@ -7855,6 +7867,11 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= +bn.js@4.11.8: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + bn.js@=2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-2.0.4.tgz#220a7cd677f7f1bfa93627ff4193776fe7819480" @@ -12087,18 +12104,18 @@ eth-json-rpc-middleware@^8.1.0: node-fetch "^2.6.7" pify "^3.0.0" -eth-json-rpc-middleware@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-9.0.0.tgz#8858713fa009e58758c34f7d8cdeb6179428ffd9" - integrity sha512-s/3BFGTjnby2CXAmWPXdNdWwmlygvRPsKRMYA3a5TJKCH8F/lVmVwGtckYRgfY3etpsEO8rMbkp6SQ+Ob1zCiQ== +eth-json-rpc-middleware@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-9.0.1.tgz#193cb05174739fb736737bbbf992e13010c4b44e" + integrity sha512-5yLNjkedXA4LTIBzzU2f7aHFJqANPsc5qCdOZy6T2p7mlDLW+0q0YBQg6Lx4sHdamOWUnJwvm70qzPAqst5zSg== dependencies: + "@metamask/eth-sig-util" "^5.0.0" "@metamask/safe-event-emitter" "^2.0.0" - "@metamask/utils" "^3.0.1" + "@metamask/utils" "^3.0.3" btoa "^1.2.1" clone "^2.1.1" eth-block-tracker "^5.0.1" eth-rpc-errors "^4.0.3" - eth-sig-util "^1.4.2" json-rpc-engine "^6.1.0" json-stable-stringify "^1.0.1" node-fetch "^2.6.7" From 9125ecf0d62a1b34ba91457fa81974ad7a98d6a5 Mon Sep 17 00:00:00 2001 From: Garrett Bear Date: Mon, 10 Oct 2022 10:59:06 -0700 Subject: [PATCH 22/33] add box height and width responsive sizes (#16111) * add box height and width responsive sizes * add Object.values() to valid sizes --- ui/components/ui/box/box.js | 41 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/ui/components/ui/box/box.js b/ui/components/ui/box/box.js index 83795b4537e1..703ec63bd964 100644 --- a/ui/components/ui/box/box.js +++ b/ui/components/ui/box/box.js @@ -23,6 +23,7 @@ const BASE_CLASS_NAME = 'box'; const Sizes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; const ValidSize = PropTypes.oneOf(Sizes); +const ValidBlockSize = PropTypes.oneOf(Object.values(BLOCK_SIZES)); const ValidSizeAndAuto = PropTypes.oneOf([...Sizes, 'auto']); export const ValidBackgroundColors = PropTypes.oneOf( Object.values(BACKGROUND_COLORS), @@ -30,6 +31,8 @@ export const ValidBackgroundColors = PropTypes.oneOf( export const ValidBorderColors = PropTypes.oneOf(Object.values(BORDER_COLORS)); export const ValidTextColors = PropTypes.oneOf(Object.values(TEXT_COLORS)); export const ValidIconColors = PropTypes.oneOf(Object.values(ICON_COLORS)); +const ValidAlignItem = PropTypes.oneOf(Object.values(ALIGN_ITEMS)); +const ValidJustifyContent = PropTypes.oneOf(Object.values(JUSTIFY_CONTENT)); const ArrayOfValidSizes = PropTypes.arrayOf(ValidSize); export const MultipleSizes = PropTypes.oneOfType([ @@ -37,6 +40,12 @@ export const MultipleSizes = PropTypes.oneOfType([ ArrayOfValidSizes, ]); +const ArrayOfValidBlockSizes = PropTypes.arrayOf(ValidBlockSize); +export const MultipleBlockSizes = PropTypes.oneOfType([ + ValidBlockSize, + ArrayOfValidBlockSizes, +]); + const ArrayOfValidSizesAndAuto = PropTypes.arrayOf(ValidSizeAndAuto); export const MultipleSizesAndAuto = PropTypes.oneOfType([ ValidSizeAndAuto, @@ -64,6 +73,18 @@ export const MultipleTextColors = PropTypes.oneOfType([ ArrayOfValidIconColors, ]); +const ArrayOfValidAlignItems = PropTypes.arrayOf(ValidAlignItem); +export const MultipleAlignItems = PropTypes.oneOfType([ + ValidAlignItem, + ArrayOfValidAlignItems, +]); + +const ArrayOfValidJustifyContents = PropTypes.arrayOf(ValidJustifyContent); +export const MultipleJustifyContents = PropTypes.oneOfType([ + ValidJustifyContent, + ArrayOfValidJustifyContents, +]); + function isValidSize(type, value) { // Only margin types allow 'auto' return ( @@ -295,14 +316,8 @@ Box.propTypes = { PropTypes.oneOf(Object.values(BORDER_STYLE)), PropTypes.arrayOf(PropTypes.oneOf(Object.values(BORDER_STYLE))), ]), - alignItems: PropTypes.oneOfType([ - PropTypes.oneOf(Object.values(ALIGN_ITEMS)), - PropTypes.arrayOf(PropTypes.oneOf(Object.values(ALIGN_ITEMS))), - ]), - justifyContent: PropTypes.oneOfType([ - PropTypes.oneOf(Object.values(JUSTIFY_CONTENT)), - PropTypes.arrayOf(PropTypes.oneOf(Object.values(JUSTIFY_CONTENT))), - ]), + alignItems: MultipleAlignItems, + justifyContent: MultipleJustifyContents, textAlign: PropTypes.oneOfType([ PropTypes.oneOf(Object.values(TEXT_ALIGN)), PropTypes.arrayOf(PropTypes.oneOf(Object.values(TEXT_ALIGN))), @@ -311,14 +326,8 @@ Box.propTypes = { PropTypes.oneOf(Object.values(DISPLAY)), PropTypes.arrayOf(PropTypes.oneOf(Object.values(DISPLAY))), ]), - width: PropTypes.oneOfType([ - PropTypes.oneOf(Object.values(BLOCK_SIZES)), - PropTypes.arrayOf(PropTypes.oneOf(Object.values(BLOCK_SIZES))), - ]), - height: PropTypes.oneOfType([ - PropTypes.oneOf(Object.values(BLOCK_SIZES)), - PropTypes.arrayOf(PropTypes.oneOf(Object.values(BLOCK_SIZES))), - ]), + width: MultipleBlockSizes, + height: MultipleBlockSizes, backgroundColor: MultipleBackgroundColors, className: PropTypes.string, /** From 321e5abab5ce142797443a5f491f3de6da7d85a0 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:59:58 +0200 Subject: [PATCH 23/33] e2e test for gas API fallback (#16137) --- test/e2e/tests/gas-api-fallback.spec.js | 69 +++++++++++++++++++ .../edit-gas-display.component.js | 1 + 2 files changed, 70 insertions(+) create mode 100644 test/e2e/tests/gas-api-fallback.spec.js diff --git a/test/e2e/tests/gas-api-fallback.spec.js b/test/e2e/tests/gas-api-fallback.spec.js new file mode 100644 index 000000000000..8fca241a0b4f --- /dev/null +++ b/test/e2e/tests/gas-api-fallback.spec.js @@ -0,0 +1,69 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); + +describe('Gas API fallback', function () { + async function mockGasApiDown(mockServer) { + await mockServer + .forGet( + 'https://gas-api.metaswap.codefi.network/networks/1/suggestedGasFees', + ) + .thenCallback(() => { + return { + statusCode: 500, + json: {}, + }; + }); + } + + const ganacheOptions = { + hardfork: 'london', + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('error message is displayed but gas recommendation is not displayed', async function () { + await withFixtures( + { + fixtures: 'imported-account', + testSpecificMock: mockGasApiDown, + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Search, public address (0x), or ENS"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + const inputAmount = await driver.findElement('.unit-input__input'); + await inputAmount.fill('1'); + + await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.clickElement({ text: 'Edit', tag: 'button' }); + + const error = await driver.isElementPresent('.error-message__text'); + const gasRecommendation = await driver.isElementPresent( + '[data-testid="gas-recommendation"]', + ); + + assert.equal(error, true, 'Error message is not displayed'); + assert.equal( + gasRecommendation, + false, + 'Gas recommendation is displayed', + ); + }, + ); + }); +}); diff --git a/ui/components/app/edit-gas-display/edit-gas-display.component.js b/ui/components/app/edit-gas-display/edit-gas-display.component.js index c81abab580e2..298820f30a8b 100644 --- a/ui/components/app/edit-gas-display/edit-gas-display.component.js +++ b/ui/components/app/edit-gas-display/edit-gas-display.component.js @@ -244,6 +244,7 @@ export default function EditGasDisplay({ )} {radioButtonsEnabled && !hideRadioButtons && ( Date: Mon, 10 Oct 2022 17:10:44 -0500 Subject: [PATCH 24/33] Persist state in metaRPCHandler so that we are sure state is persisted before sending back response to actions (#15978) * persist state in metaRPCHandler so that we are sure state is persisted before sending back response to actions --- app/scripts/background.js | 55 ++--------------- app/scripts/lib/createMetaRPCHandler.js | 7 ++- app/scripts/lib/local-store.js | 50 ++++++++++++---- app/scripts/lib/local-store.test.js | 79 +++++++++++++++++++++++++ app/scripts/lib/network-store.js | 25 +++++++- app/scripts/metamask-controller.js | 13 +++- 6 files changed, 166 insertions(+), 63 deletions(-) create mode 100644 app/scripts/lib/local-store.test.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 55d51d19fb8f..531864418e72 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -7,9 +7,8 @@ import pump from 'pump'; import debounce from 'debounce-stream'; import log from 'loglevel'; import browser from 'webextension-polyfill'; -import { storeAsStream, storeTransformStream } from '@metamask/obs-store'; +import { storeAsStream } from '@metamask/obs-store'; import PortStream from 'extension-port-stream'; -import { captureException } from '@sentry/browser'; import { ethErrors } from 'eth-rpc-errors'; import { @@ -289,16 +288,11 @@ async function loadStateFromPersistence() { if (!versionedData) { throw new Error('MetaMask - migrator returned undefined'); } + // this initializes the meta/version data as a class variable to be used for future writes + localStore.setMetadata(versionedData.meta); // write to disk - if (localStore.isSupported) { - localStore.set(versionedData); - } else { - // throw in setTimeout so as to not block boot - setTimeout(() => { - throw new Error('MetaMask - Localstore not supported'); - }); - } + localStore.set(versionedData.data); // return just the data return versionedData.data; @@ -339,6 +333,7 @@ function setupController(initState, initLangCode, remoteSourcePort) { getOpenMetamaskTabsIds: () => { return openMetamaskTabsIDs; }, + localStore, }); setupEnsIpfsResolver({ @@ -355,8 +350,7 @@ function setupController(initState, initLangCode, remoteSourcePort) { pump( storeAsStream(controller.store), debounce(1000), - storeTransformStream(versionifyData), - createStreamSink(persistData), + createStreamSink((state) => localStore.set(state)), (error) => { log.error('MetaMask - Persistence pipeline failed', error); }, @@ -364,43 +358,6 @@ function setupController(initState, initLangCode, remoteSourcePort) { setupSentryGetStateGlobal(controller); - /** - * Assigns the given state to the versioned object (with metadata), and returns that. - * - * @param {object} state - The state object as emitted by the MetaMaskController. - * @returns {VersionedData} The state object wrapped in an object that includes a metadata key. - */ - function versionifyData(state) { - versionedData.data = state; - return versionedData; - } - - let dataPersistenceFailing = false; - - async function persistData(state) { - if (!state) { - throw new Error('MetaMask - updated state is missing'); - } - if (!state.data) { - throw new Error('MetaMask - updated state does not have data'); - } - if (localStore.isSupported) { - try { - await localStore.set(state); - if (dataPersistenceFailing) { - dataPersistenceFailing = false; - } - } catch (err) { - // log error so we dont break the pipeline - if (!dataPersistenceFailing) { - dataPersistenceFailing = true; - captureException(err); - } - log.error('error setting state in local store:', err); - } - } - } - // // connect to other contexts // diff --git a/app/scripts/lib/createMetaRPCHandler.js b/app/scripts/lib/createMetaRPCHandler.js index d89156f8680c..f55319783fea 100644 --- a/app/scripts/lib/createMetaRPCHandler.js +++ b/app/scripts/lib/createMetaRPCHandler.js @@ -1,6 +1,7 @@ import { ethErrors, serializeError } from 'eth-rpc-errors'; +import { isManifestV3 } from '../../../shared/modules/mv3.utils'; -const createMetaRPCHandler = (api, outStream) => { +const createMetaRPCHandler = (api, outStream, store, localStoreApiWrapper) => { return async (data) => { if (outStream._writableState.ended) { return; @@ -22,6 +23,10 @@ const createMetaRPCHandler = (api, outStream) => { result = await api[data.method](...data.params); } catch (err) { error = err; + } finally { + if (isManifestV3 && store && data.method !== 'getState') { + localStoreApiWrapper.set(store.getState()); + } } if (outStream._writableState.ended) { diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 069853e12670..707fb1122ef2 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -1,5 +1,6 @@ import browser from 'webextension-polyfill'; import log from 'loglevel'; +import { captureException } from '@sentry/browser'; import { checkForError } from './util'; /** @@ -11,6 +12,45 @@ export default class ExtensionStore { if (!this.isSupported) { log.error('Storage local API not available.'); } + // we use this flag to avoid flooding sentry with a ton of errors: + // once data persistence fails once and it flips true we don't send further + // data persistence errors to sentry + this.dataPersistenceFailing = false; + } + + setMetadata(initMetaData) { + this.metadata = initMetaData; + } + + async set(state) { + if (!this.isSupported) { + throw new Error( + 'Metamask- cannot persist state to local store as this browser does not support this action', + ); + } + if (!state) { + throw new Error('MetaMask - updated state is missing'); + } + if (!this.metadata) { + throw new Error( + 'MetaMask - metadata must be set on instance of ExtensionStore before calling "set"', + ); + } + try { + // we format the data for storage as an object with the "data" key for the controller state object + // and the "meta" key for a metadata object containing a version number that tracks how the data shape + // has changed using migrations to adapt to backwards incompatible changes + await this._set({ data: state, meta: this.metadata }); + if (this.dataPersistenceFailing) { + this.dataPersistenceFailing = false; + } + } catch (err) { + if (!this.dataPersistenceFailing) { + this.dataPersistenceFailing = true; + captureException(err); + } + log.error('error setting state in local store:', err); + } } /** @@ -31,16 +71,6 @@ export default class ExtensionStore { return result; } - /** - * Sets the key in local state - * - * @param {object} state - The state to set - * @returns {Promise} - */ - async set(state) { - return this._set(state); - } - /** * Returns all of the keys currently saved * diff --git a/app/scripts/lib/local-store.test.js b/app/scripts/lib/local-store.test.js new file mode 100644 index 000000000000..2c3cea4055c7 --- /dev/null +++ b/app/scripts/lib/local-store.test.js @@ -0,0 +1,79 @@ +import browser from 'webextension-polyfill'; +import LocalStore from './local-store'; + +jest.mock('webextension-polyfill', () => ({ + storage: { local: true }, +})); + +const setup = ({ isSupported }) => { + browser.storage.local = isSupported; + return new LocalStore(); +}; +describe('LocalStore', () => { + afterEach(() => { + jest.resetModules(); + }); + describe('contructor', () => { + it('should set isSupported property to false when browser does not support local storage', () => { + const localStore = setup({ isSupported: false }); + + expect(localStore.isSupported).toBe(false); + }); + + it('should set isSupported property to true when browser supports local storage', () => { + const localStore = setup({ isSupported: true }); + expect(localStore.isSupported).toBe(true); + }); + }); + + describe('setMetadata', () => { + it('should set the metadata property on LocalStore', () => { + const metadata = { version: 74 }; + const localStore = setup({ isSupported: true }); + localStore.setMetadata(metadata); + + expect(localStore.metadata).toStrictEqual(metadata); + }); + }); + + describe('set', () => { + it('should throw an error if called in a browser that does not support local storage', async () => { + const localStore = setup({ isSupported: false }); + await expect(() => localStore.set()).rejects.toThrow( + 'Metamask- cannot persist state to local store as this browser does not support this action', + ); + }); + + it('should throw an error if not passed a truthy value as an argument', async () => { + const localStore = setup({ isSupported: true }); + await expect(() => localStore.set()).rejects.toThrow( + 'MetaMask - updated state is missing', + ); + }); + + it('should throw an error if passed a valid argument but metadata has not yet been set', async () => { + const localStore = setup({ isSupported: true }); + await expect(() => + localStore.set({ appState: { test: true } }), + ).rejects.toThrow( + 'MetaMask - metadata must be set on instance of ExtensionStore before calling "set"', + ); + }); + + it('should not throw if passed a valid argument and metadata has been set', async () => { + const localStore = setup({ isSupported: true }); + localStore.setMetadata({ version: 74 }); + await expect(async function () { + localStore.set({ appState: { test: true } }); + }).not.toThrow(); + }); + }); + + describe('get', () => { + it('should return undefined if called in a browser that does not support local storage', async () => { + const localStore = setup({ isSupported: false }); + const result = await localStore.get(); + expect(result).toStrictEqual(undefined); + }); + }); +}); diff --git a/app/scripts/lib/network-store.js b/app/scripts/lib/network-store.js index abee778c1519..ea6ba5876326 100644 --- a/app/scripts/lib/network-store.js +++ b/app/scripts/lib/network-store.js @@ -50,16 +50,37 @@ export default class ReadOnlyNetworkStore { return this._state; } + /** + * Set metadata/version state + * + * @param {object} metadata - The metadata/version data to set + */ + setMetadata(metadata) { + this.metadata = metadata; + } + /** * Set state * * @param {object} state - The state to set - * @returns {Promise} */ async set(state) { + if (!this.isSupported) { + throw new Error( + 'Metamask- cannot persist state to local store as this browser does not support this action', + ); + } + if (!state) { + throw new Error('MetaMask - updated state is missing'); + } + if (!this.metadata) { + throw new Error( + 'MetaMask - metadata must be set on instance of ExtensionStore before calling "set"', + ); + } if (!this._initialized) { await this._initializing; } - this._state = state; + this._state = { data: state, meta: this._metadata }; } } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 54bb1ae570f9..05522908e8df 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -201,6 +201,9 @@ export default class MetamaskController extends EventEmitter { this.controllerMessenger = new ControllerMessenger(); + // instance of a class that wraps the extension's storage local API. + this.localStoreApiWrapper = opts.localStore; + // observable state store this.store = new ComposableObservableStore({ state: initState, @@ -3480,7 +3483,15 @@ export default class MetamaskController extends EventEmitter { this.emit('controllerConnectionChanged', this.activeControllerConnections); // set up postStream transport - outStream.on('data', createMetaRPCHandler(api, outStream)); + outStream.on( + 'data', + createMetaRPCHandler( + api, + outStream, + this.store, + this.localStoreApiWrapper, + ), + ); const handleUpdate = (update) => { if (outStream._writableState.ended) { return; From b34d24937d4435e22541583c8f5ab5b6fa3e6c1e Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 11 Oct 2022 14:18:55 +0530 Subject: [PATCH 25/33] Update provider (#16131) --- package.json | 2 +- yarn.lock | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f31176b51850..281cadd30a47 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "@metamask/metamask-eth-abis": "^3.0.0", "@metamask/obs-store": "^5.0.0", "@metamask/post-message-stream": "^4.0.0", - "@metamask/providers": "^9.0.0", + "@metamask/providers": "^10.0.0", "@metamask/rpc-methods": "^0.22.0", "@metamask/slip44": "^2.1.0", "@metamask/smart-transactions-controller": "^2.3.2", diff --git a/yarn.lock b/yarn.lock index d04837698113..a1a34d9a22fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3443,6 +3443,24 @@ "@metamask/utils" "^2.0.0" readable-stream "2.3.3" +"@metamask/providers@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-10.0.0.tgz#8858f3a0d991fe3462cd056a52a74f3ffabc9373" + integrity sha512-GAaXm8+dIN66KfD4EUETyxxmUMDTnpoOsgtoWIS8kI8PdVL1wNazMK2HD03n4b66r0c2SaFdQLxvjeSpu5TyWA== + dependencies: + "@metamask/object-multiplex" "^1.1.0" + "@metamask/safe-event-emitter" "^2.0.0" + "@types/chrome" "^0.0.136" + detect-browser "^5.2.0" + eth-rpc-errors "^4.0.2" + extension-port-stream "^2.0.1" + fast-deep-equal "^2.0.1" + is-stream "^2.0.0" + json-rpc-engine "^6.1.0" + json-rpc-middleware-stream "^4.0.0" + pump "^3.0.0" + webextension-polyfill-ts "^0.25.0" + "@metamask/providers@^9.0.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-9.1.0.tgz#ccbbfd698eeb777c5c45aee91c3ad97e20eab20b" @@ -17706,6 +17724,14 @@ json-rpc-middleware-stream@^3.0.0: "@metamask/safe-event-emitter" "^2.0.0" readable-stream "^2.3.3" +json-rpc-middleware-stream@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-4.0.0.tgz#54de6f57d795525547219c1581858962618adeeb" + integrity sha512-+s8ps2cO+zmw21W7TA9wVD/5fwNi4C2O7NzLxlrEDrfzNcs3YX76Qw2fXuQLKVFeP654CIa6nkfqkFU9o7x/3g== + dependencies: + "@metamask/safe-event-emitter" "^2.0.0" + readable-stream "^2.3.3" + json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" From d4c39006a287999527b499826ea8376a6a9b133d Mon Sep 17 00:00:00 2001 From: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com> Date: Tue, 11 Oct 2022 10:21:31 -0400 Subject: [PATCH 26/33] Data from TokenListController gets cleared when the service worker restarts (#16109) --- app/scripts/metamask-controller.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 05522908e8df..1a508d4ac2d8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -250,7 +250,9 @@ export default class MetamaskController extends EventEmitter { this.tokenListController = new TokenListController({ chainId: hexToDecimal(this.networkController.getCurrentChainId()), - preventPollingOnNetworkRestart: true, + preventPollingOnNetworkRestart: initState.TokenListController + ? initState.TokenListController.preventPollingOnNetworkRestart + : true, onNetworkStateChange: (cb) => { this.networkController.store.subscribe((networkState) => { const modifiedNetworkState = { From 3a5616e80770d00146440ef7535bb56876c7daae Mon Sep 17 00:00:00 2001 From: ryanml Date: Tue, 11 Oct 2022 07:56:03 -0700 Subject: [PATCH 27/33] Remove docs.google.com from blocked domains list (#16154) --- shared/modules/provider-injection.js | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/modules/provider-injection.js b/shared/modules/provider-injection.js index c2ce0ef7e5cd..c4d74182347c 100644 --- a/shared/modules/provider-injection.js +++ b/shared/modules/provider-injection.js @@ -71,7 +71,6 @@ function blockedDomainCheck() { 'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html', 'adyen.com', 'gravityforms.com', - 'docs.google.com', 'harbourair.com', 'ani.gamer.com.tw', 'blueskybooking.com', From d4de8eae9eee6c7893ebe15f6e0949605e0ddfa0 Mon Sep 17 00:00:00 2001 From: ryanml Date: Tue, 11 Oct 2022 07:56:15 -0700 Subject: [PATCH 28/33] Show fiat conversion by default on custom networks (#16132) --- ui/selectors/selectors.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 4d4872406ca4..5b08d39fcfb9 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -543,9 +543,12 @@ export function getShowTestNetworks(state) { export function getShouldShowFiat(state) { const isMainNet = getIsMainnet(state); + const isCustomNetwork = getIsCustomNetwork(state); const conversionRate = getConversionRate(state); const { showFiatInTestnets } = getPreferences(state); - return Boolean((isMainNet || showFiatInTestnets) && conversionRate); + return Boolean( + (isMainNet || isCustomNetwork || showFiatInTestnets) && conversionRate, + ); } export function getShouldHideZeroBalanceTokens(state) { From 6995174cbca5a6955f545b386a9041701dacbdea Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 11 Oct 2022 20:34:32 +0530 Subject: [PATCH 29/33] MV3 Segment Fix (#16020) --- app/scripts/controllers/metametrics.js | 2 +- app/scripts/lib/segment/analytics.js | 275 ++++ app/scripts/lib/segment/analytics.test.js | 116 ++ .../lib/{segment.js => segment/index.js} | 4 +- lavamoat/browserify/beta/policy.json | 79 +- lavamoat/browserify/flask/policy.json | 79 +- lavamoat/browserify/main/policy.json | 79 +- lavamoat/build-system/policy.json | 1453 +++++++++++++---- package.json | 4 +- yarn.lock | 70 +- 10 files changed, 1559 insertions(+), 602 deletions(-) create mode 100644 app/scripts/lib/segment/analytics.js create mode 100644 app/scripts/lib/segment/analytics.test.js rename app/scripts/lib/{segment.js => segment/index.js} (96%) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 55a50803e90c..77f1ef39c915 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -65,7 +65,7 @@ const exceptionsToFilter = { export default class MetaMetricsController { /** * @param {object} options - * @param {object} options.segment - an instance of analytics-node for tracking + * @param {object} options.segment - an instance of analytics for tracking * events that conform to the new MetaMetrics tracking plan. * @param {object} options.preferencesStore - The preferences controller store, used * to access and subscribe to preferences that will be attached to events diff --git a/app/scripts/lib/segment/analytics.js b/app/scripts/lib/segment/analytics.js new file mode 100644 index 000000000000..c93275f9408f --- /dev/null +++ b/app/scripts/lib/segment/analytics.js @@ -0,0 +1,275 @@ +import removeSlash from 'remove-trailing-slash'; +import looselyValidate from '@segment/loosely-validate-event'; +import { isString } from 'lodash'; +import isRetryAllowed from 'is-retry-allowed'; + +const noop = () => ({}); + +// Taken from https://stackoverflow.com/a/1349426/3696652 +const characters = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +const generateRandomId = () => { + let result = ''; + const charactersLength = characters.length; + for (let i = 0; i < 20; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +}; + +// Method below is inspired from axios-retry https://github.com/softonic/axios-retry +function isNetworkError(error) { + return ( + !error.response && + Boolean(error.code) && // Prevents retrying cancelled requests + error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests + isRetryAllowed(error) + ); // Prevents retrying unsafe errors +} + +export default class Analytics { + /** + * Initialize a new `Analytics` with Segment project's `writeKey` and an + * optional dictionary of `options`. + * + * @param {string} writeKey + * @param {object} [options] - (optional) + * @property {number} [flushAt] (default: 20) + * @property {number} [flushInterval] (default: 10000) + * @property {string} [host] (default: 'https://api.segment.io') + */ + constructor(writeKey, options = {}) { + this.writeKey = writeKey; + + this.host = removeSlash(options.host || 'https://api.segment.io'); + this.flushInterval = options.flushInterval || 10000; + this.flushAt = options.flushAt || Math.max(options.flushAt, 1) || 20; + + this.queue = []; + this.path = '/v1/batch'; + this.maxQueueSize = 1024 * 450; + this.flushed = false; + this.retryCount = 3; + + Object.defineProperty(this, 'enable', { + configurable: false, + writable: false, + enumerable: true, + value: true, + }); + } + + _validate(message, type) { + looselyValidate(message, type); + } + + _message(type, message, callback) { + this._validate(message, type); + this.enqueue(type, message, callback); + return this; + } + + /** + * Send an identify `message`. + * + * @param {object} message + * @param {Function} [callback] - (optional) + * @returns {Analytics} + */ + identify(message, callback) { + return this._message('identify', message, callback); + } + + /** + * Send a track `message`. + * + * @param {object} message + * @param {Function} [callback] - (optional) + * @returns {Analytics} + */ + track(message, callback) { + return this._message('track', message, callback); + } + + /** + * Send a page `message`. + * + * @param {object} message + * @param {Function} [callback] - (optional) + * @returns {Analytics} + */ + page(message, callback) { + return this._message('page', message, callback); + } + + /** + * Add a `message` of type `type` to the queue and + * check whether it should be flushed. + * + * @param {string} type + * @param {object} msg + * @param {Function} [callback] - (optional) + */ + enqueue(type, msg, callback = noop) { + if (!this.enable) { + setImmediate(callback); + return; + } + + const message = { ...msg, type }; + + // Specifying library here helps segment to understand structure of request. + // Currently segment seems to support these source libraries only. + message.context = { + ...message.context, + library: { + name: 'analytics-node', + }, + }; + + if (!message.timestamp) { + message.timestamp = new Date(); + } + + if (!message.messageId) { + message.messageId = generateRandomId(); + } + + if (message.anonymousId && !isString(message.anonymousId)) { + message.anonymousId = JSON.stringify(message.anonymousId); + } + if (message.userId && !isString(message.userId)) { + message.userId = JSON.stringify(message.userId); + } + this.queue.push({ message, callback }); + + if (!this.flushed) { + this.flushed = true; + this.flush(); + return; + } + + const hasReachedFlushAt = this.queue.length >= this.flushAt; + const hasReachedQueueSize = + this.queue.reduce((acc, item) => acc + JSON.stringify(item).length, 0) >= + this.maxQueueSize; + if (hasReachedFlushAt || hasReachedQueueSize) { + this.flush(); + } + + if (this.flushInterval && !this.timer) { + this.timer = setTimeout(this.flush.bind(this), this.flushInterval); + } + } + + /** + * Flush the current queue + * + * @param {Function} [callback] - (optional) + */ + flush(callback = noop) { + if (!this.enable) { + setImmediate(callback); + return Promise.resolve(); + } + + if (this.timer) { + clearTimeout(this.timer); + this.timer = null; + } + + if (!this.queue.length) { + setImmediate(callback); + return Promise.resolve(); + } + + const items = this.queue.splice(0, this.flushAt); + const callbacks = items.map((item) => item.callback); + const messages = items.map((item) => item.message); + + const data = { + batch: messages, + timestamp: new Date(), + sentAt: new Date(), + }; + + const done = (err) => { + setImmediate(() => { + callbacks.forEach((fn) => fn(err, data)); + callback(err, data); + }); + }; + + const headers = { + Authorization: `Basic ${Buffer.from(this.writeKey, 'utf8').toString( + 'base64', + )}`, + }; + + return this._sendRequest( + `${this.host}${this.path}`, + { + method: 'POST', + body: JSON.stringify(data), + headers, + }, + done, + 0, + ); + } + + _retryRequest(url, body, done, retryNo) { + const delay = Math.pow(2, retryNo) * 100; + setTimeout(() => { + this._sendRequest(url, body, done, retryNo + 1); + }, delay); + } + + async _sendRequest(url, body, done, retryNo) { + return fetch(url, body) + .then(async (response) => { + if (response.ok) { + done(); + } else if ( + this._isErrorRetryable({ response }) && + retryNo <= this.retryCount + ) { + this._retryRequest(url, body, done, retryNo); + } else { + const error = new Error(response.statusText); + done(error); + } + }) + .catch((error) => { + if (this._isErrorRetryable(error) && retryNo <= this.retryCount) { + this._retryRequest(url, body, done, retryNo); + } else { + done(error); + } + }); + } + + _isErrorRetryable(error) { + // Retry Network Errors. + if (isNetworkError(error)) { + return true; + } + + if (!error.response) { + // Cannot determine if the request can be retried + return false; + } + + // Retry Server Errors (5xx). + if (error.response.status >= 500 && error.response.status <= 599) { + return true; + } + + // Retry if rate limited. + if (error.response.status === 429) { + return true; + } + + return false; + } +} diff --git a/app/scripts/lib/segment/analytics.test.js b/app/scripts/lib/segment/analytics.test.js new file mode 100644 index 000000000000..33844bb9f6a3 --- /dev/null +++ b/app/scripts/lib/segment/analytics.test.js @@ -0,0 +1,116 @@ +import Analytics from './analytics'; + +const DUMMY_KEY = 'DUMMY_KEY'; +const DUMMY_MESSAGE = { + userId: 'userId', + idValue: 'idValue', + event: 'event', +}; +const FLUSH_INTERVAL = 10000; + +global.setImmediate = (arg) => { + arg(); +}; + +global.fetch = () => + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ success: true }), + }); + +describe('Analytics', function () { + let analytics; + + beforeEach(() => { + analytics = new Analytics(DUMMY_KEY); + }); + + describe('#flush', function () { + it('first message is immediately flushed', function () { + const mock = jest.fn(analytics.flush); + analytics.flush = mock; + analytics.track(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(0); + expect(mock).toHaveBeenCalledTimes(1); + }); + + it('after first message it is called when queue size equals flushAt value', function () { + analytics = new Analytics(DUMMY_KEY, { flushAt: 3 }); + const mock = jest.fn(analytics.flush); + analytics.flush = mock; + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(0); + expect(mock).toHaveBeenCalledTimes(2); + }); + + it('except for first message it is called until queue size is less than flushAt value', function () { + analytics = new Analytics(DUMMY_KEY, { flushAt: 3 }); + const mock = jest.fn(analytics.flush); + analytics.flush = mock; + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(2); + expect(mock).toHaveBeenCalledTimes(1); + }); + + it('after first message it is called after flushInterval is elapsed', function () { + jest.useFakeTimers(); + analytics = new Analytics(DUMMY_KEY, { flushInterval: FLUSH_INTERVAL }); + const mock = jest.fn(analytics.flush); + analytics.flush = mock; + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + jest.advanceTimersByTime(FLUSH_INTERVAL); + expect(analytics.queue).toHaveLength(0); + expect(mock).toHaveBeenCalledTimes(2); + }); + + it('after first message it is not called until flushInterval is elapsed', function () { + jest.useFakeTimers(); + analytics = new Analytics(DUMMY_KEY, { flushInterval: FLUSH_INTERVAL }); + const mock = jest.fn(analytics.flush); + analytics.flush = mock; + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + jest.advanceTimersByTime(FLUSH_INTERVAL - 100); + expect(analytics.queue).toHaveLength(1); + expect(mock).toHaveBeenCalledTimes(1); + }); + + it('invokes callbacks', async function () { + const callback = jest.fn(); + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE, callback); + await analytics.flush(); + expect(callback).toHaveBeenCalledTimes(1); + }); + }); + + describe('#track', function () { + it('adds messages to ququq', function () { + analytics.track(DUMMY_MESSAGE); + analytics.track(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(1); + }); + }); + + describe('#page', function () { + it('adds messages to ququq', function () { + analytics.page(DUMMY_MESSAGE); + analytics.page(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(1); + }); + }); + + describe('#identify', function () { + it('adds messages to ququq', function () { + analytics.identify(DUMMY_MESSAGE); + analytics.identify(DUMMY_MESSAGE); + expect(analytics.queue).toHaveLength(1); + }); + }); +}); diff --git a/app/scripts/lib/segment.js b/app/scripts/lib/segment/index.js similarity index 96% rename from app/scripts/lib/segment.js rename to app/scripts/lib/segment/index.js index 1b054333b7e4..99062b820cab 100644 --- a/app/scripts/lib/segment.js +++ b/app/scripts/lib/segment/index.js @@ -1,5 +1,5 @@ -import Analytics from 'analytics-node'; -import { SECOND } from '../../../shared/constants/time'; +import { SECOND } from '../../../../shared/constants/time'; +import Analytics from './analytics'; const SEGMENT_WRITE_KEY = process.env.SEGMENT_WRITE_KEY ?? null; const SEGMENT_HOST = process.env.SEGMENT_HOST ?? null; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 3270beda279d..2a7fc52a78a2 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1430,8 +1430,8 @@ "process": true }, "packages": { - "analytics-node>ms": true, - "browserify>process": true + "browserify>process": true, + "gulp-livereload>debug>ms": true } }, "3box>ipfs>libp2p-websocket-star-multi>libp2p-websocket-star>socket.io-pull-stream>uuid": { @@ -1859,7 +1859,7 @@ "setTimeout": true }, "packages": { - "analytics-node>ms": true + "gulp-livereload>debug>ms": true } }, "3box>ipfs>stream-to-pull-stream": { @@ -3540,6 +3540,14 @@ "redux-thunk": true } }, + "@segment/loosely-validate-event": { + "packages": { + "@segment/loosely-validate-event>component-type": true, + "@segment/loosely-validate-event>join-component": true, + "browserify>assert": true, + "browserify>buffer": true + } + }, "@sentry/browser": { "globals": { "XMLHttpRequest": true, @@ -3971,71 +3979,6 @@ "pumpify>inherits": true } }, - "analytics-node": { - "globals": { - "clearTimeout": true, - "console.log": true, - "setImmediate": true, - "setTimeout": true - }, - "packages": { - "analytics-node>@segment/loosely-validate-event": true, - "analytics-node>axios": true, - "analytics-node>axios-retry": true, - "analytics-node>lodash.isstring": true, - "analytics-node>md5": true, - "analytics-node>ms": true, - "analytics-node>remove-trailing-slash": true, - "analytics-node>uuid": true, - "browserify>assert": true, - "browserify>process": true - } - }, - "analytics-node>@segment/loosely-validate-event": { - "packages": { - "analytics-node>@segment/loosely-validate-event>component-type": true, - "analytics-node>@segment/loosely-validate-event>join-component": true, - "browserify>assert": true, - "browserify>buffer": true - } - }, - "analytics-node>axios": { - "globals": { - "FormData": true, - "URLSearchParams": true, - "XMLHttpRequest": true, - "btoa": true, - "console.warn": true, - "document": true, - "location.href": true, - "navigator": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "analytics-node>axios-retry": { - "globals": { - "setTimeout": true - }, - "packages": { - "geckodriver>got>is-retry-allowed": true - } - }, - "analytics-node>md5": { - "packages": { - "analytics-node>md5>charenc": true, - "analytics-node>md5>crypt": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "analytics-node>uuid": { - "globals": { - "crypto": true, - "msCrypto": true - } - }, "await-semaphore": { "packages": { "browserify>process": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 2302a924e8eb..23c1f2f480e7 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1430,8 +1430,8 @@ "process": true }, "packages": { - "analytics-node>ms": true, - "browserify>process": true + "browserify>process": true, + "gulp-livereload>debug>ms": true } }, "3box>ipfs>libp2p-websocket-star-multi>libp2p-websocket-star>socket.io-pull-stream>uuid": { @@ -1859,7 +1859,7 @@ "setTimeout": true }, "packages": { - "analytics-node>ms": true + "gulp-livereload>debug>ms": true } }, "3box>ipfs>stream-to-pull-stream": { @@ -4332,6 +4332,14 @@ "redux-thunk": true } }, + "@segment/loosely-validate-event": { + "packages": { + "@segment/loosely-validate-event>component-type": true, + "@segment/loosely-validate-event>join-component": true, + "browserify>assert": true, + "browserify>buffer": true + } + }, "@sentry/browser": { "globals": { "XMLHttpRequest": true, @@ -4763,71 +4771,6 @@ "pumpify>inherits": true } }, - "analytics-node": { - "globals": { - "clearTimeout": true, - "console.log": true, - "setImmediate": true, - "setTimeout": true - }, - "packages": { - "analytics-node>@segment/loosely-validate-event": true, - "analytics-node>axios": true, - "analytics-node>axios-retry": true, - "analytics-node>lodash.isstring": true, - "analytics-node>md5": true, - "analytics-node>ms": true, - "analytics-node>remove-trailing-slash": true, - "analytics-node>uuid": true, - "browserify>assert": true, - "browserify>process": true - } - }, - "analytics-node>@segment/loosely-validate-event": { - "packages": { - "analytics-node>@segment/loosely-validate-event>component-type": true, - "analytics-node>@segment/loosely-validate-event>join-component": true, - "browserify>assert": true, - "browserify>buffer": true - } - }, - "analytics-node>axios": { - "globals": { - "FormData": true, - "URLSearchParams": true, - "XMLHttpRequest": true, - "btoa": true, - "console.warn": true, - "document": true, - "location.href": true, - "navigator": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "analytics-node>axios-retry": { - "globals": { - "setTimeout": true - }, - "packages": { - "geckodriver>got>is-retry-allowed": true - } - }, - "analytics-node>md5": { - "packages": { - "analytics-node>md5>charenc": true, - "analytics-node>md5>crypt": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "analytics-node>uuid": { - "globals": { - "crypto": true, - "msCrypto": true - } - }, "await-semaphore": { "packages": { "browserify>process": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 3270beda279d..2a7fc52a78a2 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1430,8 +1430,8 @@ "process": true }, "packages": { - "analytics-node>ms": true, - "browserify>process": true + "browserify>process": true, + "gulp-livereload>debug>ms": true } }, "3box>ipfs>libp2p-websocket-star-multi>libp2p-websocket-star>socket.io-pull-stream>uuid": { @@ -1859,7 +1859,7 @@ "setTimeout": true }, "packages": { - "analytics-node>ms": true + "gulp-livereload>debug>ms": true } }, "3box>ipfs>stream-to-pull-stream": { @@ -3540,6 +3540,14 @@ "redux-thunk": true } }, + "@segment/loosely-validate-event": { + "packages": { + "@segment/loosely-validate-event>component-type": true, + "@segment/loosely-validate-event>join-component": true, + "browserify>assert": true, + "browserify>buffer": true + } + }, "@sentry/browser": { "globals": { "XMLHttpRequest": true, @@ -3971,71 +3979,6 @@ "pumpify>inherits": true } }, - "analytics-node": { - "globals": { - "clearTimeout": true, - "console.log": true, - "setImmediate": true, - "setTimeout": true - }, - "packages": { - "analytics-node>@segment/loosely-validate-event": true, - "analytics-node>axios": true, - "analytics-node>axios-retry": true, - "analytics-node>lodash.isstring": true, - "analytics-node>md5": true, - "analytics-node>ms": true, - "analytics-node>remove-trailing-slash": true, - "analytics-node>uuid": true, - "browserify>assert": true, - "browserify>process": true - } - }, - "analytics-node>@segment/loosely-validate-event": { - "packages": { - "analytics-node>@segment/loosely-validate-event>component-type": true, - "analytics-node>@segment/loosely-validate-event>join-component": true, - "browserify>assert": true, - "browserify>buffer": true - } - }, - "analytics-node>axios": { - "globals": { - "FormData": true, - "URLSearchParams": true, - "XMLHttpRequest": true, - "btoa": true, - "console.warn": true, - "document": true, - "location.href": true, - "navigator": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "analytics-node>axios-retry": { - "globals": { - "setTimeout": true - }, - "packages": { - "geckodriver>got>is-retry-allowed": true - } - }, - "analytics-node>md5": { - "packages": { - "analytics-node>md5>charenc": true, - "analytics-node>md5>crypt": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "analytics-node>uuid": { - "globals": { - "crypto": true, - "msCrypto": true - } - }, "await-semaphore": { "packages": { "browserify>process": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 8ef7fd2736ed..600dd2b65905 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1809,6 +1809,7 @@ }, "packages": { "chokidar>braces": true, + "chokidar>fsevents": true, "chokidar>glob-parent": true, "chokidar>is-binary-path": true, "chokidar>normalize-path": true, @@ -1835,6 +1836,12 @@ "chokidar>braces>fill-range>to-regex-range>is-number": true } }, + "chokidar>fsevents": { + "globals": { + "process.platform": true + }, + "native": true + }, "chokidar>glob-parent": { "builtin": { "os.platform": true, @@ -2279,7 +2286,7 @@ "process": true }, "packages": { - "analytics-node>ms": true, + "gulp-livereload>debug>ms": true, "sinon>supports-color": true } }, @@ -2392,7 +2399,7 @@ "process": true }, "packages": { - "analytics-node>ms": true, + "gulp-livereload>debug>ms": true, "sinon>supports-color": true } }, @@ -3456,8 +3463,8 @@ "process": true }, "packages": { - "analytics-node>ms": true, - "gulp-livereload>chalk>supports-color": true + "gulp-livereload>chalk>supports-color": true, + "gulp-livereload>debug>ms": true } }, "gulp-livereload>event-stream": { @@ -3583,7 +3590,7 @@ "process": true }, "packages": { - "analytics-node>ms": true, + "gulp-livereload>debug>ms": true, "sinon>supports-color": true } }, @@ -3908,7 +3915,7 @@ "process": true }, "packages": { - "analytics-node>ms": true, + "gulp-livereload>debug>ms": true, "sinon>supports-color": true } }, @@ -4242,6 +4249,7 @@ "gulp-watch>chokidar>anymatch": true, "gulp-watch>chokidar>async-each": true, "gulp-watch>chokidar>braces": true, + "gulp-watch>chokidar>fsevents": true, "gulp-watch>chokidar>is-binary-path": true, "gulp-watch>chokidar>normalize-path": true, "gulp-watch>chokidar>readdirp": true, @@ -4390,552 +4398,1319 @@ "webpack>micromatch>braces>fill-range>repeat-string": true } }, - "gulp-watch>chokidar>is-binary-path": { - "builtin": { - "path.extname": true - }, - "packages": { - "gulp-watch>chokidar>is-binary-path>binary-extensions": true - } - }, - "gulp-watch>chokidar>readdirp": { + "gulp-watch>chokidar>fsevents": { "builtin": { + "events.EventEmitter": true, + "fs.stat": true, "path.join": true, - "path.relative": true, "util.inherits": true }, "globals": { + "__dirname": true, + "process.nextTick": true, + "process.platform": true, "setImmediate": true }, "packages": { - "fs-extra>graceful-fs": true, - "gulp-watch>chokidar>readdirp>micromatch": true, - "readable-stream": true + "gulp-watch>chokidar>fsevents>node-pre-gyp": true } }, - "gulp-watch>chokidar>readdirp>micromatch": { + "gulp-watch>chokidar>fsevents>node-pre-gyp": { "builtin": { - "path.basename": true, - "path.sep": true, - "util.inspect": true + "events.EventEmitter": true, + "fs.existsSync": true, + "fs.readFileSync": true, + "fs.renameSync": true, + "path.dirname": true, + "path.existsSync": true, + "path.join": true, + "path.resolve": true, + "url.parse": true, + "url.resolve": true, + "util.inherits": true }, "globals": { - "process.platform": true + "__dirname": true, + "console.log": true, + "process.arch": true, + "process.cwd": true, + "process.env": true, + "process.platform": true, + "process.version.substr": true, + "process.versions": true }, "packages": { - "gulp-watch>chokidar>braces": true, - "gulp-watch>chokidar>readdirp>micromatch>arr-diff": true, - "gulp-watch>chokidar>readdirp>micromatch>array-unique": true, - "gulp-watch>chokidar>readdirp>micromatch>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extend-shallow": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob": true, - "gulp-watch>chokidar>readdirp>micromatch>kind-of": true, - "webpack>micromatch>fragment-cache": true, - "webpack>micromatch>nanomatch": true, - "webpack>micromatch>object.pick": true, - "webpack>micromatch>regex-not": true, - "webpack>micromatch>snapdragon": true, - "webpack>micromatch>to-regex": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>define-property": { - "packages": { - "gulp>gulp-cli>isobject": true, - "webpack>micromatch>define-property>is-descriptor": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>detect-libc": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extend-shallow": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extend-shallow>is-extendable": true, - "webpack>micromatch>extend-shallow>assign-symbols": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>detect-libc": { + "builtin": { + "child_process.spawnSync": true, + "fs.readdirSync": true, + "os.platform": true + }, + "globals": { + "process.env": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extend-shallow>is-extendable": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt": { + "builtin": { + "path": true, + "stream.Stream": true, + "url": true + }, + "globals": { + "console": true, + "process.argv": true, + "process.env.DEBUG_NOPT": true, + "process.env.NOPT_DEBUG": true, + "process.platform": true + }, "packages": { - "@babel/register>clone-deep>is-plain-object": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>abbrev": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv": { + "builtin": { + "child_process.exec": true, + "path": true + }, + "globals": { + "process.env.COMPUTERNAME": true, + "process.env.ComSpec": true, + "process.env.EDITOR": true, + "process.env.HOSTNAME": true, + "process.env.PATH": true, + "process.env.PROMPT": true, + "process.env.PS1": true, + "process.env.Path": true, + "process.env.SHELL": true, + "process.env.USER": true, + "process.env.USERDOMAIN": true, + "process.env.USERNAME": true, + "process.env.VISUAL": true, + "process.env.path": true, + "process.nextTick": true, + "process.platform": true + }, "packages": { - "gulp-watch>chokidar>readdirp>micromatch>array-unique": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": true, - "webpack>micromatch>fragment-cache": true, - "webpack>micromatch>regex-not": true, - "webpack>micromatch>snapdragon": true, - "webpack>micromatch>to-regex": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": { - "packages": { - "webpack>micromatch>define-property>is-descriptor": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": { + "builtin": { + "os.homedir": true + }, + "globals": { + "process.env": true, + "process.getuid": true, + "process.platform": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": { "globals": { - "__filename": true - }, - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": true, - "webpack>micromatch>extglob>expand-brackets>posix-character-classes": true, - "webpack>micromatch>regex-not": true, - "webpack>micromatch>snapdragon": true, - "webpack>micromatch>to-regex": true + "process.env.SystemRoot": true, + "process.env.TEMP": true, + "process.env.TMP": true, + "process.env.TMPDIR": true, + "process.env.windir": true, + "process.platform": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": { "builtin": { - "fs.SyncWriteStream": true, - "net.Socket": true, - "tty.WriteStream": true, - "tty.isatty": true, + "events.EventEmitter": true, "util": true }, "globals": { - "chrome": true, - "console": true, - "document": true, - "localStorage": true, - "navigator": true, - "process": true + "process.nextTick": true, + "process.stderr": true }, "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug>ms": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>console-control-strings": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>set-blocking": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": { + "builtin": { + "events.EventEmitter": true, + "util.inherits": true + }, "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>kind-of": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>delegates": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, "packages": { - "gulp-watch>anymatch>micromatch>kind-of": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>core-util-is": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>isarray": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>process-nextick-args": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>string_decoder": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>util-deprecate": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": { - "packages": { - "gulp-watch>anymatch>micromatch>kind-of": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>core-util-is": { + "globals": { + "Buffer.isBuffer": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow>is-extendable": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>process-nextick-args": { + "globals": { + "process": true } }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>string_decoder": { "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow>is-extendable": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": true } }, - "gulp-watch>chokidar>upath": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>util-deprecate": { "builtin": { - "path": true + "util.deprecate": true } }, - "gulp-watch>fancy-log": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": { + "builtin": { + "util.format": true + }, "globals": { - "console": true, - "process.argv.indexOf": true, - "process.stderr.write": true, - "process.stdout.write": true + "clearInterval": true, + "process": true, + "setImmediate": true, + "setInterval": true }, "packages": { - "fancy-log>ansi-gray": true, - "fancy-log>color-support": true, - "fancy-log>time-stamp": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>console-control-strings": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>aproba": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>has-unicode": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>object-assign": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>signal-exit": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>wide-align": true } }, - "gulp-watch>glob-parent": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>has-unicode": { "builtin": { - "os.platform": true, - "path": true + "os.type": true }, - "packages": { - "gulp-watch>glob-parent>is-glob": true, - "gulp-watch>glob-parent>path-dirname": true - } - }, - "gulp-watch>glob-parent>is-glob": { - "packages": { - "gulp-watch>glob-parent>is-glob>is-extglob": true + "globals": { + "process.env.LANG": true, + "process.env.LC_ALL": true, + "process.env.LC_CTYPE": true } }, - "gulp-watch>glob-parent>path-dirname": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>signal-exit": { "builtin": { - "path": true, - "util.inspect": true + "assert.equal": true, + "events": true }, "globals": { - "process.platform": true + "process": true } }, - "gulp-watch>path-is-absolute": { - "globals": { - "process.platform": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>code-point-at": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true } }, - "gulp-watch>vinyl-file": { - "builtin": { - "path.resolve": true - }, - "globals": { - "process.cwd": true - }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": { "packages": { - "del>globby>pinkie-promise": true, - "fs-extra>graceful-fs": true, - "gulp-watch>vinyl-file>pify": true, - "gulp-watch>vinyl-file>strip-bom": true, - "gulp-watch>vinyl-file>strip-bom-stream": true, - "gulp-watch>vinyl-file>vinyl": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point>number-is-nan": true } }, - "gulp-watch>vinyl-file>strip-bom": { - "globals": { - "Buffer.isBuffer": true - }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": { "packages": { - "gulp>vinyl-fs>remove-bom-buffer>is-utf8": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi>ansi-regex": true } }, - "gulp-watch>vinyl-file>strip-bom-stream": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>wide-align": { "packages": { - "gulp-watch>vinyl-file>strip-bom": true, - "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true } }, - "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>set-blocking": { + "globals": { + "process.stderr": true, + "process.stdout": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": { "builtin": { - "util.inherits": true + "assert": true, + "fs": true, + "path.join": true }, "globals": { - "Buffer.concat": true, - "setImmediate": true + "process.platform": true, + "setTimeout": true }, "packages": { - "readable-stream": true + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": true } }, - "gulp-watch>vinyl-file>vinyl": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": { + "builtin": { + "assert": true, + "events.EventEmitter": true, + "fs.lstat": true, + "fs.lstatSync": true, + "fs.readdir": true, + "fs.readdirSync": true, + "fs.stat": true, + "fs.statSync": true, + "path.join": true, + "path.resolve": true, + "util": true + }, + "globals": { + "console.error": true, + "process.cwd": true, + "process.nextTick": true, + "process.platform": true + }, + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>fs.realpath": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>inflight": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>path-is-absolute": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>fs.realpath": { + "builtin": { + "fs.lstat": true, + "fs.lstatSync": true, + "fs.readlink": true, + "fs.readlinkSync": true, + "fs.realpath": true, + "fs.realpathSync": true, + "fs.stat": true, + "fs.statSync": true, + "path.normalize": true, + "path.resolve": true + }, + "globals": { + "console.error": true, + "console.trace": true, + "process.env.NODE_DEBUG": true, + "process.nextTick": true, + "process.noDeprecation": true, + "process.platform": true, + "process.throwDeprecation": true, + "process.traceDeprecation": true, + "process.version": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>inflight": { + "globals": { + "process.nextTick": true + }, + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>once>wrappy": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": { + "builtin": { + "util.inherits": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch": { + "builtin": { + "path": true + }, + "globals": { + "console.error": true + }, + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion>balanced-match": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion>concat-map": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>once>wrappy": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob>path-is-absolute": { + "globals": { + "process.platform": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": { + "globals": { + "console": true, + "process": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-watch>chokidar>is-binary-path": { + "builtin": { + "path.extname": true + }, + "packages": { + "gulp-watch>chokidar>is-binary-path>binary-extensions": true + } + }, + "gulp-watch>chokidar>readdirp": { + "builtin": { + "path.join": true, + "path.relative": true, + "util.inherits": true + }, + "globals": { + "setImmediate": true + }, + "packages": { + "fs-extra>graceful-fs": true, + "gulp-watch>chokidar>readdirp>micromatch": true, + "readable-stream": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch": { + "builtin": { + "path.basename": true, + "path.sep": true, + "util.inspect": true + }, + "globals": { + "process.platform": true + }, + "packages": { + "gulp-watch>chokidar>braces": true, + "gulp-watch>chokidar>readdirp>micromatch>arr-diff": true, + "gulp-watch>chokidar>readdirp>micromatch>array-unique": true, + "gulp-watch>chokidar>readdirp>micromatch>define-property": true, + "gulp-watch>chokidar>readdirp>micromatch>extend-shallow": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob": true, + "gulp-watch>chokidar>readdirp>micromatch>kind-of": true, + "webpack>micromatch>fragment-cache": true, + "webpack>micromatch>nanomatch": true, + "webpack>micromatch>object.pick": true, + "webpack>micromatch>regex-not": true, + "webpack>micromatch>snapdragon": true, + "webpack>micromatch>to-regex": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>define-property": { + "packages": { + "gulp>gulp-cli>isobject": true, + "webpack>micromatch>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extend-shallow": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extend-shallow>is-extendable": true, + "webpack>micromatch>extend-shallow>assign-symbols": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extend-shallow>is-extendable": { + "packages": { + "@babel/register>clone-deep>is-plain-object": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>array-unique": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": true, + "webpack>micromatch>fragment-cache": true, + "webpack>micromatch>regex-not": true, + "webpack>micromatch>snapdragon": true, + "webpack>micromatch>to-regex": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": { + "packages": { + "webpack>micromatch>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": { + "globals": { + "__filename": true + }, + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": true, + "webpack>micromatch>extglob>expand-brackets>posix-character-classes": true, + "webpack>micromatch>regex-not": true, + "webpack>micromatch>snapdragon": true, + "webpack>micromatch>to-regex": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": { + "builtin": { + "fs.SyncWriteStream": true, + "net.Socket": true, + "tty.WriteStream": true, + "tty.isatty": true, + "util": true + }, + "globals": { + "chrome": true, + "console": true, + "document": true, + "localStorage": true, + "navigator": true, + "process": true + }, + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug>ms": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": true, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>kind-of": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": { + "packages": { + "gulp-watch>anymatch>micromatch>kind-of": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": { + "packages": { + "gulp-watch>anymatch>micromatch>kind-of": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow>is-extendable": true + } + }, + "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": { + "packages": { + "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow>is-extendable": true + } + }, + "gulp-watch>chokidar>upath": { + "builtin": { + "path": true + } + }, + "gulp-watch>fancy-log": { + "globals": { + "console": true, + "process.argv.indexOf": true, + "process.stderr.write": true, + "process.stdout.write": true + }, + "packages": { + "fancy-log>ansi-gray": true, + "fancy-log>color-support": true, + "fancy-log>time-stamp": true + } + }, + "gulp-watch>glob-parent": { + "builtin": { + "os.platform": true, + "path": true + }, + "packages": { + "gulp-watch>glob-parent>is-glob": true, + "gulp-watch>glob-parent>path-dirname": true + } + }, + "gulp-watch>glob-parent>is-glob": { + "packages": { + "gulp-watch>glob-parent>is-glob>is-extglob": true + } + }, + "gulp-watch>glob-parent>path-dirname": { + "builtin": { + "path": true, + "util.inspect": true + }, + "globals": { + "process.platform": true + } + }, + "gulp-watch>path-is-absolute": { + "globals": { + "process.platform": true + } + }, + "gulp-watch>vinyl-file": { + "builtin": { + "path.resolve": true + }, + "globals": { + "process.cwd": true + }, + "packages": { + "del>globby>pinkie-promise": true, + "fs-extra>graceful-fs": true, + "gulp-watch>vinyl-file>pify": true, + "gulp-watch>vinyl-file>strip-bom": true, + "gulp-watch>vinyl-file>strip-bom-stream": true, + "gulp-watch>vinyl-file>vinyl": true + } + }, + "gulp-watch>vinyl-file>strip-bom": { + "globals": { + "Buffer.isBuffer": true + }, + "packages": { + "gulp>vinyl-fs>remove-bom-buffer>is-utf8": true + } + }, + "gulp-watch>vinyl-file>strip-bom-stream": { + "packages": { + "gulp-watch>vinyl-file>strip-bom": true, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream": true + } + }, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream": { + "builtin": { + "util.inherits": true + }, + "globals": { + "Buffer.concat": true, + "setImmediate": true + }, + "packages": { + "readable-stream": true + } + }, + "gulp-watch>vinyl-file>vinyl": { + "builtin": { + "buffer.Buffer": true, + "path.basename": true, + "path.dirname": true, + "path.extname": true, + "path.join": true, + "path.relative": true, + "stream.PassThrough": true, + "stream.Stream": true + }, + "globals": { + "process.cwd": true + }, + "packages": { + "gulp-watch>vinyl-file>vinyl>clone": true, + "gulp-watch>vinyl-file>vinyl>clone-stats": true, + "gulp-watch>vinyl-file>vinyl>replace-ext": true + } + }, + "gulp-watch>vinyl-file>vinyl>clone": { + "globals": { + "Buffer": true + } + }, + "gulp-watch>vinyl-file>vinyl>clone-stats": { + "builtin": { + "fs.Stats": true + } + }, + "gulp-watch>vinyl-file>vinyl>replace-ext": { + "builtin": { + "path.basename": true, + "path.dirname": true, + "path.extname": true, + "path.join": true + } + }, + "gulp-zip": { + "builtin": { + "buffer.constants.MAX_LENGTH": true, + "path.join": true + }, + "packages": { + "gulp-zip>get-stream": true, + "gulp-zip>plugin-error": true, + "gulp-zip>through2": true, + "gulp-zip>yazl": true, + "vinyl": true + } + }, + "gulp-zip>get-stream": { + "builtin": { + "buffer.constants.MAX_LENGTH": true, + "stream.PassThrough": true + }, + "globals": { + "Buffer.concat": true + }, + "packages": { + "pump": true + } + }, + "gulp-zip>plugin-error": { + "builtin": { + "util.inherits": true + }, + "packages": { + "gulp-watch>ansi-colors": true, + "gulp-zip>plugin-error>arr-union": true, + "gulp-zip>plugin-error>extend-shallow": true, + "webpack>micromatch>arr-diff": true + } + }, + "gulp-zip>plugin-error>extend-shallow": { + "packages": { + "gulp-zip>plugin-error>extend-shallow>is-extendable": true, + "webpack>micromatch>extend-shallow>assign-symbols": true + } + }, + "gulp-zip>plugin-error>extend-shallow>is-extendable": { + "packages": { + "@babel/register>clone-deep>is-plain-object": true + } + }, + "gulp-zip>through2": { + "builtin": { + "util.inherits": true + }, + "globals": { + "process.nextTick": true + }, + "packages": { + "gulp-zip>through2>readable-stream": true + } + }, + "gulp-zip>through2>readable-stream": { "builtin": { "buffer.Buffer": true, + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.env.READABLE_STREAM": true, + "process.nextTick": true, + "process.stderr": true, + "process.stdout": true + }, + "packages": { + "@storybook/api>util-deprecate": true, + "browserify>string_decoder": true, + "pumpify>inherits": true + } + }, + "gulp-zip>yazl": { + "builtin": { + "events.EventEmitter": true, + "fs.createReadStream": true, + "fs.stat": true, + "stream.PassThrough": true, + "stream.Transform": true, + "util.inherits": true, + "zlib.DeflateRaw": true, + "zlib.deflateRaw": true + }, + "globals": { + "Buffer": true, + "setImmediate": true, + "utf8FileName.length": true + }, + "packages": { + "gulp-zip>yazl>buffer-crc32": true + } + }, + "gulp-zip>yazl>buffer-crc32": { + "builtin": { + "buffer.Buffer": true + } + }, + "gulp>glob-watcher": { + "packages": { + "gulp>glob-watcher>anymatch": true, + "gulp>glob-watcher>async-done": true, + "gulp>glob-watcher>chokidar": true, + "gulp>glob-watcher>is-negated-glob": true, + "gulp>glob-watcher>just-debounce": true, + "gulp>undertaker>object.defaults": true + } + }, + "gulp>glob-watcher>anymatch": { + "builtin": { + "path.sep": true + }, + "packages": { + "gulp>glob-watcher>anymatch>micromatch": true, + "gulp>glob-watcher>anymatch>normalize-path": true + } + }, + "gulp>glob-watcher>anymatch>micromatch": { + "builtin": { + "path.basename": true, + "path.sep": true, + "util.inspect": true + }, + "globals": { + "process.platform": true + }, + "packages": { + "3box>ipfs>kind-of": true, + "gulp>glob-watcher>anymatch>micromatch>define-property": true, + "gulp>glob-watcher>anymatch>micromatch>extend-shallow": true, + "gulp>glob-watcher>chokidar>braces": true, + "webpack>micromatch>arr-diff": true, + "webpack>micromatch>array-unique": true, + "webpack>micromatch>extglob": true, + "webpack>micromatch>fragment-cache": true, + "webpack>micromatch>nanomatch": true, + "webpack>micromatch>object.pick": true, + "webpack>micromatch>regex-not": true, + "webpack>micromatch>snapdragon": true, + "webpack>micromatch>to-regex": true + } + }, + "gulp>glob-watcher>anymatch>micromatch>define-property": { + "packages": { + "gulp>gulp-cli>isobject": true, + "webpack>micromatch>define-property>is-descriptor": true + } + }, + "gulp>glob-watcher>anymatch>micromatch>extend-shallow": { + "packages": { + "gulp>glob-watcher>anymatch>micromatch>extend-shallow>is-extendable": true, + "webpack>micromatch>extend-shallow>assign-symbols": true + } + }, + "gulp>glob-watcher>anymatch>micromatch>extend-shallow>is-extendable": { + "packages": { + "@babel/register>clone-deep>is-plain-object": true + } + }, + "gulp>glob-watcher>anymatch>normalize-path": { + "packages": { + "vinyl>remove-trailing-separator": true + } + }, + "gulp>glob-watcher>async-done": { + "builtin": { + "domain.create": true + }, + "globals": { + "process.nextTick": true + }, + "packages": { + "end-of-stream": true, + "gulp>glob-watcher>async-done>process-nextick-args": true, + "gulp>glob-watcher>async-done>stream-exhaust": true, + "pump>once": true + } + }, + "gulp>glob-watcher>async-done>process-nextick-args": { + "globals": { + "process": true + } + }, + "gulp>glob-watcher>async-done>stream-exhaust": { + "builtin": { + "stream.Writable": true, + "util.inherits": true + }, + "globals": { + "setImmediate": true + } + }, + "gulp>glob-watcher>chokidar": { + "builtin": { + "events.EventEmitter": true, + "fs": true, "path.basename": true, "path.dirname": true, "path.extname": true, "path.join": true, "path.relative": true, - "stream.PassThrough": true, - "stream.Stream": true + "path.resolve": true, + "path.sep": true }, "globals": { - "process.cwd": true + "clearTimeout": true, + "console.error": true, + "process.env.CHOKIDAR_INTERVAL": true, + "process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR": true, + "process.env.CHOKIDAR_USEPOLLING": true, + "process.nextTick": true, + "process.platform": true, + "setTimeout": true }, "packages": { - "gulp-watch>vinyl-file>vinyl>clone": true, - "gulp-watch>vinyl-file>vinyl>clone-stats": true, - "gulp-watch>vinyl-file>vinyl>replace-ext": true + "eslint>is-glob": true, + "gulp-watch>chokidar>async-each": true, + "gulp-watch>glob-parent": true, + "gulp-watch>path-is-absolute": true, + "gulp>glob-watcher>anymatch": true, + "gulp>glob-watcher>chokidar>braces": true, + "gulp>glob-watcher>chokidar>fsevents": true, + "gulp>glob-watcher>chokidar>is-binary-path": true, + "gulp>glob-watcher>chokidar>normalize-path": true, + "gulp>glob-watcher>chokidar>readdirp": true, + "gulp>glob-watcher>chokidar>upath": true, + "pumpify>inherits": true } }, - "gulp-watch>vinyl-file>vinyl>clone": { - "globals": { - "Buffer": true + "gulp>glob-watcher>chokidar>braces": { + "packages": { + "gulp>glob-watcher>chokidar>braces>fill-range": true, + "gulp>gulp-cli>isobject": true, + "gulp>undertaker>arr-flatten": true, + "webpack>micromatch>array-unique": true, + "webpack>micromatch>braces>repeat-element": true, + "webpack>micromatch>braces>snapdragon-node": true, + "webpack>micromatch>braces>split-string": true, + "webpack>micromatch>extglob>extend-shallow": true, + "webpack>micromatch>snapdragon": true, + "webpack>micromatch>to-regex": true } }, - "gulp-watch>vinyl-file>vinyl>clone-stats": { + "gulp>glob-watcher>chokidar>braces>fill-range": { "builtin": { - "fs.Stats": true + "util.inspect": true + }, + "packages": { + "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, + "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": true, + "webpack>micromatch>braces>fill-range>repeat-string": true, + "webpack>micromatch>extglob>extend-shallow": true } }, - "gulp-watch>vinyl-file>vinyl>replace-ext": { + "gulp>glob-watcher>chokidar>braces>fill-range>is-number": { + "packages": { + "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": true + } + }, + "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": { + "packages": { + "browserify>insert-module-globals>is-buffer": true + } + }, + "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": { + "packages": { + "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, + "webpack>micromatch>braces>fill-range>repeat-string": true + } + }, + "gulp>glob-watcher>chokidar>fsevents": { "builtin": { - "path.basename": true, + "events.EventEmitter": true, + "fs.stat": true, + "path.join": true, + "util.inherits": true + }, + "globals": { + "__dirname": true, + "process.nextTick": true, + "process.platform": true, + "setImmediate": true + }, + "packages": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp": { + "builtin": { + "events.EventEmitter": true, + "fs.existsSync": true, + "fs.readFileSync": true, + "fs.renameSync": true, "path.dirname": true, - "path.extname": true, - "path.join": true + "path.existsSync": true, + "path.join": true, + "path.resolve": true, + "url.parse": true, + "url.resolve": true, + "util.inherits": true + }, + "globals": { + "__dirname": true, + "console.log": true, + "process.arch": true, + "process.cwd": true, + "process.env": true, + "process.platform": true, + "process.version.substr": true, + "process.versions": true + }, + "packages": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>detect-libc": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>semver": true } }, - "gulp-zip": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>detect-libc": { "builtin": { - "buffer.constants.MAX_LENGTH": true, - "path.join": true + "child_process.spawnSync": true, + "fs.readdirSync": true, + "os.platform": true + }, + "globals": { + "process.env": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt": { + "builtin": { + "path": true, + "stream.Stream": true, + "url": true + }, + "globals": { + "console": true, + "process.argv": true, + "process.env.DEBUG_NOPT": true, + "process.env.NOPT_DEBUG": true, + "process.platform": true }, "packages": { - "gulp-zip>get-stream": true, - "gulp-zip>plugin-error": true, - "gulp-zip>through2": true, - "gulp-zip>yazl": true, - "vinyl": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>abbrev": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv": true } }, - "gulp-zip>get-stream": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv": { "builtin": { - "buffer.constants.MAX_LENGTH": true, - "stream.PassThrough": true + "child_process.exec": true, + "path": true }, "globals": { - "Buffer.concat": true + "process.env.COMPUTERNAME": true, + "process.env.ComSpec": true, + "process.env.EDITOR": true, + "process.env.HOSTNAME": true, + "process.env.PATH": true, + "process.env.PROMPT": true, + "process.env.PS1": true, + "process.env.Path": true, + "process.env.SHELL": true, + "process.env.USER": true, + "process.env.USERDOMAIN": true, + "process.env.USERNAME": true, + "process.env.VISUAL": true, + "process.env.path": true, + "process.nextTick": true, + "process.platform": true }, "packages": { - "pump": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": true } }, - "gulp-zip>plugin-error": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": { "builtin": { - "util.inherits": true + "os.homedir": true }, - "packages": { - "gulp-watch>ansi-colors": true, - "gulp-zip>plugin-error>arr-union": true, - "gulp-zip>plugin-error>extend-shallow": true, - "webpack>micromatch>arr-diff": true + "globals": { + "process.env": true, + "process.getuid": true, + "process.platform": true } }, - "gulp-zip>plugin-error>extend-shallow": { - "packages": { - "gulp-zip>plugin-error>extend-shallow>is-extendable": true, - "webpack>micromatch>extend-shallow>assign-symbols": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": { + "globals": { + "process.env.SystemRoot": true, + "process.env.TEMP": true, + "process.env.TMP": true, + "process.env.TMPDIR": true, + "process.env.windir": true, + "process.platform": true } }, - "gulp-zip>plugin-error>extend-shallow>is-extendable": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog": { + "builtin": { + "events.EventEmitter": true, + "util": true + }, + "globals": { + "process.nextTick": true, + "process.stderr": true + }, "packages": { - "@babel/register>clone-deep>is-plain-object": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>console-control-strings": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>set-blocking": true } }, - "gulp-zip>through2": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": { "builtin": { + "events.EventEmitter": true, "util.inherits": true }, - "globals": { - "process.nextTick": true - }, "packages": { - "gulp-zip>through2>readable-stream": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>delegates": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream": true } }, - "gulp-zip>through2>readable-stream": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream": { "builtin": { - "buffer.Buffer": true, "events.EventEmitter": true, "stream": true, "util": true }, "globals": { + "process.browser": true, "process.env.READABLE_STREAM": true, - "process.nextTick": true, "process.stderr": true, - "process.stdout": true + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true }, "packages": { - "@storybook/api>util-deprecate": true, - "browserify>string_decoder": true, - "pumpify>inherits": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>core-util-is": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>isarray": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>process-nextick-args": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>string_decoder": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>util-deprecate": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": true } }, - "gulp-zip>yazl": { - "builtin": { - "events.EventEmitter": true, - "fs.createReadStream": true, - "fs.stat": true, - "stream.PassThrough": true, - "stream.Transform": true, - "util.inherits": true, - "zlib.DeflateRaw": true, - "zlib.deflateRaw": true - }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>core-util-is": { "globals": { - "Buffer": true, - "setImmediate": true, - "utf8FileName.length": true - }, - "packages": { - "gulp-zip>yazl>buffer-crc32": true + "Buffer.isBuffer": true } }, - "gulp-zip>yazl>buffer-crc32": { - "builtin": { - "buffer.Buffer": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>process-nextick-args": { + "globals": { + "process": true } }, - "gulp>glob-watcher": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>string_decoder": { "packages": { - "gulp>glob-watcher>anymatch": true, - "gulp>glob-watcher>async-done": true, - "gulp>glob-watcher>chokidar": true, - "gulp>glob-watcher>is-negated-glob": true, - "gulp>glob-watcher>just-debounce": true, - "gulp>undertaker>object.defaults": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": true } }, - "gulp>glob-watcher>anymatch": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet>readable-stream>util-deprecate": { "builtin": { - "path.sep": true - }, - "packages": { - "gulp>glob-watcher>anymatch>micromatch": true, - "gulp>glob-watcher>anymatch>normalize-path": true + "util.deprecate": true } }, - "gulp>glob-watcher>anymatch>micromatch": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge": { "builtin": { - "path.basename": true, - "path.sep": true, - "util.inspect": true + "util.format": true }, "globals": { - "process.platform": true + "clearInterval": true, + "process": true, + "setImmediate": true, + "setInterval": true }, "packages": { - "3box>ipfs>kind-of": true, - "gulp>glob-watcher>anymatch>micromatch>define-property": true, - "gulp>glob-watcher>anymatch>micromatch>extend-shallow": true, - "gulp>glob-watcher>chokidar>braces": true, - "webpack>micromatch>arr-diff": true, - "webpack>micromatch>array-unique": true, - "webpack>micromatch>extglob": true, - "webpack>micromatch>fragment-cache": true, - "webpack>micromatch>nanomatch": true, - "webpack>micromatch>object.pick": true, - "webpack>micromatch>regex-not": true, - "webpack>micromatch>snapdragon": true, - "webpack>micromatch>to-regex": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>console-control-strings": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>aproba": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>has-unicode": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>object-assign": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>signal-exit": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>wide-align": true } }, - "gulp>glob-watcher>anymatch>micromatch>define-property": { - "packages": { - "gulp>gulp-cli>isobject": true, - "webpack>micromatch>define-property>is-descriptor": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>has-unicode": { + "builtin": { + "os.type": true + }, + "globals": { + "process.env.LANG": true, + "process.env.LC_ALL": true, + "process.env.LC_CTYPE": true } }, - "gulp>glob-watcher>anymatch>micromatch>extend-shallow": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>signal-exit": { + "builtin": { + "assert.equal": true, + "events": true + }, + "globals": { + "process": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": { "packages": { - "gulp>glob-watcher>anymatch>micromatch>extend-shallow>is-extendable": true, - "webpack>micromatch>extend-shallow>assign-symbols": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>code-point-at": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true } }, - "gulp>glob-watcher>anymatch>micromatch>extend-shallow>is-extendable": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": { "packages": { - "@babel/register>clone-deep>is-plain-object": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point>number-is-nan": true } }, - "gulp>glob-watcher>anymatch>normalize-path": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": { "packages": { - "vinyl>remove-trailing-separator": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi>ansi-regex": true } }, - "gulp>glob-watcher>async-done": { - "builtin": { - "domain.create": true - }, - "globals": { - "process.nextTick": true - }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>wide-align": { "packages": { - "end-of-stream": true, - "gulp>glob-watcher>async-done>process-nextick-args": true, - "gulp>glob-watcher>async-done>stream-exhaust": true, - "pump>once": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true } }, - "gulp>glob-watcher>async-done>process-nextick-args": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>npmlog>set-blocking": { "globals": { - "process": true + "process.stderr": true, + "process.stdout": true } }, - "gulp>glob-watcher>async-done>stream-exhaust": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf": { "builtin": { - "stream.Writable": true, - "util.inherits": true + "assert": true, + "fs": true, + "path.join": true }, "globals": { - "setImmediate": true + "process.platform": true, + "setTimeout": true + }, + "packages": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob": true } }, - "gulp>glob-watcher>chokidar": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob": { "builtin": { + "assert": true, "events.EventEmitter": true, - "fs": true, - "path.basename": true, - "path.dirname": true, - "path.extname": true, + "fs.lstat": true, + "fs.lstatSync": true, + "fs.readdir": true, + "fs.readdirSync": true, + "fs.stat": true, + "fs.statSync": true, "path.join": true, - "path.relative": true, "path.resolve": true, - "path.sep": true + "util": true }, "globals": { - "clearTimeout": true, "console.error": true, - "process.env.CHOKIDAR_INTERVAL": true, - "process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR": true, - "process.env.CHOKIDAR_USEPOLLING": true, + "process.cwd": true, "process.nextTick": true, - "process.platform": true, - "setTimeout": true + "process.platform": true }, "packages": { - "eslint>is-glob": true, - "gulp-watch>chokidar>async-each": true, - "gulp-watch>glob-parent": true, - "gulp-watch>path-is-absolute": true, - "gulp>glob-watcher>anymatch": true, - "gulp>glob-watcher>chokidar>braces": true, - "gulp>glob-watcher>chokidar>is-binary-path": true, - "gulp>glob-watcher>chokidar>normalize-path": true, - "gulp>glob-watcher>chokidar>readdirp": true, - "gulp>glob-watcher>chokidar>upath": true, - "pumpify>inherits": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>fs.realpath": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>inflight": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>path-is-absolute": true } }, - "gulp>glob-watcher>chokidar>braces": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>fs.realpath": { + "builtin": { + "fs.lstat": true, + "fs.lstatSync": true, + "fs.readlink": true, + "fs.readlinkSync": true, + "fs.realpath": true, + "fs.realpathSync": true, + "fs.stat": true, + "fs.statSync": true, + "path.normalize": true, + "path.resolve": true + }, + "globals": { + "console.error": true, + "console.trace": true, + "process.env.NODE_DEBUG": true, + "process.nextTick": true, + "process.noDeprecation": true, + "process.platform": true, + "process.throwDeprecation": true, + "process.traceDeprecation": true, + "process.version": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>inflight": { + "globals": { + "process.nextTick": true + }, "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range": true, - "gulp>gulp-cli>isobject": true, - "gulp>undertaker>arr-flatten": true, - "webpack>micromatch>array-unique": true, - "webpack>micromatch>braces>repeat-element": true, - "webpack>micromatch>braces>snapdragon-node": true, - "webpack>micromatch>braces>split-string": true, - "webpack>micromatch>extglob>extend-shallow": true, - "webpack>micromatch>snapdragon": true, - "webpack>micromatch>to-regex": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>once>wrappy": true } }, - "gulp>glob-watcher>chokidar>braces>fill-range": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>inherits": { "builtin": { - "util.inspect": true + "util.inherits": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch": { + "builtin": { + "path": true + }, + "globals": { + "console.error": true }, "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, - "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": true, - "webpack>micromatch>braces>fill-range>repeat-string": true, - "webpack>micromatch>extglob>extend-shallow": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion": true } }, - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion": { "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion>balanced-match": true, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>minimatch>brace-expansion>concat-map": true } }, - "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": { + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>once": { "packages": { - "browserify>insert-module-globals>is-buffer": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>once>wrappy": true } }, - "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": { - "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, - "webpack>micromatch>braces>fill-range>repeat-string": true + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>rimraf>glob>path-is-absolute": { + "globals": { + "process.platform": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>semver": { + "globals": { + "console": true, + "process": true + } + }, + "gulp>glob-watcher>chokidar>fsevents>node-pre-gyp>tar>safe-buffer": { + "builtin": { + "buffer": true } }, "gulp>glob-watcher>chokidar>is-binary-path": { diff --git a/package.json b/package.json index 281cadd30a47..770f1dc4a69f 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "@ngraveio/bc-ur": "^1.1.6", "@popperjs/core": "^2.4.0", "@reduxjs/toolkit": "^1.6.2", + "@segment/loosely-validate-event": "^2.0.0", "@sentry/browser": "^6.0.0", "@sentry/integrations": "^6.0.0", "@sentry/types": "^6.0.1", @@ -152,7 +153,6 @@ "@truffle/decoder": "^5.1.0", "@zxing/browser": "^0.0.10", "@zxing/library": "0.8.0", - "analytics-node": "^3.4.0-beta.3", "await-semaphore": "^0.1.1", "base32-encode": "^1.2.0", "base64-js": "^1.5.1", @@ -189,6 +189,7 @@ "globalthis": "^1.0.1", "human-standard-token-abi": "^2.0.0", "immer": "^9.0.6", + "is-retry-allowed": "^2.2.0", "jest-junit": "^14.0.1", "json-rpc-engine": "^6.1.0", "json-rpc-middleware-stream": "^2.1.1", @@ -226,6 +227,7 @@ "readable-stream": "^2.3.3", "redux": "^4.0.5", "redux-thunk": "^2.3.0", + "remove-trailing-slash": "^0.1.1", "reselect": "^3.0.1", "safe-event-emitter": "^1.0.1", "ses": "^0.12.4", diff --git a/yarn.lock b/yarn.lock index a1a34d9a22fa..7f7083c38d66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6632,20 +6632,6 @@ amdefine@>=0.0.4: resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= -analytics-node@^3.4.0-beta.3: - version "3.4.0-beta.3" - resolved "https://registry.yarnpkg.com/analytics-node/-/analytics-node-3.4.0-beta.3.tgz#5eb0694598cff493c64faf5efc1225533a253f13" - integrity sha512-NIdpxiwlZ4cKgs9MDlDe89b5bg/pMq2W7XTA+cjzCM66IwW3ujZhVE49vk+zG6Yrxk0s/DXmennJ+cCQIsTKMA== - dependencies: - "@segment/loosely-validate-event" "^2.0.0" - axios "^0.19.2" - axios-retry "^3.0.2" - lodash.isstring "^4.0.1" - md5 "^2.2.1" - ms "^2.0.0" - remove-trailing-slash "^0.1.0" - uuid "^3.2.1" - ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -7337,14 +7323,7 @@ axe-core@^4.2.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.3.tgz#b55cd8e8ddf659fe89b064680e1c6a4dceab0325" integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA== -axios-retry@^3.0.2: - version "3.1.8" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.8.tgz#ffcfed757e1fab8cbf832f8505bb0e0af47c520c" - integrity sha512-yPw5Y4Bg6Dgmhm35KaJFtlh23s1TecW0HsUerK4/IS1UKl0gtN2aJqdEKtVomiOS/bDo5w4P3sqgki/M10eF8Q== - dependencies: - is-retry-allowed "^1.1.0" - -axios@^0.19.2, axios@^0.21.2: +axios@^0.21.2: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== @@ -8902,11 +8881,6 @@ character-reference-invalid@^1.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.1.tgz#942835f750e4ec61a308e60c2ef8cc1011202efc" integrity sha1-lCg191Dk7GGjCOYMLvjMEBEgLvw= -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= - check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -9936,11 +9910,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= - crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -13493,9 +13462,9 @@ fnv1a@^1.0.1: integrity sha1-kV4tbQI8Q9UiStn20qPEFW9XEvU= follow-redirects@^1.14.0, follow-redirects@^1.14.9: - version "1.15.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" - integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== for-each@^0.3.3: version "0.3.3" @@ -16198,7 +16167,7 @@ is-boolean-object@^1.0.0, is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.0.2, is-buffer@^1.1.0, is-buffer@^1.1.5, is-buffer@~1.1.6: +is-buffer@^1.0.2, is-buffer@^1.1.0, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -16676,11 +16645,16 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: +is-retry-allowed@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-retry-allowed@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -19202,11 +19176,6 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - lodash.map@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" @@ -19581,15 +19550,6 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -md5@^2.2.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - mdast-squeeze-paragraphs@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" @@ -24600,10 +24560,10 @@ remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= -remove-trailing-slash@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.0.tgz#1498e5df0984c27e49b76ebf06887ca2d01150d2" - integrity sha1-FJjl3wmEwn5Jt26/Boh8otARUNI= +remove-trailing-slash@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" + integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== renderkid@^2.0.1: version "2.0.3" From 385e92986495b9583ec5d93309b513466bf84a67 Mon Sep 17 00:00:00 2001 From: ryanml Date: Tue, 11 Oct 2022 08:05:03 -0700 Subject: [PATCH 30/33] Fixing forgot password action after wallet creation (#16156) --- ui/pages/routes/routes.component.js | 8 ++++++-- ui/pages/routes/routes.container.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index bae8d9055dd3..f56361e00cce 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -113,6 +113,7 @@ export default class Routes extends Component { currentChainId: PropTypes.string, shouldShowSeedPhraseReminder: PropTypes.bool, portfolioTooltipIsBeingShown: PropTypes.bool, + forgottenPassword: PropTypes.bool, }; static contextTypes = { @@ -165,7 +166,10 @@ export default class Routes extends Component { } renderRoutes() { - const { autoLockTimeLimit, setLastActiveTime } = this.props; + const { autoLockTimeLimit, setLastActiveTime, forgottenPassword } = + this.props; + const RestoreVaultComponent = forgottenPassword ? Route : Initialized; + const routes = ( {process.env.ONBOARDING_V2 && ( @@ -174,7 +178,7 @@ export default class Routes extends Component { - Date: Tue, 11 Oct 2022 18:56:34 +0200 Subject: [PATCH 31/33] [FLASK] `snaps-monorepo@0.22.2` (#16161) * snaps-monorepo@0.22.2 * Update LavaMoat policies * Fix eth_accounts permission for Snaps * Update iframe execution environment * Dedupe yarn.lock and rerun LavaMoat policy gen * Add policy override for nanoid --- app/scripts/metamask-controller.js | 2 +- lavamoat/browserify/beta/policy.json | 21 ++++-- lavamoat/browserify/flask/policy.json | 58 ++++++++++----- lavamoat/browserify/main/policy.json | 21 ++++-- lavamoat/browserify/policy-override.json | 5 ++ package.json | 6 +- .../permissions-connect.component.js | 10 ++- yarn.lock | 70 +++++++++++-------- 8 files changed, 127 insertions(+), 66 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 1a508d4ac2d8..f7b8390f148d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -659,7 +659,7 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(flask) this.snapExecutionService = new IframeExecutionService({ iframeUrl: new URL( - 'https://metamask.github.io/iframe-execution-environment/0.9.0', + 'https://metamask.github.io/iframe-execution-environment/0.9.1', ), messenger: this.controllerMessenger.getRestricted({ name: 'ExecutionService', diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2a7fc52a78a2..1ab56a362b4f 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -3389,10 +3389,9 @@ "ethers>@ethersproject/wallet>@ethersproject/properties": true } }, - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": { + "@metamask/rpc-methods>nanoid": { "globals": { - "TextEncoder": true, - "crypto": true + "crypto.getRandomValues": true } }, "@metamask/smart-transactions-controller": { @@ -4525,7 +4524,13 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { @@ -4681,10 +4686,16 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": true } }, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": { "globals": { "crypto": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 23c1f2f480e7..cd23cc3b57af 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -3551,6 +3551,7 @@ "packages": { "@metamask/rpc-methods>@metamask/controllers": true, "@metamask/rpc-methods>@metamask/key-tree": true, + "@metamask/rpc-methods>nanoid": true, "@metamask/snap-utils": true, "@metamask/snap-utils>superstruct": true, "eth-block-tracker>@metamask/utils": true, @@ -3586,7 +3587,7 @@ "@metamask/rpc-methods>@metamask/controllers>@ethersproject/abi": true, "@metamask/rpc-methods>@metamask/controllers>eth-method-registry": true, "@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": true, - "@metamask/rpc-methods>@metamask/controllers>nanoid": true, + "@metamask/rpc-methods>nanoid": true, "@metamask/smart-transactions-controller>@ethersproject/providers": true, "browserify>buffer": true, "browserify>events": true, @@ -3712,10 +3713,10 @@ "@metamask/rpc-methods>@metamask/key-tree": { "packages": { "@metamask/rpc-methods>@metamask/key-tree>@noble/ed25519": true, - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true, "@metamask/rpc-methods>@metamask/key-tree>@noble/secp256k1": true, - "@metamask/rpc-methods>@metamask/key-tree>@scure/base": true, "@metamask/rpc-methods>@metamask/key-tree>@scure/bip39": true, + "@metamask/snap-utils>@noble/hashes": true, + "@metamask/snap-utils>@scure/base": true, "browserify>buffer": true } }, @@ -3727,12 +3728,6 @@ "browserify>browser-resolve": true } }, - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/rpc-methods>@metamask/key-tree>@noble/secp256k1": { "globals": { "crypto": true @@ -3741,16 +3736,15 @@ "browserify>browser-resolve": true } }, - "@metamask/rpc-methods>@metamask/key-tree>@scure/base": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - } - }, "@metamask/rpc-methods>@metamask/key-tree>@scure/bip39": { "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true, - "@metamask/rpc-methods>@metamask/key-tree>@scure/base": true + "@metamask/snap-utils>@noble/hashes": true, + "@metamask/snap-utils>@scure/base": true + } + }, + "@metamask/rpc-methods>nanoid": { + "globals": { + "crypto.getRandomValues": true } }, "@metamask/smart-transactions-controller": { @@ -4259,6 +4253,8 @@ "packages": { "@babel/core": true, "@babel/core>@babel/types": true, + "@metamask/snap-utils>@noble/hashes": true, + "@metamask/snap-utils>@scure/base": true, "@metamask/snap-utils>ajv": true, "@metamask/snap-utils>rfdc": true, "@metamask/snap-utils>superstruct": true, @@ -4272,6 +4268,18 @@ "semver": true } }, + "@metamask/snap-utils>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/snap-utils>@scure/base": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + } + }, "@metamask/snap-utils>rfdc": { "packages": { "browserify>buffer": true @@ -5351,7 +5359,13 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { @@ -5507,10 +5521,16 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": true } }, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": { "globals": { "crypto": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2a7fc52a78a2..1ab56a362b4f 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -3389,10 +3389,9 @@ "ethers>@ethersproject/wallet>@ethersproject/properties": true } }, - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": { + "@metamask/rpc-methods>nanoid": { "globals": { - "TextEncoder": true, - "crypto": true + "crypto.getRandomValues": true } }, "@metamask/smart-transactions-controller": { @@ -4525,7 +4524,13 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { @@ -4681,10 +4686,16 @@ "crypto": true }, "packages": { - "@metamask/rpc-methods>@metamask/key-tree>@noble/hashes": true, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": true } }, + "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>@ethereumjs/util>ethereum-cryptography>@noble/secp256k1": { "globals": { "crypto": true diff --git a/lavamoat/browserify/policy-override.json b/lavamoat/browserify/policy-override.json index 4089a7536d6e..388f87f48335 100644 --- a/lavamoat/browserify/policy-override.json +++ b/lavamoat/browserify/policy-override.json @@ -97,6 +97,11 @@ "crypto.getRandomValues": true } }, + "@metamask/rpc-methods>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, "@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/package.json b/package.json index 770f1dc4a69f..756de20282f9 100644 --- a/package.json +++ b/package.json @@ -135,11 +135,11 @@ "@metamask/obs-store": "^5.0.0", "@metamask/post-message-stream": "^4.0.0", "@metamask/providers": "^10.0.0", - "@metamask/rpc-methods": "^0.22.0", + "@metamask/rpc-methods": "^0.22.2", "@metamask/slip44": "^2.1.0", "@metamask/smart-transactions-controller": "^2.3.2", - "@metamask/snap-controllers": "^0.22.0", - "@metamask/snap-utils": "^0.22.0", + "@metamask/snap-controllers": "^0.22.2", + "@metamask/snap-utils": "^0.22.2", "@ngraveio/bc-ur": "^1.1.6", "@popperjs/core": "^2.4.0", "@reduxjs/toolkit": "^1.6.2", diff --git a/ui/pages/permissions-connect/permissions-connect.component.js b/ui/pages/permissions-connect/permissions-connect.component.js index 4d411c8f4d15..93306a76f5c5 100644 --- a/ui/pages/permissions-connect/permissions-connect.component.js +++ b/ui/pages/permissions-connect/permissions-connect.component.js @@ -313,7 +313,10 @@ export default class PermissionConnect extends Component { { - approvePendingApproval(requestId, true); + approvePendingApproval(requestId, { + ...permissionsRequest, + approvedAccounts: selectedAccountAddresses, + }); this.redirect(true); }} rejectSnapInstall={(requestId) => { @@ -340,7 +343,10 @@ export default class PermissionConnect extends Component { { - approvePendingApproval(requestId, true); + approvePendingApproval(requestId, { + ...permissionsRequest, + approvedAccounts: selectedAccountAddresses, + }); this.redirect(true); }} rejectSnapUpdate={(requestId) => { diff --git a/yarn.lock b/yarn.lock index 7f7083c38d66..90279c10d75d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3329,16 +3329,16 @@ resolved "https://registry.yarnpkg.com/@metamask/etherscan-link/-/etherscan-link-2.2.0.tgz#76314d0c1405a0669fc4a0a19e0877bd3d0c389f" integrity sha512-xUgehvgU+ZbzeJ44m4sUtsyf6Dwou+SlYhiKfi6lkRcbWh6Jl3TCi0YM9C7XWgxfnLSdQBO1ndvcp0kslKgMsA== -"@metamask/execution-environments@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@metamask/execution-environments/-/execution-environments-0.22.0.tgz#2dd67add467e64fc6e992cb36461f20959ed87fd" - integrity sha512-mb5O3HX5Nrt0urAPWohiyB9w465Qk12tF1hXz+vjwFZe4LAbTHza7XsbvTzAy1XD99JjhtLMi+IwaHp8GELcDg== +"@metamask/execution-environments@^0.22.2": + version "0.22.2" + resolved "https://registry.yarnpkg.com/@metamask/execution-environments/-/execution-environments-0.22.2.tgz#174f4e37ed060b81cf29343581f35ad7c3a3182a" + integrity sha512-zfSP8L+KVrHGgZnnjauUpZD6GxDMGB5JI8Oq8BrsEtTZG9gZc7Sn5Jhx+6TuXKft1DLsjb4zM1trnAEgfXZ1aw== dependencies: "@metamask/object-multiplex" "^1.2.0" "@metamask/post-message-stream" "^6.0.0" "@metamask/providers" "^9.0.0" - "@metamask/snap-types" "^0.22.0" - "@metamask/snap-utils" "^0.22.0" + "@metamask/snap-types" "^0.22.2" + "@metamask/snap-utils" "^0.22.2" "@metamask/utils" "^3.1.0" eth-rpc-errors "^4.0.3" pump "^3.0.0" @@ -3479,17 +3479,18 @@ pump "^3.0.0" webextension-polyfill-ts "^0.25.0" -"@metamask/rpc-methods@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.22.0.tgz#17ee8db33deba5152d531123139fd3ea651e49ef" - integrity sha512-FCVbf68zgHHThG2OAOp9u7iBO1hjIMjo8S85bXsGtStUp9KjiGxnuQhyNK7b/Ny+WuHI+GP26abXRIyS2ampfA== +"@metamask/rpc-methods@^0.22.2": + version "0.22.2" + resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.22.2.tgz#4f60dcbbc0f9aebf86099b79639b7a711d4de31d" + integrity sha512-60InoQ9xteiJvpwRfCi8A4rCnBKazkLNuLnIochOuzPTIjH48GdEODaUQzOuwd/WGUNFstUI5yIGAv0NEr2EYA== dependencies: "@metamask/controllers" "^31.0.0" "@metamask/key-tree" "^5.0.2" - "@metamask/snap-utils" "^0.22.0" + "@metamask/snap-utils" "^0.22.2" "@metamask/types" "^1.1.0" "@metamask/utils" "^3.1.0" eth-rpc-errors "^4.0.2" + nanoid "^3.1.31" superstruct "^0.16.5" "@metamask/safe-event-emitter@^2.0.0": @@ -3517,19 +3518,19 @@ isomorphic-fetch "^3.0.0" lodash "^4.17.21" -"@metamask/snap-controllers@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.22.0.tgz#bb1dfb7551cfca74b17addad2390ad80a6df8b7a" - integrity sha512-k7TgYyzZna54ns3o9GjnLiHJDT3xvkG4i+zSEJSMPzqAy5Su5p2yMiTe/awEwTVFBMsC9xtX9owc0lArkk8NZw== +"@metamask/snap-controllers@^0.22.2": + version "0.22.2" + resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.22.2.tgz#d11ff1c5c35d5b659acb4f1e1365ae5b7055d828" + integrity sha512-QOtzlx9hlo4uCZhnrcYj0ChAL1deHUKS/A9sKUIWcFZpxpce+9mVyAljnz3CJkr2CCH8w7/MkfclDsLcoMci/A== dependencies: "@metamask/browser-passworder" "^3.0.0" "@metamask/controllers" "^31.0.0" - "@metamask/execution-environments" "^0.22.0" + "@metamask/execution-environments" "^0.22.2" "@metamask/object-multiplex" "^1.1.0" "@metamask/post-message-stream" "^6.0.0" - "@metamask/rpc-methods" "^0.22.0" - "@metamask/snap-types" "^0.22.0" - "@metamask/snap-utils" "^0.22.0" + "@metamask/rpc-methods" "^0.22.2" + "@metamask/snap-types" "^0.22.2" + "@metamask/snap-utils" "^0.22.2" "@metamask/utils" "^3.1.0" "@xstate/fsm" "^2.0.0" concat-stream "^2.0.0" @@ -3543,23 +3544,25 @@ readable-web-to-node-stream "^3.0.2" tar-stream "^2.2.0" -"@metamask/snap-types@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.22.0.tgz#4d74e34eea69a7afe0ad9a4d54be83cf5391bf9e" - integrity sha512-XwJNk+Qbtr7xjuh1Iz7wqybp+xB3H6uRJjlOqtgIoOui9V2zfL/At/FzHMMvaLeUsWJhOVSJP5qmEzCYaOEvmQ== +"@metamask/snap-types@^0.22.2": + version "0.22.2" + resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.22.2.tgz#590cfdd6088d77df6d103ceabdab4ae4d1bdcf03" + integrity sha512-8/KVU53ctZra7lQ9pjMScOXCBT7b3cmy2nilFDUHRPxEpw9XEgVtQVeekV7AVsXMcLEZdck+8tj5l7KUj5qxHg== dependencies: "@metamask/providers" "^9.0.0" - "@metamask/snap-utils" "^0.22.0" + "@metamask/snap-utils" "^0.22.2" "@metamask/types" "^1.1.0" -"@metamask/snap-utils@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@metamask/snap-utils/-/snap-utils-0.22.0.tgz#1815eecfc8a388a4ae6744664ff28f58404730ee" - integrity sha512-mwe72I/sVMVogNU+gxUU1P2Kos4S/4lEX1MUz7Hr79jfYzTgwTfxz/gaMubjD6CF2q0ZvF5JQr6OBk6ZRLHhCw== +"@metamask/snap-utils@^0.22.2": + version "0.22.2" + resolved "https://registry.yarnpkg.com/@metamask/snap-utils/-/snap-utils-0.22.2.tgz#040b2fc1c6ccd406b049084d90542f77e9a51572" + integrity sha512-hhQHsHS6xkwmqvPrDnrXgu8IIEtaPwLr7PUwqIDSHBeBgbhlsbS7R63nhMtrRxognLmnWj0xWvAvoz25o+Q/Rw== dependencies: "@babel/core" "^7.18.6" - "@metamask/snap-types" "^0.22.0" + "@metamask/snap-types" "^0.22.2" "@metamask/utils" "^3.1.0" + "@noble/hashes" "^1.1.3" + "@scure/base" "^1.1.1" ajv "^8.11.0" eth-rpc-errors "^4.0.3" fast-deep-equal "^3.1.3" @@ -3626,11 +3629,16 @@ resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.6.0.tgz#b55f7c9e532b478bf1d7c4f609e1f3a37850b583" integrity sha512-UKju89WV37IUALIMfKhKW3psO8AqmrE/GvH6QbPKjzolQ98zM7WmGUeY+xdIgSf5tqPFf75ZCYMgym6E9Jsw3Q== -"@noble/hashes@1.1.2", "@noble/hashes@^1.0.0", "@noble/hashes@~1.1.1": +"@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== +"@noble/hashes@^1.0.0", "@noble/hashes@^1.1.3", "@noble/hashes@~1.1.1": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.3.tgz#360afc77610e0a61f3417e497dcf36862e4f8111" + integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A== + "@noble/secp256k1@1.6.3", "@noble/secp256k1@~1.6.0": version "1.6.3" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.3.tgz#7eed12d9f4404b416999d0c87686836c4c5c9b94" @@ -3781,7 +3789,7 @@ redux-thunk "^2.3.0" reselect "^4.0.0" -"@scure/base@^1.0.0", "@scure/base@~1.1.0": +"@scure/base@^1.0.0", "@scure/base@^1.1.1", "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== From 33522a7b46386bfebfbb3600c150decef1cf2084 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Tue, 11 Oct 2022 11:27:29 -0600 Subject: [PATCH 32/33] Fix @keystonehq/bc-ur-registry patch (#16155) We use the `@keystonehq/bc-ur-registry` package for integration with Keystone devices. This package is peculiar as it not only ships with JavaScript files but also original TypeScript files. When we started adding support for TypeScript into the build system, we realized that the TypeScript files were apparently developed using a different TypeScript config than we use and therefore resulted in errors in our build process. So we added a patch which removed these TypeScript files so that we would fall back to using the compiled JavaScript files. This removed type information but fixed our build system. Since then, we've bumped this package and the files we removed have changed, so the patch is no longer valid. This commit recreates the patch so that we no longer get warnings from `patch-package`. --- ...tonehq+bc-ur-registry+0.5.0-alpha.5.patch} | 309 +++++++++++++----- 1 file changed, 226 insertions(+), 83 deletions(-) rename patches/{@keystonehq+bc-ur-registry+0.4.4.patch => @keystonehq+bc-ur-registry+0.5.0-alpha.5.patch} (87%) diff --git a/patches/@keystonehq+bc-ur-registry+0.4.4.patch b/patches/@keystonehq+bc-ur-registry+0.5.0-alpha.5.patch similarity index 87% rename from patches/@keystonehq+bc-ur-registry+0.4.4.patch rename to patches/@keystonehq+bc-ur-registry+0.5.0-alpha.5.patch index eec0a3388e85..b99840ebf59a 100644 --- a/patches/@keystonehq+bc-ur-registry+0.4.4.patch +++ b/patches/@keystonehq+bc-ur-registry+0.5.0-alpha.5.patch @@ -40,14 +40,15 @@ index a5f9f7d..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoAccount.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoAccount.ts deleted file mode 100644 -index 753e535..0000000 +index e6efeeb..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoAccount.ts +++ /dev/null -@@ -1,57 +0,0 @@ +@@ -1,58 +0,0 @@ -import { CryptoOutput } from '.'; -import { decodeToDataItem, DataItem } from './lib'; -import { RegistryItem } from './RegistryItem'; -import { RegistryTypes } from './RegistryType'; +-import { DataItemMap } from './types'; - -enum Keys { - masterFingerprint = 1, @@ -70,7 +71,7 @@ index 753e535..0000000 - public getOutputDescriptors = () => this.outputDescriptors; - - public toDataItem = () => { -- const map = {}; +- const map: DataItemMap = {}; - if (this.masterFingerprint) { - map[Keys.masterFingerprint] = this.masterFingerprint.readUInt32BE(0); - } @@ -103,13 +104,14 @@ index 753e535..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoCoinInfo.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoCoinInfo.ts deleted file mode 100644 -index 0201682..0000000 +index 843b50c..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoCoinInfo.ts +++ /dev/null -@@ -1,58 +0,0 @@ +@@ -1,59 +0,0 @@ -import { decodeToDataItem, DataItem } from './lib'; -import { RegistryItem } from './RegistryItem'; -import { RegistryTypes } from './RegistryType'; +-import { DataItemMap } from './types'; - -enum Keys { - type = '1', @@ -143,7 +145,7 @@ index 0201682..0000000 - }; - - public toDataItem = () => { -- const map = {}; +- const map: DataItemMap = {}; - if (this.type) { - map[Keys.type] = this.type; - } @@ -167,13 +169,14 @@ index 0201682..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoECKey.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoECKey.ts deleted file mode 100644 -index 1e964fc..0000000 +index 54c3c4b..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoECKey.ts +++ /dev/null -@@ -1,59 +0,0 @@ +@@ -1,68 +0,0 @@ -import { decodeToDataItem, DataItem } from './lib'; -import { RegistryItem } from './RegistryItem'; -import { RegistryTypes } from './RegistryType'; +-import { DataItemMap, ICryptoKey } from './types'; - -enum Keys { - curve = 1, @@ -181,17 +184,21 @@ index 1e964fc..0000000 - data, -} - --export class CryptoECKey extends RegistryItem { +-export class CryptoECKey extends RegistryItem implements ICryptoKey { - private data: Buffer; -- private curve: number; -- private privateKey: boolean; +- private curve: number | undefined; +- private privateKey: boolean | undefined; - constructor(args: { data: Buffer; curve?: number; privateKey?: boolean }) { - super(); - this.data = args.data; - this.curve = args.curve; -- this.privateKey = args.privateKey; +- this.privateKey = args.privateKey || undefined; - } - +- isECKey = () => { +- return true; +- }; +- - public getCurve = () => this.curve || 0; - public isPrivateKey = () => this.privateKey || false; - public getData = () => this.data; @@ -201,7 +208,7 @@ index 1e964fc..0000000 - }; - - toDataItem = () => { -- const map = {}; +- const map: DataItemMap = {}; - if (this.curve) { - map[Keys.curve] = this.curve; - } @@ -212,6 +219,10 @@ index 1e964fc..0000000 - return new DataItem(map); - }; - +- getOutputDescriptorContent = () => { +- return this.data.toString('hex'); +- } +- - static fromDataItem = (dataItem: DataItem) => { - const map = dataItem.getData(); - const curve = map[Keys.curve]; @@ -232,16 +243,20 @@ index 1e964fc..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoHDKey.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoHDKey.ts deleted file mode 100644 -index bbfd331..0000000 +index 8fc2a82..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoHDKey.ts +++ /dev/null -@@ -1,210 +0,0 @@ +@@ -1,237 +0,0 @@ +-// eslint-disable-next-line @typescript-eslint/ban-ts-comment +-// @ts-ignore -import { encode } from 'bs58check'; -import { CryptoCoinInfo } from './CryptoCoinInfo'; -import { CryptoKeypath } from './CryptoKeypath'; -import { decodeToDataItem, DataItem } from './lib'; -import { RegistryItem } from './RegistryItem'; -import { RegistryTypes } from './RegistryType'; +-import { DataItemMap, ICryptoKey } from './types'; +-import { PathComponent } from './PathComponent'; - -enum Keys { - is_master = 1, @@ -274,17 +289,22 @@ index bbfd331..0000000 - name?: string; - note?: string; -}; --export class CryptoHDKey extends RegistryItem { -- private master: boolean; -- private privateKey: boolean; -- private key: Buffer; -- private chainCode: Buffer; -- private useInfo: CryptoCoinInfo; -- private origin: CryptoKeypath; -- private children: CryptoKeypath; -- private parentFingerprint: Buffer; -- private name: string; -- private note: string; +- +-export class CryptoHDKey extends RegistryItem implements ICryptoKey { +- private master?: boolean; +- private privateKey?: boolean; +- private key?: Buffer; +- private chainCode?: Buffer; +- private useInfo?: CryptoCoinInfo; +- private origin?: CryptoKeypath; +- private children?: CryptoKeypath; +- private parentFingerprint?: Buffer; +- private name?: string; +- private note?: string; +- +- isECKey = () => { +- return false; +- }; - - public getKey = () => this.key; - public getChainCode = () => this.chainCode; @@ -299,22 +319,24 @@ index bbfd331..0000000 - public getBip32Key = () => { - let version: Buffer; - let depth: number; -- let index: number; +- let index = 0; - let parentFingerprint: Buffer = Buffer.alloc(4).fill(0); -- if(this.isMaster()) { +- if (this.isMaster()) { - // version bytes defined on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format -- version = Buffer.from("0488ADE4", "hex") +- version = Buffer.from('0488ADE4', 'hex'); - depth = 0; - index = 0; - } else { -- depth = this.getOrigin().getComponents().length || this.getOrigin().getDepth(); -- const paths = this.getOrigin().getComponents(); +- depth = this.getOrigin()?.getComponents().length || this.getOrigin()?.getDepth() as number; +- const paths = this.getOrigin()?.getComponents() as PathComponent[]; - const lastPath = paths[paths.length - 1]; -- if(lastPath) { +- if (lastPath) { - index = lastPath.isHardened() ? lastPath.getIndex()! + 0x80000000 : lastPath.getIndex()!; -- parentFingerprint = this.getParentFingerprint(); +- if (this.getParentFingerprint()) { +- parentFingerprint = this.getParentFingerprint() as Buffer; +- } - } -- if(this.isPrivateKey()) { +- if (this.isPrivateKey()) { - version = Buffer.from('0488ADE4', 'hex'); - } else { - version = Buffer.from('0488B21E', 'hex'); @@ -326,13 +348,29 @@ index bbfd331..0000000 - indexBuffer.writeUInt32BE(index, 0); - const chainCode = this.getChainCode(); - const key = this.getKey(); -- return encode(Buffer.concat([version, depthBuffer, parentFingerprint, indexBuffer, chainCode, key])); -- } +- return encode(Buffer.concat([version, depthBuffer, parentFingerprint, indexBuffer, chainCode as Buffer, key as Buffer])); +- }; - - public getRegistryType = () => { - return RegistryTypes.CRYPTO_HDKEY; - }; - +- public getOutputDescriptorContent = () => { +- let result = ''; +- if (this.getOrigin()) { +- if (this.getOrigin()?.getSourceFingerprint() && this.getOrigin()?.getPath()) { +- result += `${this.getOrigin()?.getSourceFingerprint()?.toString('hex')}/${this.getOrigin()?.getPath()}`; +- } +- } +- result += this.getBip32Key(); +- if (this.getChildren()) { +- if (this.getChildren()?.getPath()) { +- result += `/${this.getChildren()?.getPath()}`; +- } +- } +- return result; +- }; +- - constructor(args: DeriveKeyProps | MasterKeyProps) { - super(); - if (args.isMaster) { @@ -362,7 +400,7 @@ index bbfd331..0000000 - }; - - public toDataItem = () => { -- const map = {}; +- const map: DataItemMap = {}; - if (this.master) { - map[Keys.is_master] = true; - map[Keys.key_data] = this.key; @@ -418,8 +456,8 @@ index bbfd331..0000000 - const children = map[Keys.children] - ? CryptoKeypath.fromDataItem(map[Keys.children]) - : undefined; -- let _parentFingerprint = map[Keys.parent_fingerprint]; -- let parentFingerprint: Buffer; +- const _parentFingerprint = map[Keys.parent_fingerprint]; +- let parentFingerprint: Buffer | undefined = undefined; - if (_parentFingerprint) { - parentFingerprint = Buffer.alloc(4); - parentFingerprint.writeUInt32BE(_parentFingerprint, 0); @@ -448,14 +486,15 @@ index bbfd331..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoKeypath.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoKeypath.ts deleted file mode 100644 -index 4babe91..0000000 +index 00146ce..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoKeypath.ts +++ /dev/null -@@ -1,95 +0,0 @@ +@@ -1,96 +0,0 @@ -import { decodeToDataItem, DataItem } from './lib'; -import { PathComponent } from './PathComponent'; -import { RegistryItem } from './RegistryItem'; -import { RegistryTypes } from './RegistryType'; +-import { DataItemMap } from './types'; - -enum Keys { - components = 1, @@ -494,16 +533,16 @@ index 4babe91..0000000 - public getDepth = () => this.depth; - - toDataItem = () => { -- const map: Record = {}; -- const components = []; +- const map: DataItemMap = {}; +- const components: (number | boolean | any[])[] = []; - this.components && - this.components.forEach((component) => { - if (component.isWildcard()) { - components.push([]); - } else { -- components.push(component.getIndex()); +- components.push(component.getIndex() as number); - } -- components.push(component.isHardened() ? true : false); +- components.push(component.isHardened()); - }); - map[Keys.components] = components; - if (this.sourceFingerprint) { @@ -533,7 +572,7 @@ index 4babe91..0000000 - } - } - const _sourceFingerprint = map[Keys.source_fingerprint]; -- let sourceFingerprint: Buffer; +- let sourceFingerprint: Buffer | undefined; - if (_sourceFingerprint) { - sourceFingerprint = Buffer.alloc(4); - sourceFingerprint.writeUInt32BE(_sourceFingerprint, 0); @@ -549,10 +588,10 @@ index 4babe91..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/CryptoOutput.ts b/node_modules/@keystonehq/bc-ur-registry/src/CryptoOutput.ts deleted file mode 100644 -index cd3009c..0000000 +index 90abf6f..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/CryptoOutput.ts +++ /dev/null -@@ -1,114 +0,0 @@ +@@ -1,127 +0,0 @@ -import { CryptoECKey } from './CryptoECKey'; -import { CryptoHDKey } from './CryptoHDKey'; -import { decodeToDataItem, DataItem } from './lib'; @@ -599,6 +638,18 @@ index cd3009c..0000000 - - public getScriptExpressions = () => this.scriptExpressions; - +- private _toOutputDescriptor = (seIndex: number): string => { +- if (seIndex >= this.scriptExpressions.length) { +- return this.cryptoKey.getOutputDescriptorContent(); +- } else { +- return `${this.scriptExpressions[seIndex].getExpression()}(${this._toOutputDescriptor(seIndex + 1)})`; +- } +- }; +- +- public toString = () => { +- return this._toOutputDescriptor(0); +- }; +- - toDataItem = () => { - let dataItem = this.cryptoKey.toDataItem(); - if ( @@ -625,9 +676,10 @@ index cd3009c..0000000 - public static fromDataItem = (dataItem: DataItem) => { - const scriptExpressions: ScriptExpression[] = []; - let _dataItem = dataItem; +- // eslint-disable-next-line no-constant-condition - while (true) { -- let _tag = _dataItem.getTag() || undefined; -- const se = ScriptExpression.fromTag(_tag); +- let _tag = _dataItem.getTag(); +- const se = ScriptExpression.fromTag(_tag as number); - if (se) { - scriptExpressions.push(se); - if (_dataItem.getData() instanceof DataItem) { @@ -646,7 +698,7 @@ index cd3009c..0000000 - (scriptExpressions[seLength - 1].getExpression() === - ScriptExpressions.MULTISIG.getExpression() || - scriptExpressions[seLength - 1].getExpression() === -- ScriptExpressions.SORTED_MULTISIG.getExpression()); +- ScriptExpressions.SORTED_MULTISIG.getExpression()); - //TODO: judge is multi key by scriptExpressions - if (isMultiKey) { - const multiKey = MultiKey.fromDataItem(_dataItem); @@ -707,10 +759,10 @@ index 626b647..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/Decoder/index.ts b/node_modules/@keystonehq/bc-ur-registry/src/Decoder/index.ts deleted file mode 100644 -index 0460694..0000000 +index 5d7e3fe..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/Decoder/index.ts +++ /dev/null -@@ -1,40 +0,0 @@ +@@ -1,41 +0,0 @@ -import { URDecoder } from '@ngraveio/bc-ur'; -import { - Bytes, @@ -723,6 +775,7 @@ index 0460694..0000000 - CryptoPSBT, -} from '..'; -import { RegistryTypes } from '../RegistryType'; +-import { UnknownURTypeError } from '../errors'; - -export class URRegistryDecoder extends URDecoder { - public resultRegistryType = () => { @@ -745,7 +798,7 @@ index 0460694..0000000 - case RegistryTypes.CRYPTO_ACCOUNT.getType(): - return CryptoAccount.fromCBOR(ur.cbor); - default: -- throw new Error( +- throw new UnknownURTypeError( - `#[ur-registry][Decoder][fn.resultRegistryType]: registry type ${ur.type} is not supported now`, - ); - } @@ -753,15 +806,16 @@ index 0460694..0000000 -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/MultiKey.ts b/node_modules/@keystonehq/bc-ur-registry/src/MultiKey.ts deleted file mode 100644 -index 0522fbd..0000000 +index ced19dc..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/MultiKey.ts +++ /dev/null -@@ -1,54 +0,0 @@ +@@ -1,60 +0,0 @@ -import { CryptoECKey } from './CryptoECKey'; -import { CryptoHDKey } from './CryptoHDKey'; -import { DataItem } from './lib/DataItem'; -import { RegistryItem } from './RegistryItem'; -import { RegistryType, RegistryTypes } from './RegistryType'; +-import { DataItemMap } from './types'; - -enum Keys { - threshold = 1, @@ -769,24 +823,24 @@ index 0522fbd..0000000 -} - -export class MultiKey extends RegistryItem { +- // eslint-disable-next-line @typescript-eslint/ban-ts-comment +- // @ts-ignore - getRegistryType: () => RegistryType; - - constructor( - private threshold: number, -- private ecKeys: CryptoECKey[], -- private hdKeys: CryptoHDKey[], +- private keys: (CryptoECKey | CryptoHDKey)[], - ) { - super(); - } - - getThreshold = () => this.threshold; -- getEcKeys = () => this.ecKeys as CryptoECKey[]; -- getHdKeys = () => this.hdKeys as CryptoHDKey[]; +- getKeys = () => this.keys; - - toDataItem = () => { -- const map = {}; +- const map: DataItemMap = {}; - map[Keys.threshold] = this.threshold; -- const keys: DataItem[] = [...this.ecKeys, ...this.hdKeys].map((k) => { +- const keys: DataItem[] = this.keys.map((k) => { - const dataItem = k.toDataItem(); - dataItem.setTag(k.getRegistryType().getTag()); - return dataItem; @@ -795,20 +849,25 @@ index 0522fbd..0000000 - return new DataItem(map); - }; - +- getOutputDescriptorContent = () => { +- return [this.getThreshold(), +- this.keys.map(k => k.getOutputDescriptorContent()).join(','), +- ].join(','); +- }; +- - static fromDataItem = (dataItem: DataItem) => { - const map = dataItem.getData(); - const threshold = map[Keys.threshold]; -- const keys = map[Keys.keys] as DataItem[]; -- const ecKeys = []; -- const hdKeys = []; -- keys.forEach((k) => { +- const _keys = map[Keys.keys] as DataItem[]; +- const keys: (CryptoECKey | CryptoHDKey)[] = []; +- _keys.forEach((k) => { - if (k.getTag() === RegistryTypes.CRYPTO_HDKEY.getTag()) { -- hdKeys.push(CryptoHDKey.fromDataItem(k)); +- keys.push(CryptoHDKey.fromDataItem(k)); - } else if (k.getTag() === RegistryTypes.CRYPTO_ECKEY.getTag()) { -- ecKeys.push(CryptoECKey.fromDataItem(k)); +- keys.push(CryptoECKey.fromDataItem(k)); - } - }); -- return new MultiKey(threshold, ecKeys, hdKeys); +- return new MultiKey(threshold, keys); - }; -} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/PathComponent.ts b/node_modules/@keystonehq/bc-ur-registry/src/PathComponent.ts @@ -914,7 +973,7 @@ index 64637bc..0000000 -}; diff --git a/node_modules/@keystonehq/bc-ur-registry/src/ScriptExpression.ts b/node_modules/@keystonehq/bc-ur-registry/src/ScriptExpression.ts deleted file mode 100644 -index fdd3f05..0000000 +index 8fbf0db..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/ScriptExpression.ts +++ /dev/null @@ -1,26 +0,0 @@ @@ -940,16 +999,27 @@ index fdd3f05..0000000 - WITNESS_PUBLIC_KEY_HASH: new ScriptExpression(404, 'wpkh'), - COMBO: new ScriptExpression(405, 'combo'), - MULTISIG: new ScriptExpression(406, 'multi'), -- SORTED_MULTISIG: new ScriptExpression(407, 'sorted'), +- SORTED_MULTISIG: new ScriptExpression(407, 'sortedmulti'), - ADDRESS: new ScriptExpression(307, 'addr'), - RAW_SCRIPT: new ScriptExpression(408, 'raw'), -}; +diff --git a/node_modules/@keystonehq/bc-ur-registry/src/errors/index.ts b/node_modules/@keystonehq/bc-ur-registry/src/errors/index.ts +deleted file mode 100644 +index dd2b0bd..0000000 +--- a/node_modules/@keystonehq/bc-ur-registry/src/errors/index.ts ++++ /dev/null +@@ -1,5 +0,0 @@ +-export class UnknownURTypeError extends Error { +- constructor(message: string) { +- super(message); +- } +-} diff --git a/node_modules/@keystonehq/bc-ur-registry/src/index.ts b/node_modules/@keystonehq/bc-ur-registry/src/index.ts deleted file mode 100644 -index 172a1e5..0000000 +index bb07bc8..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/index.ts +++ /dev/null -@@ -1,89 +0,0 @@ +@@ -1,110 +0,0 @@ -import './patchCBOR'; - -import { CryptoHDKey } from './CryptoHDKey'; @@ -971,6 +1041,7 @@ index 172a1e5..0000000 -import { ScriptExpressions } from './ScriptExpression'; -import { PathComponent } from './PathComponent'; - +-import { RegistryItem } from './RegistryItem'; -import { RegistryTypes, RegistryType } from './RegistryType'; - -import { @@ -983,7 +1054,6 @@ index 172a1e5..0000000 -} from './lib'; - -export { DataItem } from './lib'; --export { RegistryItem } from './RegistryItem'; - -import { patchTags } from './utils'; - @@ -1014,9 +1084,12 @@ index 172a1e5..0000000 - -const extend = { - RegistryTypes, +- RegistryItem, - RegistryType, +- - decodeToDataItem, - encodeDataItem, +- - cbor, -}; - @@ -1038,6 +1111,24 @@ index 172a1e5..0000000 - extend, -}; - +-export * from './errors'; +-export * from './Decoder'; +-export * from './lib'; +-export * from './CryptoAccount' +-export * from './CryptoPSBT' +-export * from './CryptoHDKey' +-export * from './CryptoOutput' +-export * from './CryptoCoinInfo' +-export * from './CryptoECKey' +-export * from './MultiKey' +-export * from './CryptoKeypath' +-export * from './patchCBOR' +-export * from './PathComponent' +-export * from './RegistryItem' +-export * from './RegistryType' +-export * from './types' +-export * from './utils' +- -export default URlib; diff --git a/node_modules/@keystonehq/bc-ur-registry/src/lib/DataItem.ts b/node_modules/@keystonehq/bc-ur-registry/src/lib/DataItem.ts deleted file mode 100644 @@ -1070,12 +1161,54 @@ index 9727f7e..0000000 - return this.data; - }; -} +diff --git a/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.d.ts b/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.d.ts +deleted file mode 100644 +index 6374ba7..0000000 +--- a/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.d.ts ++++ /dev/null +@@ -1,36 +0,0 @@ +-export namespace config { +- const useToJSON: boolean; +-} +-export function addWriter(format: any, writerFunction: any): void; +-export function addReader(format: any, readerFunction: any): void; +-export function encode(data: any, format: any): any; +-export function encodeDataItem(data: any, format?: any): any; +-export function decode(data: any, format: any): any; +-export function decodeToDataItem(data: any, format?: any): import("./DataItem").DataItem; +-export function addSemanticEncode(tag: any, fn: any): { +- config: { +- useToJSON: boolean; +- }; +- addWriter: (format: any, writerFunction: any) => void; +- addReader: (format: any, readerFunction: any) => void; +- encode: (data: any, format: any) => any; +- encodeDataItem: (data: any, format: any) => any; +- decode: (data: any, format: any) => any; +- decodeToDataItem: (data: any, format: any) => import("./DataItem").DataItem; +- addSemanticEncode: (tag: any, fn: any) => any; +- addSemanticDecode: (tag: any, fn: any) => any; +-}; +-export function addSemanticDecode(tag: any, fn: any): { +- config: { +- useToJSON: boolean; +- }; +- addWriter: (format: any, writerFunction: any) => void; +- addReader: (format: any, readerFunction: any) => void; +- encode: (data: any, format: any) => any; +- encodeDataItem: (data: any, format: any) => any; +- decode: (data: any, format: any) => any; +- decodeToDataItem: (data: any, format: any) => import("./DataItem").DataItem; +- addSemanticEncode: (tag: any, fn: any) => any; +- addSemanticDecode: (tag: any, fn: any) => any; +-}; +-//# sourceMappingURL=cbor-sync.d.ts.map diff --git a/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.js b/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.js deleted file mode 100644 -index 63e5b3a..0000000 +index df8db90..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/lib/cbor-sync.js +++ /dev/null -@@ -1,695 +0,0 @@ +@@ -1,693 +0,0 @@ -(function (global, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); @@ -1531,8 +1664,6 @@ index 63e5b3a..0000000 - semanticDecoders[tag] = fn; - return this; - }, -- Reader: Reader, -- Writer: Writer, - }; - - /** Node.js Buffers **/ @@ -1788,7 +1919,7 @@ index deb0156..0000000 -export { DataItem } from './DataItem'; diff --git a/node_modules/@keystonehq/bc-ur-registry/src/patchCBOR.ts b/node_modules/@keystonehq/bc-ur-registry/src/patchCBOR.ts deleted file mode 100644 -index b9909a7..0000000 +index 218e912..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/patchCBOR.ts +++ /dev/null @@ -1,11 +0,0 @@ @@ -1802,17 +1933,29 @@ index b9909a7..0000000 -const scriptExpressionTags = Object.values(ScriptExpressions).map((se) => - se.getTag(), -); --patchTags(registryTags.concat(scriptExpressionTags)); +-patchTags(registryTags.concat(scriptExpressionTags) as number[]); +diff --git a/node_modules/@keystonehq/bc-ur-registry/src/types.ts b/node_modules/@keystonehq/bc-ur-registry/src/types.ts +deleted file mode 100644 +index 29aa370..0000000 +--- a/node_modules/@keystonehq/bc-ur-registry/src/types.ts ++++ /dev/null +@@ -1,6 +0,0 @@ +-export interface ICryptoKey { +- isECKey: () => boolean; +- getOutputDescriptorContent: () => string; +-} +- +-export type DataItemMap = Record; diff --git a/node_modules/@keystonehq/bc-ur-registry/src/utils.ts b/node_modules/@keystonehq/bc-ur-registry/src/utils.ts deleted file mode 100644 -index ee39b78..0000000 +index e38112b..0000000 --- a/node_modules/@keystonehq/bc-ur-registry/src/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { addSemanticDecode, addSemanticEncode, DataItem } from './lib'; - --const alreadyPatchedTag = []; --export const patchTags = (tags: number[]) => { +-const alreadyPatchedTag: number[] = []; +-export const patchTags = (tags: number[]): void => { - tags.forEach((tag) => { - if (alreadyPatchedTag.find((i) => i === tag)) return; - addSemanticEncode(tag, (data: any) => { From 7149da8d3d42b8bf64f23c8678c69bd911a2b441 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Tue, 11 Oct 2022 10:54:50 -0700 Subject: [PATCH 33/33] Continue converting tests from enzyme to @testing-library/react (#16032) --- .../app/asset-list-item/asset-list-item.js | 1 + .../reject-transactions.test.js.snap | 52 +++++ .../reject-transactions.test.js | 49 +++-- .../transaction-confirmed.test.js.snap | 42 ++++ .../transaction-confirmed.test.js | 34 +-- .../selected-account-component.test.js.snap | 56 +++++ .../selected-account-component.test.js | 42 ++-- .../selected-account.component.js | 1 + .../__snapshots__/token-cell.test.js.snap | 105 +++++++++ .../app/token-cell/token-cell.test.js | 77 ++----- ...action-activity-log.component.test.js.snap | 103 +++++++++ ...transaction-activity-log.component.test.js | 204 +++++------------- .../ui/alert/__snapshots__/index.test.js.snap | 15 ++ ui/components/ui/alert/index.test.js | 23 +- .../__snapshots__/reveal-seed.test.js.snap | 92 ++++++++ ui/pages/keychains/reveal-seed.js | 1 + ui/pages/keychains/reveal-seed.test.js | 48 +++-- .../__snapshots__/unlock-page.test.js.snap | 101 +++++++++ ui/pages/unlock-page/unlock-page.component.js | 2 + .../unlock-page/unlock-page.component.test.js | 29 --- .../unlock-page/unlock-page.container.test.js | 48 ----- ui/pages/unlock-page/unlock-page.test.js | 65 ++++++ 22 files changed, 823 insertions(+), 367 deletions(-) create mode 100644 ui/components/app/modals/reject-transactions/__snapshots__/reject-transactions.test.js.snap create mode 100644 ui/components/app/modals/transaction-confirmed/__snapshots__/transaction-confirmed.test.js.snap create mode 100644 ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap create mode 100644 ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap create mode 100644 ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap create mode 100644 ui/components/ui/alert/__snapshots__/index.test.js.snap create mode 100644 ui/pages/keychains/__snapshots__/reveal-seed.test.js.snap create mode 100644 ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap delete mode 100644 ui/pages/unlock-page/unlock-page.component.test.js delete mode 100644 ui/pages/unlock-page/unlock-page.container.test.js create mode 100644 ui/pages/unlock-page/unlock-page.test.js diff --git a/ui/components/app/asset-list-item/asset-list-item.js b/ui/components/app/asset-list-item/asset-list-item.js index bc19aff878c8..f05992bb4e85 100644 --- a/ui/components/app/asset-list-item/asset-list-item.js +++ b/ui/components/app/asset-list-item/asset-list-item.js @@ -111,6 +111,7 @@ const AssetListItem = ({ title={ + + + + +`; diff --git a/ui/components/app/modals/reject-transactions/reject-transactions.test.js b/ui/components/app/modals/reject-transactions/reject-transactions.test.js index e8ec7a7b5bff..ce61a0c04bb3 100644 --- a/ui/components/app/modals/reject-transactions/reject-transactions.test.js +++ b/ui/components/app/modals/reject-transactions/reject-transactions.test.js @@ -1,45 +1,44 @@ import React from 'react'; -import sinon from 'sinon'; -import { mount } from 'enzyme'; -import RejectTransactionsModal from './reject-transactions.container'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import RejectTransactionsModal from '.'; describe('Reject Transactions Model', () => { - let wrapper; - const props = { - onSubmit: sinon.spy(), - hideModal: sinon.spy(), + onSubmit: jest.fn(), + hideModal: jest.fn(), unapprovedTxCount: 2, }; - beforeEach(() => { - wrapper = mount(, { - context: { - t: (str) => str, - }, - }); - }); + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + ); - afterEach(() => { - props.hideModal.resetHistory(); + expect(container).toMatchSnapshot(); }); it('hides modal when cancel button is clicked', () => { - const cancelButton = wrapper.find( - '.btn-secondary.modal-container__footer-button', + const { queryByText } = renderWithProvider( + , ); - cancelButton.simulate('click'); - expect(props.hideModal.calledOnce).toStrictEqual(true); + fireEvent.click(queryByText('[cancel]')); + + expect(props.onSubmit).not.toHaveBeenCalled(); + expect(props.hideModal).toHaveBeenCalled(); }); it('onSubmit is called and hides modal when reject all clicked', async () => { - const rejectAllButton = wrapper.find( - '.btn-primary.modal-container__footer-button', + const { queryByText } = renderWithProvider( + , ); - rejectAllButton.simulate('click'); - expect(await props.onSubmit.calledOnce).toStrictEqual(true); - expect(props.hideModal.calledOnce).toStrictEqual(true); + fireEvent.click(queryByText('[rejectAll]')); + + await waitFor(() => { + expect(props.onSubmit).toHaveBeenCalled(); + expect(props.hideModal).toHaveBeenCalled(); + }); }); }); diff --git a/ui/components/app/modals/transaction-confirmed/__snapshots__/transaction-confirmed.test.js.snap b/ui/components/app/modals/transaction-confirmed/__snapshots__/transaction-confirmed.test.js.snap new file mode 100644 index 000000000000..becdc38e4f52 --- /dev/null +++ b/ui/components/app/modals/transaction-confirmed/__snapshots__/transaction-confirmed.test.js.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transaction Confirmed should match snapshot 1`] = ` +
+ +
+`; diff --git a/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js b/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js index 0e1658242192..411324f4b7ac 100644 --- a/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js +++ b/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js @@ -1,26 +1,30 @@ import React from 'react'; -import sinon from 'sinon'; -import { mount } from 'enzyme'; -import TransactionConfirmed from './transaction-confirmed.container'; +import { fireEvent } from '@testing-library/react'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import TransactionConfirmed from '.'; describe('Transaction Confirmed', () => { + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + ); + + expect(container).toMatchSnapshot(); + }); + it('clicks ok to submit and hide modal', () => { const props = { - onSubmit: sinon.spy(), - hideModal: sinon.spy(), + onSubmit: jest.fn(), + hideModal: jest.fn(), }; - const wrapper = mount( + + const { queryByText } = renderWithProvider( , - { - context: { - t: (str) => str, - }, - }, ); - const submit = wrapper.find('.btn-primary.modal-container__footer-button'); - submit.simulate('click'); - expect(props.onSubmit.calledOnce).toStrictEqual(true); - expect(props.hideModal.calledOnce).toStrictEqual(true); + fireEvent.click(queryByText('[ok]')); + + expect(props.onSubmit).toHaveBeenCalled(); + expect(props.hideModal).toHaveBeenCalled(); }); }); diff --git a/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap new file mode 100644 index 000000000000..30f4376f7176 --- /dev/null +++ b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectedAccount Component should match snapshot 1`] = ` +
+ +
+`; diff --git a/ui/components/app/selected-account/selected-account-component.test.js b/ui/components/app/selected-account/selected-account-component.test.js index bc55c7e7e37c..d2bd5197dcc3 100644 --- a/ui/components/app/selected-account/selected-account-component.test.js +++ b/ui/components/app/selected-account/selected-account-component.test.js @@ -1,24 +1,32 @@ import React from 'react'; -import { render } from 'enzyme'; -import SelectedAccount from './selected-account.component'; +import configureMockStore from 'redux-mock-store'; +import copyToClipboard from 'copy-to-clipboard'; +import { fireEvent } from '@testing-library/react'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import mockState from '../../../../test/data/mock-state.json'; +import SelectedAccount from '.'; + +jest.mock('copy-to-clipboard'); describe('SelectedAccount Component', () => { - it('should render checksummed address', () => { - const wrapper = render( - , - { context: { t: () => undefined } }, - ); - // Checksummed version of address is displayed - expect(wrapper.find('.selected-account__address').text()).toStrictEqual( - '0x1B8...5C9D', + const mockStore = configureMockStore()(mockState); + + it('should match snapshot', () => { + const { container } = renderWithProvider(, mockStore); + + expect(container).toMatchSnapshot(); + }); + + it('should copy checksum address to clipboard when button is clicked', () => { + const { queryByTestId } = renderWithProvider( + , + mockStore, ); - expect(wrapper.find('.selected-account__name').text()).toStrictEqual( - 'testName', + + fireEvent.click(queryByTestId('selected-account-click')); + + expect(copyToClipboard).toHaveBeenCalledWith( + '0x0DCD5D886577d5081B0c52e242Ef29E70Be3E7bc', ); }); }); diff --git a/ui/components/app/selected-account/selected-account.component.js b/ui/components/app/selected-account/selected-account.component.js index 06609b54f263..df7b07e18ea5 100644 --- a/ui/components/app/selected-account/selected-account.component.js +++ b/ui/components/app/selected-account/selected-account.component.js @@ -48,6 +48,7 @@ class SelectedAccount extends Component { > + +
+

+ $0.52 USD +

+
+ + + +`; diff --git a/ui/components/app/token-cell/token-cell.test.js b/ui/components/app/token-cell/token-cell.test.js index e7fe6069b014..8179047e818c 100644 --- a/ui/components/app/token-cell/token-cell.test.js +++ b/ui/components/app/token-cell/token-cell.test.js @@ -1,18 +1,12 @@ import React from 'react'; import thunk from 'redux-thunk'; -import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; -import { mount } from 'enzyme'; -import sinon from 'sinon'; -import { MemoryRouter } from 'react-router-dom'; - -import Identicon from '../../ui/identicon'; +import { fireEvent } from '@testing-library/react'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; import TokenCell from '.'; describe('Token Cell', () => { - let wrapper; - - const state = { + const mockState = { metamask: { currentCurrency: 'usd', selectedAddress: '0xAddress', @@ -29,60 +23,33 @@ describe('Token Cell', () => { }, }; - const middlewares = [thunk]; - const mockStore = configureMockStore(middlewares); - const store = mockStore(state); + const mockStore = configureMockStore([thunk])(mockState); - let onClick; + const props = { + address: '0xAnotherToken', + symbol: 'TEST', + string: '5.000', + currentCurrency: 'usd', + onClick: jest.fn(), + }; - beforeEach(() => { - onClick = sinon.stub(); - wrapper = mount( - - - - - , + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + mockStore, ); - }); - afterEach(() => { - sinon.restore(); + expect(container).toMatchSnapshot(); }); - it('renders Identicon with props from token cell', () => { - expect(wrapper.find(Identicon).prop('address')).toStrictEqual( - '0xAnotherToken', - ); - }); - - it('renders token balance', () => { - expect(wrapper.find('.asset-list-item__token-value').text()).toStrictEqual( - '5.000', - ); - }); - - it('renders token symbol', () => { - expect(wrapper.find('.asset-list-item__token-symbol').text()).toStrictEqual( - 'TEST', + it('calls onClick when clicked', () => { + const { queryByTestId } = renderWithProvider( + , + mockStore, ); - }); - it('renders converted fiat amount', () => { - expect(wrapper.find('.list-item__subheading').text()).toStrictEqual( - '$0.52 USD', - ); - }); + fireEvent.click(queryByTestId('token-button')); - it('calls onClick when clicked', () => { - expect(!onClick.called).toStrictEqual(true); - wrapper.simulate('click'); - expect(onClick.called).toStrictEqual(true); + expect(props.onClick).toHaveBeenCalled(); }); }); diff --git a/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap b/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap new file mode 100644 index 000000000000..cc5eeea68fee --- /dev/null +++ b/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TransactionActivityLog Component should match snapshot 1`] = ` +
+
+
+ [activityLog] +
+
+
+
+ +
+
+
+ [transactionCreated] +
+
+
+
+
+ +
+
+
+ [transactionSubmitted] +
+
+
+
+
+ +
+
+
+ [transactionResubmitted] +
+
+
+
+
+ +
+
+
+ [transactionConfirmed] +
+
+
+
+
+
+`; diff --git a/ui/components/app/transaction-activity-log/transaction-activity-log.component.test.js b/ui/components/app/transaction-activity-log/transaction-activity-log.component.test.js index 1c80d9fa9732..3308136d1ce7 100644 --- a/ui/components/app/transaction-activity-log/transaction-activity-log.component.test.js +++ b/ui/components/app/transaction-activity-log/transaction-activity-log.component.test.js @@ -1,163 +1,55 @@ import React from 'react'; -import { shallow } from 'enzyme'; -import TransactionActivityLog from './transaction-activity-log.component'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import TransactionActivityLog from '.'; describe('TransactionActivityLog Component', () => { - it('should render properly', () => { - const activities = [ - { - eventKey: 'transactionCreated', - hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', - id: 2005383477493174, - timestamp: 1543957986150, - value: '0x2386f26fc10000', - }, - { - eventKey: 'transactionSubmitted', - hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', - id: 2005383477493174, - timestamp: 1543957987853, - value: '0x1319718a5000', - }, - { - eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 2005383477493175, - timestamp: 1543957991563, - value: '0x1502634b5800', - }, - { - eventKey: 'transactionConfirmed', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 2005383477493175, - timestamp: 1543958029960, - value: '0x1502634b5800', - }, - ]; - - const wrapper = shallow( - undefined} - onRetry={() => undefined} - primaryTransactionStatus="confirmed" - />, - { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, + const activities = [ + { + eventKey: 'transactionCreated', + hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', + id: 2005383477493174, + timestamp: 1543957986150, + value: '0x2386f26fc10000', + }, + { + eventKey: 'transactionSubmitted', + hash: '0xe46c7f9b39af2fbf1c53e66f72f80343ab54c2c6dba902d51fb98ada08fe1a63', + id: 2005383477493174, + timestamp: 1543957987853, + value: '0x1319718a5000', + }, + { + eventKey: 'transactionResubmitted', + hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + id: 2005383477493175, + timestamp: 1543957991563, + value: '0x1502634b5800', + }, + { + eventKey: 'transactionConfirmed', + hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', + id: 2005383477493175, + timestamp: 1543958029960, + value: '0x1502634b5800', + }, + ]; + + const props = { + activities, + className: 'test-class', + inlineRetryIndex: -1, + inlineCancelIndex: -1, + nativeCurrency: 'ETH', + onCancel: jest.fn(), + onRetry: jest.fn(), + primaryTransactionStatus: 'confirmed', + }; + + it('should match snapshot', () => { + const { container } = renderWithProvider( + , ); - expect(wrapper.hasClass('transaction-activity-log')).toStrictEqual(true); - expect(wrapper.hasClass('test-class')).toStrictEqual(true); - }); - - it('should render inline retry and cancel buttons for earliest pending transaction', () => { - const activities = [ - { - eventKey: 'transactionCreated', - hash: '0xa', - id: 1, - timestamp: 1, - value: '0x1', - }, - { - eventKey: 'transactionSubmitted', - hash: '0xa', - id: 1, - timestamp: 2, - value: '0x1', - }, - { - eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 2, - timestamp: 3, - value: '0x1', - }, - { - eventKey: 'transactionCancelAttempted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 3, - timestamp: 4, - value: '0x1', - }, - ]; - - const wrapper = shallow( - undefined} - onRetry={() => undefined} - primaryTransactionStatus="pending" - isEarliestNonce - />, - { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, - ); - - expect(wrapper.hasClass('transaction-activity-log')).toStrictEqual(true); - expect(wrapper.hasClass('test-class')).toStrictEqual(true); - expect(wrapper.find('.transaction-activity-log__action-link')).toHaveLength( - 2, - ); - }); - - it('should not render inline retry and cancel buttons for newer pending transactions', () => { - const activities = [ - { - eventKey: 'transactionCreated', - hash: '0xa', - id: 1, - timestamp: 1, - value: '0x1', - }, - { - eventKey: 'transactionSubmitted', - hash: '0xa', - id: 1, - timestamp: 2, - value: '0x1', - }, - { - eventKey: 'transactionResubmitted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 2, - timestamp: 3, - value: '0x1', - }, - { - eventKey: 'transactionCancelAttempted', - hash: '0x7d09d337fc6f5d6fe2dbf3a6988d69532deb0a82b665f9180b5a20db377eea87', - id: 3, - timestamp: 4, - value: '0x1', - }, - ]; - - const wrapper = shallow( - undefined} - onRetry={() => undefined} - primaryTransactionStatus="pending" - isEarliestNonce={false} - />, - { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, - ); - - expect(wrapper.hasClass('transaction-activity-log')).toStrictEqual(true); - expect(wrapper.hasClass('test-class')).toStrictEqual(true); - expect(wrapper.find('.transaction-activity-log__action-link')).toHaveLength( - 0, - ); + expect(container).toMatchSnapshot(); }); }); diff --git a/ui/components/ui/alert/__snapshots__/index.test.js.snap b/ui/components/ui/alert/__snapshots__/index.test.js.snap new file mode 100644 index 000000000000..f048d799182a --- /dev/null +++ b/ui/components/ui/alert/__snapshots__/index.test.js.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Alert renders nothing with no visible boolean in state 1`] = `
`; + +exports[`Alert renders with visible boolean in state 1`] = ` + +`; diff --git a/ui/components/ui/alert/index.test.js b/ui/components/ui/alert/index.test.js index 7689d6d83ed3..7c5900f811e9 100644 --- a/ui/components/ui/alert/index.test.js +++ b/ui/components/ui/alert/index.test.js @@ -1,16 +1,25 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; import Alert from '.'; describe('Alert', () => { - let wrapper; + it('renders nothing with no visible boolean in state', () => { + const props = { + visible: false, + }; + + const { container } = renderWithProvider(); - beforeEach(() => { - wrapper = shallow(); + expect(container).toMatchSnapshot(); }); - it('renders nothing with no visible boolean in state', () => { - const alert = wrapper.find('.global-alert'); - expect(alert).toHaveLength(0); + it('renders with visible boolean in state', () => { + const props = { + visible: true, + }; + + const { container } = renderWithProvider(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/ui/pages/keychains/__snapshots__/reveal-seed.test.js.snap b/ui/pages/keychains/__snapshots__/reveal-seed.test.js.snap new file mode 100644 index 000000000000..7006aa5797ed --- /dev/null +++ b/ui/pages/keychains/__snapshots__/reveal-seed.test.js.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Reveal Seed Page should match snapshot 1`] = ` +
+
+
+
+ Secret Recovery Phrase +
+
+ If you ever change browsers or move computers, you will need this Secret Recovery Phrase to access your accounts. Save them somewhere safe and secret. +
+
+
+
+ +
+
+ DO NOT share this phrase with anyone! +
+
+ These words can be used to steal all your accounts. +
+
+
+
+
+ +
+ +
+
+
+
+ +
+
+`; diff --git a/ui/pages/keychains/reveal-seed.js b/ui/pages/keychains/reveal-seed.js index 44bf74e187d6..a57611f2678b 100644 --- a/ui/pages/keychains/reveal-seed.js +++ b/ui/pages/keychains/reveal-seed.js @@ -85,6 +85,7 @@ class RevealSeedPage extends Component {
({ + requestRevealSeedWords: () => mockRequestRevealSeedWords, +})); + describe('Reveal Seed Page', () => { - it('form submit', () => { - const props = { - history: { - push: sinon.spy(), - }, - requestRevealSeedWords: sinon.stub().resolves(), + const mockState = { + history: { mostRecentOverviewPage: '/', - }; - const wrapper = mount(, { - context: { - t: (str) => str, - }, + }, + }; + const mockStore = configureMockStore([thunk])(mockState); + + it('should match snapshot', () => { + const { container } = renderWithProvider(, mockStore); + + expect(container).toMatchSnapshot(); + }); + + it('form submit', () => { + const { queryByTestId, queryByText } = renderWithProvider( + , + mockStore, + ); + + fireEvent.change(queryByTestId('input-password'), { + target: { value: 'password' }, }); - wrapper.find('form').simulate('submit'); - expect(props.requestRevealSeedWords.calledOnce).toStrictEqual(true); + fireEvent.click(queryByText('Next')); + + expect(mockRequestRevealSeedWords).toHaveBeenCalled(); }); }); diff --git a/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap b/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap new file mode 100644 index 000000000000..a8ed6e41e3ee --- /dev/null +++ b/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Unlock Page should match snapshot 1`] = ` + +`; diff --git a/ui/pages/unlock-page/unlock-page.component.js b/ui/pages/unlock-page/unlock-page.component.js index 690124793d60..33a3aff834e9 100644 --- a/ui/pages/unlock-page/unlock-page.component.js +++ b/ui/pages/unlock-page/unlock-page.component.js @@ -150,6 +150,7 @@ export default class UnlockPage extends Component { return (