diff --git a/.circleci/config.yml b/.circleci/config.yml index 973ee001a..a2ab03bfc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -391,7 +391,7 @@ jobs: destination: test-artifacts test-e2e-firefox: - executor: node-browsers + executor: node-browsers-medium-plus steps: - checkout - run: diff --git a/.circleci/scripts/create-lavamoat-viz.sh b/.circleci/scripts/create-lavamoat-viz.sh index 53e520f27..db1dc3979 100755 --- a/.circleci/scripts/create-lavamoat-viz.sh +++ b/.circleci/scripts/create-lavamoat-viz.sh @@ -11,7 +11,7 @@ BUILD_DEST="./build-artifacts/build-viz/" mkdir -p "${BUILD_DEST}" # generate lavamoat debug config -yarn lavamoat:debug +yarn lavamoat:debug:build # generate viz npx lavamoat-viz --dest "${BUILD_DEST}" \ No newline at end of file diff --git a/.circleci/scripts/validate-allow-scripts.sh b/.circleci/scripts/validate-allow-scripts.sh index e466f039c..de45520ad 100755 --- a/.circleci/scripts/validate-allow-scripts.sh +++ b/.circleci/scripts/validate-allow-scripts.sh @@ -6,7 +6,7 @@ set -o pipefail yarn allow-scripts auto -if git diff --exit-code --quiet +if git diff --exit-code then echo "allow-scripts configuration is up-to-date" else diff --git a/.circleci/scripts/validate-lavamoat-policy.sh b/.circleci/scripts/validate-lavamoat-policy.sh index 4eab30b75..d674cd3f0 100755 --- a/.circleci/scripts/validate-lavamoat-policy.sh +++ b/.circleci/scripts/validate-lavamoat-policy.sh @@ -6,7 +6,7 @@ set -o pipefail yarn lavamoat:auto -if git diff --exit-code --quiet +if git diff --exit-code then echo "LavaMoat policy is up-to-date" else diff --git a/.eslintrc.js b/.eslintrc.js index ca9fe4677..7f8d6695e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -183,6 +183,7 @@ module.exports = { 'nyc.config.js', 'stylelint.config.js', 'app/scripts/lockdown-run.js', + 'app/scripts/lockdown-more.js', 'development/**/*.js', 'test/e2e/**/*.js', 'test/lib/wait-until-called.js', @@ -197,6 +198,7 @@ module.exports = { { files: [ 'app/scripts/lockdown-run.js', + 'app/scripts/lockdown-more.js', 'test/unit-global/protect-intrinsics.test.js', ], globals: { diff --git a/.storybook/actions/sb-send-action.js b/.storybook/actions/sb-send-action.js new file mode 100644 index 000000000..c1e66e41c --- /dev/null +++ b/.storybook/actions/sb-send-action.js @@ -0,0 +1,9 @@ +export const updateSendAsset = (type) => ({ + type: 'send/updateSendAsset', + payload: type, +}); + +export const updateSendStage = (stage) => ({ + type: 'send/updateSendStage', + payload: stage, +}); diff --git a/.storybook/initial-states/approval-screens/add-suggested-token.js b/.storybook/initial-states/approval-screens/add-suggested-token.js index 0b623e3f7..5cd10451c 100644 --- a/.storybook/initial-states/approval-screens/add-suggested-token.js +++ b/.storybook/initial-states/approval-screens/add-suggested-token.js @@ -1,65 +1,83 @@ -export const suggestedTokens = { - "0x6b175474e89094c44da98b954eedeac495271d0f": { - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "symbol": "META", - "decimals": 18, - "image": "metamark.svg", - "unlisted": false +export const suggestedAssets = [ + { + asset: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'META', + decimals: 18, + image: 'metamark.svg', + unlisted: false }, - "0xB8c77482e45F1F44dE1745F52C74426C631bDD52": { - "address": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "symbol": "0X", - "decimals": 18, - "image": "0x.svg", - "unlisted": false + }, + { + asset: { + 'address': '0xB8c77482e45F1F44dE1745F52C74426C631bDD52', + 'symbol': '0X', + 'decimals': 18, + 'image': '0x.svg', + 'unlisted': false }, - "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984": { - "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", - "symbol": "AST", - "decimals": 18, - "image": "ast.png", - "unlisted": false + }, + { + asset: { + 'address': '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', + 'symbol': 'AST', + 'decimals': 18, + 'image': 'ast.png', + 'unlisted': false }, - "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2": { - "address": "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2", - "symbol": "BAT", - "decimals": 18, - "image": "BAT_icon.svg", - "unlisted": false + }, + { + asset: { + 'address': '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', + 'symbol': 'BAT', + 'decimals': 18, + 'image': 'BAT_icon.svg', + 'unlisted': false }, - "0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1": { - "address": "0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1", - "symbol": "CVL", - "decimals": 18, - "image": "CVL_token.svg", - "unlisted": false + }, + { + asset: { + 'address': '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1', + 'symbol': 'CVL', + 'decimals': 18, + 'image': 'CVL_token.svg', + 'unlisted': false }, - "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e": { - "address": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e", - "symbol": "GLA", - "decimals": 18, - "image": "gladius.svg", - "unlisted": false + }, + { + asset: { + 'address': '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e', + 'symbol': 'GLA', + 'decimals': 18, + 'image': 'gladius.svg', + 'unlisted': false }, - "0x467Bccd9d29f223BcE8043b84E8C8B282827790F": { - "address": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", - "symbol": "GNO", - "decimals": 18, - "image": "gnosis.svg", - "unlisted": false + }, + { + asset: { + 'address': '0x467Bccd9d29f223BcE8043b84E8C8B282827790F', + 'symbol': 'GNO', + 'decimals': 18, + 'image': 'gnosis.svg', + 'unlisted': false }, - "0xff20817765cb7f73d4bde2e66e067e58d11095c2": { - "address": "0xff20817765cb7f73d4bde2e66e067e58d11095c2", - "symbol": "OMG", - "decimals": 18, - "image": "omg.jpg", - "unlisted": false + }, + { + asset: { + 'address': '0xff20817765cb7f73d4bde2e66e067e58d11095c2', + 'symbol': 'OMG', + 'decimals': 18, + 'image': 'omg.jpg', + 'unlisted': false }, - "0x8e870d67f660d95d5be530380d0ec0bd388289e1": { - "address": "0x8e870d67f660d95d5be530380d0ec0bd388289e1", - "symbol": "WED", - "decimals": 18, - "image": "wed.png", - "unlisted": false + }, + { + asset: { + 'address': '0x8e870d67f660d95d5be530380d0ec0bd388289e1', + 'symbol': 'WED', + 'decimals': 18, + 'image': 'wed.png', + 'unlisted': false }, - } \ No newline at end of file + }, +] diff --git a/.storybook/reducers/sb-history-reducer.js b/.storybook/reducers/sb-history-reducer.js new file mode 100644 index 000000000..a3d282a27 --- /dev/null +++ b/.storybook/reducers/sb-history-reducer.js @@ -0,0 +1,9 @@ +import testData from '../test-data'; + +const initialState = { ...testData.history }; +export default function historySBReducer(state = initialState, action) { + switch (action.type) { + default: + return state; + } +} diff --git a/.storybook/reducers/sb-send-reducer.js b/.storybook/reducers/sb-send-reducer.js new file mode 100644 index 000000000..c53cd1bb7 --- /dev/null +++ b/.storybook/reducers/sb-send-reducer.js @@ -0,0 +1,19 @@ +import testData from '../test-data'; + +const initialState = { ...testData.send }; +export default function sendSBReducer(state = initialState, action) { + switch (action.type) { + case 'send/updateSendStage': + return { + ...state, + stage: action.payload, + }; + case 'send/updateSendAsset': + return { + ...state, + asset: { ...state.asset, type: action.payload }, + }; + default: + return state; + } +} diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 766196d2f..1e1e0e397 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -1,5 +1,3 @@ -import { TRANSACTION_STATUSES } from '../shared/constants/transaction'; - const state = { invalidCustomNetwork: { state: 'CLOSED', @@ -16,11 +14,109 @@ const state = { url: 'https://metamask.github.io/test-dapp/', }, metamask: { + tokenList: { + '0x6b175474e89094c44da98b954eedeac495271d0f': { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'META', + decimals: 18, + image: 'metamark.svg', + unlisted: false + }, + '0xB8c77482e45F1F44dE1745F52C74426C631bDD52': { + address: '0xB8c77482e45F1F44dE1745F52C74426C631bDD52', + symbol: '0X', + decimals: 18, + image: '0x.svg', + unlisted: false + }, + '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': { + address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', + symbol: 'AST', + decimals: 18, + image: 'ast.png', + unlisted: false + }, + '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2': { + address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', + symbol: 'BAT', + decimals: 18, + image: 'BAT_icon.svg', + unlisted: false + }, + '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1': { + address: '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1', + symbol: 'CVL', + decimals: 18, + image: 'CVL_token.svg', + unlisted: false + }, + '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e': { + address: '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e', + symbol: 'GLA', + decimals: 18, + image: 'gladius.svg', + unlisted: false + }, + '0x467Bccd9d29f223BcE8043b84E8C8B282827790F': { + address: '0x467Bccd9d29f223BcE8043b84E8C8B282827790F', + symbol: 'GNO', + decimals: 18, + image: 'gnosis.svg', + unlisted: false + }, + '0xff20817765cb7f73d4bde2e66e067e58d11095c2': { + address: '0xff20817765cb7f73d4bde2e66e067e58d11095c2', + symbol: 'OMG', + decimals: 18, + image: 'omg.jpg', + unlisted: false + }, + '0x8e870d67f660d95d5be530380d0ec0bd388289e1': { + address: '0x8e870d67f660d95d5be530380d0ec0bd388289e1', + symbol: 'WED', + decimals: 18, + image: 'wed.png', + unlisted: false + }, + }, networkDetails: { EIPS: { 1559: true, }, }, + gasFeeEstimates: '0x5208', + swapsState: { + quotes: {}, + fetchParams: null, + tokens: null, + tradeTxId: null, + approveTxId: null, + quotesLastFetched: null, + customMaxGas: '', + customGasPrice: null, + selectedAggId: null, + customApproveTxData: '', + errorKey: '', + topAggId: null, + routeState: '', + swapsFeatureIsLive: false, + swapsQuoteRefreshTime: 60000, + }, + accountArray: [ + { + name: 'This is a Really Long Account Name', + address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4', + index: 0, + balance: '0x176e5b6f173ebe66', + }, + { + name: 'Account 2', + address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', + index: 1, + balance: '0x2d3142f5000', + }, + ], + connectedAccounts: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'], isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, @@ -103,12 +199,6 @@ const state = { }, }, }, - recipient: { - address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0', - nickname: 'John Doe', - error: '', - warning: '', - }, addresses: [ { address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0', @@ -366,6 +456,15 @@ const state = { value: '0x9c2686', }, ], + [ + { + note: 'txStateManager: setting status to confirmed', + op: 'replace', + path: '/status', + timestamp: 1629582721178, + value: 'confirmed', + }, + ], [ { note: 'txStateManager: setting status to confirmed', @@ -794,7 +893,7 @@ const state = { '0xaD6D458402F60fD3Bd25163575031ACDce07538D': './sai.svg', }, hiddenTokens: [], - suggestedTokens: {}, + suggestedAssets: {}, useNonceField: false, usePhishDetect: true, lostIdentities: {}, @@ -1165,6 +1264,11 @@ const state = { balance: '0x0', details: null, }, + stage: 'ADD_RECIPIENT', + amount: '3782dace9d900000', + gas: { + price: null, + }, }, confirmTransaction: { txData: { diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 50fa63a2e..3217ceb56 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -1124,15 +1124,6 @@ "viewContact": { "message": "ዕውቂያን ይመልከቱ" }, - "viewOnCustomBlockExplorer": { - "message": "በ $1ይመልከቱ" - }, - "viewOnEtherscan": { - "message": "በ Etherscan ላይ ይመልከቱ" - }, - "viewinExplorer": { - "message": "በኤክስፕሎረር ተመልከት" - }, "visitWebSite": { "message": "ድረ ገጻችንን ይጎብኙ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 5f37cb4e1..3c63ec354 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -1120,15 +1120,6 @@ "viewContact": { "message": "عرض جهة الاتصال" }, - "viewOnCustomBlockExplorer": { - "message": "عرض في $1" - }, - "viewOnEtherscan": { - "message": "عرضه على Etherscan" - }, - "viewinExplorer": { - "message": "عرض في متصفح Explorer" - }, "visitWebSite": { "message": "قم بزيارة موقعنا على الإنترنت" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 57196e3b3..ceaa2f9f6 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -1123,15 +1123,6 @@ "viewContact": { "message": "Преглед на контакта" }, - "viewOnCustomBlockExplorer": { - "message": "Преглед на $1" - }, - "viewOnEtherscan": { - "message": "Преглед на Etherscan" - }, - "viewinExplorer": { - "message": "Преглед в Explorer" - }, "visitWebSite": { "message": "Посетете нашият уеб сайт" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 19c45effd..84369b869 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -1127,15 +1127,6 @@ "viewContact": { "message": "পরিচিতি দেখুন" }, - "viewOnCustomBlockExplorer": { - "message": "$1 এ দেখুন" - }, - "viewOnEtherscan": { - "message": "Etherscan দেখুন" - }, - "viewinExplorer": { - "message": "এক্সপ্লোরারে দেখুন" - }, "visitWebSite": { "message": "আমাদের ওয়েবসাইট দেখুন" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index fe3311ead..8f5c9aa15 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -1096,15 +1096,6 @@ "viewContact": { "message": "Veure Contacte" }, - "viewOnCustomBlockExplorer": { - "message": "Mostra a $1" - }, - "viewOnEtherscan": { - "message": "Veure a Etherscan" - }, - "viewinExplorer": { - "message": "Mostra a Explorer" - }, "visitWebSite": { "message": "Visita el nostre lloc web" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index c4c147bda..64c677d92 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -1096,15 +1096,6 @@ "viewContact": { "message": "Vis kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Se på $1" - }, - "viewOnEtherscan": { - "message": "Se på Etherscan" - }, - "viewinExplorer": { - "message": "Vis i stifinder" - }, "visitWebSite": { "message": "Besøg vores webside" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index d6e52d78b..2165ab0da 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1087,15 +1087,6 @@ "viewContact": { "message": "Kontakt anzeigen" }, - "viewOnCustomBlockExplorer": { - "message": "Für $1 ansehen" - }, - "viewOnEtherscan": { - "message": "Auf Etherscan ansehen" - }, - "viewinExplorer": { - "message": "Im Explorer anzeigen" - }, "visitWebSite": { "message": "Gehe zu unserer Webseite" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index e7239b9ae..91d8915e4 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1121,15 +1121,6 @@ "viewContact": { "message": "Εμφάνιση Επαφής" }, - "viewOnCustomBlockExplorer": { - "message": "Προβολή σε $1" - }, - "viewOnEtherscan": { - "message": "Προβολή στο Etherscan" - }, - "viewinExplorer": { - "message": "Προβολή στον Εξερευνητή" - }, "visitWebSite": { "message": "Επισκεφθείτε τον ιστότοπό μας" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index e892f5040..38ec6484f 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -259,6 +259,22 @@ "betaWelcome": { "message": "Welcome to MetaMask Beta" }, + "blockExplorerAccountAction": { + "message": "Account", + "description": "This is used with viewOnEtherscan and viewInExplorer e.g View Account in Explorer" + }, + "blockExplorerAssetAction": { + "message": "Asset", + "description": "This is used with viewOnEtherscan and viewInExplorer e.g View Asset in Explorer" + }, + "blockExplorerSwapAction": { + "message": "Swap", + "description": "This is used with viewOnEtherscan e.g View Swap on Etherscan" + }, + "blockExplorerTransactionAction": { + "message": "Transaction", + "description": "This is used with viewOnCustomBlockExplorer and viewOnEtherscan e.g View Transaction on Etherscan" + }, "blockExplorerUrl": { "message": "Block Explorer URL" }, @@ -405,7 +421,7 @@ "message": "You have 1 account connected to this site." }, "connectedAccountsEmptyDescription": { - "message": "MetaMask is not connected this site. To connect to a web3 site, find the connect button on their site." + "message": "MetaMask is not connected to this site. To connect to a web3 site, find and click the connect button." }, "connectedSites": { "message": "Connected sites" @@ -1026,6 +1042,9 @@ "getStarted": { "message": "Get Started" }, + "goBack": { + "message": "Go Back" + }, "goerli": { "message": "Goerli Test Network" }, @@ -1191,6 +1210,9 @@ "ipfsGatewayDescription": { "message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution." }, + "jsDeliver": { + "message": "jsDeliver" + }, "jsonFile": { "message": "JSON File", "description": "format for importing an account" @@ -1601,6 +1623,14 @@ "message": "\"$1\" will close this tab and direct back to $2", "description": "Return the user to the site that initiated onboarding" }, + "onboardingShowIncomingTransactionsDescription": { + "message": "Showing incoming transactions in your wallet relies on communication with $1. Etherscan will have access to your Ethereum address and your IP address. View $2.", + "description": "$1 is a clickable link with text defined by the 'etherscan' key. $2 is a clickable link with text defined by the 'privacyMsg' key." + }, + "onboardingUsePhishingDetectionDescription": { + "message": "Phishing detection alerts rely on communication with $1. jsDeliver will have access to your IP address. View $2.", + "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" + }, "onlyAddTrustedNetworks": { "message": "A malicious network provider can lie about the state of the blockchain and record your network activity. Only add custom networks you trust." }, @@ -1884,6 +1914,12 @@ "seedPhraseEnterMissingWords": { "message": "Confirm Secret Recovery Phrase" }, + "seedPhraseIntroNotRecommendedButtonCopy": { + "message": "Remind me later (not recommended)" + }, + "seedPhraseIntroRecommendedButtonCopy": { + "message": "Secure my wallet (recommended)" + }, "seedPhraseIntroSidebarBulletFour": { "message": "Write down and store in multiple secret places." }, @@ -1897,13 +1933,13 @@ "message": "Store in a bank vault." }, "seedPhraseIntroSidebarCopyOne": { - "message": "Your Secret Recovery Phrase is the “master key” to your wallet and funds." + "message": "Your Secret Recovery Phrase is a 12-word phrase that is the “master key” to your wallet and your funds" }, "seedPhraseIntroSidebarCopyThree": { - "message": "If someone asks for your Secret Recovery Phrase, they are most likely trying to scam you." + "message": "If someone asks for your recovery phrase they are likely trying to scam you and steal your wallet funds" }, "seedPhraseIntroSidebarCopyTwo": { - "message": "Never, ever share your Secret Recovery Phrase, even with MetaMask!" + "message": "Never, ever share your Secret Recovery Phrase, not even with MetaMask!" }, "seedPhraseIntroSidebarTitleOne": { "message": "What is a Secret Recovery Phrase?" @@ -1995,6 +2031,12 @@ "separateEachWord": { "message": "Separate each word with a single space" }, + "setAdvancedPrivacySettings": { + "message": "Set advanced privacy settings" + }, + "setAdvancedPrivacySettingsDetails": { + "message": "MetaMask uses these trusted third-party services to enhance product usability and safety." + }, "settings": { "message": "Settings" }, @@ -2055,6 +2097,15 @@ "signed": { "message": "Signed" }, + "skip": { + "message": "Skip" + }, + "skipAccountSecurity": { + "message": "Skip Account Security?" + }, + "skipAccountSecurityDetails": { + "message": "I understand that until I back up my Secret Recovery Phrase, I may lose my accounts and all of their assets." + }, "slow": { "message": "Slow" }, @@ -2684,6 +2735,9 @@ "tryAgain": { "message": "Try again" }, + "turnOnTokenDetection": { + "message": "Turn on Token Detection" + }, "typePassword": { "message": "Type your MetaMask password" }, @@ -2784,13 +2838,16 @@ "message": "View More" }, "viewOnCustomBlockExplorer": { - "message": "View at $1" + "message": "View $1 at $2", + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" }, "viewOnEtherscan": { - "message": "View on Etherscan" + "message": "View $1 on Etherscan", + "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, "viewinExplorer": { - "message": "View in Explorer" + "message": "View $1 in Explorer", + "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, "visitWebSite": { "message": "Visit our web site" diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index b799d2d59..61253b8af 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Ver más" }, - "viewOnCustomBlockExplorer": { - "message": "Ver en $1" - }, - "viewOnEtherscan": { - "message": "Ver en Etherscan" - }, - "viewinExplorer": { - "message": "Ver en el explorador" - }, "visitWebSite": { "message": "Visite nuestro sitio web" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index b799d2d59..61253b8af 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Ver más" }, - "viewOnCustomBlockExplorer": { - "message": "Ver en $1" - }, - "viewOnEtherscan": { - "message": "Ver en Etherscan" - }, - "viewinExplorer": { - "message": "Ver en el explorador" - }, "visitWebSite": { "message": "Visite nuestro sitio web" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index f44cca3d0..56ace12ae 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -1117,15 +1117,6 @@ "viewContact": { "message": "Kuva kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Vaata $1" - }, - "viewOnEtherscan": { - "message": "Kuva Etherscanil" - }, - "viewinExplorer": { - "message": "Kuva Exploreris" - }, "visitWebSite": { "message": "Külastage meie veebilehte" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 96b9ece48..b4eb1580c 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -1127,15 +1127,6 @@ "viewContact": { "message": "مشاهده تماس" }, - "viewOnCustomBlockExplorer": { - "message": "مشاهده در 1$1" - }, - "viewOnEtherscan": { - "message": "مشاهده در ایترسکن" - }, - "viewinExplorer": { - "message": "مشاهده در براوزر" - }, "visitWebSite": { "message": "از وب سایت ما دیدن نمایید" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 2baae1b63..a7eb15365 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -1124,15 +1124,6 @@ "viewContact": { "message": "Näytä yhteyshenkilö" }, - "viewOnCustomBlockExplorer": { - "message": "Tarkastele kohdassa $1" - }, - "viewOnEtherscan": { - "message": "Näytä Etherscanissa" - }, - "viewinExplorer": { - "message": "Tarkastele Explorerissa" - }, "visitWebSite": { "message": "Vieraile verkkosivustollamme" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index a472c8bd0..235694a2f 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -1021,15 +1021,6 @@ "viewContact": { "message": "Tingnan ang Contact" }, - "viewOnCustomBlockExplorer": { - "message": "Tingnan sa $1" - }, - "viewOnEtherscan": { - "message": "Tingnan sa Etherscan" - }, - "viewinExplorer": { - "message": "Tingnan sa Explorer" - }, "visitWebSite": { "message": "Bisitahin ang aming web site" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index f43a8f73f..6421c9c9e 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1103,15 +1103,6 @@ "viewContact": { "message": "Voir contact" }, - "viewOnCustomBlockExplorer": { - "message": "Afficher sur $1" - }, - "viewOnEtherscan": { - "message": "Voir sur Etherscan" - }, - "viewinExplorer": { - "message": "Afficher dans Explorer" - }, "visitWebSite": { "message": "Visitez notre site web" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 3ddc4e4fb..0fca79788 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -1121,15 +1121,6 @@ "viewContact": { "message": "הצג איש קשר" }, - "viewOnCustomBlockExplorer": { - "message": "הצג ב- $1" - }, - "viewOnEtherscan": { - "message": "הצג ב-Etherscan" - }, - "viewinExplorer": { - "message": "הצג באקספלורר" - }, "visitWebSite": { "message": "בקר/י באתר שלנו" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index de8052516..938b2d6fa 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "और देखें" }, - "viewOnCustomBlockExplorer": { - "message": "$1 पर देखें" - }, - "viewOnEtherscan": { - "message": "Etherscan पर देखें" - }, - "viewinExplorer": { - "message": "एक्सप्लोरर में देखें" - }, "visitWebSite": { "message": "हमारी वेबसाइट पर जाएँ" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 656fd84f9..bf117d2ba 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -1117,15 +1117,6 @@ "viewContact": { "message": "Prikaži kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Prikaži u $1" - }, - "viewOnEtherscan": { - "message": "Prikaži na Etherscanu" - }, - "viewinExplorer": { - "message": "Prikaži u Exploreru" - }, "visitWebSite": { "message": "Posjetite naše mrežno mjesto" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 6cab69c61..0b11ad742 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -688,9 +688,6 @@ "viewAccount": { "message": "Wè Kont" }, - "viewOnEtherscan": { - "message": "Wè sou Etherscan" - }, "visitWebSite": { "message": "Vizite sit entènèt nou an" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 7e8cec14b..77ead06f9 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -1117,15 +1117,6 @@ "viewContact": { "message": "Névjegy megtekintése" }, - "viewOnCustomBlockExplorer": { - "message": "Megtekintés $1-kor" - }, - "viewOnEtherscan": { - "message": "Nézze meg Etherscanen" - }, - "viewinExplorer": { - "message": "Megtekintés Explorerben" - }, "visitWebSite": { "message": "Látogass el weboldalunkra" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 80f539ad7..7df93469d 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Lihat Selengkapnya" }, - "viewOnCustomBlockExplorer": { - "message": "Lihat di $1" - }, - "viewOnEtherscan": { - "message": "Lihat di Etherscan" - }, - "viewinExplorer": { - "message": "Lihat di Explorer" - }, "visitWebSite": { "message": "Kunjungi situs web kami" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 57122608d..7752a1a4e 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1947,15 +1947,6 @@ "viewContact": { "message": "Visualizza contatto" }, - "viewOnCustomBlockExplorer": { - "message": "Vedi su $1" - }, - "viewOnEtherscan": { - "message": "Vedi su Etherscan" - }, - "viewinExplorer": { - "message": "Vista in Explorer" - }, "visitWebSite": { "message": "Visita il nostro sito web" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index e6f295cc6..c7f368b3e 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "詳細を表示" }, - "viewOnCustomBlockExplorer": { - "message": "$1 に表示" - }, - "viewOnEtherscan": { - "message": "Etherscan で表示" - }, - "viewinExplorer": { - "message": "Explorer で表示" - }, "visitWebSite": { "message": "当社の Web サイトにアクセス" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 7aad7aed4..33566d0e1 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -1127,15 +1127,6 @@ "viewContact": { "message": "ಸಂಪರ್ಕವನ್ನು ವೀಕ್ಷಿಸಿ" }, - "viewOnCustomBlockExplorer": { - "message": "$1 ನಲ್ಲಿ ವೀಕ್ಷಿಸಿ" - }, - "viewOnEtherscan": { - "message": "ಎಥೆರ್‌ಸ್ಕ್ಯಾನ್‌ನಲ್ಲಿ ವೀಕ್ಷಿಸಿ" - }, - "viewinExplorer": { - "message": "ಎಕ್ಸ್‌ಪ್ಲೋರರ್‌ನಲ್ಲಿ ವೀಕ್ಷಿಸಿ" - }, "visitWebSite": { "message": "ನಮ್ಮ ವೆಬ್ ಸೈಟ್ ಅನ್ನು ಭೇಟಿ ಮಾಡಿ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index d62801f6a..d3346651a 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "더 보기" }, - "viewOnCustomBlockExplorer": { - "message": "$1에서 보기" - }, - "viewOnEtherscan": { - "message": "Etherscan에서 보기" - }, - "viewinExplorer": { - "message": "탐색기에서 보기" - }, "visitWebSite": { "message": "당사 웹사이트 방문하기" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index f315161d8..d0e00c629 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -1127,15 +1127,6 @@ "viewContact": { "message": "Peržiūrėti kontaktą" }, - "viewOnCustomBlockExplorer": { - "message": "Peržiūrėti $1" - }, - "viewOnEtherscan": { - "message": "Peržiūrėti „Etherscan“" - }, - "viewinExplorer": { - "message": "Peržiūrėti naršyklėje" - }, "visitWebSite": { "message": "Apsilankykite mūsų svetainėje" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 3fdcc90a0..95ca3aac9 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -1123,15 +1123,6 @@ "viewContact": { "message": "Skatīt līgumu" }, - "viewOnCustomBlockExplorer": { - "message": "Skatīt $1" - }, - "viewOnEtherscan": { - "message": "Skatīt Etherscan" - }, - "viewinExplorer": { - "message": "Skatīt Explorer" - }, "visitWebSite": { "message": "Apmeklējiet mūsu tīmekļa vietni" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index 38f440b04..aca80b0f5 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -1101,15 +1101,6 @@ "viewContact": { "message": "Lihat Kenalan" }, - "viewOnCustomBlockExplorer": { - "message": "Lihat pada $1" - }, - "viewOnEtherscan": { - "message": "Lihat di Etherscan" - }, - "viewinExplorer": { - "message": "Lihat di Explorer" - }, "visitWebSite": { "message": "Kunjungi laman web kami" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index c63a23962..d23287630 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -1102,15 +1102,6 @@ "viewContact": { "message": "Se kontrakt" }, - "viewOnCustomBlockExplorer": { - "message": "Vis ved $1 " - }, - "viewOnEtherscan": { - "message": "Vis på Etherscan " - }, - "viewinExplorer": { - "message": "Se i Explorer" - }, "visitWebSite": { "message": "Besøk nettsiden vår " }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index b4c123481..9e9a3842c 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Tumingin Pa" }, - "viewOnCustomBlockExplorer": { - "message": "Tingnan sa $1" - }, - "viewOnEtherscan": { - "message": "Tingnan sa Etherscan" - }, - "viewinExplorer": { - "message": "Tingnan sa Explorer" - }, "visitWebSite": { "message": "Bisitahin ang aming website" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 4c7b7383d..d014eaf77 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -1115,15 +1115,6 @@ "viewContact": { "message": "Wyświetl kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Wyświetl w $1" - }, - "viewOnEtherscan": { - "message": "Zobacz na Etherscan" - }, - "viewinExplorer": { - "message": "Wyświetl w przeglądarce" - }, "visitWebSite": { "message": "Odwiedź naszą stronę" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 79879c23f..23fa47567 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Exibir Mais" }, - "viewOnCustomBlockExplorer": { - "message": "Exibir em $1" - }, - "viewOnEtherscan": { - "message": "Exibir no Etherscan" - }, - "viewinExplorer": { - "message": "Exibir no Explorer" - }, "visitWebSite": { "message": "Visite nosso website" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 9e934ab69..390abc7f0 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -1108,15 +1108,6 @@ "viewContact": { "message": "Vizualizare contact" }, - "viewOnCustomBlockExplorer": { - "message": "Vizualizați la $1" - }, - "viewOnEtherscan": { - "message": "Vizualizați pe Etherscan" - }, - "viewinExplorer": { - "message": "Vizualizare în Explorator" - }, "visitWebSite": { "message": "Accesați site-ul nostru" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 4d7457124..af81d4be3 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Посмотреть больше" }, - "viewOnCustomBlockExplorer": { - "message": "Посмотреть на $1" - }, - "viewOnEtherscan": { - "message": "Посмотреть на Etherscan" - }, - "viewinExplorer": { - "message": "Проводник в проводнике" - }, "visitWebSite": { "message": "Посетите наш веб-сайт" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 0a5af86c0..3fca411cd 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -1084,15 +1084,6 @@ "viewContact": { "message": "Zobraziť kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Zobraziť na $1" - }, - "viewOnEtherscan": { - "message": "Zobraziť na Etherscan" - }, - "viewinExplorer": { - "message": "Zobraziť v Exploreri" - }, "visitWebSite": { "message": "Navštivte naši stránku" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 2aa7c40d3..be803fe10 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -1112,15 +1112,6 @@ "viewContact": { "message": "Ogled stika" }, - "viewOnCustomBlockExplorer": { - "message": "Ogled na $1 " - }, - "viewOnEtherscan": { - "message": "Poglej na Etherscan" - }, - "viewinExplorer": { - "message": "Ogled v Explorerju" - }, "visitWebSite": { "message": "Obiščite našo spletno stran" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 5a21f3df1..4190db660 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -1112,15 +1112,6 @@ "viewContact": { "message": "Pogledaj kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Pogledaj na $1" - }, - "viewOnEtherscan": { - "message": "Pogledaj na Etherscan-u" - }, - "viewinExplorer": { - "message": "Pogledati u Explorer-u" - }, "visitWebSite": { "message": "Posetite našu veb lokaciju" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 790027eda..0a42affa6 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -1102,15 +1102,6 @@ "viewContact": { "message": "Visa kontakt" }, - "viewOnCustomBlockExplorer": { - "message": "Visa vid $1" - }, - "viewOnEtherscan": { - "message": "Visa på Etherscan" - }, - "viewinExplorer": { - "message": "Visa i Utforskaren" - }, "visitWebSite": { "message": "Besök vår hemsida" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 79c583c7b..5c3aed3c9 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -1105,15 +1105,6 @@ "viewContact": { "message": "Tazama Mawasiliano" }, - "viewOnCustomBlockExplorer": { - "message": "Tazama kwenye $1" - }, - "viewOnEtherscan": { - "message": "Tazama kwenye Etherscan" - }, - "viewinExplorer": { - "message": "Tazama kwenye Explorer" - }, "visitWebSite": { "message": "Tembelea Tovuti yetu" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index c65591572..fa48e14f6 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1900,15 +1900,6 @@ "viewContact": { "message": "Tingnan ang Contact" }, - "viewOnCustomBlockExplorer": { - "message": "Tingnan sa $1" - }, - "viewOnEtherscan": { - "message": "Tingnan sa Etherscan" - }, - "viewinExplorer": { - "message": "Tingnan sa Explorer" - }, "visitWebSite": { "message": "Bisitahin ang aming website" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index a9d372722..49509ac46 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -1127,15 +1127,6 @@ "viewContact": { "message": "Переглянути контакт" }, - "viewOnCustomBlockExplorer": { - "message": "Дивитись на $1" - }, - "viewOnEtherscan": { - "message": "Дивитись на Etherscan" - }, - "viewinExplorer": { - "message": "Дивитись в Explorer" - }, "visitWebSite": { "message": "Відвідайте наш веб-сайт" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 1553f11ee..5426ec6e5 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -2386,15 +2386,6 @@ "viewMore": { "message": "Xem thêm" }, - "viewOnCustomBlockExplorer": { - "message": "Xem tại $1" - }, - "viewOnEtherscan": { - "message": "Xem trên Etherscan" - }, - "viewinExplorer": { - "message": "Xem trên trình khám phá" - }, "visitWebSite": { "message": "Truy cập trang web của chúng tôi" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 1a83650d4..cbc14db78 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1924,15 +1924,6 @@ "viewContact": { "message": "查看联系人" }, - "viewOnCustomBlockExplorer": { - "message": "在 $1 查看" - }, - "viewOnEtherscan": { - "message": "在 Etherscan(以太坊浏览器)上查看" - }, - "viewinExplorer": { - "message": "在浏览器中查看" - }, "visitWebSite": { "message": "访问我们的网站" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 045826588..86263d617 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1115,15 +1115,6 @@ "viewContact": { "message": "觀看聯絡資訊" }, - "viewOnCustomBlockExplorer": { - "message": "在 $1 瀏覽" - }, - "viewOnEtherscan": { - "message": "在 Etherscan 上瀏覽" - }, - "viewinExplorer": { - "message": "在 Explorer 上瀏覽" - }, "visitWebSite": { "message": "造訪我們的網站" }, diff --git a/app/background.html b/app/background.html index 2faa31411..447efa60e 100644 --- a/app/background.html +++ b/app/background.html @@ -6,11 +6,18 @@ - - - + {{@if(it.useLavamoat)}} + + + + {{#else}} + + + + + {{/if}} {{@each(it.jsBundles) => val}} - + {{/each}} diff --git a/app/home.html b/app/home.html index 5350b31dd..d44eb6663 100644 --- a/app/home.html +++ b/app/home.html @@ -12,11 +12,18 @@
- - - + {{@if(it.useLavamoat)}} + + + + {{#else}} + + + + + {{/if}} {{@each(it.jsBundles) => val}} - + {{/each}} diff --git a/app/images/warning-icon.png b/app/images/warning-icon.png new file mode 100644 index 000000000..06b4be332 Binary files /dev/null and b/app/images/warning-icon.png differ diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 6c328d0c6..e4f55da26 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -35,6 +35,7 @@ "globalthis.js", "lockdown-install.js", "lockdown-run.js", + "lockdown-more.js", "contentscript.js" ], "run_at": "document_start", diff --git a/app/manifest/_beta_modifications.json b/app/manifest/_beta_modifications.json index a505eb7f4..33a2da321 100644 --- a/app/manifest/_beta_modifications.json +++ b/app/manifest/_beta_modifications.json @@ -22,6 +22,5 @@ "512": "images/icon-512.png" }, "name": "__MSG_appName__ Beta", - "short_name": "__MSG_appName__ Beta", - "version": "" + "short_name": "__MSG_appName__ Beta" } diff --git a/app/notification.html b/app/notification.html index 55b98c960..1002a37ef 100644 --- a/app/notification.html +++ b/app/notification.html @@ -35,11 +35,18 @@
- - - + {{@if(it.useLavamoat)}} + + + + {{#else}} + + + + + {{/if}} {{@each(it.jsBundles) => val}} - + {{/each}} diff --git a/app/phishing.html b/app/phishing.html index dd180fb77..30accb9bf 100644 --- a/app/phishing.html +++ b/app/phishing.html @@ -5,6 +5,7 @@ + diff --git a/app/popup.html b/app/popup.html index c94b82df8..e24978ad7 100644 --- a/app/popup.html +++ b/app/popup.html @@ -12,11 +12,18 @@
- - - + {{@if(it.useLavamoat)}} + + + + {{#else}} + + + + + {{/if}} {{@each(it.jsBundles) => val}} - + {{/each}} diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 0aa43d339..82131dee0 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -405,8 +405,9 @@ export default class TransactionController extends EventEmitter { * @returns {Promise} resolves with txMeta */ async addTxGasDefaults(txMeta, getCodeResponse) { - const eip1559Compatibility = await this.getEIP1559Compatibility(); - + const eip1559Compatibility = + txMeta.txParams.type !== TRANSACTION_ENVELOPE_TYPES.LEGACY && + (await this.getEIP1559Compatibility()); const { gasPrice: defaultGasPrice, maxFeePerGas: defaultMaxFeePerGas, diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 56669d267..e4bc6ca20 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -525,6 +525,58 @@ describe('Transaction Controller', function () { stub2.restore(); }); + it('should not add maxFeePerGas and maxPriorityFeePerGas to type-0 transactions', async function () { + const TEST_GASPRICE = '0x12a05f200'; + + const stub1 = sinon + .stub(txController, 'getEIP1559Compatibility') + .returns(true); + + const stub2 = sinon + .stub(txController, '_getDefaultGasFees') + .callsFake(() => ({ gasPrice: TEST_GASPRICE })); + + txController.txStateManager._addTransactionsToState([ + { + id: 1, + status: TRANSACTION_STATUSES.UNAPPROVED, + metamaskNetworkId: currentNetworkId, + txParams: { + to: VALID_ADDRESS, + from: VALID_ADDRESS_TWO, + type: '0x0', + }, + history: [{}], + }, + ]); + const txMeta = { + id: 1, + txParams: { + from: '0xc684832530fcbddae4b4230a47e991ddcec2831d', + to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', + type: '0x0', + }, + history: [{}], + }; + providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' }; + providerResultStub.eth_estimateGas = '5209'; + + const txMetaWithDefaults = await txController.addTxGasDefaults(txMeta); + + assert.equal( + txMetaWithDefaults.txParams.maxFeePerGas, + undefined, + 'should not have maxFeePerGas', + ); + assert.equal( + txMetaWithDefaults.txParams.maxPriorityFeePerGas, + undefined, + 'should not have max priority fee per gas', + ); + stub1.restore(); + stub2.restore(); + }); + it('should not add gasPrice if the fee data is available from the dapp', async function () { const TEST_GASPRICE = '0x12a05f200'; const TEST_MAX_FEE_PER_GAS = '0x12a05f200'; diff --git a/app/scripts/lockdown-more.js b/app/scripts/lockdown-more.js new file mode 100644 index 000000000..7db50e43f --- /dev/null +++ b/app/scripts/lockdown-more.js @@ -0,0 +1,91 @@ +// Make all "object" and "function" own properties of globalThis +// non-configurable and non-writable, when possible. +// We call a property that is non-configurable and non-writable, +// "non-modifiable". +try { + /** + * `lockdown` only hardens the properties enumerated by the + * universalPropertyNames constant specified in 'ses/src/whitelist'. This + * function makes all function and object properties on the start compartment + * global non-configurable and non-writable, unless they are already + * non-configurable. + * + * It is critical that this function runs at the right time during + * initialization, which should always be immediately after `lockdown` has been + * called. At the time of writing, the modifications this function makes to the + * runtime environment appear to be non-breaking, but that could change with + * the addition of dependencies, or the order of our scripts in our HTML files. + * Exercise caution. + * + * See inline comments for implementation details. + * + * We write this function in IIFE format to avoid polluting global scope. + */ + (function protectIntrinsics() { + const namedIntrinsics = Reflect.ownKeys(new Compartment().globalThis); + + // These named intrinsics are not automatically hardened by `lockdown` + const shouldHardenManually = new Set(['eval', 'Function']); + + const globalProperties = new Set([ + // universalPropertyNames is a constant added by lockdown to global scope + // at the time of writing, it is initialized in 'ses/src/whitelist'. + // These properties tend to be non-enumerable. + ...namedIntrinsics, + + // TODO: Also include the named platform globals + // This grabs every enumerable property on globalThis. + // ...Object.keys(globalThis), + ]); + + globalProperties.forEach((propertyName) => { + const descriptor = Reflect.getOwnPropertyDescriptor( + globalThis, + propertyName, + ); + + if (descriptor) { + if (descriptor.configurable) { + // If the property on globalThis is configurable, make it + // non-configurable. If it has no accessor properties, also make it + // non-writable. + if (hasAccessor(descriptor)) { + Object.defineProperty(globalThis, propertyName, { + configurable: false, + }); + } else { + Object.defineProperty(globalThis, propertyName, { + configurable: false, + writable: false, + }); + } + } + + if (shouldHardenManually.has(propertyName)) { + harden(globalThis[propertyName]); + } + } + }); + + /** + * Checks whether the given propertyName descriptor has any accessors, i.e. the + * properties `get` or `set`. + * + * We want to make globals non-writable, and we can't set the `writable` + * property and accessor properties at the same time. + * + * @param {Object} descriptor - The propertyName descriptor to check. + * @returns {boolean} Whether the propertyName descriptor has any accessors. + */ + function hasAccessor(descriptor) { + return 'set' in descriptor || 'get' in descriptor; + } + })(); +} catch (error) { + console.error('Protecting intrinsics failed:', error); + if (globalThis?.sentry.captureException) { + globalThis.sentry.captureException( + new Error(`Protecting intrinsics failed: ${error.message}`), + ); + } +} diff --git a/app/scripts/lockdown-run.js b/app/scripts/lockdown-run.js index 3c7276fdf..0d869cc7f 100644 --- a/app/scripts/lockdown-run.js +++ b/app/scripts/lockdown-run.js @@ -20,95 +20,3 @@ try { ); } } - -// Make all "object" and "function" own properties of globalThis -// non-configurable and non-writable, when possible. -// We call the a property that is non-configurable and non-writable, -// "non-modifiable". -try { - /** - * `lockdown` only hardens the properties enumerated by the - * universalPropertyNames constant specified in 'ses/src/whitelist'. This - * function makes all function and object properties on the start compartment - * global non-configurable and non-writable, unless they are already - * non-configurable. - * - * It is critical that this function runs at the right time during - * initialization, which should always be immediately after `lockdown` has been - * called. At the time of writing, the modifications this function makes to the - * runtime environment appear to be non-breaking, but that could change with - * the addition of dependencies, or the order of our scripts in our HTML files. - * Exercise caution. - * - * See inline comments for implementation details. - * - * We write this function in IIFE format to avoid polluting global scope. - */ - (function protectIntrinsics() { - const namedIntrinsics = Reflect.ownKeys(new Compartment().globalThis); - - // These named intrinsics are not automatically hardened by `lockdown` - const shouldHardenManually = new Set(['eval', 'Function']); - - const globalProperties = new Set([ - // universalPropertyNames is a constant added by lockdown to global scope - // at the time of writing, it is initialized in 'ses/src/whitelist'. - // These properties tend to be non-enumerable. - ...namedIntrinsics, - - // TODO: Also include the named platform globals - // This grabs every enumerable property on globalThis. - // ...Object.keys(globalThis), - ]); - - globalProperties.forEach((propertyName) => { - const descriptor = Reflect.getOwnPropertyDescriptor( - globalThis, - propertyName, - ); - - if (descriptor) { - if (descriptor.configurable) { - // If the property on globalThis is configurable, make it - // non-configurable. If it has no accessor properties, also make it - // non-writable. - if (hasAccessor(descriptor)) { - Object.defineProperty(globalThis, propertyName, { - configurable: false, - }); - } else { - Object.defineProperty(globalThis, propertyName, { - configurable: false, - writable: false, - }); - } - } - - if (shouldHardenManually.has(propertyName)) { - harden(globalThis[propertyName]); - } - } - }); - - /** - * Checks whether the given propertyName descriptor has any accessors, i.e. the - * properties `get` or `set`. - * - * We want to make globals non-writable, and we can't set the `writable` - * property and accessor properties at the same time. - * - * @param {Object} descriptor - The propertyName descriptor to check. - * @returns {boolean} Whether the propertyName descriptor has any accessors. - */ - function hasAccessor(descriptor) { - return 'set' in descriptor || 'get' in descriptor; - } - })(); -} catch (error) { - console.error('Protecting intrinsics failed:', error); - if (globalThis.sentry && globalThis.sentry.captureException) { - globalThis.sentry.captureException( - new Error(`Protecting intrinsics failed: ${error.message}`), - ); - } -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ae05d10d8..3608732fc 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -32,6 +32,7 @@ import { TRANSACTION_STATUSES } from '../../shared/constants/transaction'; import { GAS_API_BASE_URL, GAS_DEV_API_BASE_URL, + SWAPS_CLIENT_ID, } from '../../shared/constants/swaps'; import { MAINNET_CHAIN_ID } from '../../shared/constants/network'; import { KEYRING_TYPES } from '../../shared/constants/hardware-wallets'; @@ -201,6 +202,7 @@ export default class MetamaskController extends EventEmitter { this.gasFeeController = new GasFeeController({ interval: 10000, messenger: gasFeeMessenger, + clientId: SWAPS_CLIENT_ID, getProvider: () => this.networkController.getProviderAndBlockTracker().provider, onNetworkStateChange: this.networkController.on.bind( diff --git a/development/build/README.md b/development/build/README.md index 6c671be27..0e29f78ec 100644 --- a/development/build/README.md +++ b/development/build/README.md @@ -40,8 +40,6 @@ Commands: e2e tests. Options: - --beta-version If the build type is "beta", the beta version number. - [number] [default: 0] --build-type The "type" of build to create. One of: "beta", "main" [string] [default: "main"] --lint-fence-files Whether files with code fences should be linted after diff --git a/development/build/etc.js b/development/build/etc.js index c30bbe9b8..f68da192a 100644 --- a/development/build/etc.js +++ b/development/build/etc.js @@ -5,17 +5,12 @@ const del = require('del'); const pify = require('pify'); const pump = pify(require('pump')); const { version } = require('../../package.json'); - const { createTask, composeParallel } = require('./task'); +const { BuildTypes } = require('./utils'); module.exports = createEtcTasks; -function createEtcTasks({ - betaVersionsMap, - browserPlatforms, - isBeta, - livereload, -}) { +function createEtcTasks({ browserPlatforms, buildType, livereload }) { const clean = createTask('clean', async function clean() { await del(['./dist/*']); await Promise.all( @@ -33,20 +28,19 @@ function createEtcTasks({ const zip = createTask( 'zip', composeParallel( - ...browserPlatforms.map((platform) => - createZipTask(platform, isBeta ? betaVersionsMap[platform] : undefined), - ), + ...browserPlatforms.map((platform) => createZipTask(platform, buildType)), ), ); return { clean, reload, zip }; } -function createZipTask(platform, betaVersion) { +function createZipTask(platform, buildType) { return async () => { - const path = betaVersion - ? `metamask-BETA-${platform}-${betaVersion}` - : `metamask-${platform}-${version}`; + const path = + buildType === BuildTypes.main + ? `metamask-${platform}-${version}` + : `metamask-${buildType}-${platform}-${version}`; await pump( gulp.src(`dist/${platform}/**`), gulpZip(`${path}.zip`), diff --git a/development/build/index.js b/development/build/index.js index 01c9b50da..cbea6e799 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -5,7 +5,6 @@ // const livereload = require('gulp-livereload'); const minimist = require('minimist'); -const { version } = require('../../package.json'); const { createTask, composeSeries, @@ -17,7 +16,7 @@ const createScriptTasks = require('./scripts'); const createStyleTasks = require('./styles'); const createStaticAssetTasks = require('./static'); const createEtcTasks = require('./etc'); -const { BuildTypes, getNextBetaVersionMap } = require('./utils'); +const { BuildTypes, getBrowserVersionMap } = require('./utils'); // packages required dynamically via browserify configuration in dependencies require('loose-envify'); @@ -34,10 +33,8 @@ defineAndRunBuildTasks(); function defineAndRunBuildTasks() { const { - betaVersion, buildType, entryTask, - isBeta, isLavaMoat, shouldIncludeLockdown, shouldLintFenceFiles, @@ -46,26 +43,19 @@ function defineAndRunBuildTasks() { const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera']; - let betaVersionsMap; - if (isBeta) { - betaVersionsMap = getNextBetaVersionMap( - version, - betaVersion, - browserPlatforms, - ); - } + const browserVersionMap = getBrowserVersionMap(browserPlatforms); const staticTasks = createStaticAssetTasks({ livereload, browserPlatforms, shouldIncludeLockdown, - isBeta, + buildType, }); const manifestTasks = createManifestTasks({ browserPlatforms, - betaVersionsMap, - isBeta, + browserVersionMap, + buildType, }); const styleTasks = createStyleTasks({ livereload }); @@ -81,8 +71,7 @@ function defineAndRunBuildTasks() { const { clean, reload, zip } = createEtcTasks({ livereload, browserPlatforms, - betaVersionsMap, - isBeta, + buildType, }); // build for development (livereload) @@ -146,7 +135,6 @@ function defineAndRunBuildTasks() { function parseArgv() { const NamedArgs = { - BetaVersion: 'beta-version', BuildType: 'build-type', LintFenceFiles: 'lint-fence-files', OmitLockdown: 'omit-lockdown', @@ -161,7 +149,6 @@ function parseArgv() { ], string: [NamedArgs.BuildType], default: { - [NamedArgs.BetaVersion]: 0, [NamedArgs.BuildType]: BuildTypes.main, [NamedArgs.LintFenceFiles]: true, [NamedArgs.OmitLockdown]: false, @@ -180,11 +167,6 @@ function parseArgv() { throw new Error('MetaMask build: No entry task specified.'); } - const betaVersion = argv[NamedArgs.BetaVersion]; - if (!Number.isInteger(betaVersion) || betaVersion < 0) { - throw new Error(`MetaMask build: Invalid beta version: "${betaVersion}"`); - } - const buildType = argv[NamedArgs.BuildType]; if (!(buildType in BuildTypes)) { throw new Error(`MetaMask build: Invalid build type: "${buildType}"`); @@ -198,10 +180,8 @@ function parseArgv() { : !/dev/iu.test(entryTask); return { - betaVersion: String(betaVersion), buildType, entryTask, - isBeta: argv[NamedArgs.BuildType] === BuildTypes.beta, isLavaMoat: process.argv[0].includes('lavamoat'), shouldIncludeLockdown: argv[NamedArgs.OmitLockdown], shouldLintFenceFiles, diff --git a/development/build/manifest.js b/development/build/manifest.js index 3e80ea5b5..e14c3d786 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -3,14 +3,18 @@ const path = require('path'); const { merge, cloneDeep } = require('lodash'); const baseManifest = require('../../app/manifest/_base.json'); -const { version } = require('../../package.json'); const betaManifestModifications = require('../../app/manifest/_beta_modifications.json'); const { createTask, composeSeries } = require('./task'); +const { BuildTypes } = require('./utils'); module.exports = createManifestTasks; -function createManifestTasks({ betaVersionsMap, browserPlatforms, isBeta }) { +function createManifestTasks({ + browserPlatforms, + browserVersionMap, + buildType, +}) { // merge base manifest with per-platform manifests const prepPlatforms = async () => { return Promise.all( @@ -28,9 +32,8 @@ function createManifestTasks({ betaVersionsMap, browserPlatforms, isBeta }) { const result = merge( cloneDeep(baseManifest), platformModifications, - isBeta - ? getBetaModifications(platform, betaVersionsMap) - : { version }, + browserVersionMap[platform], + getBuildModifications(buildType), ); const dir = path.join('.', 'dist', platform); await fs.mkdir(dir, { recursive: true }); @@ -109,16 +112,10 @@ async function writeJson(obj, file) { return fs.writeFile(file, JSON.stringify(obj, null, 2)); } -function getBetaModifications(platform, betaVersionsMap) { - if (!betaVersionsMap || typeof betaVersionsMap !== 'object') { - throw new Error('MetaMask build: Expected object beta versions map.'); +function getBuildModifications(buildType) { + const buildModifications = {}; + if (buildType === BuildTypes.beta) { + Object.assign(buildModifications, betaManifestModifications); } - - const betaVersion = betaVersionsMap[platform]; - - return { - ...betaManifestModifications, - version: betaVersion, - ...(platform === 'firefox' ? {} : { version_name: 'beta' }), - }; + return buildModifications; } diff --git a/development/build/scripts.js b/development/build/scripts.js index da7e73e26..e681be02f 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -4,6 +4,7 @@ const { writeFileSync, readFileSync } = require('fs'); const EventEmitter = require('events'); const gulp = require('gulp'); const watch = require('gulp-watch'); +const Vinyl = require('vinyl'); const source = require('vinyl-source-stream'); const buffer = require('vinyl-buffer'); const log = require('fancy-log'); @@ -20,13 +21,15 @@ const endOfStream = pify(require('end-of-stream')); const labeledStreamSplicer = require('labeled-stream-splicer').obj; const wrapInStream = require('pumpify').obj; const Sqrl = require('squirrelly'); -const lavaPack = require('@lavamoat/lavapack'); +const lavapack = require('@lavamoat/lavapack'); +const lavamoatBrowserify = require('lavamoat-browserify'); const terser = require('terser'); const bifyModuleGroups = require('bify-module-groups'); const metamaskrc = require('rc')('metamask', { INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, + ONBOARDING_V2: process.env.ONBOARDING_V2, SEGMENT_HOST: process.env.SEGMENT_HOST, SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY, SEGMENT_LEGACY_WRITE_KEY: process.env.SEGMENT_LEGACY_WRITE_KEY, @@ -259,7 +262,22 @@ function createFactoredBuild({ // set bundle entries bundlerOpts.entries = [...entryFiles]; + // setup lavamoat + // lavamoat will add lavapack but it will be removed by bify-module-groups + // we will re-add it later by installing a lavapack runtime + const lavamoatOpts = { + policy: path.resolve(__dirname, '../../lavamoat/browserify/policy.json'), + policyOverride: path.resolve( + __dirname, + '../../lavamoat/browserify/policy-override.json', + ), + writeAutoPolicy: process.env.WRITE_AUTO_POLICY, + }; + Object.assign(bundlerOpts, lavamoatBrowserify.args); + bundlerOpts.plugin.push([lavamoatBrowserify, lavamoatOpts]); + // setup bundle factoring with bify-module-groups plugin + // note: this will remove lavapack, but its ok bc we manually readd it later Object.assign(bundlerOpts, bifyModuleGroups.plugin.args); bundlerOpts.plugin = [...bundlerOpts.plugin, [bifyModuleGroups.plugin]]; @@ -281,18 +299,24 @@ function createFactoredBuild({ groupingMap: sizeGroupMap, }), ); - pipeline.get('vinyl').unshift( - // convert each module group into a stream with a single vinyl file - streamFlatMap((moduleGroup) => { - const filename = `${moduleGroup.label}.js`; - const childStream = wrapInStream( - moduleGroup.stream, - lavaPack({ raw: true, hasExports: true, includePrelude: false }), - source(filename), - ); - return childStream; + // converts each module group into a single vinyl file containing its bundle + const moduleGroupPackerStream = streamFlatMap((moduleGroup) => { + const filename = `${moduleGroup.label}.js`; + const childStream = wrapInStream( + moduleGroup.stream, + // we manually readd lavapack here bc bify-module-groups removes it + lavapack({ raw: true, hasExports: true, includePrelude: false }), + source(filename), + ); + return childStream; + }); + pipeline.get('vinyl').unshift(moduleGroupPackerStream, buffer()); + // add lavamoat policy loader file to packer output + moduleGroupPackerStream.push( + new Vinyl({ + path: 'policy-load.js', + contents: lavapack.makePolicyLoaderStream(lavamoatOpts), }), - buffer(), ); // setup bundle destination browserPlatforms.forEach((platform) => { @@ -306,36 +330,58 @@ function createFactoredBuild({ const commonSet = sizeGroupMap.get('common'); // create entry points for each file for (const [groupLabel, groupSet] of sizeGroupMap.entries()) { - // skip "common" group, they are added tp all other groups + // skip "common" group, they are added to all other groups if (groupSet === commonSet) continue; switch (groupLabel) { case 'ui': { - renderHtmlFile('popup', groupSet, commonSet, browserPlatforms); - renderHtmlFile( - 'notification', + renderHtmlFile({ + htmlName: 'popup', groupSet, commonSet, browserPlatforms, - ); - renderHtmlFile('home', groupSet, commonSet, browserPlatforms); + useLavamoat: false, + }); + renderHtmlFile({ + htmlName: 'notification', + groupSet, + commonSet, + browserPlatforms, + useLavamoat: false, + }); + renderHtmlFile({ + htmlName: 'home', + groupSet, + commonSet, + browserPlatforms, + useLavamoat: false, + }); break; } case 'background': { - renderHtmlFile('background', groupSet, commonSet, browserPlatforms); - break; - } - case 'content-script': { - renderHtmlFile( - 'trezor-usb-permissions', + renderHtmlFile({ + htmlName: 'background', groupSet, commonSet, browserPlatforms, - ); + useLavamoat: false, + }); + break; + } + case 'content-script': { + renderHtmlFile({ + htmlName: 'trezor-usb-permissions', + groupSet, + commonSet, + browserPlatforms, + useLavamoat: false, + }); break; } default: { - throw new Error(`buildsys - unknown groupLabel "${groupLabel}"`); + throw new Error( + `build/scripts - unknown groupLabel "${groupLabel}"`, + ); } } } @@ -612,6 +658,7 @@ function getEnvironmentVariables({ buildType, devMode, testing }) { ? process.env.SEGMENT_PROD_LEGACY_WRITE_KEY : metamaskrc.SEGMENT_LEGACY_WRITE_KEY, SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS === '1', + ONBOARDING_V2: metamaskrc.ONBOARDING_V2 === '1', }; } @@ -635,13 +682,24 @@ function getEnvironment({ devMode, testing }) { return 'other'; } -function renderHtmlFile(htmlName, groupSet, commonSet, browserPlatforms) { +function renderHtmlFile({ + htmlName, + groupSet, + commonSet, + browserPlatforms, + useLavamoat, +}) { + if (useLavamoat === undefined) { + throw new Error( + 'build/scripts/renderHtmlFile - must specify "useLavamoat" option', + ); + } const htmlFilePath = `./app/${htmlName}.html`; const htmlTemplate = readFileSync(htmlFilePath, 'utf8'); const jsBundles = [...commonSet.values(), ...groupSet.values()].map( (label) => `./${label}.js`, ); - const htmlOutput = Sqrl.render(htmlTemplate, { jsBundles }); + const htmlOutput = Sqrl.render(htmlTemplate, { jsBundles, useLavamoat }); browserPlatforms.forEach((platform) => { const dest = `./dist/${platform}/${htmlName}.html`; // we dont have a way of creating async events atm diff --git a/development/build/static.js b/development/build/static.js index 341b7d56b..5addd1b10 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -6,6 +6,7 @@ const glob = require('fast-glob'); const locales = require('../../app/_locales/index.json'); const { createTask, composeSeries } = require('./task'); +const { BuildTypes } = require('./utils'); const EMPTY_JS_FILE = './development/empty.js'; @@ -13,26 +14,30 @@ module.exports = function createStaticAssetTasks({ livereload, browserPlatforms, shouldIncludeLockdown = true, - isBeta, + buildType, }) { const [copyTargetsProd, copyTargetsDev] = getCopyTargets( shouldIncludeLockdown, ); - const copyTargetsBeta = [ - ...copyTargetsProd, - { - src: './app/build-types/beta/', - dest: `images`, - }, - ]; + const additionalBuildTargets = { + [BuildTypes.beta]: [ + { + src: './app/build-types/beta/', + dest: `images`, + }, + ], + }; - const targets = isBeta ? copyTargetsBeta : copyTargetsProd; + if (Object.keys(additionalBuildTargets).includes(buildType)) { + copyTargetsProd.push(...additionalBuildTargets[buildType]); + copyTargetsDev.push(...additionalBuildTargets[buildType]); + } const prod = createTask( 'static:prod', composeSeries( - ...targets.map((target) => { + ...copyTargetsProd.map((target) => { return async function copyStaticAssets() { await performCopy(target); }; @@ -143,11 +148,22 @@ function getCopyTargets(shouldIncludeLockdown) { : EMPTY_JS_FILE, dest: `lockdown-run.js`, }, + { + src: shouldIncludeLockdown + ? `./app/scripts/lockdown-more.js` + : EMPTY_JS_FILE, + dest: `lockdown-more.js`, + }, { // eslint-disable-next-line node/no-extraneous-require src: require.resolve('@lavamoat/lavapack/src/runtime-cjs.js'), dest: `runtime-cjs.js`, }, + { + // eslint-disable-next-line node/no-extraneous-require + src: require.resolve('@lavamoat/lavapack/src/runtime.js'), + dest: `runtime-lavamoat.js`, + }, { src: `./app/phishing.html`, dest: `phishing.html`, diff --git a/development/build/utils.js b/development/build/utils.js index 0b8503d19..4413ab899 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -1,24 +1,5 @@ -/** - * @returns {Object} An object with browser as key and next version of beta - * as the value. E.g. { firefox: '9.6.0.beta0', chrome: '9.6.0.1' } - */ -function getNextBetaVersionMap(currentVersion, betaVersion, platforms) { - const [major, minor] = currentVersion.split('.'); - - return platforms.reduce((platformMap, platform) => { - platformMap[platform] = [ - // Keeps the current major - major, - // Bump the minor version - Number(minor) + 1, - // This isn't typically used - 0, - // The beta number - `${platform === 'firefox' ? 'beta' : ''}${betaVersion}`, - ].join('.'); - return platformMap; - }, {}); -} +const semver = require('semver'); +const { version } = require('../../package.json'); const BuildTypes = { beta: 'beta', @@ -26,7 +7,57 @@ const BuildTypes = { main: 'main', }; +/** + * Map the current version to a format that is compatible with each browser. + * + * The given version number is assumed to be a SemVer version number. Additionally, if the version + * has a prerelease component, it is assumed to have the format ". { + const versionParts = [major, minor, patch]; + const browserSpecificVersion = {}; + if (prerelease) { + if (platform === 'firefox') { + versionParts.push(`${buildType}${buildVersion}`); + } else { + versionParts.push(buildVersion); + browserSpecificVersion.version_name = buildType; + } + } + browserSpecificVersion.version = versionParts.join('.'); + platformMap[platform] = browserSpecificVersion; + return platformMap; + }, {}); +} + module.exports = { BuildTypes, - getNextBetaVersionMap, + getBrowserVersionMap, }; diff --git a/lavamoat/browserify/policy-override.json b/lavamoat/browserify/policy-override.json new file mode 100644 index 000000000..71fd98f61 --- /dev/null +++ b/lavamoat/browserify/policy-override.json @@ -0,0 +1,55 @@ +{ + "resources": { + "browser-resolve": { + "packages": { + "core-js": true + } + }, + "babel-runtime": { + "packages": { + "@babel/runtime": true + } + }, + "node-fetch": { + "globals": { + "fetch": true + } + }, + "lodash": { + "globals": { + "setTimeout": true, + "clearTimeout": true + } + }, + "@ethersproject/random": { + "globals": { + "crypto.getRandomValues": true + } + }, + "browser-passworder": { + "globals": { + "crypto": true + } + }, + "randombytes": { + "globals": { + "crypto.getRandomValues": true + } + }, + "extensionizer": { + "globals": { + "console": true + } + }, + "web3": { + "globals": { + "XMLHttpRequest": true + } + }, + "storage": { + "globals": { + "localStorage": true + } + } + } +} diff --git a/lavamoat/browserify/policy.json b/lavamoat/browserify/policy.json new file mode 100644 index 000000000..766fae5a4 --- /dev/null +++ b/lavamoat/browserify/policy.json @@ -0,0 +1,4656 @@ +{ + "resources": { + "3box": { + "globals": { + "console.error": true, + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "3box-orbitdb-plugins": true, + "3id-resolver": true, + "@babel/runtime": true, + "buffer": true, + "did-jwt": true, + "elliptic": true, + "ethers": true, + "graphql-request": true, + "https-did-resolver": true, + "ipfs": true, + "ipfs-did-document": true, + "ipfs-log": true, + "ipfs-mini": true, + "is-ipfs": true, + "js-sha256": true, + "multihashes": true, + "muport-did-resolver": true, + "node-fetch": true, + "orbit-db": true, + "orbit-db-access-controllers": true, + "orbit-db-identity-provider": true, + "orbit-db-pubsub": true, + "process": true, + "store": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "3box-orbitdb-plugins": { + "globals": { + "console.log": true + }, + "packages": { + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "events": true, + "ipfs-log": true, + "is-ipfs": true, + "orbit-db-access-controllers": true, + "orbit-db-io": true, + "safe-buffer": true + } + }, + "3id-resolver": { + "packages": { + "@babel/runtime": true, + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "ipfs-did-document": true + } + }, + "@babel/runtime": { + "packages": { + "regenerator-runtime": true + } + }, + "@download/blockies": { + "globals": { + "document.createElement": true + } + }, + "@ensdomains/content-hash": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cids": true, + "js-base64": true, + "multicodec": true, + "multihashes": true + } + }, + "@ethereumjs/common": { + "packages": { + "buffer": true, + "crc-32": true, + "ethereumjs-util": true, + "events": true + } + }, + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/common": true, + "buffer": true, + "ethereumjs-util": true, + "is-buffer": true + } + }, + "@ethersproject/abi": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/address": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/rlp": true + } + }, + "@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/bytes": true + } + }, + "@ethersproject/basex": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/bignumber": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "bn.js": true + } + }, + "@ethersproject/bytes": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/constants": { + "packages": { + "@ethersproject/bignumber": true + } + }, + "@ethersproject/contracts": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/hdnode": { + "packages": { + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/wordlists": true + } + }, + "@ethersproject/json-wallets": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hdnode": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "aes-js": true, + "scrypt-js": true + } + }, + "@ethersproject/keccak256": { + "packages": { + "@ethersproject/bytes": true, + "js-sha3": true + } + }, + "@ethersproject/logger": { + "globals": { + "console": true + } + }, + "@ethersproject/networks": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/pbkdf2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/sha2": true + } + }, + "@ethersproject/properties": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/providers": { + "globals": { + "WebSocket": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "console.warn": true, + "name": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/networks": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/web": true, + "bech32": true + } + }, + "@ethersproject/random": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/rlp": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/sha2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "hash.js": true + } + }, + "@ethersproject/signing-key": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "elliptic": true + } + }, + "@ethersproject/solidity": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/strings": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/transactions": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/rlp": true, + "@ethersproject/signing-key": true + } + }, + "@ethersproject/units": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/signing-key": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/web": { + "globals": { + "clearTimeout": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/base64": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/wordlists": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@formatjs/intl-relativetimeformat": { + "globals": { + "Intl": true + }, + "packages": { + "@formatjs/intl-utils": true + } + }, + "@formatjs/intl-utils": { + "globals": { + "Intl.getCanonicalLocales": true + } + }, + "@material-ui/core": { + "globals": { + "Image": true, + "_formatMuiErrorMessage": true, + "addEventListener": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "getSelection": true, + "innerHeight": true, + "innerWidth": true, + "matchMedia": true, + "navigator": true, + "performance.now": true, + "removeEventListener": true, + "requestAnimationFrame": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/styles": true, + "@material-ui/system": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "popper.js": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "react-transition-group": true + } + }, + "@material-ui/styles": { + "globals": { + "console.error": true, + "console.warn": true, + "document.createComment": true, + "document.head": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "jss": true, + "jss-plugin-camel-case": true, + "jss-plugin-default-unit": true, + "jss-plugin-global": true, + "jss-plugin-nested": true, + "jss-plugin-props-sort": true, + "jss-plugin-rule-value-function": true, + "jss-plugin-vendor-prefixer": true, + "prop-types": true, + "react": true + } + }, + "@material-ui/system": { + "globals": { + "console.error": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "prop-types": true + } + }, + "@material-ui/utils": { + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react-is": true + } + }, + "@metamask/controllers": { + "globals": { + "Headers": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "@metamask/contract-metadata": true, + "abort-controller": true, + "async-mutex": true, + "await-semaphore": true, + "buffer": true, + "eth-ens-namehash": true, + "eth-json-rpc-infura": true, + "eth-keyring-controller": true, + "eth-method-registry": true, + "eth-phishing-detect": true, + "eth-query": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "ethereumjs-tx": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "ethers": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "events": true, + "human-standard-collectible-abi": true, + "human-standard-token-abi": true, + "immer": true, + "isomorphic-fetch": true, + "jsonschema": true, + "nanoid": true, + "punycode": true, + "single-call-balance-checker-abi": true, + "uuid": true, + "web3": true, + "web3-provider-engine": true + } + }, + "@metamask/eth-ledger-bridge-keyring": { + "globals": { + "addEventListener": true, + "console.log": true, + "document.createElement": true, + "document.head.appendChild": true, + "fetch": true, + "removeEventListener": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true + } + }, + "@metamask/eth-token-tracker": { + "globals": { + "console.warn": true + }, + "packages": { + "@babel/runtime": true, + "deep-equal": true, + "eth-block-tracker": true, + "ethjs": true, + "ethjs-contract": true, + "ethjs-query": true, + "human-standard-token-abi": true, + "safe-event-emitter": true + } + }, + "@metamask/etherscan-link": { + "globals": { + "URL": true + } + }, + "@metamask/jazzicon": { + "globals": { + "document.createElement": true, + "document.createElementNS": true + }, + "packages": { + "color": true, + "mersenne-twister": true + } + }, + "@metamask/logo": { + "globals": { + "addEventListener": true, + "document.body.appendChild": true, + "document.createElementNS": true, + "innerHeight": true, + "innerWidth": true, + "requestAnimationFrame": true + }, + "packages": { + "gl-mat4": true, + "gl-vec3": true + } + }, + "@metamask/obs-store": { + "globals": { + "localStorage": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "stream-browserify": true, + "through2": true + } + }, + "@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "@popperjs/core": { + "globals": { + "Element": true, + "HTMLElement": true, + "ShadowRoot": true, + "console.error": true, + "console.warn": true, + "document": true, + "navigator.userAgent": true + } + }, + "@reduxjs/toolkit": { + "globals": { + "AbortController": true, + "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, + "console.error": true, + "console.info": true, + "console.warn": true + }, + "packages": { + "immer": true, + "redux": true, + "redux-thunk": true, + "reselect": true + } + }, + "@segment/loosely-validate-event": { + "packages": { + "assert": true, + "buffer": true, + "component-type": true, + "join-component": true + } + }, + "@sentry/browser": { + "globals": { + "XMLHttpRequest": true, + "document.body": true, + "document.createElement": true, + "document.head": true, + "setTimeout": true + }, + "packages": { + "@sentry/core": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/core": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@sentry/hub": true, + "@sentry/minimal": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/hub": { + "globals": { + "setTimeout": true + }, + "packages": { + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "localforage": true, + "tslib": true + } + }, + "@sentry/minimal": { + "packages": { + "@sentry/hub": true, + "tslib": true + } + }, + "@sentry/utils": { + "globals": { + "CustomEvent": true, + "DOMError": true, + "DOMException": true, + "Element": true, + "ErrorEvent": true, + "Event": true, + "Headers": true, + "Request": true, + "Response": true, + "XMLHttpRequest.prototype": true, + "clearTimeout": true, + "console.error": true, + "document": true, + "setTimeout": true + }, + "packages": { + "process": true, + "tslib": true + } + }, + "@sindresorhus/is": { + "packages": { + "is-buffer": true, + "util": true + } + }, + "@zxing/library": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "btoa": true, + "clearTimeout": true, + "define": true, + "document.createElement": true, + "document.createElementNS": true, + "document.getElementById": true, + "navigator.mediaDevices.enumerateDevices": true, + "navigator.mediaDevices.getUserMedia": true, + "setTimeout": true + } + }, + "abort-controller": { + "globals": { + "AbortController": true + } + }, + "abstract-leveldown": { + "packages": { + "is-buffer": true, + "process": true, + "xtend": true + } + }, + "accounting": { + "globals": { + "define": true + } + }, + "aes-js": { + "globals": { + "define": true + } + }, + "analytics-node": { + "globals": { + "clearTimeout": true, + "console.log": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "@segment/loosely-validate-event": true, + "assert": true, + "axios": true, + "axios-retry": true, + "lodash.isstring": true, + "md5": true, + "ms": true, + "process": true, + "remove-trailing-slash": true, + "uuid": true + } + }, + "asap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document.createTextNode": true, + "setInterval": true, + "setTimeout": true + } + }, + "asn1.js": { + "packages": { + "bn.js": true, + "buffer": true, + "inherits": true, + "minimalistic-assert": true, + "vm-browserify": true + } + }, + "assemblyscript": { + "globals": { + "WebAssembly.Instance": true, + "WebAssembly.Module": true, + "WebAssembly.instantiateStreaming": true, + "console.log": true + } + }, + "assert": { + "globals": { + "Buffer": true + }, + "packages": { + "object-assign": true, + "util": true + } + }, + "async": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "timers-browserify": true + } + }, + "async-iterator-to-pull-stream": { + "packages": { + "get-iterator": true, + "pull-stream-to-async-iterator": true + } + }, + "async-iterator-to-stream": { + "packages": { + "process": true, + "readable-stream": true + } + }, + "async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "tslib": true + } + }, + "await-semaphore": { + "packages": { + "process": true, + "timers-browserify": true + } + }, + "axios": { + "globals": { + "FormData": true, + "URLSearchParams": true, + "XMLHttpRequest": true, + "btoa": true, + "document": true, + "location.href": true, + "navigator": true + }, + "packages": { + "process": true + } + }, + "axios-retry": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-retry-allowed": true + } + }, + "babel-runtime": { + "packages": { + "core-js": true, + "regenerator-runtime": true + } + }, + "backoff": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "events": true, + "precond": true, + "util": true + } + }, + "base-x": { + "packages": { + "safe-buffer": true + } + }, + "base32-encode": { + "packages": { + "to-data-view": true + } + }, + "base64url": { + "packages": { + "buffer": true + } + }, + "bignumber.js": { + "globals": { + "crypto": true, + "define": true + }, + "packages": { + "crypto-browserify": true + } + }, + "bip39": { + "packages": { + "create-hash": true, + "pbkdf2": true, + "randombytes": true, + "safe-buffer": true, + "unorm": true + } + }, + "bip66": { + "packages": { + "safe-buffer": true + } + }, + "bl": { + "packages": { + "buffer": true, + "readable-stream": true, + "util": true + } + }, + "blakejs": { + "globals": { + "console.log": true + }, + "packages": { + "buffer": true + } + }, + "blob": { + "globals": { + "Blob": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "WebKitBlobBuilder": true + } + }, + "bn.js": { + "packages": { + "browser-resolve": true + } + }, + "borc": { + "globals": { + "console": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "ieee754": true, + "iso-url": true + } + }, + "brorand": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "browser-resolve": true + } + }, + "browser-passworder": { + "globals": { + "btoa": true, + "crypto.getRandomValues": true, + "crypto.subtle.decrypt": true, + "crypto.subtle.deriveKey": true, + "crypto.subtle.encrypt": true, + "crypto.subtle.importKey": true + }, + "packages": { + "browserify-unibabel": true + } + }, + "browserify-aes": { + "packages": { + "buffer": true, + "buffer-xor": true, + "cipher-base": true, + "evp_bytestokey": true, + "inherits": true, + "safe-buffer": true + } + }, + "browserify-cipher": { + "packages": { + "browserify-aes": true, + "browserify-des": true, + "evp_bytestokey": true + } + }, + "browserify-des": { + "packages": { + "buffer": true, + "cipher-base": true, + "des.js": true, + "inherits": true + } + }, + "browserify-rsa": { + "packages": { + "bn.js": true, + "buffer": true, + "randombytes": true + } + }, + "browserify-sign": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "create-hmac": true, + "elliptic": true, + "inherits": true, + "parse-asn1": true, + "stream-browserify": true + } + }, + "browserify-unibabel": { + "globals": { + "atob": true, + "btoa": true + } + }, + "bs58": { + "packages": { + "base-x": true + } + }, + "bs58check": { + "packages": { + "bs58": true, + "create-hash": true, + "safe-buffer": true + } + }, + "btoa": { + "packages": { + "buffer": true + } + }, + "buffer": { + "globals": { + "console": true + }, + "packages": { + "base64-js": true, + "ieee754": true + } + }, + "buffer-split": { + "packages": { + "buffer-indexof": true + } + }, + "buffer-xor": { + "packages": { + "buffer": true + } + }, + "cids": { + "packages": { + "buffer": true, + "class-is": true, + "is-buffer": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "uint8arrays": true + } + }, + "cipher-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true, + "string_decoder": true + } + }, + "classnames": { + "globals": { + "classNames": "write", + "define": true + } + }, + "clone": { + "packages": { + "buffer": true + } + }, + "coinstring": { + "packages": { + "bs58": true, + "buffer": true, + "create-hash": true + } + }, + "color": { + "packages": { + "clone": true, + "color-convert": true, + "color-string": true + } + }, + "color-convert": { + "packages": { + "color-name": true + } + }, + "color-string": { + "packages": { + "color-name": true + } + }, + "cookiejar": { + "globals": { + "console.warn": true + } + }, + "copy-to-clipboard": { + "globals": { + "clipboardData.setData": true, + "console.error": true, + "console.warn": true, + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.createRange": true, + "document.execCommand": true, + "document.getSelection": true, + "navigator.userAgent": true, + "prompt": true + }, + "packages": { + "toggle-selection": true + } + }, + "core-js": { + "globals": { + "PromiseRejectionEvent": true, + "__e": "write", + "__g": "write", + "document.createTextNode": true, + "postMessage": true, + "setTimeout": true + } + }, + "core-util-is": { + "packages": { + "is-buffer": true + } + }, + "crc-32": { + "globals": { + "DO_NOT_EXPORT_CRC": true, + "define": true + } + }, + "create-ecdh": { + "packages": { + "bn.js": true, + "buffer": true, + "elliptic": true + } + }, + "create-hash": { + "packages": { + "cipher-base": true, + "inherits": true, + "md5.js": true, + "ripemd160": true, + "sha.js": true + } + }, + "create-hmac": { + "packages": { + "cipher-base": true, + "create-hash": true, + "inherits": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "cross-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true + } + }, + "crypto-browserify": { + "packages": { + "browserify-cipher": true, + "browserify-sign": true, + "create-ecdh": true, + "create-hash": true, + "create-hmac": true, + "diffie-hellman": true, + "pbkdf2": true, + "public-encrypt": true, + "randombytes": true, + "randomfill": true + } + }, + "crypto-js": { + "globals": { + "define": true + } + }, + "css-vendor": { + "globals": { + "document.createElement": true, + "document.documentElement": true, + "getComputedStyle": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true + } + }, + "currency-formatter": { + "packages": { + "accounting": true, + "locale-currency": true, + "object-assign": true + } + }, + "data-queue": { + "packages": { + "events": true + } + }, + "datastore-core": { + "packages": { + "async": true, + "buffer": true, + "interface-datastore": true, + "pull-many": true, + "pull-stream": true + } + }, + "datastore-level": { + "packages": { + "buffer": true, + "encoding-down": true, + "interface-datastore": true, + "level-js": true, + "levelup": true, + "pull-stream": true + } + }, + "datastore-pubsub": { + "packages": { + "assert": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-datastore": true, + "multibase": true + } + }, + "debounce": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "debounce-stream": { + "packages": { + "debounce": true, + "duplexer": true, + "through": true + } + }, + "debug": { + "globals": { + "chrome": true, + "console": true, + "document": true, + "localStorage": true, + "navigator": true, + "process": true + }, + "packages": { + "ms": true, + "process": true + } + }, + "deep-equal": { + "packages": { + "is-arguments": true, + "is-date-object": true, + "is-regex": true, + "object-is": true, + "object-keys": true, + "regexp.prototype.flags": true + } + }, + "deep-extend": { + "packages": { + "buffer": true + } + }, + "deferred-leveldown": { + "packages": { + "abstract-leveldown": true, + "inherits": true + } + }, + "define-properties": { + "packages": { + "object-keys": true + } + }, + "des.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "did-jwt": { + "packages": { + "@babel/runtime": true, + "@stablelib/utf8": true, + "base64url": true, + "buffer": true, + "did-resolver": true, + "elliptic": true, + "js-sha256": true, + "js-sha3": true, + "tweetnacl": true, + "tweetnacl-util": true, + "uport-base64url": true + } + }, + "diffie-hellman": { + "packages": { + "bn.js": true, + "buffer": true, + "miller-rabin": true, + "randombytes": true + } + }, + "dlv": { + "globals": { + "define": true + } + }, + "dnd-core": { + "packages": { + "asap": true, + "invariant": true, + "lodash": true, + "redux": true + } + }, + "dom-helpers": { + "globals": { + "document": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true + } + }, + "drbg.js": { + "packages": { + "buffer": true, + "create-hmac": true + } + }, + "duplexer": { + "packages": { + "stream-browserify": true + } + }, + "elliptic": { + "packages": { + "bn.js": true, + "brorand": true, + "hash.js": true, + "hmac-drbg": true, + "inherits": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "encoding-down": { + "packages": { + "abstract-leveldown": true, + "inherits": true, + "level-codec": true, + "level-errors": true + } + }, + "end-of-stream": { + "packages": { + "once": true, + "process": true + } + }, + "engine.io-client": { + "globals": { + "MozWebSocket": true, + "WebSocket": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "addEventListener": true, + "attachEvent": true, + "clearTimeout": true, + "document": true, + "location": true, + "navigator": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "buffer": true, + "component-emitter": true, + "component-inherit": true, + "debug": true, + "engine.io-parser": true, + "has-cors": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "yeast": true + } + }, + "engine.io-parser": { + "globals": { + "FileReader": true, + "btoa": true, + "navigator": true + }, + "packages": { + "after": true, + "arraybuffer.slice": true, + "base64-arraybuffer": true, + "blob": true, + "has-binary2": true + } + }, + "errno": { + "packages": { + "prr": true + } + }, + "es-abstract": { + "packages": { + "function-bind": true, + "has-symbols": true + } + }, + "eth-block-tracker": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "eth-query": true, + "json-rpc-random-id": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-ens-namehash": { + "globals": { + "name": "write" + }, + "packages": { + "buffer": true, + "idna-uts46": true, + "idna-uts46-hx": true, + "js-sha3": true + } + }, + "eth-hd-keyring": { + "packages": { + "bip39": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-wallet": true + } + }, + "eth-json-rpc-filters": { + "globals": { + "console.error": true, + "results": "write" + }, + "packages": { + "await-semaphore": true, + "eth-json-rpc-middleware": true, + "eth-query": true, + "json-rpc-engine": true, + "lodash.flatmap": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-json-rpc-infura": { + "globals": { + "setTimeout": true + }, + "packages": { + "eth-json-rpc-middleware": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "node-fetch": true + } + }, + "eth-json-rpc-middleware": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "btoa": true, + "clone": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "json-rpc-engine": true, + "json-stable-stringify": true, + "node-fetch": true, + "pify": true, + "safe-event-emitter": true, + "url": true + } + }, + "eth-keyring-controller": { + "packages": { + "bip39": true, + "browser-passworder": true, + "eth-hd-keyring": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-util": true, + "events": true, + "loglevel": true, + "obs-store": true + } + }, + "eth-method-registry": { + "packages": { + "ethjs": true + } + }, + "eth-phishing-detect": { + "packages": { + "fast-levenshtein": true + } + }, + "eth-query": { + "packages": { + "json-rpc-random-id": true, + "xtend": true + } + }, + "eth-rpc-errors": { + "packages": { + "fast-safe-stringify": true + } + }, + "eth-sig-util": { + "packages": { + "buffer": true, + "ethereumjs-abi": true, + "ethereumjs-util": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "eth-simple-keyring": { + "packages": { + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "events": true + } + }, + "eth-trezor-keyring": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true, + "trezor-connect": true + } + }, + "ethereum-cryptography": { + "packages": { + "assert": true, + "bs58check": true, + "buffer": true, + "create-hmac": true, + "hash.js": true, + "keccak": true, + "randombytes": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "ethereumjs-util": true + } + }, + "ethereumjs-tx": { + "packages": { + "buffer": true, + "ethereum-common": true, + "ethereumjs-util": true + } + }, + "ethereumjs-util": { + "packages": { + "assert": true, + "bn.js": true, + "buffer": true, + "create-hash": true, + "elliptic": true, + "ethereum-cryptography": true, + "ethjs-util": true, + "is-buffer": true, + "keccak": true, + "rlp": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-wallet": { + "packages": { + "aes-js": true, + "bs58check": true, + "buffer": true, + "crypto-browserify": true, + "ethereum-cryptography": true, + "ethereumjs-util": true, + "randombytes": true, + "safe-buffer": true, + "scrypt-js": true, + "scryptsy": true, + "utf8": true, + "uuid": true + } + }, + "ethers": { + "globals": { + "MessageChannel": true, + "XMLHttpRequest": true, + "atob": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "crypto.getRandomValues": true, + "define": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/base64": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/contracts": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/providers": true, + "@ethersproject/random": true, + "@ethersproject/rlp": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/solidity": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/units": true, + "@ethersproject/wallet": true, + "@ethersproject/web": true, + "@ethersproject/wordlists": true + } + }, + "ethjs": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "bn.js": true, + "buffer": true, + "ethjs-abi": true, + "ethjs-contract": true, + "ethjs-filter": true, + "ethjs-provider-http": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-contract": { + "packages": { + "babel-runtime": true, + "ethjs-abi": true, + "ethjs-filter": true, + "ethjs-util": true, + "js-sha3": true, + "promise-to-callback": true + } + }, + "ethjs-ens": { + "packages": { + "eth-ens-namehash": true, + "ethereum-ens-network-map": true, + "ethjs-contract": true, + "ethjs-query": true + } + }, + "ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "ethjs-format": { + "packages": { + "ethjs-schema": true, + "ethjs-util": true, + "number-to-bn": true, + "strip-hex-prefix": true + } + }, + "ethjs-provider-http": { + "packages": { + "xhr2": true + } + }, + "ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "babel-runtime": true, + "ethjs-format": true, + "ethjs-rpc": true, + "promise-to-callback": true + } + }, + "ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, + "ethjs-unit": { + "packages": { + "bn.js": true, + "number-to-bn": true + } + }, + "ethjs-util": { + "packages": { + "buffer": true, + "is-hex-prefixed": true, + "strip-hex-prefix": true + } + }, + "events": { + "globals": { + "console": true + } + }, + "evp_bytestokey": { + "packages": { + "md5.js": true, + "safe-buffer": true + } + }, + "extension-port-stream": { + "packages": { + "buffer": true, + "stream-browserify": true + } + }, + "extensionizer": { + "globals": { + "browser": true, + "chrome": true + } + }, + "fast-json-patch": { + "globals": { + "addEventListener": true, + "clearTimeout": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "fast-deep-equal": true + } + }, + "fast-levenshtein": { + "globals": { + "Intl": true, + "Levenshtein": "write", + "console.log": true, + "define": true, + "importScripts": true, + "postMessage": true + } + }, + "fsm-event": { + "packages": { + "assert": true, + "events": true, + "fsm": true + } + }, + "fuse.js": { + "globals": { + "console": true, + "define": true + } + }, + "get-browser-rtc": { + "globals": { + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "webkitRTCIceCandidate": true, + "webkitRTCPeerConnection": true, + "webkitRTCSessionDescription": true + } + }, + "get-params": { + "globals": { + "GetParams": "write" + } + }, + "graphql-request": { + "globals": { + "fetch": true + }, + "packages": { + "cross-fetch": true + } + }, + "hamt-sharding": { + "packages": { + "is-buffer": true, + "sparse-array": true + } + }, + "has-binary2": { + "globals": { + "Blob": true, + "File": true + }, + "packages": { + "buffer": true, + "isarray": true + } + }, + "has-cors": { + "globals": { + "XMLHttpRequest": true + } + }, + "hash-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "hash.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "hdkey": { + "packages": { + "assert": true, + "coinstring": true, + "crypto-browserify": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "heap": { + "globals": { + "define": true + } + }, + "hi-base32": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "history": { + "globals": { + "addEventListener": true, + "confirm": true, + "document": true, + "history": true, + "location": true, + "navigator.userAgent": true, + "removeEventListener": true + }, + "packages": { + "resolve-pathname": true, + "tiny-invariant": true, + "tiny-warning": true, + "value-equal": true + } + }, + "hmac-drbg": { + "packages": { + "hash.js": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "hoist-non-react-statics": { + "packages": { + "react-is": true + } + }, + "https-browserify": { + "packages": { + "stream-http": true, + "url": true + } + }, + "https-did-resolver": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "browser-resolve": true, + "did-resolver": true + } + }, + "human-to-milliseconds": { + "packages": { + "promisify-es6": true + } + }, + "idb-readable-stream": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.upperBound": true + }, + "packages": { + "stream-browserify": true, + "xtend": true + } + }, + "idna-uts46": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "idna-uts46-hx": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "immediate": { + "globals": { + "MessageChannel": true, + "MutationObserver": true, + "WebKitMutationObserver": true, + "clearTimeout": true, + "document.createElement": true, + "document.createTextNode": true, + "document.documentElement.appendChild": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "interface-connection": { + "packages": { + "pull-defer": true + } + }, + "interface-datastore": { + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "err-code": true, + "os-browserify": true, + "path-browserify": true, + "pull-defer": true, + "pull-stream": true, + "uuid": true + } + }, + "ip": { + "packages": { + "buffer": true, + "os-browserify": true + } + }, + "ipfs": { + "globals": { + "AbortController": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "async": true, + "async-iterator-all": true, + "async-iterator-to-pull-stream": true, + "async-iterator-to-stream": true, + "base32.js": true, + "bignumber.js": true, + "browser-resolve": true, + "buffer": true, + "callbackify": true, + "cids": true, + "class-is": true, + "datastore-core": true, + "datastore-pubsub": true, + "debug": true, + "dlv": true, + "err-code": true, + "events": true, + "fnv1a": true, + "fsm-event": true, + "human-to-milliseconds": true, + "interface-datastore": true, + "ipfs-bitswap": true, + "ipfs-block": true, + "ipfs-block-service": true, + "ipfs-mfs": true, + "ipfs-repo": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipfs-utils": true, + "ipld": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "ipns": true, + "is-buffer": true, + "is-ipfs": true, + "is-pull-stream": true, + "is-stream": true, + "iso-url": true, + "just-flatten-it": true, + "kind-of": true, + "libp2p": true, + "libp2p-bootstrap": true, + "libp2p-crypto": true, + "libp2p-kad-dht": true, + "libp2p-keychain": true, + "libp2p-record": true, + "libp2p-secio": true, + "libp2p-webrtc-star": true, + "libp2p-websocket-star-multi": true, + "libp2p-websockets": true, + "mafmt": true, + "merge-options": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "promisify-es6": true, + "protons": true, + "pull-cat": true, + "pull-defer": true, + "pull-mplex": true, + "pull-pushable": true, + "pull-sort": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "pull-stream-to-stream": true, + "pull-traverse": true, + "readable-stream": true, + "receptacle": true, + "stream-to-pull-stream": true, + "superstruct": true, + "timers-browserify": true, + "varint": true + } + }, + "ipfs-bitswap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "cids": true, + "debug": true, + "events": true, + "ipfs-block": true, + "just-debounce-it": true, + "lodash.isequalwith": true, + "moving-average": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "varint-decoder": true + } + }, + "ipfs-block": { + "packages": { + "cids": true, + "class-is": true, + "is-buffer": true + } + }, + "ipfs-block-service": { + "packages": { + "async": true + } + }, + "ipfs-log": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "json-stringify-deterministic": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "p-whilst": true + } + }, + "ipfs-mfs": { + "globals": { + "Blob": true, + "FileReader": true + }, + "packages": { + "assert": true, + "async-iterator-last": true, + "browser-resolve": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "hamt-sharding": true, + "interface-datastore": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipld-dag-pb": true, + "mortice": true, + "multicodec": true, + "multihashes": true, + "promisify-es6": true + } + }, + "ipfs-mini": { + "globals": { + "XMLHttpRequest": true + } + }, + "ipfs-pubsub-1on1": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "events": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "ipfs-pubsub-peer-monitor": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "ipfs-repo": { + "packages": { + "assert": true, + "async": true, + "base32.js": true, + "bignumber.js": true, + "buffer": true, + "cids": true, + "datastore-core": true, + "datastore-level": true, + "debug": true, + "dlv": true, + "interface-datastore": true, + "ipfs-block": true, + "just-safe-set": true, + "path-browserify": true, + "pull-stream": true, + "sort-keys": true, + "timers-browserify": true + } + }, + "ipfs-unixfs": { + "packages": { + "protons": true + } + }, + "ipfs-unixfs-exporter": { + "packages": { + "async-iterator-last": true, + "buffer": true, + "cids": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipfs-unixfs-importer": true, + "is-buffer": true + } + }, + "ipfs-unixfs-importer": { + "packages": { + "async-iterator-all": true, + "async-iterator-batch": true, + "async-iterator-first": true, + "bl": true, + "buffer": true, + "deep-extend": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipld-dag-pb": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "rabin-wasm": true, + "superstruct": true + } + }, + "ipfs-utils": { + "globals": { + "FileReader": true + }, + "packages": { + "is-buffer": true, + "is-pull-stream": true, + "is-stream": true, + "kind-of": true, + "readable-stream": true + } + }, + "ipld": { + "packages": { + "cids": true, + "ipfs-block": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "is-buffer": true, + "merge-options": true, + "multicodec": true, + "promisify-es6": true, + "typical": true + } + }, + "ipld-dag-cbor": { + "packages": { + "borc": true, + "buffer": true, + "cids": true, + "is-buffer": true, + "is-circular": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipld-dag-pb": { + "packages": { + "assert": true, + "buffer": true, + "cids": true, + "class-is": true, + "is-buffer": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "stable": true + } + }, + "ipld-raw": { + "packages": { + "cids": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipns": { + "packages": { + "base32-encode": true, + "buffer": true, + "debug": true, + "interface-datastore": true, + "libp2p-crypto": true, + "multihashes": true, + "peer-id": true, + "protons": true, + "timestamp-nano": true + } + }, + "is-dom": { + "globals": { + "Node": true + }, + "packages": { + "is-object": true, + "is-window": true + } + }, + "is-in-browser": { + "globals": { + "document": true + } + }, + "is-ip": { + "packages": { + "ip-regex": true + } + }, + "is-ipfs": { + "packages": { + "bs58": true, + "buffer": true, + "cids": true, + "mafmt": true, + "multiaddr": true, + "multibase": true, + "multihashes": true + } + }, + "is-regex": { + "packages": { + "has-symbols": true + } + }, + "iso-random-stream": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "buffer": true + } + }, + "iso-url": { + "globals": { + "URL": true, + "URLSearchParams": true, + "location": true + } + }, + "isomorphic-fetch": { + "globals": { + "fetch.bind": true + }, + "packages": { + "whatwg-fetch": true + } + }, + "js-base64": { + "globals": { + "Base64": "write", + "TextDecoder": true, + "TextEncoder": true, + "atob": true, + "btoa": true, + "define": true + }, + "packages": { + "buffer": true + } + }, + "js-sha256": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "js-sha3": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "jsan": { + "globals": { + "console.warn": true + } + }, + "json-rpc-engine": { + "packages": { + "@metamask/safe-event-emitter": true, + "eth-rpc-errors": true, + "safe-event-emitter": true + } + }, + "json-rpc-middleware-stream": { + "packages": { + "readable-stream": true + } + }, + "json-stable-stringify": { + "packages": { + "jsonify": true + } + }, + "jsonschema": { + "packages": { + "url": true + } + }, + "jss": { + "globals": { + "CSS": true, + "document.createElement": true, + "document.querySelector": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true, + "tiny-warning": true + } + }, + "jss-plugin-camel-case": { + "packages": { + "hyphenate-style-name": true + } + }, + "jss-plugin-default-unit": { + "globals": { + "CSS": true + }, + "packages": { + "jss": true + } + }, + "jss-plugin-global": { + "packages": { + "@babel/runtime": true, + "jss": true + } + }, + "jss-plugin-nested": { + "packages": { + "@babel/runtime": true, + "tiny-warning": true + } + }, + "jss-plugin-rule-value-function": { + "packages": { + "jss": true, + "tiny-warning": true + } + }, + "jss-plugin-vendor-prefixer": { + "packages": { + "css-vendor": true, + "jss": true + } + }, + "just-debounce-it": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "k-bucket": { + "packages": { + "events": true, + "randombytes": true + } + }, + "keccak": { + "packages": { + "buffer": true, + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "latency-monitor": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document": true, + "performance": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "debug": true, + "events": true, + "lodash": true, + "process": true + } + }, + "level-codec": { + "packages": { + "buffer": true + } + }, + "level-errors": { + "packages": { + "errno": true + } + }, + "level-iterator-stream": { + "packages": { + "inherits": true, + "readable-stream": true, + "xtend": true + } + }, + "level-js": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.only": true, + "IDBKeyRange.upperBound": true, + "indexedDB": true + }, + "packages": { + "abstract-leveldown": true, + "buffer": true, + "idb-readable-stream": true, + "immediate": true, + "inherits": true, + "is-buffer": true, + "ltgt": true, + "process": true, + "stream-browserify": true, + "typedarray-to-buffer": true, + "util": true, + "xtend": true + } + }, + "levelup": { + "packages": { + "assert": true, + "deferred-leveldown": true, + "events": true, + "level-errors": true, + "level-iterator-stream": true, + "process": true, + "util": true, + "xtend": true + } + }, + "libp2p": { + "packages": { + "async": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "is-buffer": true, + "libp2p-connection-manager": true, + "libp2p-floodsub": true, + "libp2p-ping": true, + "libp2p-switch": true, + "libp2p-websockets": true, + "multiaddr": true, + "once": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "process": true, + "superstruct": true + } + }, + "libp2p-bootstrap": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "mafmt": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true + } + }, + "libp2p-circuit": { + "packages": { + "async": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-connection-manager": { + "packages": { + "debug": true, + "events": true, + "latency-monitor": true + } + }, + "libp2p-crypto": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "asn1.js": true, + "async": true, + "browserify-aes": true, + "bs58": true, + "buffer": true, + "iso-random-stream": true, + "libp2p-crypto-secp256k1": true, + "multihashing-async": true, + "node-forge": true, + "protons": true, + "tweetnacl": true + } + }, + "libp2p-crypto-secp256k1": { + "packages": { + "async": true, + "bs58": true, + "multihashing-async": true, + "secp256k1": true + } + }, + "libp2p-floodsub": { + "packages": { + "assert": true, + "async": true, + "debug": true, + "libp2p-pubsub": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-identify": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-kad-dht": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "abort-controller": true, + "assert": true, + "async": true, + "base32.js": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "events": true, + "hashlru": true, + "heap": true, + "interface-datastore": true, + "is-buffer": true, + "k-bucket": true, + "libp2p-crypto": true, + "libp2p-record": true, + "multihashes": true, + "multihashing-async": true, + "p-queue": true, + "p-times": true, + "peer-id": true, + "peer-info": true, + "promise-to-callback": true, + "promisify-es6": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "varint": true, + "xor-distance": true + } + }, + "libp2p-keychain": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "buffer": true, + "err-code": true, + "interface-datastore": true, + "libp2p-crypto": true, + "merge-options": true, + "node-forge": true, + "pull-stream": true, + "sanitize-filename": true + } + }, + "libp2p-ping": { + "packages": { + "debug": true, + "events": true, + "libp2p-crypto": true, + "pull-handshake": true, + "pull-stream": true + } + }, + "libp2p-pubsub": { + "packages": { + "async": true, + "bs58": true, + "buffer": true, + "debug": true, + "err-code": true, + "events": true, + "is-buffer": true, + "libp2p-crypto": true, + "protons": true, + "pull-length-prefixed": true, + "pull-pushable": true, + "pull-stream": true, + "time-cache": true + } + }, + "libp2p-record": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "buffer-split": true, + "err-code": true, + "is-buffer": true, + "multihashing-async": true, + "protons": true + } + }, + "libp2p-secio": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "interface-connection": true, + "libp2p-crypto": true, + "multihashing-async": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-defer": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-switch": { + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "class-is": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "hashlru": true, + "interface-connection": true, + "libp2p-circuit": true, + "libp2p-identify": true, + "moving-average": true, + "multiaddr": true, + "multistream-select": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "retimer": true + } + }, + "libp2p-webrtc-star": { + "packages": { + "async": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "simple-peer": true, + "socket.io-client": true, + "stream-to-pull-stream": true, + "webrtcsupport": true + } + }, + "libp2p-websocket-star": { + "globals": { + "console.error": true + }, + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "libp2p-crypto": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "socket.io-client": true, + "socket.io-pull-stream": true, + "uuid": true + } + }, + "libp2p-websocket-star-multi": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "libp2p-websocket-star": true, + "mafmt": true, + "multiaddr": true, + "once": true + } + }, + "libp2p-websockets": { + "packages": { + "class-is": true, + "debug": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "os-browserify": true, + "pull-ws": true + } + }, + "locale-currency": { + "globals": { + "countryCode": true + } + }, + "localforage": { + "globals": { + "Blob": true, + "BlobBuilder": true, + "FileReader": true, + "IDBKeyRange": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "OIndexedDB": true, + "WebKitBlobBuilder": true, + "atob": true, + "btoa": true, + "console.error": true, + "console.info": true, + "console.warn": true, + "define": true, + "fetch": true, + "indexedDB": true, + "localStorage": true, + "mozIndexedDB": true, + "msIndexedDB": true, + "navigator.platform": true, + "navigator.userAgent": true, + "openDatabase": true, + "setTimeout": true, + "webkitIndexedDB": true + } + }, + "lodash": { + "globals": { + "define": true + } + }, + "lodash.throttle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "loglevel": { + "globals": { + "console": true, + "define": true, + "document.cookie": true, + "localStorage": true, + "log": "write" + } + }, + "logplease": { + "globals": { + "LOG": true, + "console.error": true, + "console.log": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "process": true, + "util": true + } + }, + "lru": { + "packages": { + "events": true, + "inherits": true + } + }, + "ltgt": { + "packages": { + "is-buffer": true + } + }, + "luxon": { + "globals": { + "Intl": true + } + }, + "mafmt": { + "packages": { + "multiaddr": true + } + }, + "md5": { + "packages": { + "charenc": true, + "crypt": true, + "is-buffer": true + } + }, + "md5.js": { + "packages": { + "hash-base": true, + "inherits": true, + "safe-buffer": true + } + }, + "merge-options": { + "packages": { + "is-plain-obj": true + } + }, + "miller-rabin": { + "packages": { + "bn.js": true, + "brorand": true + } + }, + "mini-create-react-context": { + "packages": { + "@babel/runtime": true, + "gud": true, + "prop-types": true, + "react": true, + "tiny-warning": true + } + }, + "mortice": { + "globals": { + "Worker": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "observable-webworkers": true, + "p-queue": true, + "process": true, + "promise-timeout": true, + "shortid": true + } + }, + "multiaddr": { + "packages": { + "bs58": true, + "buffer": true, + "class-is": true, + "hi-base32": true, + "ip": true, + "is-ip": true, + "varint": true + } + }, + "multiaddr-to-uri": { + "packages": { + "multiaddr": true + } + }, + "multibase": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@multiformats/base-x": true, + "base-x": true, + "buffer": true, + "web-encoding": true + } + }, + "multicodec": { + "packages": { + "buffer": true, + "uint8arrays": true, + "varint": true + } + }, + "multihashes": { + "packages": { + "bs58": true, + "buffer": true, + "multibase": true, + "uint8arrays": true, + "varint": true, + "web-encoding": true + } + }, + "multihashing-async": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "blakejs": true, + "buffer": true, + "err-code": true, + "js-sha3": true, + "multihashes": true, + "murmurhash3js": true, + "murmurhash3js-revisited": true, + "nodeify": true, + "process": true + } + }, + "multistream-select": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-connection": true, + "once": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true, + "semver": true, + "varint": true + } + }, + "muport-did-resolver": { + "packages": { + "@babel/runtime": true, + "did-resolver": true, + "node-fetch": true + } + }, + "murmurhash3js": { + "globals": { + "define": true + } + }, + "murmurhash3js-revisited": { + "globals": { + "define": true + } + }, + "nanoid": { + "globals": { + "crypto": true, + "msCrypto": true, + "navigator": true + }, + "packages": { + "buffer": true, + "crypto-browserify": true + } + }, + "node-forge": { + "globals": { + "Blob": true, + "MutationObserver": true, + "QuotaExceededError": true, + "URL.createObjectURL": true, + "URL.revokeObjectURL": true, + "Worker": true, + "addEventListener": true, + "document": true, + "jQuery": true, + "localStorage": true, + "location": true, + "navigator": true, + "postMessage": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "process": true, + "timers-browserify": true + } + }, + "nodeify": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true, + "promise": true, + "timers-browserify": true + } + }, + "nonce-tracker": { + "packages": { + "assert": true, + "await-semaphore": true, + "ethjs-query": true + } + }, + "number-to-bn": { + "packages": { + "bn.js": true, + "strip-hex-prefix": true + } + }, + "obj-multiplex": { + "globals": { + "console.warn": true + }, + "packages": { + "end-of-stream": true, + "once": true, + "readable-stream": true + } + }, + "obs-store": { + "packages": { + "safe-event-emitter": true, + "xtend": true + } + }, + "once": { + "packages": { + "wrappy": true + } + }, + "orbit-db": { + "globals": { + "console.log": true + }, + "packages": { + "cids": true, + "ipfs-pubsub-1on1": true, + "logplease": true, + "multihashes": true, + "orbit-db-access-controllers": true, + "orbit-db-cache": true, + "orbit-db-counterstore": true, + "orbit-db-docstore": true, + "orbit-db-eventstore": true, + "orbit-db-feedstore": true, + "orbit-db-identity-provider": true, + "orbit-db-io": true, + "orbit-db-keystore": true, + "orbit-db-kvstore": true, + "orbit-db-pubsub": true, + "path-browserify": true + } + }, + "orbit-db-access-controllers": { + "globals": { + "console.log": true + }, + "packages": { + "events": true, + "orbit-db-io": true, + "p-map-series": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "orbit-db-cache": { + "packages": { + "level-js": true, + "logplease": true, + "path-browserify": true + } + }, + "orbit-db-counterstore": { + "packages": { + "crdts": true, + "orbit-db-store": true + } + }, + "orbit-db-docstore": { + "packages": { + "orbit-db-store": true, + "p-map": true, + "readable-stream": true + } + }, + "orbit-db-eventstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-feedstore": { + "packages": { + "orbit-db-eventstore": true + } + }, + "orbit-db-identity-provider": { + "packages": { + "orbit-db-keystore": true + } + }, + "orbit-db-io": { + "packages": { + "buffer": true, + "cids": true, + "ipld-dag-pb": true + } + }, + "orbit-db-keystore": { + "globals": { + "console.error": true, + "console.log": true + }, + "packages": { + "elliptic": true, + "level-js": true, + "levelup": true, + "libp2p-crypto": true, + "lru": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "orbit-db-kvstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-pubsub": { + "packages": { + "buffer": true, + "ipfs-pubsub-peer-monitor": true, + "logplease": true, + "p-series": true + } + }, + "orbit-db-store": { + "globals": { + "clearInterval": true, + "console.error": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "events": true, + "ipfs-log": true, + "logplease": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "readable-stream": true + } + }, + "os-browserify": { + "globals": { + "location": true, + "navigator": true + } + }, + "p-each-series": { + "packages": { + "p-reduce": true + } + }, + "p-map-series": { + "packages": { + "p-reduce": true + } + }, + "p-queue": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "eventemitter3": true + } + }, + "p-series": { + "packages": { + "@sindresorhus/is": true, + "p-reduce": true + } + }, + "p-times": { + "packages": { + "p-map": true + } + }, + "parse-asn1": { + "packages": { + "asn1.js": true, + "browserify-aes": true, + "buffer": true, + "evp_bytestokey": true, + "pbkdf2": true + } + }, + "path-browserify": { + "packages": { + "process": true + } + }, + "path-to-regexp": { + "packages": { + "isarray": true + } + }, + "pbkdf2": { + "globals": { + "crypto": true, + "process": true + }, + "packages": { + "create-hash": true, + "process": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "peer-book": { + "packages": { + "bs58": true, + "is-buffer": true, + "peer-id": true, + "peer-info": true + } + }, + "peer-id": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "class-is": true, + "libp2p-crypto": true, + "multihashes": true + } + }, + "peer-info": { + "packages": { + "assert": true, + "multiaddr": true, + "peer-id": true, + "unique-by": true + } + }, + "popper.js": { + "globals": { + "MSInputMethodContext": true, + "Node.DOCUMENT_POSITION_FOLLOWING": true, + "cancelAnimationFrame": true, + "console.warn": true, + "define": true, + "devicePixelRatio": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "precond": { + "packages": { + "util": true + } + }, + "process": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "process-nextick-args": { + "packages": { + "process": true + } + }, + "promise": { + "globals": { + "setImediate": true, + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true + } + }, + "promise-timeout": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "promise-to-callback": { + "packages": { + "is-fn": true, + "set-immediate-shim": true + } + }, + "prop-types": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "react-is": true + } + }, + "protons": { + "packages": { + "buffer": true, + "is-buffer": true, + "protocol-buffers-schema": true, + "safe-buffer": true, + "signed-varint": true, + "varint": true + } + }, + "public-encrypt": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "parse-asn1": true, + "randombytes": true + } + }, + "pubnub": { + "globals": { + "ActiveXObject": true, + "XMLHttpRequest": true, + "addEventListener": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "define": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "location": true, + "navigator": true, + "setInterval": true, + "setTimeout": true + } + }, + "pull-handshake": { + "packages": { + "pull-cat": true, + "pull-pair": true, + "pull-pushable": true, + "pull-reader": true + } + }, + "pull-length-prefixed": { + "packages": { + "pull-pushable": true, + "pull-reader": true, + "safe-buffer": true, + "varint": true + } + }, + "pull-mplex": { + "packages": { + "async": true, + "buffer": true, + "debug": true, + "events": true, + "interface-connection": true, + "looper": true, + "pull-abortable": true, + "pull-pushable": true, + "pull-stream": true, + "pull-through": true, + "varint": true + } + }, + "pull-reader": { + "globals": { + "cb": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "buffer": true + } + }, + "pull-sort": { + "packages": { + "pull-defer": true, + "pull-stream": true + } + }, + "pull-stream": { + "globals": { + "console.log": true + } + }, + "pull-stream-to-async-iterator": { + "packages": { + "pull-stream": true + } + }, + "pull-stream-to-stream": { + "packages": { + "process": true, + "stream-browserify": true, + "timers-browserify": true + } + }, + "pull-through": { + "packages": { + "looper": true + } + }, + "pull-ws": { + "globals": { + "WebSocket": true, + "location": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "https-browserify": true, + "process": true, + "relative-url": true, + "safe-buffer": true, + "stream-http": true, + "timers-browserify": true, + "url": true + } + }, + "pump": { + "packages": { + "browser-resolve": true, + "end-of-stream": true, + "once": true, + "process": true + } + }, + "punycode": { + "globals": { + "define": true + } + }, + "qrcode-generator": { + "globals": { + "define": true + } + }, + "rabin-wasm": { + "globals": { + "Blob": true, + "Response": true, + "WebAssembly": true + }, + "packages": { + "assemblyscript": true + } + }, + "randombytes": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "safe-buffer": true + } + }, + "randomfill": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "randombytes": true, + "safe-buffer": true + } + }, + "react": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "prop-types": true + } + }, + "react-dnd": { + "globals": { + "console.error": true + }, + "packages": { + "disposables": true, + "dnd-core": true, + "hoist-non-react-statics": true, + "invariant": true, + "lodash": true, + "prop-types": true, + "react": true, + "shallowequal": true + } + }, + "react-dnd-html5-backend": { + "globals": { + "Image": true, + "console.warn": true, + "devicePixelRatio": true, + "document": true, + "navigator.userAgent": true, + "safari": true, + "setTimeout": true + } + }, + "react-dom": { + "globals": { + "MSApp": true, + "__REACT_DEVTOOLS_GLOBAL_HOOK__": true, + "addEventListener": true, + "clearTimeout": true, + "clipboardData": true, + "console": true, + "dispatchEvent": true, + "document": true, + "event": "write", + "jest": true, + "location.protocol": true, + "navigator.userAgent.indexOf": true, + "performance": true, + "removeEventListener": true, + "self": true, + "setTimeout": true, + "top": true, + "trustedTypes": true + }, + "packages": { + "object-assign": true, + "prop-types": true, + "react": true, + "scheduler": true + } + }, + "react-fast-compare": { + "globals": { + "Element": true, + "console.warn": true + } + }, + "react-idle-timer": { + "globals": { + "clearTimeout": true, + "document": true, + "setTimeout": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-inspector": { + "globals": { + "Node.CDATA_SECTION_NODE": true, + "Node.COMMENT_NODE": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_TYPE_NODE": true, + "Node.ELEMENT_NODE": true, + "Node.PROCESSING_INSTRUCTION_NODE": true, + "Node.TEXT_NODE": true + }, + "packages": { + "babel-runtime": true, + "is-dom": true, + "prop-types": true, + "react": true + } + }, + "react-is": { + "globals": { + "console": true + } + }, + "react-popper": { + "globals": { + "document": true + }, + "packages": { + "@popperjs/core": true, + "react": true, + "react-fast-compare": true, + "warning": true + } + }, + "react-redux": { + "globals": { + "console": true, + "document": true + }, + "packages": { + "@babel/runtime": true, + "hoist-non-react-statics": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "redux": true + } + }, + "react-router": { + "packages": { + "history": true, + "hoist-non-react-statics": true, + "mini-create-react-context": true, + "path-to-regexp": true, + "prop-types": true, + "react": true, + "react-is": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-router-dom": { + "packages": { + "history": true, + "prop-types": true, + "react": true, + "react-router": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-simple-file-input": { + "globals": { + "File": true, + "FileReader": true, + "console.warn": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-tippy": { + "globals": { + "Element": true, + "MSStream": true, + "MutationObserver": true, + "addEventListener": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "define": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator.maxTouchPoints": true, + "navigator.msMaxTouchPoints": true, + "navigator.userAgent": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + }, + "packages": { + "popper.js": true, + "react": true, + "react-dom": true + } + }, + "react-toggle-button": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "define": true, + "performance": true, + "setTimeout": true + }, + "packages": { + "react": true + } + }, + "react-transition-group": { + "globals": { + "Element": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "chain-function": true, + "dom-helpers": true, + "prop-types": true, + "react": true, + "react-dom": true, + "warning": true + } + }, + "readable-stream": { + "packages": { + "browser-resolve": true, + "buffer": true, + "core-util-is": true, + "events": true, + "inherits": true, + "isarray": true, + "process": true, + "process-nextick-args": true, + "safe-buffer": true, + "string_decoder": true, + "timers-browserify": true, + "util-deprecate": true + } + }, + "receptacle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "ms": true + } + }, + "redux": { + "globals": { + "console": true + }, + "packages": { + "symbol-observable": true + } + }, + "redux-devtools-core": { + "globals": { + "ErrorUtils": true, + "console": true, + "devToolsOptions": true, + "onerror": "write", + "serializeState": true + }, + "packages": { + "get-params": true, + "jsan": true, + "lodash": true, + "nanoid": true, + "remotedev-serialize": true + } + }, + "redux-devtools-instrument": { + "globals": { + "chrome": true, + "console.error": true, + "process": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "symbol-observable": true + } + }, + "regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "regexp.prototype.flags": { + "packages": { + "define-properties": true, + "es-abstract": true + } + }, + "relative-url": { + "packages": { + "url": true + } + }, + "remote-redux-devtools": { + "globals": { + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "jsan": true, + "redux-devtools-core": true, + "redux-devtools-instrument": true, + "rn-host-detect": true, + "socketcluster-client": true + } + }, + "retimer": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "ripemd160": { + "packages": { + "buffer": true, + "hash-base": true, + "inherits": true + } + }, + "rlp": { + "packages": { + "bn.js": true, + "buffer": true + } + }, + "rn-host-detect": { + "globals": { + "__DEV__": true, + "__fbBatchedBridgeConfig": true, + "console": true + } + }, + "rpc-cap": { + "packages": { + "@metamask/controllers": true, + "eth-rpc-errors": true, + "is-subset": true, + "json-rpc-engine": true, + "uuid": true + } + }, + "safe-buffer": { + "packages": { + "buffer": true + } + }, + "safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true, + "util": true + } + }, + "sanitize-filename": { + "packages": { + "truncate-utf8-bytes": true + } + }, + "sc-channel": { + "packages": { + "component-emitter": true + } + }, + "sc-formatter": { + "globals": { + "Buffer": true + } + }, + "scheduler": { + "globals": { + "MessageChannel": true, + "cancelAnimationFrame": true, + "clearTimeout": true, + "console": true, + "navigator": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "scrypt-js": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "timers-browserify": true + } + }, + "scryptsy": { + "packages": { + "buffer": true, + "pbkdf2": true + } + }, + "secp256k1": { + "packages": { + "bip66": true, + "bn.js": true, + "create-hash": true, + "drbg.js": true, + "elliptic": true, + "is-buffer": true, + "safe-buffer": true + } + }, + "semaphore": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "semver": { + "globals": { + "console": true + }, + "packages": { + "process": true + } + }, + "set-immediate-shim": { + "globals": { + "setTimeout.apply": true + }, + "packages": { + "timers-browserify": true + } + }, + "sha.js": { + "packages": { + "inherits": true, + "safe-buffer": true + } + }, + "shortid": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "nanoid": true + } + }, + "signed-varint": { + "packages": { + "varint": true + } + }, + "simple-peer": { + "globals": { + "clearInterval": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "debug": true, + "get-browser-rtc": true, + "inherits": true, + "randombytes": true, + "readable-stream": true + } + }, + "socket.io-client": { + "globals": { + "clearTimeout": true, + "location": true, + "setTimeout": true + }, + "packages": { + "backo2": true, + "component-bind": true, + "component-emitter": true, + "debug": true, + "engine.io-client": true, + "has-binary2": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "socket.io-parser": true, + "to-array": true + } + }, + "socket.io-parser": { + "globals": { + "Blob": true, + "File": true, + "FileReader": true + }, + "packages": { + "buffer": true, + "component-emitter": true, + "debug": true, + "isarray": true + } + }, + "socket.io-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "buffer": true, + "data-queue": true, + "debug": true, + "pull-stream": true, + "uuid": true + } + }, + "socketcluster-client": { + "globals": { + "WebSocket": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "clearTimeout": true, + "localStorage": true, + "location": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "clone": true, + "component-emitter": true, + "linked-list": true, + "querystring-es3": true, + "sc-channel": true, + "sc-errors": true, + "sc-formatter": true, + "uuid": true + } + }, + "sort-keys": { + "packages": { + "is-plain-obj": true + } + }, + "stable": { + "globals": { + "define": true + } + }, + "store": { + "globals": { + "ActiveXObject": true, + "console": true + } + }, + "stream-browserify": { + "packages": { + "events": true, + "inherits": true, + "readable-stream": true + } + }, + "stream-http": { + "globals": { + "AbortController": true, + "Blob": true, + "MSStreamReader": true, + "ReadableStream": true, + "WritableStream": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "clearTimeout": true, + "fetch": true, + "location.protocol.search": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "builtin-status-codes": true, + "inherits": true, + "process": true, + "readable-stream": true, + "url": true, + "xtend": true + } + }, + "stream-to-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "looper": true, + "process": true, + "pull-stream": true + } + }, + "string_decoder": { + "packages": { + "safe-buffer": true + } + }, + "strip-hex-prefix": { + "packages": { + "is-hex-prefixed": true + } + }, + "textarea-caret": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.querySelector": true, + "getCaretCoordinates": "write", + "getComputedStyle": true, + "mozInnerScreenX": true + } + }, + "through": { + "packages": { + "process": true, + "stream-browserify": true + } + }, + "through2": { + "packages": { + "process": true, + "readable-stream": true, + "util": true, + "xtend": true + } + }, + "time-cache": { + "packages": { + "lodash.throttle": true + } + }, + "timers-browserify": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "tiny-warning": { + "globals": { + "console": true + } + }, + "toggle-selection": { + "globals": { + "document.activeElement": true, + "document.getSelection": true + } + }, + "trezor-connect": { + "globals": { + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "fetch": true, + "location": true, + "navigator": true, + "open": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "events": true, + "whatwg-fetch": true + } + }, + "truncate-utf8-bytes": { + "packages": { + "utf8-byte-length": true + } + }, + "tslib": { + "globals": { + "define": true + } + }, + "tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browser-resolve": true + } + }, + "tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browser-resolve": true + } + }, + "typedarray-to-buffer": { + "packages": { + "buffer": true, + "is-typedarray": true + } + }, + "typical": { + "globals": { + "define": true + } + }, + "uint8arrays": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "multibase": true, + "web-encoding": true + } + }, + "unorm": { + "globals": { + "define": true + } + }, + "uport-base64url": { + "packages": { + "buffer": true + } + }, + "url": { + "packages": { + "punycode": true, + "querystring-es3": true + } + }, + "utf8": { + "globals": { + "define": true + } + }, + "util": { + "globals": { + "console.error": true, + "console.log": true, + "console.trace": true, + "process": true + }, + "packages": { + "inherits": true, + "process": true + } + }, + "util-deprecate": { + "globals": { + "console.trace": true, + "console.warn": true, + "localStorage": true + } + }, + "uuid": { + "globals": { + "crypto": true, + "msCrypto": true + } + }, + "varint-decoder": { + "packages": { + "is-buffer": true, + "varint": true + } + }, + "vm-browserify": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true + } + }, + "warning": { + "globals": { + "console": true + } + }, + "web-encoding": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "util": true + } + }, + "web3": { + "globals": { + "Web3": "write", + "XMLHttpRequest": "write", + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "crypto-js": true, + "utf8": true, + "xhr2-cookies": true + } + }, + "web3-provider-engine": { + "globals": { + "WebSocket": true, + "console": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "async": true, + "backoff": true, + "browser-resolve": true, + "buffer": true, + "eth-block-tracker": true, + "eth-json-rpc-filters": true, + "eth-json-rpc-infura": true, + "eth-json-rpc-middleware": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "json-stable-stringify": true, + "semaphore": true, + "util": true, + "xtend": true + } + }, + "web3-stream-provider": { + "globals": { + "setTimeout": true + }, + "packages": { + "readable-stream": true, + "util": true, + "uuid": true + } + }, + "webrtcsupport": { + "globals": { + "AudioContext": true, + "MediaStream": true, + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "document": true, + "location.protocol": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "navigator.getUserMedia": true, + "navigator.mozGetUserMedia": true, + "navigator.msGetUserMedia": true, + "navigator.userAgent.match": true, + "navigator.webkitGetUserMedia": true, + "webkitAudioContext": true, + "webkitMediaStream": true, + "webkitRTCPeerConnection": true + } + }, + "whatwg-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true, + "define": true, + "setTimeout": true + } + }, + "xhr2": { + "globals": { + "XMLHttpRequest": true + } + }, + "xhr2-cookies": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cookiejar": true, + "https-browserify": true, + "os-browserify": true, + "process": true, + "stream-http": true, + "url": true + } + }, + "xor-distance": { + "packages": { + "buffer": true + } + } + } +} \ No newline at end of file diff --git a/lavamoat/node/policy.json b/lavamoat/node/policy.json index 8fc5fcd16..8399643d6 100644 --- a/lavamoat/node/policy.json +++ b/lavamoat/node/policy.json @@ -824,8 +824,8 @@ "@gulp-sourcemaps/identity-map": { "packages": { "acorn": true, - "css": true, "normalize-path": true, + "postcss": true, "source-map": true, "through2": true } @@ -840,18 +840,22 @@ "builtin": { "assert": true, "buffer.Buffer.from": true, + "fs.readFileSync": true, "path.join": true, "path.relative": true }, "globals": { "__dirname": true, - "process.cwd": true + "process.cwd": true, + "setTimeout": true }, "packages": { "JSONStream": true, "combine-source-map": true, "convert-source-map": true, "json-stable-stringify": true, + "lavamoat-core": true, + "readable-stream": true, "through2": true, "umd": true } @@ -962,15 +966,6 @@ "uri-js": true } }, - "amdefine": { - "builtin": { - "path.dirname": true - }, - "globals": { - "__filename": true, - "process.nextTick": true - } - }, "ansi-colors": { "packages": { "ansi-wrap": true @@ -1407,6 +1402,15 @@ "buffer.Buffer": true } }, + "clone-deep": { + "packages": { + "for-own": true, + "is-plain-object": true, + "kind-of": true, + "lazy-cache": true, + "shallow-clone": true + } + }, "clone-regexp": { "packages": { "is-regexp": true @@ -1465,6 +1469,7 @@ "concat-stream": { "globals": { "Buffer.concat": true, + "Buffer.from": true, "Buffer.isBuffer": true }, "packages": { @@ -1481,7 +1486,7 @@ "path.resolve": true }, "globals": { - "Buffer": true + "Buffer.from": true }, "packages": { "safe-buffer": true @@ -1540,13 +1545,13 @@ "css": { "builtin": { "fs.readFileSync": true, - "path.dirname": true + "path.dirname": true, + "path.sep": true }, "packages": { "inherits": true, "source-map": true, - "source-map-resolve": true, - "urix": true + "source-map-resolve": true } }, "d": { @@ -2436,7 +2441,8 @@ "path.sep": true }, "globals": { - "Buffer": true + "Buffer.concat": true, + "Buffer.from": true }, "packages": { "@gulp-sourcemaps/identity-map": true, @@ -2595,7 +2601,7 @@ }, "inline-source-map": { "globals": { - "Buffer": true + "Buffer.from": true }, "packages": { "source-map": true @@ -2820,6 +2826,70 @@ "es6-weak-map": true } }, + "lavamoat-browserify": { + "builtin": { + "fs.existsSync": true, + "fs.mkdirSync": true, + "fs.readFileSync": true, + "fs.writeFileSync": true, + "path.dirname": true, + "path.extname": true, + "path.resolve": true, + "util.callbackify": true + }, + "globals": { + "console.warn": true, + "process.cwd": true + }, + "packages": { + "@lavamoat/lavapack": true, + "concat-stream": true, + "duplexify": true, + "json-stable-stringify": true, + "lavamoat-core": true, + "readable-stream": true, + "through2": true + } + }, + "lavamoat-core": { + "builtin": { + "events": true, + "fs.existsSync": true, + "fs.readFileSync": true, + "module.createRequire": true, + "module.createRequireFromPath": true, + "path.extname": true, + "path.join": true, + "path.sep": true + }, + "globals": { + "__dirname": true, + "console.warn": true, + "define": true + }, + "packages": { + "fromentries": true, + "json-stable-stringify": true, + "lavamoat-tofu": true, + "merge-deep": true, + "resolve": true + } + }, + "lavamoat-tofu": { + "globals": { + "console.log": true + }, + "packages": { + "@babel/parser": true, + "@babel/traverse": true + } + }, + "lazy-cache": { + "globals": { + "process.env.TRAVIS": true, + "process.env.UNLAZY": true + } + }, "lazystream": { "builtin": { "util.inherits": true @@ -2870,6 +2940,11 @@ "js-tokens": true } }, + "lru-cache": { + "packages": { + "yallist": true + } + }, "lru-queue": { "packages": { "es5-ext": true @@ -2936,6 +3011,13 @@ "timers-ext": true } }, + "merge-deep": { + "packages": { + "arr-union": true, + "clone-deep": true, + "kind-of": true + } + }, "merge-source-map": { "packages": { "source-map": true @@ -3000,6 +3082,12 @@ "is-extendable": true } }, + "mixin-object": { + "packages": { + "for-in": true, + "is-extendable": true + } + }, "mkdirp": { "builtin": { "fs": true, @@ -3732,6 +3820,9 @@ "globals": { "console": true, "process": true + }, + "packages": { + "lru-cache": true } }, "set-value": { @@ -3742,6 +3833,14 @@ "split-string": true } }, + "shallow-clone": { + "packages": { + "is-extendable": true, + "kind-of": true, + "lazy-cache": true, + "mixin-object": true + } + }, "shasum": { "builtin": { "buffer.Buffer.isBuffer": true, @@ -3816,16 +3915,15 @@ "console.time": true, "console.timeEnd": true, "fetch": true - }, - "packages": { - "amdefine": true } }, "source-map-resolve": { "builtin": { + "path.sep": true, "url.resolve": true }, "globals": { + "TextDecoder": true, "setImmediate": true }, "packages": { @@ -4594,4 +4692,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 3dc9c235d..cef917819 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,10 @@ "dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'", "forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010", "dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'", - "test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/**/*.test.js'", + "test:unit": "./test/test-unit-combined.sh", + "test:unit:jest": "./test/test-unit-jest.sh", "test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js", - "test:unit:jest": "./test/run-jest.sh", + "test:unit:mocha": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/migrations/*.test.js' --recursive './app/**/*.test.js'", "test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --ignore './app/scripts/migrations/*.test.js' --recursive './app/**/*.test.js'", "test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/scripts/controllers/permissions/*.test.js'", "test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive", @@ -64,11 +65,14 @@ "storybook:deploy": "storybook-to-ghpages --existing-output-dir storybook-build --remote storybook --branch master", "update-changelog": "auto-changelog update", "generate:migration": "./development/generate-migration.sh", - "lavamoat:auto": "lavamoat ./development/build/index.js --writeAutoPolicy", - "lavamoat:debug": "lavamoat ./development/build/index.js --writeAutoPolicyDebug" + "lavamoat:build:auto": "lavamoat ./development/build/index.js --writeAutoPolicy", + "lavamoat:debug:build": "lavamoat ./development/build/index.js --writeAutoPolicyDebug", + "lavamoat:background:auto": "WRITE_AUTO_POLICY=1 yarn build prod", + "lavamoat:auto": "yarn lavamoat:build:auto && yarn lavamoat:background:auto" }, "resolutions": { "**/regenerator-runtime": "^0.13.7", + "**/caniuse-lite": "1.0.30001265", "**/configstore/dot-prop": "^5.1.1", "**/ethers/elliptic": "^6.5.4", "**/knex/minimist": "^1.2.5", @@ -102,7 +106,7 @@ "@fortawesome/fontawesome-free": "^5.13.0", "@material-ui/core": "^4.11.0", "@metamask/contract-metadata": "^1.28.0", - "@metamask/controllers": "^16.0.0", + "@metamask/controllers": "^17.0.0", "@metamask/eth-ledger-bridge-keyring": "^0.7.0", "@metamask/eth-token-tracker": "^3.0.1", "@metamask/etherscan-link": "^2.1.0", @@ -216,7 +220,7 @@ "@babel/preset-react": "^7.0.0", "@babel/register": "^7.5.5", "@lavamoat/allow-scripts": "^1.0.6", - "@lavamoat/lavapack": "^1.0.4", + "@lavamoat/lavapack": "^2.0.3", "@metamask/auto-changelog": "^2.1.0", "@metamask/eslint-config": "^6.0.0", "@metamask/eslint-config-jest": "^6.0.0", @@ -278,7 +282,7 @@ "gulp-livereload": "4.0.0", "gulp-rename": "^2.0.0", "gulp-rtlcss": "^1.4.0", - "gulp-sourcemaps": "^2.6.0", + "gulp-sourcemaps": "^3.0.0", "gulp-stylelint": "^13.0.0", "gulp-watch": "^5.0.1", "gulp-zip": "^4.0.0", @@ -287,7 +291,8 @@ "jest": "^26.6.3", "jsdom": "^11.2.0", "koa": "^2.7.0", - "lavamoat": "^5.3.1", + "lavamoat": "^5.3.4", + "lavamoat-browserify": "^14.0.3", "lavamoat-viz": "^6.0.9", "lockfile-lint": "^4.0.0", "loose-envify": "^1.4.0", @@ -312,6 +317,7 @@ "sass": "^1.32.4", "sass-loader": "^10.1.1", "selenium-webdriver": "4.0.0-alpha.7", + "semver": "^7.3.5", "serve-handler": "^6.1.2", "sinon": "^9.0.0", "source-map": "^0.7.2", @@ -323,6 +329,7 @@ "terser": "^5.7.0", "through2": "^4.0.2", "ttest": "^2.1.1", + "vinyl": "^2.2.1", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", "vinyl-sourcemaps-apply": "^0.2.1", diff --git a/patches/abort-controller+3.0.0.patch b/patches/abort-controller+3.0.0.patch new file mode 100644 index 000000000..2210446d2 --- /dev/null +++ b/patches/abort-controller+3.0.0.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/abort-controller/browser.js b/node_modules/abort-controller/browser.js +index b0c5ec3..c8c8018 100644 +--- a/node_modules/abort-controller/browser.js ++++ b/node_modules/abort-controller/browser.js +@@ -2,12 +2,7 @@ + "use strict" + + /*eslint-disable @mysticatea/prettier */ +-const { AbortController, AbortSignal } = +- typeof self !== "undefined" ? self : +- typeof window !== "undefined" ? window : +- /* otherwise */ undefined ++const { AbortController } = globalThis; + /*eslint-enable @mysticatea/prettier */ + + module.exports = AbortController +-module.exports.AbortSignal = AbortSignal +-module.exports.default = AbortController diff --git a/patches/combine-source-map++convert-source-map+1.1.3.patch b/patches/combine-source-map++convert-source-map+1.1.3.patch new file mode 100644 index 000000000..c24f12817 --- /dev/null +++ b/patches/combine-source-map++convert-source-map+1.1.3.patch @@ -0,0 +1,22 @@ +diff --git a/node_modules/combine-source-map/node_modules/convert-source-map/index.js b/node_modules/combine-source-map/node_modules/convert-source-map/index.js +index bfe92d1..bee1ffe 100644 +--- a/node_modules/combine-source-map/node_modules/convert-source-map/index.js ++++ b/node_modules/combine-source-map/node_modules/convert-source-map/index.js +@@ -9,7 +9,7 @@ var mapFileCommentRx = + /(?:\/\/[@#][ \t]+sourceMappingURL=([^\s'"]+?)[ \t]*$)|(?:\/\*[@#][ \t]+sourceMappingURL=([^\*]+?)[ \t]*(?:\*\/){1}[ \t]*$)/mg + + function decodeBase64(base64) { +- return new Buffer(base64, 'base64').toString(); ++ return Buffer.from(base64, 'base64').toString(); + } + + function stripComment(sm) { +@@ -60,7 +60,7 @@ Converter.prototype.toJSON = function (space) { + + Converter.prototype.toBase64 = function () { + var json = this.toJSON(); +- return new Buffer(json).toString('base64'); ++ return Buffer.from(json).toString('base64'); + }; + + Converter.prototype.toComment = function (options) { diff --git a/patches/gulp-sourcemaps+3.0.0.patch b/patches/gulp-sourcemaps+3.0.0.patch new file mode 100644 index 000000000..056bcb8e2 --- /dev/null +++ b/patches/gulp-sourcemaps+3.0.0.patch @@ -0,0 +1,44 @@ +diff --git a/node_modules/gulp-sourcemaps/src/init/index.internals.js b/node_modules/gulp-sourcemaps/src/init/index.internals.js +index 7104555..7dfe218 100644 +--- a/node_modules/gulp-sourcemaps/src/init/index.internals.js ++++ b/node_modules/gulp-sourcemaps/src/init/index.internals.js +@@ -72,7 +72,7 @@ module.exports = function(options, file, fileContent) { + + }); + // remove source map comment from source +- file.contents = new Buffer(sources.content, 'utf8'); ++ file.contents = Buffer.from(sources.content, 'utf8'); + } + + } +diff --git a/node_modules/gulp-sourcemaps/src/write/index.internals.js b/node_modules/gulp-sourcemaps/src/write/index.internals.js +index 89cee60..adfe8d1 100644 +--- a/node_modules/gulp-sourcemaps/src/write/index.internals.js ++++ b/node_modules/gulp-sourcemaps/src/write/index.internals.js +@@ -99,7 +99,7 @@ module.exports = function(destPath, options) { + + if (destPath === undefined || destPath === null) { + // encode source map into comment +- var base64Map = new Buffer(JSON.stringify(sourceMap)).toString('base64'); ++ var base64Map = Buffer.from(JSON.stringify(sourceMap)).toString('base64'); + comment = commentFormatter('data:application/json;charset=' + options.charset + ';base64,' + base64Map); + } else { + var mapFile = path.join(destPath, file.relative) + '.map'; +@@ -130,7 +130,7 @@ module.exports = function(destPath, options) { + + var sourceMapFile = file.clone(options.clone || { deep: false, contents: false }); + sourceMapFile.path = sourceMapPath; +- sourceMapFile.contents = new Buffer(JSON.stringify(sourceMap)); ++ sourceMapFile.contents = Buffer.from(JSON.stringify(sourceMap)); + sourceMapFile.stat = { + isFile: function() { return true; }, + isDirectory: function() { return false; }, +@@ -164,7 +164,7 @@ module.exports = function(destPath, options) { + + // append source map comment + if (options.addComment) { +- file.contents = Buffer.concat([file.contents, new Buffer(comment)]); ++ file.contents = Buffer.concat([file.contents, Buffer.from(comment)]); + } + } + diff --git a/patches/inline-source-map+0.6.2.patch b/patches/inline-source-map+0.6.2.patch new file mode 100644 index 000000000..5e5ae09a0 --- /dev/null +++ b/patches/inline-source-map+0.6.2.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/inline-source-map/index.js b/node_modules/inline-source-map/index.js +index df74d61..7641aad 100644 +--- a/node_modules/inline-source-map/index.js ++++ b/node_modules/inline-source-map/index.js +@@ -91,7 +91,7 @@ Generator.prototype.addSourceContent = function (sourceFile, sourcesContent) { + */ + Generator.prototype.base64Encode = function () { + var map = this.toString(); +- return new Buffer(map).toString('base64'); ++ return Buffer.from(map).toString('base64'); + }; + + /** diff --git a/patches/regenerator-runtime+0.13.7.patch b/patches/regenerator-runtime+0.13.7.patch index 1710d779a..778bc62ca 100644 --- a/patches/regenerator-runtime+0.13.7.patch +++ b/patches/regenerator-runtime+0.13.7.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/regenerator-runtime/runtime.js b/node_modules/regenerator-runtime/runtime.js -index 547b8c6..c53a471 100644 +index 547b8c6..885626e 100644 --- a/node_modules/regenerator-runtime/runtime.js +++ b/node_modules/regenerator-runtime/runtime.js @@ -5,7 +5,7 @@ @@ -65,3 +65,12 @@ index 547b8c6..c53a471 100644 function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; +@@ -733,7 +734,7 @@ var runtime = (function (exports) { + )); + + try { +- regeneratorRuntime = runtime; ++ globalThis.regeneratorRuntime = runtime; + } catch (accidentalStrictMode) { + // This module should not be running in strict mode, so the above + // assignment should always work unless something is misconfigured. Just diff --git a/shared/constants/swaps.js b/shared/constants/swaps.js index 5da0d08d8..7f9262d1e 100644 --- a/shared/constants/swaps.js +++ b/shared/constants/swaps.js @@ -177,3 +177,5 @@ export const ETHEREUM = 'ethereum'; export const POLYGON = 'polygon'; export const BSC = 'bsc'; export const RINKEBY = 'rinkeby'; + +export const SWAPS_CLIENT_ID = 'extension'; diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 8b6171339..e8c979fd1 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -31,6 +31,11 @@ "name": "Test Account 2" } }, + "networkDetails": { + "EIPS": { + "1559": true + } + }, "cachedBalances": {}, "incomingTransactions": {}, "unapprovedTxs": { diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index dca25366a..5eb5ad8fb 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -130,7 +130,7 @@ async function withFixtures(options, testSuite) { if (webDriver) { await webDriver.quit(); } - if (dappServer) { + if (dappServer && dappServer.listening) { await new Promise((resolve, reject) => { dappServer.close((error) => { if (error) { diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index 74ea431f2..3f57d00ae 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -100,7 +100,7 @@ describe('MetaMask', function () { }); it('clicks the "No thanks" option on the metametrics opt-in screen', async function () { - await driver.clickElement('.btn-default'); + await driver.clickElement('.btn-secondary'); await driver.delay(largeDelayMs); }); diff --git a/test/e2e/run-all.sh b/test/e2e/run-all.sh deleted file mode 100755 index 88cc695d8..000000000 --- a/test/e2e/run-all.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -x -set -e -set -u -set -o pipefail - -readonly __DIR__=$( cd "${BASH_SOURCE[0]%/*}" && pwd ) - -for spec in "${__DIR__}"/tests/*.spec.js -do - node "${__DIR__}/run-e2e-test.js" "${spec}" -done - -node "${__DIR__}/run-e2e-test.js" "${__DIR__}/metamask-ui.spec.js" diff --git a/test/e2e/tests/contract-interactions.spec.js b/test/e2e/tests/contract-interactions.spec.js index e94c18f0a..6ef4cc4fb 100644 --- a/test/e2e/tests/contract-interactions.spec.js +++ b/test/e2e/tests/contract-interactions.spec.js @@ -1,5 +1,5 @@ const { strict: assert } = require('assert'); -const { withFixtures } = require('../helpers'); +const { withFixtures, regularDelayMs } = require('../helpers'); describe('Deploy contract and call contract methods', function () { let windowHandles; @@ -32,6 +32,7 @@ describe('Deploy contract and call contract methods', function () { await driver.openNewPage('http://127.0.0.1:8080/'); await driver.clickElement({ text: 'Connect', tag: 'button' }); await driver.waitUntilXWindowHandles(3); + await driver.delay(5000); windowHandles = await driver.getAllWindowHandles(); extension = windowHandles[0]; dapp = await driver.switchToWindowWithTitle( @@ -86,11 +87,13 @@ describe('Deploy contract and call contract methods', function () { await driver.switchToWindow(dapp); await driver.clickElement('#depositButton'); await driver.waitUntilXWindowHandles(3); + await driver.delay(5000); windowHandles = await driver.getAllWindowHandles(); await driver.switchToWindowWithTitle( 'MetaMask Notification', windowHandles, ); + await driver.delay(regularDelayMs); await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.waitUntilXWindowHandles(2); await driver.switchToWindow(extension); @@ -110,11 +113,13 @@ describe('Deploy contract and call contract methods', function () { await driver.switchToWindow(dapp); await driver.clickElement('#withdrawButton'); await driver.waitUntilXWindowHandles(3); + await driver.delay(5000); windowHandles = await driver.getAllWindowHandles(); await driver.switchToWindowWithTitle( 'MetaMask Notification', windowHandles, ); + await driver.delay(regularDelayMs); await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.waitUntilXWindowHandles(2); await driver.switchToWindow(extension); diff --git a/test/e2e/tests/custom-rpc-history.spec.js b/test/e2e/tests/custom-rpc-history.spec.js index 08a2bdd31..078cb124f 100644 --- a/test/e2e/tests/custom-rpc-history.spec.js +++ b/test/e2e/tests/custom-rpc-history.spec.js @@ -48,7 +48,7 @@ describe('Stores custom RPC history', function () { await chainIdInput.clear(); await chainIdInput.sendKeys(chainId.toString()); - await driver.clickElement('.network-form__footer .btn-secondary'); + await driver.clickElement('.network-form__footer .btn-primary'); await driver.findElement({ text: networkName, tag: 'span' }); }, ); @@ -192,7 +192,7 @@ describe('Stores custom RPC history', function () { await driver.clickElement({ text: 'Custom RPC', tag: 'span' }); // cancel new custom rpc - await driver.clickElement('.network-form__footer button.btn-default'); + await driver.clickElement('.network-form__footer button.btn-secondary'); const networkListItems = await driver.findClickableElements( '.networks-tab__networks-list-name', @@ -209,7 +209,7 @@ describe('Stores custom RPC history', function () { ); await driver.clickElement( - '.button.btn-danger.modal-container__footer-button', + '.button.btn-danger-primary.modal-container__footer-button', ); // wait for confirm delete modal to be removed from DOM. diff --git a/test/e2e/tests/from-import-ui.spec.js b/test/e2e/tests/from-import-ui.spec.js index 176b51e48..a7fba5982 100644 --- a/test/e2e/tests/from-import-ui.spec.js +++ b/test/e2e/tests/from-import-ui.spec.js @@ -38,7 +38,7 @@ describe('Metamask Import UI', function () { await driver.clickElement({ text: 'Import wallet', tag: 'button' }); // clicks the "No thanks" option on the metametrics opt-in screen - await driver.clickElement('.btn-default'); + await driver.clickElement('.btn-secondary'); // Import Secret Recovery Phrase await driver.fill( diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/incremental-security.spec.js index 185a0d8c0..f6e5e5066 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/incremental-security.spec.js @@ -42,7 +42,7 @@ describe('Incremental Security', function () { await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); // clicks the "No thanks" option on the metametrics opt-in screen - await driver.clickElement('.btn-default'); + await driver.clickElement('.btn-secondary'); // accepts a secure password await driver.fill( diff --git a/test/e2e/webdriver/chrome.js b/test/e2e/webdriver/chrome.js index bf3c2d023..9a1e1294b 100644 --- a/test/e2e/webdriver/chrome.js +++ b/test/e2e/webdriver/chrome.js @@ -16,13 +16,10 @@ class ChromeDriver { .setChromeOptions(options); const service = new chrome.ServiceBuilder(); - // Enables Chrome logging. + // Enables Chrome logging. Default: enabled // Especially useful for discovering why Chrome has crashed, but can also // be useful for revealing console errors (from the page or background). - if ( - process.env.ENABLE_CHROME_LOGGING && - process.env.ENABLE_CHROME_LOGGING !== 'false' - ) { + if (process.env.ENABLE_CHROME_LOGGING !== 'false') { service.setStdio('inherit').enableChromeLogging(); } if (port) { diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index d7a742399..ad8430794 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -277,13 +277,13 @@ class Driver { async switchToWindowWithTitle( title, - windowHandles, + initialWindowHandles, delayStep = 1000, timeout = 5000, ) { + let windowHandles = + initialWindowHandles || (await this.driver.getAllWindowHandles()); let timeElapsed = 0; - // eslint-disable-next-line no-param-reassign - windowHandles = windowHandles || (await this.driver.getAllWindowHandles()); while (timeElapsed <= timeout) { for (const handle of windowHandles) { await this.driver.switchTo().window(handle); @@ -294,6 +294,8 @@ class Driver { } await this.delay(delayStep); timeElapsed += delayStep; + // refresh the window handles + windowHandles = await this.driver.getAllWindowHandles(); } throw new Error(`No window with title: ${title}`); diff --git a/test/test-unit-combined.sh b/test/test-unit-combined.sh new file mode 100755 index 000000000..d793ba752 --- /dev/null +++ b/test/test-unit-combined.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -x +set -e +set -u +set -o pipefail + +concurrently --raw -n mocha,jest,global \ + "yarn test:unit:mocha" \ + "yarn test:unit:jest" \ + "yarn test:unit:global" diff --git a/test/run-jest.sh b/test/test-unit-jest.sh similarity index 78% rename from test/run-jest.sh rename to test/test-unit-jest.sh index 40b208732..384124920 100755 --- a/test/run-jest.sh +++ b/test/test-unit-jest.sh @@ -5,6 +5,6 @@ set -e set -u set -o pipefail -concurrently \ +concurrently -n production,development \ "jest --config=./jest.config.js $*" \ "jest --config=./development/jest.config.js $*" diff --git a/test/unit-global/protect-intrinsics.test.js b/test/unit-global/protect-intrinsics.test.js index 5075080f9..3958d7762 100644 --- a/test/unit-global/protect-intrinsics.test.js +++ b/test/unit-global/protect-intrinsics.test.js @@ -1,5 +1,6 @@ import 'ses/lockdown'; import '../../app/scripts/lockdown-run'; +import '../../app/scripts/lockdown-more'; import { strict as assert } from 'assert'; // These are Agoric inventions, and we don't care about them. diff --git a/ui/components/app/account-menu/account-menu.component.js b/ui/components/app/account-menu/account-menu.component.js index 41c809be8..c391a08aa 100644 --- a/ui/components/app/account-menu/account-menu.component.js +++ b/ui/components/app/account-menu/account-menu.component.js @@ -19,6 +19,7 @@ import { } from '../../../helpers/constants/routes'; import TextField from '../../ui/text-field'; import SearchIcon from '../../ui/search-icon'; +import Button from '../../ui/button'; import { isBeta } from '../../../helpers/utils/build-types'; @@ -324,7 +325,7 @@ export default class AccountMenu extends Component {
{t('myAccounts')} - +
diff --git a/ui/components/app/account-menu/account-menu.test.js b/ui/components/app/account-menu/account-menu.test.js index fc715ead1..501c187dd 100644 --- a/ui/components/app/account-menu/account-menu.test.js +++ b/ui/components/app/account-menu/account-menu.test.js @@ -3,6 +3,7 @@ import sinon from 'sinon'; import configureMockStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import { mountWithRouter } from '../../../../test/lib/render-helpers'; +import Button from '../../ui/button'; import AccountMenu from '.'; describe('Account Menu', () => { @@ -103,7 +104,7 @@ describe('Account Menu', () => { let logout; it('logout', () => { - logout = wrapper.find('.account-menu__lock-button'); + logout = wrapper.find(Button); expect(logout).toHaveLength(1); }); diff --git a/ui/components/app/account-menu/index.scss b/ui/components/app/account-menu/index.scss index 8f1f5c8c8..18059a7e8 100644 --- a/ui/components/app/account-menu/index.scss +++ b/ui/components/app/account-menu/index.scss @@ -97,14 +97,14 @@ align-items: center; } - &__lock-button { + & &__lock-button { @include H7; - border: 1px solid $dusty-gray; + border: 1px solid $ui-white; background-color: transparent; color: $white; - border-radius: 4px; padding: 3.5px 24px; + width: 59px; } &__item-icon { diff --git a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js index 93f3e5ee3..e9e3117ac 100644 --- a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js +++ b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js @@ -6,7 +6,6 @@ import { I18nContext } from '../../../contexts/i18n'; import FormField from '../../ui/form-field'; import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas'; import { getGasFormErrorText } from '../../../helpers/constants/gas'; -import { checkNetworkAndAccountSupports1559 } from '../../../selectors'; import { getIsGasEstimatesLoading } from '../../../ducks/metamask/metamask'; export default function AdvancedGasControls({ @@ -24,15 +23,13 @@ export default function AdvancedGasControls({ maxFeeFiat, gasErrors, minimumGasLimit, + supportsEIP1559, }) { const t = useContext(I18nContext); - const networkAndAccountSupport1559 = useSelector( - checkNetworkAndAccountSupports1559, - ); const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading); const showFeeMarketFields = - networkAndAccountSupport1559 && + supportsEIP1559 && (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET || gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE || isGasEstimatesLoading); @@ -54,7 +51,6 @@ export default function AdvancedGasControls({ value={gasLimit} allowDecimals={false} numeric - autoFocus /> {showFeeMarketFields ? ( <> @@ -132,4 +128,5 @@ AdvancedGasControls.propTypes = { maxFeeFiat: PropTypes.string, gasErrors: PropTypes.object, minimumGasLimit: PropTypes.string, + supportsEIP1559: PropTypes.bool, }; diff --git a/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js b/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js new file mode 100644 index 000000000..f99cd1618 --- /dev/null +++ b/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js @@ -0,0 +1,39 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; + +import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas'; +import { renderWithProvider } from '../../../../test/jest/rendering'; + +import AdvancedGasControls from './advanced-gas-controls.component'; + +const renderComponent = (props) => { + const store = configureMockStore([])({ metamask: { identities: [] } }); + return renderWithProvider(, store); +}; + +describe('AdvancedGasControls Component', () => { + it('should render correctly', () => { + expect(() => { + renderComponent(); + }).not.toThrow(); + }); + + it('should not render maxFee and maxPriorityFee inputs if supportsEIP1559 is false', () => { + const { queryByText } = renderComponent({ supportsEIP1559: false }); + expect(queryByText('Gas Limit')).toBeInTheDocument(); + expect(queryByText('Gas price')).toBeInTheDocument(); + expect(queryByText('Max fee')).not.toBeInTheDocument(); + expect(queryByText('Max priority fee')).not.toBeInTheDocument(); + }); + + it('should render maxFee and maxPriorityFee inputs if supportsEIP1559 is true', () => { + const { queryByText } = renderComponent({ + gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET, + supportsEIP1559: true, + }); + expect(queryByText('Gas price')).not.toBeInTheDocument(); + expect(queryByText('Gas Limit')).toBeInTheDocument(); + expect(queryByText('Max fee')).toBeInTheDocument(); + expect(queryByText('Max priority fee')).toBeInTheDocument(); + }); +}); diff --git a/ui/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.scss b/ui/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.scss index de7010883..a1a170466 100644 --- a/ui/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.scss +++ b/ui/components/app/alerts/invalid-custom-network-alert/invalid-custom-network-alert.scss @@ -37,7 +37,6 @@ & &-button { height: 40px; width: 50%; - border-radius: 100px; margin-right: 24px; &:last-of-type { diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index 1b887bba4..cbcac50eb 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -76,7 +76,6 @@ const UnconnectedAccountAlert = () => { disabled={alertState === LOADING} onClick={onClose} type="primary" - rounded className="unconnected-account-alert__dismiss-button" > {t('dismiss')} diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss index 11c12f420..cedd14617 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss @@ -22,7 +22,6 @@ height: 40px; width: 100px; border: 0; - border-radius: 100px; } &__error { diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index aabadf245..d76c2998f 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -46,3 +46,4 @@ @import 'transaction-total-banner/index'; @import 'wallet-overview/index'; @import 'whats-new-popup/index'; +@import 'loading-network-screen/index' diff --git a/ui/components/app/cancel-button/cancel-button.js b/ui/components/app/cancel-button/cancel-button.js index bef23f98c..0efce2212 100644 --- a/ui/components/app/cancel-button/cancel-button.js +++ b/ui/components/app/cancel-button/cancel-button.js @@ -33,11 +33,10 @@ export default function CancelButton({ const btn = (
- {networkAndAccountSupport1559 && - !requireDappAcknowledgement && - showEducationButton && ( -
- -
- )} + {supportsEIP1559 && !requireDappAcknowledgement && showEducationButton && ( +
+ +
+ )}
); diff --git a/ui/components/app/edit-gas-popover/edit-gas-popover.component.js b/ui/components/app/edit-gas-popover/edit-gas-popover.component.js index 64280984c..5825143bc 100644 --- a/ui/components/app/edit-gas-popover/edit-gas-popover.component.js +++ b/ui/components/app/edit-gas-popover/edit-gas-popover.component.js @@ -29,6 +29,7 @@ import { import LoadingHeartBeat from '../../ui/loading-heartbeat'; import { checkNetworkAndAccountSupports1559 } from '../../../selectors'; import { useIncrementedGasFees } from '../../../hooks/useIncrementedGasFees'; +import { isLegacyTransaction } from '../../../helpers/utils/transactions.util'; export default function EditGasPopover({ popoverTitle = '', @@ -42,9 +43,9 @@ export default function EditGasPopover({ }) { const t = useContext(I18nContext); const dispatch = useDispatch(); - const networkAndAccountSupport1559 = useSelector( - checkNetworkAndAccountSupports1559, - ); + const supportsEIP1559 = + useSelector(checkNetworkAndAccountSupports1559) && + !isLegacyTransaction(transaction?.txParams); const gasLoadingAnimationIsShowing = useSelector( getGasLoadingAnimationIsShowing, ); @@ -52,7 +53,7 @@ export default function EditGasPopover({ const showEducationButton = (mode === EDIT_GAS_MODES.MODIFY_IN_PLACE || mode === EDIT_GAS_MODES.SWAPS) && - networkAndAccountSupport1559; + supportsEIP1559; const [showEducationContent, setShowEducationContent] = useState(false); const [warning] = useState(null); @@ -132,7 +133,7 @@ export default function EditGasPopover({ closePopover(); } - const newGasSettings = networkAndAccountSupport1559 + const newGasSettings = supportsEIP1559 ? { gas: decimalToHex(gasLimit), gasLimit: decimalToHex(gasLimit), @@ -149,7 +150,7 @@ export default function EditGasPopover({ const cleanTransactionParams = { ...updatedTransaction.txParams }; - if (networkAndAccountSupport1559) { + if (supportsEIP1559) { delete cleanTransactionParams.gasPrice; } @@ -182,7 +183,7 @@ export default function EditGasPopover({ break; case EDIT_GAS_MODES.SWAPS: // This popover component should only be used for the "FEE_MARKET" type in Swaps. - if (networkAndAccountSupport1559) { + if (supportsEIP1559) { dispatch(updateSwapsUserFeeLevel(estimateToUse || 'custom')); dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings)); } @@ -201,7 +202,7 @@ export default function EditGasPopover({ gasPrice, maxFeePerGas, maxPriorityFeePerGas, - networkAndAccountSupport1559, + supportsEIP1559, estimateToUse, estimatedBaseFee, ]); diff --git a/ui/components/app/edit-gas-popover/edit-gas-popover.stories.js b/ui/components/app/edit-gas-popover/edit-gas-popover.stories.js index 93d7cc830..b18d834be 100644 --- a/ui/components/app/edit-gas-popover/edit-gas-popover.stories.js +++ b/ui/components/app/edit-gas-popover/edit-gas-popover.stories.js @@ -1,31 +1,89 @@ import React from 'react'; +import { Provider } from 'react-redux'; +import { action } from '@storybook/addon-actions'; +import { boolean } from '@storybook/addon-knobs'; +import { decGWEIToHexWEI } from '../../../helpers/utils/conversions.util'; +import configureStore from '../../../store/store'; +import testData from '../../../../.storybook/test-data'; +import { EDIT_GAS_MODES } from '../../../../shared/constants/gas'; import EditGasPopover from '.'; +const store = configureStore(testData); + export default { title: 'Edit Gas Display Popover', + decorators: [(story) => {story()}], id: __filename, }; -export const basic = () => { +export const Basic = () => { return (
- + action(`Close Edit Gas Popover`)()} + minimumGasLimit="5700" + />
); }; -export const basicWithDifferentButtonText = () => { +export const BasicWithDifferentButtonText = () => { return (
- + action(`Close Edit Gas Popover`)()} + minimumGasLimit="5700" + />
); }; -export const educationalContentFlow = () => { +export const EducationalContentFlow = () => { return (
- + action(`Close Edit Gas Popover`)()} + minimumGasLimit="5700" + />
); }; diff --git a/ui/components/app/home-notification/index.scss b/ui/components/app/home-notification/index.scss index 8d522a0e4..62a556fbb 100644 --- a/ui/components/app/home-notification/index.scss +++ b/ui/components/app/home-notification/index.scss @@ -71,7 +71,6 @@ & &__ignore-button { border-color: #6a737d; box-sizing: border-box; - border-radius: 6px; color: $white; background-color: inherit; height: 34px; @@ -95,7 +94,6 @@ & &__accept-button { border-color: #6a737d; box-sizing: border-box; - border-radius: 6px; color: $white; background-color: inherit; height: 34px; diff --git a/ui/components/app/loading-network-screen/index.scss b/ui/components/app/loading-network-screen/index.scss new file mode 100644 index 000000000..95039f422 --- /dev/null +++ b/ui/components/app/loading-network-screen/index.scss @@ -0,0 +1,6 @@ +.loading-overlay__error-buttons { + button { + margin: 5px; + padding: 5px 30px; + } +} diff --git a/ui/components/app/loading-network-screen/loading-network-screen.component.js b/ui/components/app/loading-network-screen/loading-network-screen.component.js index 7f2f2df48..0b3f05229 100644 --- a/ui/components/app/loading-network-screen/loading-network-screen.component.js +++ b/ui/components/app/loading-network-screen/loading-network-screen.component.js @@ -71,7 +71,7 @@ export default class LoadingNetworkScreen extends PureComponent { {this.context.t('somethingWentWrong')}
{exportPrivateKeyFeatureEnabled ? ( diff --git a/ui/components/app/modals/cancel-transaction/cancel-transaction.component.js b/ui/components/app/modals/cancel-transaction/cancel-transaction.component.js index 9b436f7d9..f98ce7c7b 100644 --- a/ui/components/app/modals/cancel-transaction/cancel-transaction.component.js +++ b/ui/components/app/modals/cancel-transaction/cancel-transaction.component.js @@ -55,7 +55,6 @@ export default class CancelTransaction extends PureComponent { onCancel={this.handleCancel} submitText={t('yesLetsTry')} cancelText={t('nevermind')} - submitType="secondary" submitDisabled={busy} >
diff --git a/ui/components/app/modals/confirm-delete-network/confirm-delete-network.component.js b/ui/components/app/modals/confirm-delete-network/confirm-delete-network.component.js index a8be936a5..74b48bb85 100644 --- a/ui/components/app/modals/confirm-delete-network/confirm-delete-network.component.js +++ b/ui/components/app/modals/confirm-delete-network/confirm-delete-network.component.js @@ -30,7 +30,7 @@ export default class ConfirmDeleteNetwork extends PureComponent { onCancel={() => this.props.hideModal()} submitText={t('delete')} cancelText={t('cancel')} - submitType="danger" + submitType="danger-primary" > { it('clicks cancel to hide modal', () => { const cancelButton = wrapper.find( - '.button.btn-default.modal-container__footer-button', + '.button.btn-secondary.modal-container__footer-button', ); cancelButton.simulate('click'); @@ -43,7 +43,7 @@ describe('Confirm Delete Network', () => { it('clicks delete to delete the target and hides modal', async () => { const deleteButton = wrapper.find( - '.button.btn-danger.modal-container__footer-button', + '.button.btn-danger-primary.modal-container__footer-button', ); deleteButton.simulate('click'); diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js index e7bfd69cd..891e40f87 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js @@ -95,7 +95,6 @@ export default class ConfirmRemoveAccount extends Component { onCancel={this.handleCancel} submitText={t('remove')} cancelText={t('nevermind')} - submitType="secondary" >
{this.renderSelectedAccount()} diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js index da59aeffa..f55fec4be 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js @@ -51,14 +51,14 @@ describe('Confirm Remove Account', () => { }); it('nevermind', () => { - const nevermind = wrapper.find({ type: 'default' }); + const nevermind = wrapper.find({ type: 'secondary' }); nevermind.simulate('click'); expect(props.hideModal.calledOnce).toStrictEqual(true); }); it('remove', async () => { - const remove = wrapper.find({ type: 'secondary' }); + const remove = wrapper.find({ type: 'primary' }); remove.simulate('click'); expect(await props.removeAccount.calledOnce).toStrictEqual(true); diff --git a/ui/components/app/modals/confirm-reset-account/confirm-reset-account.component.js b/ui/components/app/modals/confirm-reset-account/confirm-reset-account.component.js index c4e5a9a17..f9c4fe8fb 100644 --- a/ui/components/app/modals/confirm-reset-account/confirm-reset-account.component.js +++ b/ui/components/app/modals/confirm-reset-account/confirm-reset-account.component.js @@ -25,7 +25,7 @@ export default class ConfirmResetAccount extends PureComponent { onCancel={() => this.props.hideModal()} submitText={t('reset')} cancelText={t('nevermind')} - submitType="danger" + submitType="danger-primary" > { it('hides modal when nevermind button is clicked', () => { const nevermind = wrapper.find( - '.btn-default.modal-container__footer-button', + '.btn-secondary.modal-container__footer-button', ); nevermind.simulate('click'); @@ -33,7 +33,9 @@ describe('Confirm Reset Account', () => { }); it('resets account and hides modal when reset button is clicked', async () => { - const reset = wrapper.find('.btn-danger.modal-container__footer-button'); + const reset = wrapper.find( + '.btn-danger-primary.modal-container__footer-button', + ); reset.simulate('click'); expect(await props.resetAccount.calledOnce).toStrictEqual(true); diff --git a/ui/components/app/modals/customize-nonce/customize-nonce.component.js b/ui/components/app/modals/customize-nonce/customize-nonce.component.js index d2cacc816..91357d89e 100644 --- a/ui/components/app/modals/customize-nonce/customize-nonce.component.js +++ b/ui/components/app/modals/customize-nonce/customize-nonce.component.js @@ -37,11 +37,8 @@ const CustomizeNonce = ({ hideModal(); }} submitText={t('save')} - submitType="primary" onCancel={() => hideModal()} cancelText={t('cancel')} - cancelType="secondary" - rounded contentClass="customize-nonce-modal-content" containerClass="customize-nonce-modal-container" > diff --git a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js index 2e100353f..b6cfec569 100644 --- a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js +++ b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js @@ -226,7 +226,6 @@ export default class EditApprovalPermission extends PureComponent { hideModal(); }} submitText={t('save')} - submitType="primary" contentClass="edit-approval-permission-modal-content" containerClass="edit-approval-permission-modal-container" submitDisabled={disabled} diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js index ba6e4ca8b..ae378f3ce 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js @@ -93,7 +93,7 @@ export default class ExportPrivateKeyModal extends Component {
{!privateKey && (
diff --git a/ui/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.test.js b/ui/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.test.js index 7b90b24ff..ff6650652 100644 --- a/ui/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.test.js +++ b/ui/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.test.js @@ -28,7 +28,9 @@ describe('MetaMetrics Opt In', () => { }); it('passes false to setParticipateInMetaMetrics and hides modal', async () => { - const noThanks = wrapper.find('.btn-default.page-container__footer-button'); + const noThanks = wrapper.find( + '.btn-secondary.page-container__footer-button', + ); noThanks.simulate('click'); expect(await props.setParticipateInMetaMetrics.calledOnce).toStrictEqual( diff --git a/ui/components/app/modals/qr-scanner/qr-scanner.component.js b/ui/components/app/modals/qr-scanner/qr-scanner.component.js index fac593717..610c2631b 100644 --- a/ui/components/app/modals/qr-scanner/qr-scanner.component.js +++ b/ui/components/app/modals/qr-scanner/qr-scanner.component.js @@ -221,7 +221,6 @@ export default class QrScanner extends Component { onSubmit={this.tryAgain} cancelText={t('cancel')} submitText={t('tryAgain')} - submitButtonType="confirm" /> ); diff --git a/ui/components/app/modals/reject-transactions/reject-transactions.component.js b/ui/components/app/modals/reject-transactions/reject-transactions.component.js index 3bb4cd9d9..6ef0daa91 100644 --- a/ui/components/app/modals/reject-transactions/reject-transactions.component.js +++ b/ui/components/app/modals/reject-transactions/reject-transactions.component.js @@ -32,7 +32,6 @@ export default class RejectTransactionsModal extends PureComponent { onCancel={hideModal} submitText={t('rejectAll')} cancelText={t('cancel')} - submitType="secondary" >
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 043f9bab7..e8ec7a7b5 100644 --- a/ui/components/app/modals/reject-transactions/reject-transactions.test.js +++ b/ui/components/app/modals/reject-transactions/reject-transactions.test.js @@ -26,7 +26,7 @@ describe('Reject Transactions Model', () => { it('hides modal when cancel button is clicked', () => { const cancelButton = wrapper.find( - '.btn-default.modal-container__footer-button', + '.btn-secondary.modal-container__footer-button', ); cancelButton.simulate('click'); @@ -35,7 +35,7 @@ describe('Reject Transactions Model', () => { it('onSubmit is called and hides modal when reject all clicked', async () => { const rejectAllButton = wrapper.find( - '.btn-secondary.modal-container__footer-button', + '.btn-primary.modal-container__footer-button', ); rejectAllButton.simulate('click'); 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 84111a9ee..0e1658242 100644 --- a/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js +++ b/ui/components/app/modals/transaction-confirmed/transaction-confirmed.test.js @@ -17,9 +17,7 @@ describe('Transaction Confirmed', () => { }, }, ); - const submit = wrapper.find( - '.btn-secondary.modal-container__footer-button', - ); + const submit = wrapper.find('.btn-primary.modal-container__footer-button'); submit.simulate('click'); expect(props.onSubmit.calledOnce).toStrictEqual(true); diff --git a/ui/components/app/permission-page-container/permission-page-container.component.js b/ui/components/app/permission-page-container/permission-page-container.component.js index a8378f746..2a8daa2f6 100644 --- a/ui/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/components/app/permission-page-container/permission-page-container.component.js @@ -141,7 +141,6 @@ export default class PermissionPageContainer extends Component { cancelText={this.context.t('cancel')} onSubmit={() => this.onSubmit()} submitText={this.context.t('connect')} - submitButtonType="confirm" buttonSizeLarge={false} />
diff --git a/ui/components/app/recovery-phrase-reminder/recovery-phrase-reminder.js b/ui/components/app/recovery-phrase-reminder/recovery-phrase-reminder.js index 1b8b66ba3..23dd36442 100644 --- a/ui/components/app/recovery-phrase-reminder/recovery-phrase-reminder.js +++ b/ui/components/app/recovery-phrase-reminder/recovery-phrase-reminder.js @@ -75,7 +75,7 @@ export default function RecoveryPhraseReminder({ onConfirm, hasBackedUp }) { - diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index c999cf282..41312296c 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -290,7 +290,7 @@ export default class SignatureRequestOriginal extends Component { return (
@@ -181,8 +181,13 @@ export default class TransactionListItemDetails extends PureComponent { containerClassName="transaction-list-item-details__header-button-tooltip-container" title={ blockExplorerUrl - ? t('viewOnCustomBlockExplorer', [blockExplorerUrl]) - : t('viewOnEtherscan') + ? t('viewOnCustomBlockExplorer', [ + t('blockExplorerTransactionAction'), + blockExplorerUrl, + ]) + : t('viewOnEtherscan', [ + t('blockExplorerTransactionAction'), + ]) } >
diff --git a/ui/components/ui/popover/popover.component.js b/ui/components/ui/popover/popover.component.js index c4bae4ffc..637f07528 100644 --- a/ui/components/ui/popover/popover.component.js +++ b/ui/components/ui/popover/popover.component.js @@ -20,6 +20,7 @@ const Popover = ({ centerTitle, }) => { const t = useI18nContext(); + const showHeader = title || onBack || subtitle || onClose; return (
{CustomBackground ? ( @@ -32,36 +33,38 @@ const Popover = ({ ref={popoverRef} > {showArrow ?
: null} -
-
-

- {onBack ? ( + {showHeader && ( +
+
+

+ {onBack ? ( +

+ {onClose ? (

- {onClose ? ( -
+ {subtitle ? ( +

{subtitle}

) : null} -
- {subtitle ? ( -

{subtitle}

- ) : null} - + + )} {children ? (
{children} @@ -78,7 +81,7 @@ const Popover = ({ }; Popover.propTypes = { - title: PropTypes.string.isRequired, + title: PropTypes.string, subtitle: PropTypes.string, children: PropTypes.node, footer: PropTypes.node, diff --git a/ui/components/ui/radio-group/radio-group.component.js b/ui/components/ui/radio-group/radio-group.component.js index 7bc0dae6b..90c136fb9 100644 --- a/ui/components/ui/radio-group/radio-group.component.js +++ b/ui/components/ui/radio-group/radio-group.component.js @@ -24,8 +24,8 @@ function Connector({ isFirst, isLast }) { } Connector.propTypes = { - isFirst: PropTypes.boolean, - isLast: PropTypes.boolean, + isFirst: PropTypes.bool, + isLast: PropTypes.bool, }; export default function RadioGroup({ options, name, selectedValue, onChange }) { diff --git a/ui/components/ui/slider/index.js b/ui/components/ui/slider/index.js new file mode 100644 index 000000000..52e836261 --- /dev/null +++ b/ui/components/ui/slider/index.js @@ -0,0 +1,3 @@ +import Slider from './slider.component'; + +export default Slider; diff --git a/ui/components/ui/slider/index.scss b/ui/components/ui/slider/index.scss new file mode 100644 index 000000000..00ff33766 --- /dev/null +++ b/ui/components/ui/slider/index.scss @@ -0,0 +1,48 @@ +.slider { + display: inline-block; + width: 100%; + + &__heading, + &__footer { + display: flex; + justify-content: space-between; + } + + &__heading-title { + display: flex; + align-items: center; + + > p { + margin-left: 10px; + font-size: 14px; + } + } + + &__heading-detail > p { + font-size: 14px; + } + + &__footer-info { + display: flex; + align-items: center; + + > p { + font-size: 12px; + } + } + + &__footer-edit > button { + border: none; + background: none; + font-size: 12px; + color: $Blue-500; + + &:focus { + outline: none; + } + } + + h6 { + margin-inline-end: 6px; + } +} diff --git a/ui/components/ui/slider/slider.component.js b/ui/components/ui/slider/slider.component.js new file mode 100644 index 000000000..9bdb7309b --- /dev/null +++ b/ui/components/ui/slider/slider.component.js @@ -0,0 +1,135 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import MaterialSlider from '@material-ui/core/Slider'; +import { withStyles } from '@material-ui/core/styles'; + +import { + COLORS, + FONT_WEIGHT, + TYPOGRAPHY, +} from '../../../helpers/constants/design-system'; + +import InfoTooltip from '../info-tooltip/info-tooltip'; +import Typography from '../typography/typography'; + +const styles = { + root: { + height: 6, + padding: '6px 0', + }, + rail: { + borderRadius: 50, + background: '#D6D9DC', + height: 6, + }, + track: { + borderRadius: 50, + background: '#037DD6', + height: 6, + }, + thumb: { + 'height': 20, + 'width': 20, + 'marginTop': -7, + 'marginLeft': -7, + 'backgroundColor': '#037DD6', + 'border': '1px solid #EAF6FF', + 'boxSizing': 'border-box', + 'boxShadow': '0px 0px 14px 0px rgba(0, 0, 0, 0.18)', + '&:focus, &$active': { + height: 20, + width: 20, + marginTop: -7, + marginLeft: -7, + boxShadow: '0px 0px 14px 0px rgba(0, 0, 0, 0.18)', + }, + '&:hover': { + height: 22, + width: 22, + marginTop: -8, + marginLeft: -8, + border: 'none', + boxShadow: '0px 0px 14px 0px rgba(0, 0, 0, 0.18)', + }, + }, +}; + +const Slider = ({ + editText, + infoText, + onEdit, + titleDetail, + titleText, + tooltipText, + valueText, + ...rest +}) => ( +
+
+
+ {titleText && ( + + {titleText} + + )} + {tooltipText && ( + + )} + {valueText && ( + + {valueText} + + )} +
+ {titleDetail && ( +
+ + {titleDetail} + +
+ )} +
+ +
+
+ {infoText && ( + + {infoText} + + )} +
+
+ {onEdit && ( + + )} +
+
+
+); + +Slider.defaultProps = { + editText: 'Edit', +}; + +Slider.propTypes = { + editText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + infoText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + titleDetail: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + titleText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + tooltipText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + valueText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + max: PropTypes.number, + min: PropTypes.number, + onChange: PropTypes.func, + onEdit: PropTypes.func, + step: PropTypes.number, + value: PropTypes.number, +}; + +export default withStyles(styles)(Slider); diff --git a/ui/components/ui/slider/slider.component.test.js b/ui/components/ui/slider/slider.component.test.js new file mode 100644 index 000000000..d28e2adca --- /dev/null +++ b/ui/components/ui/slider/slider.component.test.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; + +import Slider from './slider.component'; + +describe('Slider Component', () => { + describe('rendering', () => { + it('should render properly', () => { + expect(() => { + render(); + }).not.toThrow(); + }); + + it('should contain passed header props', () => { + const wrapper = render( + , + ); + + expect(wrapper.getAllByText('Slider Title Text')).toBeDefined(); + expect(wrapper.getAllByText('$ 00.00')).toBeDefined(); + expect(wrapper.getAllByText('100 GWEI')).toBeDefined(); + }); + + it('should contain passed footer props', () => { + const wrapper = render( + { + console.log('on edit click'); + }} + />, + ); + + expect(wrapper.getAllByText('Footer Info Text')).toBeDefined(); + expect( + wrapper.getByRole('button', { name: 'edit as numeric input' }), + ).toBeDefined(); + expect(wrapper.getAllByText('Edit GWEI')).toBeDefined(); + }); + + it('should call onEdit callback when edit button is clicked', () => { + const mockEditFn = jest.fn(); + const wrapper = render( + , + ); + + const editButton = wrapper.getByRole('button'); + fireEvent.click(editButton); + expect(mockEditFn).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/ui/components/ui/slider/slider.stories.js b/ui/components/ui/slider/slider.stories.js new file mode 100644 index 000000000..316ae3929 --- /dev/null +++ b/ui/components/ui/slider/slider.stories.js @@ -0,0 +1,33 @@ +import React from 'react'; +import Slider from '.'; + +export default { + title: 'Slider', + id: __filename, +}; + +export const slider = () => ; + +export const sliderWithSteps = () => ; + +export const sliderWithHeader = () => ( + +); + +export const sliderWithFooter = () => ( + { + console.log('on edit click'); + }} + /> +); diff --git a/ui/components/ui/truncated-definition-list/truncated-definition-list.js b/ui/components/ui/truncated-definition-list/truncated-definition-list.js index 2382b045b..f7354cffd 100644 --- a/ui/components/ui/truncated-definition-list/truncated-definition-list.js +++ b/ui/components/ui/truncated-definition-list/truncated-definition-list.js @@ -49,7 +49,6 @@ export default function TruncatedDefinitionList({ -
diff --git a/ui/pages/create-account/connect-hardware/account-list.js b/ui/pages/create-account/connect-hardware/account-list.js index 96a31bd05..29922fcd2 100644 --- a/ui/pages/create-account/connect-hardware/account-list.js +++ b/ui/pages/create-account/connect-hardware/account-list.js @@ -194,7 +194,7 @@ class AccountList extends Component { return (
diff --git a/ui/pages/onboarding-flow/onboarding-app-header/index.scss b/ui/pages/onboarding-flow/onboarding-app-header/index.scss new file mode 100644 index 000000000..68202b7fb --- /dev/null +++ b/ui/pages/onboarding-flow/onboarding-app-header/index.scss @@ -0,0 +1,67 @@ +.onboarding-app-header { + align-items: center; + background: $white; + position: relative; + z-index: $header-z-index; + display: flex; + flex-flow: column nowrap; + width: 100%; + flex: 0 0 auto; + + @media screen and (max-width: $break-small) { + padding: 1rem; + z-index: $mobile-header-z-index; + } + + @media screen and (min-width: $break-large) { + height: 75px; + justify-content: center; + } + + &__metafox-logo { + &--icon { + height: 32px; + + @media screen and (min-width: $break-large) { + display: none; + } + } + + &--horizontal { + @media screen and (max-width: $break-small) { + display: none; + } + } + } + + &__contents { + display: flex; + flex-flow: row nowrap; + width: 100%; + justify-content: space-between; + + @media screen and (max-width: $break-small) { + height: 100%; + } + + @media screen and (min-width: $break-large) { + width: 85vw; + } + + @media screen and (min-width: 769px) { + width: 90vw; + } + + @media screen and (min-width: 1281px) { + width: 62vw; + } + } + + &__logo-container { + display: flex; + flex-direction: row; + align-items: center; + flex: 0 0 auto; + margin-right: 1rem; + } +} diff --git a/ui/pages/onboarding-flow/onboarding-app-header/onboarding-app-header.js b/ui/pages/onboarding-flow/onboarding-app-header/onboarding-app-header.js new file mode 100644 index 000000000..ad5da2255 --- /dev/null +++ b/ui/pages/onboarding-flow/onboarding-app-header/onboarding-app-header.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import MetaFoxLogo from '../../../components/ui/metafox-logo'; +import Dropdown from '../../../components/ui/dropdown'; +import { getCurrentLocale } from '../../../ducks/metamask/metamask'; +import { updateCurrentLocale } from '../../../store/actions'; +import locales from '../../../../app/_locales/index.json'; + +export default function OnboardingAppHeader() { + const dispatch = useDispatch(); + const currentLocale = useSelector(getCurrentLocale); + const localeOptions = locales.map((locale) => { + return { + name: locale.name, + value: locale.code, + }; + }); + + return ( +
+
+ + + dispatch(updateCurrentLocale(newLocale)) + } + /> +
+
+ ); +} diff --git a/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js b/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js new file mode 100644 index 000000000..3512f6f2f --- /dev/null +++ b/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { Redirect } from 'react-router-dom'; +import { + DEFAULT_ROUTE, + ONBOARDING_COMPLETION_ROUTE, + ONBOARDING_GET_STARTED_ROUTE, + ONBOARDING_UNLOCK_ROUTE, + LOCK_ROUTE, +} from '../../../helpers/constants/routes'; +import { + getCompletedOnboarding, + getIsInitialized, + getIsUnlocked, + getSeedPhraseBackedUp, +} from '../../../ducks/metamask/metamask'; + +export default function OnboardingFlowSwitch() { + const completedOnboarding = useSelector(getCompletedOnboarding); + const isInitialized = useSelector(getIsInitialized); + const seedPhraseBackedUp = useSelector(getSeedPhraseBackedUp); + const isUnlocked = useSelector(getIsUnlocked); + + if (completedOnboarding) { + return ; + } + + if (seedPhraseBackedUp !== null) { + return ; + } + + if (isUnlocked) { + return ; + } + + if (!isInitialized) { + return ; + } + + return ; +} diff --git a/ui/pages/onboarding-flow/onboarding-flow.js b/ui/pages/onboarding-flow/onboarding-flow.js new file mode 100644 index 000000000..c00af0977 --- /dev/null +++ b/ui/pages/onboarding-flow/onboarding-flow.js @@ -0,0 +1,122 @@ +import React, { useEffect, useState } from 'react'; +import { Switch, Route, useHistory } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import Unlock from '../unlock-page'; +import { + ONBOARDING_CREATE_PASSWORD_ROUTE, + ONBOARDING_REVIEW_SRP_ROUTE, + ONBOARDING_CONFIRM_SRP_ROUTE, + ONBOARDING_UNLOCK_ROUTE, + DEFAULT_ROUTE, + ONBOARDING_SECURE_YOUR_WALLET_ROUTE, + ONBOARDING_PRIVACY_SETTINGS_ROUTE, +} from '../../helpers/constants/routes'; +import { + getCompletedOnboarding, + getIsInitialized, + getIsUnlocked, + getSeedPhraseBackedUp, +} from '../../ducks/metamask/metamask'; +import { + createNewVaultAndGetSeedPhrase, + unlockAndGetSeedPhrase, +} from '../../store/actions'; +import { getFirstTimeFlowTypeRoute } from '../../selectors'; +import OnboardingFlowSwitch from './onboarding-flow-switch/onboarding-flow-switch'; +import NewAccount from './new-account/new-account'; +import ReviewRecoveryPhrase from './recovery-phrase/review-recovery-phrase'; +import SecureYourWallet from './secure-your-wallet/secure-your-wallet'; +import ConfirmRecoveryPhrase from './recovery-phrase/confirm-recovery-phrase'; +import PrivacySettings from './privacy-settings/privacy-settings'; + +export default function OnboardingFlow() { + const [seedPhrase, setSeedPhrase] = useState(''); + const dispatch = useDispatch(); + const history = useHistory(); + const isInitialized = useSelector(getIsInitialized); + const isUnlocked = useSelector(getIsUnlocked); + const completedOnboarding = useSelector(getCompletedOnboarding); + const seedPhraseBackedUp = useSelector(getSeedPhraseBackedUp); + const nextRoute = useSelector(getFirstTimeFlowTypeRoute); + + useEffect(() => { + // For ONBOARDING_V2 dev purposes, + // Remove when ONBOARDING_V2 dev complete + if (process.env.ONBOARDING_V2) { + history.push(ONBOARDING_PRIVACY_SETTINGS_ROUTE); + return; + } + + if (completedOnboarding && seedPhraseBackedUp) { + history.push(DEFAULT_ROUTE); + return; + } + + if (isInitialized && !isUnlocked) { + history.push(ONBOARDING_UNLOCK_ROUTE); + } + }, [ + history, + completedOnboarding, + isInitialized, + isUnlocked, + seedPhraseBackedUp, + ]); + + const handleCreateNewAccount = async (password) => { + const newSeedPhrase = await dispatch( + createNewVaultAndGetSeedPhrase(password), + ); + setSeedPhrase(newSeedPhrase); + }; + + const handleUnlock = async (password) => { + const retreivedSeedPhrase = await dispatch( + unlockAndGetSeedPhrase(password), + ); + setSeedPhrase(retreivedSeedPhrase); + history.push(nextRoute); + }; + + return ( +
+
+ + ( + + )} + /> + + } + /> + } + /> + ( + + )} + /> + + + +
+
+ ); +} diff --git a/ui/pages/onboarding-flow/privacy-settings/index.scss b/ui/pages/onboarding-flow/privacy-settings/index.scss new file mode 100644 index 000000000..e5a6d059b --- /dev/null +++ b/ui/pages/onboarding-flow/privacy-settings/index.scss @@ -0,0 +1,50 @@ +.privacy-settings { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + &__header { + display: flex; + justify-content: center; + flex-direction: column; + text-align: center; + max-width: 500px; + margin: 24px; + } + + &__settings { + display: flex; + justify-content: center; + flex-direction: column; + text-align: center; + max-width: 620px; + margin-bottom: 20px; + + a { + color: $Blue-500; + + &:hover { + cursor: pointer; + color: $Blue-300; + } + } + } + + &__setting { + display: flex; + justify-content: center; + flex-direction: column; + text-align: left; + max-width: 430px; + + &__toggle { + margin-left: 42px; + } + } + + & button { + max-width: 50%; + padding: 15px; + } +} diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js new file mode 100644 index 000000000..e372e1130 --- /dev/null +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js @@ -0,0 +1,113 @@ +import React, { useState } from 'react'; +import { useHistory } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; + +import Button from '../../../components/ui/button'; +import Typography from '../../../components/ui/typography'; +import { + FONT_WEIGHT, + TYPOGRAPHY, +} from '../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { + setFeatureFlag, + setUsePhishDetect, + setUseTokenDetection, +} from '../../../store/actions'; +import { ONBOARDING_PIN_EXTENSION_ROUTE } from '../../../helpers/constants/routes'; +import { Setting } from './setting'; + +export default function PrivacySettings() { + const t = useI18nContext(); + const dispatch = useDispatch(); + const history = useHistory(); + const [usePhishingDetection, setUsePhishingDetection] = useState(true); + const [turnOnTokenDetection, setTurnOnTokenDetection] = useState(true); + const [showIncomingTransactions, setShowIncomingTransactions] = useState( + true, + ); + + const handleSubmit = () => { + dispatch( + setFeatureFlag('showIncomingTransactions', showIncomingTransactions), + ); + dispatch(setUsePhishDetect(usePhishingDetection)); + dispatch(setUseTokenDetection(turnOnTokenDetection)); + history.push(ONBOARDING_PIN_EXTENSION_ROUTE); + }; + + return ( + <> +
+
+ + {t('setAdvancedPrivacySettings')} + + + {t('setAdvancedPrivacySettingsDetails')} + +
+
+ + {t('etherscan')} + , + + {t('privacyMsg')} + , + ])} + /> + + {t('jsDeliver')} + , + + {t('privacyMsg')} + , + ])} + /> + +
+ +
+ + ); +} diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.stories.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.stories.js new file mode 100644 index 000000000..c0f775439 --- /dev/null +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.stories.js @@ -0,0 +1,15 @@ +import React from 'react'; +import PrivacySettings from './privacy-settings'; + +export default { + title: 'Onboarding - Privacy Settings', + id: __filename, +}; + +export const Base = () => { + return ( +
+ +
+ ); +}; diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js new file mode 100644 index 000000000..51c9df987 --- /dev/null +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js @@ -0,0 +1,66 @@ +import React from 'react'; +import { fireEvent } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as actions from '../../../store/actions'; +import { renderWithProvider } from '../../../../test/jest'; +import PrivacySettings from './privacy-settings'; + +describe('Privacy Settings Onboarding View', () => { + const mockStore = { + metamask: { + provider: { + type: 'test', + }, + }, + }; + + const store = configureMockStore([thunk])(mockStore); + const setFeatureFlagStub = jest.fn(); + const setUsePhishDetectStub = jest.fn(); + const setUseTokenDetectionStub = jest.fn(); + + actions._setBackgroundConnection({ + setFeatureFlag: setFeatureFlagStub, + setUsePhishDetect: setUsePhishDetectStub, + setUseTokenDetection: setUseTokenDetectionStub, + }); + + it('should update preferences', () => { + const { container, getByText } = renderWithProvider( + , + store, + ); + // All settings are initialized toggled to true + expect(setFeatureFlagStub).toHaveBeenCalledTimes(0); + expect(setUsePhishDetectStub).toHaveBeenCalledTimes(0); + expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(0); + const toggles = container.querySelectorAll('input[type=checkbox]'); + const submitButton = getByText('Done'); + + // toggle to false + fireEvent.click(toggles[0]); + fireEvent.click(toggles[1]); + fireEvent.click(toggles[2]); + fireEvent.click(submitButton); + + expect(setFeatureFlagStub).toHaveBeenCalledTimes(1); + expect(setUsePhishDetectStub).toHaveBeenCalledTimes(1); + expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(1); + expect(setFeatureFlagStub.mock.calls[0][1]).toStrictEqual(false); + expect(setUsePhishDetectStub.mock.calls[0][0]).toStrictEqual(false); + expect(setUseTokenDetectionStub.mock.calls[0][0]).toStrictEqual(false); + + // toggle back to true + fireEvent.click(toggles[0]); + fireEvent.click(toggles[1]); + fireEvent.click(toggles[2]); + fireEvent.click(submitButton); + expect(setFeatureFlagStub).toHaveBeenCalledTimes(2); + expect(setUsePhishDetectStub).toHaveBeenCalledTimes(2); + expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(2); + expect(setFeatureFlagStub.mock.calls[1][1]).toStrictEqual(true); + expect(setUsePhishDetectStub.mock.calls[1][0]).toStrictEqual(true); + expect(setUseTokenDetectionStub.mock.calls[1][0]).toStrictEqual(true); + }); +}); diff --git a/ui/pages/onboarding-flow/privacy-settings/setting.js b/ui/pages/onboarding-flow/privacy-settings/setting.js new file mode 100644 index 000000000..82ba1275c --- /dev/null +++ b/ui/pages/onboarding-flow/privacy-settings/setting.js @@ -0,0 +1,33 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Box from '../../../components/ui/box'; +import Typography from '../../../components/ui/typography'; +import ToggleButton from '../../../components/ui/toggle-button'; +import { + JUSTIFY_CONTENT, + TYPOGRAPHY, + FONT_WEIGHT, +} from '../../../helpers/constants/design-system'; + +export const Setting = ({ value, setValue, title, description }) => { + return ( + +
+ + {title} + + {description} +
+
+ setValue(!val)} /> +
+
+ ); +}; + +Setting.propTypes = { + value: PropTypes.bool, + setValue: PropTypes.func, + title: PropTypes.string, + description: PropTypes.string, +}; diff --git a/ui/pages/onboarding-flow/recovery-phrase/confirm-recovery-phrase.js b/ui/pages/onboarding-flow/recovery-phrase/confirm-recovery-phrase.js index 52d3926e1..2828b5fd7 100644 --- a/ui/pages/onboarding-flow/recovery-phrase/confirm-recovery-phrase.js +++ b/ui/pages/onboarding-flow/recovery-phrase/confirm-recovery-phrase.js @@ -80,7 +80,6 @@ export default function ConfirmRecoveryPhrase({ seedPhrase = '' }) { />
) : ( + + + + + {t('seedPhraseIntroSidebarTitleOne')} + + + {t('seedPhraseIntroSidebarCopyOne')} + + + + + {t('seedPhraseIntroSidebarTitleTwo')} + +
    +
  • {t('seedPhraseIntroSidebarBulletOne')}
  • +
  • {t('seedPhraseIntroSidebarBulletTwo')}
  • +
  • {t('seedPhraseIntroSidebarBulletThree')}
  • +
  • {t('seedPhraseIntroSidebarBulletFour')}
  • +
+
+ + + {t('seedPhraseIntroSidebarTitleThree')} + + + {t('seedPhraseIntroSidebarCopyTwo')} + + + + + {t('seedPhraseIntroSidebarCopyThree')} + + +
+ ); +} diff --git a/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.stories.js b/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.stories.js new file mode 100644 index 000000000..6951b001c --- /dev/null +++ b/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.stories.js @@ -0,0 +1,15 @@ +import React from 'react'; +import SecureYourWallet from './secure-your-wallet'; + +export default { + title: 'Onboarding - Secure Your Wallet', + id: __filename, +}; + +export const Base = () => { + return ( +
+ +
+ ); +}; diff --git a/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.test.js b/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.test.js new file mode 100644 index 000000000..15e5db2c0 --- /dev/null +++ b/ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.test.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { fireEvent } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import reactRouterDom from 'react-router-dom'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import { ONBOARDING_COMPLETION_ROUTE } from '../../../helpers/constants/routes'; +import SecureYourWallet from './secure-your-wallet'; + +describe('Secure Your Wallet Onboarding View', () => { + const useHistoryOriginal = reactRouterDom.useHistory; + const pushMock = jest.fn(); + beforeAll(() => { + jest + .spyOn(reactRouterDom, 'useHistory') + .mockImplementation() + .mockReturnValue({ push: pushMock }); + }); + + afterAll(() => { + reactRouterDom.useHistory = useHistoryOriginal; + }); + + const mockStore = { + metamask: { + provider: { + type: 'test', + }, + }, + }; + + const store = configureMockStore()(mockStore); + it('should show a popover asking the user if they want to skip account security if they click "Remind me later"', () => { + const { queryAllByText, getByText } = renderWithProvider( + , + store, + ); + const remindMeLaterButton = getByText('Remind me later (not recommended)'); + expect(queryAllByText('Skip Account Security?')).toHaveLength(0); + fireEvent.click(remindMeLaterButton); + expect(queryAllByText('Skip Account Security?')).toHaveLength(1); + }); + + it('should not be able to click "skip" until "Skip Account Security" terms are agreed to', () => { + const { getByText, getByTestId } = renderWithProvider( + , + store, + ); + const remindMeLaterButton = getByText('Remind me later (not recommended)'); + fireEvent.click(remindMeLaterButton); + const skipButton = getByText('Skip'); + fireEvent.click(skipButton); + expect(pushMock).toHaveBeenCalledTimes(0); + const checkbox = getByTestId('skip-srp-backup-popover-checkbox'); + fireEvent.click(checkbox); + fireEvent.click(skipButton); + expect(pushMock).toHaveBeenCalledTimes(1); + expect(pushMock).toHaveBeenCalledWith(ONBOARDING_COMPLETION_ROUTE); + }); +}); diff --git a/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js b/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js new file mode 100644 index 000000000..00ceb4558 --- /dev/null +++ b/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js @@ -0,0 +1,79 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { useHistory } from 'react-router-dom'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import Button from '../../../components/ui/button'; +import Popover from '../../../components/ui/popover'; +import Box from '../../../components/ui/box'; +import Typography from '../../../components/ui/typography'; +import { + ALIGN_ITEMS, + FLEX_DIRECTION, + FONT_WEIGHT, + JUSTIFY_CONTENT, + TYPOGRAPHY, +} from '../../../helpers/constants/design-system'; +import Checkbox from '../../../components/ui/check-box'; +import { ONBOARDING_COMPLETION_ROUTE } from '../../../helpers/constants/routes'; + +export default function SkipSRPBackup({ handleClose }) { + const [checked, setChecked] = useState(false); + const t = useI18nContext(); + const history = useHistory(); + return ( + + + + + } + > + + + + {t('skipAccountSecurity')} + + + { + setChecked(!checked); + }} + checked={checked} + dataTestId="skip-srp-backup-popover-checkbox" + /> + + {t('skipAccountSecurityDetails')} + + + + + ); +} + +SkipSRPBackup.propTypes = { + handleClose: PropTypes.func, +}; diff --git a/ui/pages/pages.scss b/ui/pages/pages.scss index 5cbc7932e..300bdcf4a 100644 --- a/ui/pages/pages.scss +++ b/ui/pages/pages.scss @@ -19,3 +19,4 @@ @import 'settings/index'; @import 'swaps/index'; @import 'unlock-page/index'; +@import 'onboarding-flow/index'; diff --git a/ui/pages/permissions-connect/choose-account/choose-account.component.js b/ui/pages/permissions-connect/choose-account/choose-account.component.js index 8e245e62e..d4fc98216 100644 --- a/ui/pages/permissions-connect/choose-account/choose-account.component.js +++ b/ui/pages/permissions-connect/choose-account/choose-account.component.js @@ -224,7 +224,7 @@ export default class ChooseAccount extends Component {
diff --git a/ui/pages/permissions-connect/choose-account/index.scss b/ui/pages/permissions-connect/choose-account/index.scss index d02f5136b..4fcd11e70 100644 --- a/ui/pages/permissions-connect/choose-account/index.scss +++ b/ui/pages/permissions-connect/choose-account/index.scss @@ -179,7 +179,7 @@ width: 124px; } - .btn-default { + .btn-secondary { background: white; margin-left: 16px; } diff --git a/ui/pages/permissions-connect/permissions-connect.stories.js b/ui/pages/permissions-connect/permissions-connect.stories.js index 6eff21540..87af63ee2 100644 --- a/ui/pages/permissions-connect/permissions-connect.stories.js +++ b/ui/pages/permissions-connect/permissions-connect.stories.js @@ -74,7 +74,6 @@ export const PermissionPageContainerComponent = () => { cancelButtonType="default" onSubmit={action('Account(s) Connected')} submitText="connect" - submitButtonType="confirm" buttonSizeLarge={false} />
diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index 4b631c302..23515aa89 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -31,6 +31,7 @@ import AppHeader from '../../components/app/app-header'; import UnlockPage from '../unlock-page'; import Alerts from '../../components/app/alerts'; import Asset from '../asset'; +import OnboardingAppHeader from '../onboarding-flow/onboarding-app-header/onboarding-app-header'; import { IMPORT_TOKEN_ROUTE, @@ -39,7 +40,6 @@ import { CONFIRM_TRANSACTION_ROUTE, CONNECT_ROUTE, DEFAULT_ROUTE, - INITIALIZE_ROUTE, INITIALIZE_UNLOCK_ROUTE, LOCK_ROUTE, MOBILE_SYNC_ROUTE, @@ -53,6 +53,8 @@ import { BUILD_QUOTE_ROUTE, CONFIRMATION_V_NEXT_ROUTE, CONFIRM_IMPORT_TOKEN_ROUTE, + INITIALIZE_ROUTE, + ONBOARDING_ROUTE, } from '../../helpers/constants/routes'; import { @@ -62,6 +64,7 @@ import { import { getEnvironmentType } from '../../../app/scripts/lib/util'; import { isBeta } from '../../helpers/utils/build-types'; import ConfirmationPage from '../confirmation'; +import OnboardingFlow from '../onboarding-flow/onboarding-flow'; export default class Routes extends Component { static propTypes = { @@ -114,9 +117,11 @@ export default class Routes extends Component { renderRoutes() { const { autoLockTimeLimit, setLastActiveTime } = this.props; - const routes = ( + {process.env.ONBOARDING_V2 && ( + + )} @@ -225,7 +230,7 @@ export default class Routes extends Component { const isInitializing = Boolean( matchPath(location.pathname, { - path: INITIALIZE_ROUTE, + path: process.env.ONBOARDING_V2 ? ONBOARDING_ROUTE : INITIALIZE_ROUTE, exact: false, }), ); @@ -261,6 +266,17 @@ export default class Routes extends Component { return isHandlingPermissionsRequest || isHandlingAddEthereumChainRequest; } + showOnboardingHeader() { + const { location } = this.props; + + return Boolean( + matchPath(location.pathname, { + path: ONBOARDING_ROUTE, + exact: false, + }), + ); + } + render() { const { isLoading, @@ -315,6 +331,9 @@ export default class Routes extends Component { } /> )} + {process.env.ONBOARDING_V2 && this.showOnboardingHeader() && ( + + )} - {!networkAndAccountSupports1559 && } + {networkOrAccountNotSupports1559 && } {this.props.showHexData && }
diff --git a/ui/pages/send/send-content/send-content.container.js b/ui/pages/send/send-content/send-content.container.js index a1f4daf46..83b38dfeb 100644 --- a/ui/pages/send/send-content/send-content.container.js +++ b/ui/pages/send/send-content/send-content.container.js @@ -4,7 +4,7 @@ import { getAddressBookEntry, getIsEthGasPriceFetched, getNoGasPriceFetched, - checkNetworkAndAccountSupports1559, + checkNetworkOrAccountNotSupports1559, } from '../../../selectors'; import { getIsAssetSendable, getSendTo } from '../../../ducks/send'; @@ -25,7 +25,9 @@ function mapStateToProps(state) { isEthGasPrice: getIsEthGasPriceFetched(state), noGasPrice: getNoGasPriceFetched(state), to, - networkAndAccountSupports1559: checkNetworkAndAccountSupports1559(state), + networkOrAccountNotSupports1559: checkNetworkOrAccountNotSupports1559( + state, + ), }; } diff --git a/ui/pages/send/send-header/send-header.stories.js b/ui/pages/send/send-header/send-header.stories.js new file mode 100644 index 000000000..034623bb3 --- /dev/null +++ b/ui/pages/send/send-header/send-header.stories.js @@ -0,0 +1,54 @@ +import React, { useEffect } from 'react'; +import { combineReducers, createStore } from 'redux'; +import { Provider } from 'react-redux'; + +import { select } from '@storybook/addon-knobs'; +import { + updateSendStage, + updateSendAsset, +} from '../../../../.storybook/actions/sb-send-action'; + +import sendSBReducer from '../../../../.storybook/reducers/sb-send-reducer'; +import historySBReducer from '../../../../.storybook/reducers/sb-history-reducer'; + +import { ASSET_TYPES, SEND_STAGES } from '../../../ducks/send'; +import SendHeader from './send-header.component'; + +export default { + title: 'SendHeader', + id: __filename, +}; + +export const SendHeaderComponent = () => { + const store = createStore( + combineReducers({ send: sendSBReducer, history: historySBReducer }), + ); + const state = store.getState(); + const { send } = state; + const asset = + select('Asset', [ASSET_TYPES.NATIVE, ASSET_TYPES.TOKEN]) || send.asset; + + const stage = + select('Stage', [ + SEND_STAGES.ADD_RECIPIENT, + SEND_STAGES.DRAFT, + SEND_STAGES.EDIT, + SEND_STAGES.INACTIVE, + ]) || send.stage; + + useEffect(() => { + store.dispatch(updateSendAsset(asset)); + }, [store, asset]); + + useEffect(() => { + store.dispatch(updateSendStage(stage)); + }, [store, stage]); + + return ( + +
+ +
+
+ ); +}; diff --git a/ui/pages/settings/contact-list-tab/add-contact/add-contact.component.js b/ui/pages/settings/contact-list-tab/add-contact/add-contact.component.js index 6ce7f06f0..3ed6296d6 100644 --- a/ui/pages/settings/contact-list-tab/add-contact/add-contact.component.js +++ b/ui/pages/settings/contact-list-tab/add-contact/add-contact.component.js @@ -153,7 +153,6 @@ export default class AddContact extends PureComponent { history.push(CONTACT_LIST_ROUTE); }} submitText={this.context.t('save')} - submitButtonType="confirm" />
); diff --git a/ui/pages/settings/contact-list-tab/contact-list-tab.component.js b/ui/pages/settings/contact-list-tab/contact-list-tab.component.js index 2f4b135f0..0f315517f 100644 --- a/ui/pages/settings/contact-list-tab/contact-list-tab.component.js +++ b/ui/pages/settings/contact-list-tab/contact-list-tab.component.js @@ -80,7 +80,6 @@ export default class ContactListTab extends Component { viewingContact || editingContact, })} type="secondary" - rounded onClick={() => { history.push(CONTACT_ADD_ROUTE); }} diff --git a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js index 51419b302..0f64dfa15 100644 --- a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js +++ b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js @@ -177,7 +177,6 @@ export default class EditContact extends PureComponent { history.push(`${viewRoute}/${address}`); }} submitText={this.context.t('save')} - submitButtonType="confirm" />
); diff --git a/ui/pages/settings/contact-list-tab/index.scss b/ui/pages/settings/contact-list-tab/index.scss index 4084afa0f..8f00641b6 100644 --- a/ui/pages/settings/contact-list-tab/index.scss +++ b/ui/pages/settings/contact-list-tab/index.scss @@ -257,7 +257,6 @@ top: 85px; right: 16px; width: auto; - border-radius: 100px; @media screen and (max-width: $break-small) { top: 16px; diff --git a/ui/pages/settings/networks-tab/index.scss b/ui/pages/settings/networks-tab/index.scss index 40a182264..d8da8cf79 100644 --- a/ui/pages/settings/networks-tab/index.scss +++ b/ui/pages/settings/networks-tab/index.scss @@ -232,11 +232,11 @@ width: 93%; } - .btn-default { + .btn-secondary { margin-right: 0.375rem; } - .btn-secondary { + .btn-primary { margin-left: 0.375rem; } diff --git a/ui/pages/settings/networks-tab/network-form/network-form.component.js b/ui/pages/settings/networks-tab/network-form/network-form.component.js index e2968001d..2e722031e 100644 --- a/ui/pages/settings/networks-tab/network-form/network-form.component.js +++ b/ui/pages/settings/networks-tab/network-form/network-form.component.js @@ -629,14 +629,14 @@ export default class NetworkForm extends PureComponent { )}
`; @@ -15,7 +15,7 @@ exports[`ViewOnEtherScanLink renders the component with initial props 1`] = `
- View on Etherscan + View Swap on Etherscan
`; diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js index ff7b275eb..5ba179505 100644 --- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js +++ b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js @@ -34,8 +34,11 @@ export default function ViewOnEtherScanLink({ }} > {isCustomBlockExplorerUrl - ? t('viewOnCustomBlockExplorer', [getURLHostName(blockExplorerUrl)]) - : t('viewOnEtherscan')} + ? t('viewOnCustomBlockExplorer', [ + t('blockExplorerSwapAction'), + getURLHostName(blockExplorerUrl), + ]) + : t('viewOnEtherscan', [t('blockExplorerSwapAction')])}
); } diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js index 91e32b82c..0fc96d87d 100644 --- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js +++ b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js @@ -18,7 +18,7 @@ describe('ViewOnEtherScanLink', () => { const { container, getByText } = renderWithProvider( , ); - expect(getByText('View on Etherscan')).toBeInTheDocument(); + expect(getByText('View Swap on Etherscan')).toBeInTheDocument(); expect(container).toMatchSnapshot(); }); @@ -31,7 +31,9 @@ describe('ViewOnEtherScanLink', () => { })} />, ); - expect(getByText('View at custom-blockchain.explorer')).toBeInTheDocument(); + expect( + getByText('View Swap at custom-blockchain.explorer'), + ).toBeInTheDocument(); expect(container).toMatchSnapshot(); }); }); diff --git a/ui/pages/swaps/fee-card/fee-card.stories.js b/ui/pages/swaps/fee-card/fee-card.stories.js index 4597edad7..b25c4b575 100644 --- a/ui/pages/swaps/fee-card/fee-card.stories.js +++ b/ui/pages/swaps/fee-card/fee-card.stories.js @@ -1,6 +1,7 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; import { text, boolean, number, object } from '@storybook/addon-knobs'; +import { MAINNET_CHAIN_ID } from '../../../../shared/constants/network'; import FeeCard from './fee-card'; const tokenApprovalTextComponent = ( @@ -31,6 +32,8 @@ export const WithAllProps = () => { fee: text('secondaryFee', '100 USD'), maxFee: text('secondaryMaxFee', '200 USD'), }} + chainId={MAINNET_CHAIN_ID} + networkAndAccountSupports1559={false} onFeeCardMaxRowClick={action('Clicked max fee row link')} tokenApprovalTextComponent={tokenApprovalTextComponent} tokenApprovalSourceTokenSymbol="ABC" @@ -68,6 +71,8 @@ export const WithoutThirdRow = () => { isBestQuote={boolean('isBestQuote', true)} savings={object('savings 1', { total: '8.55' })} metaMaskFee="0.875" + chainId={MAINNET_CHAIN_ID} + networkAndAccountSupports1559={false} /> ); @@ -86,6 +91,8 @@ export const WithOnlyRequiredProps = () => { metaMaskFee="0.875" onQuotesClick={action('Clicked quotes link')} numberOfQuotes={2} + chainId={MAINNET_CHAIN_ID} + networkAndAccountSupports1559={false} /> ); diff --git a/ui/pages/swaps/import-token/import-token.js b/ui/pages/swaps/import-token/import-token.js index 9be183878..88a0645a8 100644 --- a/ui/pages/swaps/import-token/import-token.js +++ b/ui/pages/swaps/import-token/import-token.js @@ -27,15 +27,13 @@ export default function ImportToken({ type="secondary" className="page-container__footer-button" onClick={onImportTokenCloseClick} - rounded > {t('cancel')} diff --git a/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js b/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js index 13ee5afa8..d74b50460 100644 --- a/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js +++ b/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js @@ -139,7 +139,7 @@ export default function ItemList({ )} {result.notImported && ( - )} diff --git a/ui/pages/swaps/select-quote-popover/index.scss b/ui/pages/swaps/select-quote-popover/index.scss index ad305a3f8..e2a3a2cc7 100644 --- a/ui/pages/swaps/select-quote-popover/index.scss +++ b/ui/pages/swaps/select-quote-popover/index.scss @@ -2,7 +2,6 @@ .select-quote-popover { &__button { - border-radius: 100px; height: 39px; width: 140px; } diff --git a/ui/pages/swaps/select-quote-popover/select-quote-popover.js b/ui/pages/swaps/select-quote-popover/select-quote-popover.js index c3efcba48..c4f9e8977 100644 --- a/ui/pages/swaps/select-quote-popover/select-quote-popover.js +++ b/ui/pages/swaps/select-quote-popover/select-quote-popover.js @@ -57,7 +57,7 @@ const SelectQuotePopover = ({ const footer = ( <>