From 3ac4e7d051c43b743ffb3165c28aa22c21d2d9b3 Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Tue, 8 Mar 2022 16:34:06 +0000 Subject: [PATCH 01/10] Version v10.11.1 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ffb0292c..64f6c27b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.11.1] + ## [10.11.0] ### Added - Swaps: Add support for Smart Transactions on Mainnet and Rinkeby ([#12676](https://github.com/MetaMask/metamask-extension/pull/12676)) @@ -2764,7 +2766,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.11.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.11.1...HEAD +[10.11.1]: https://github.com/MetaMask/metamask-extension/compare/v10.11.0...v10.11.1 [10.11.0]: https://github.com/MetaMask/metamask-extension/compare/v10.10.2...v10.11.0 [10.10.2]: https://github.com/MetaMask/metamask-extension/compare/v10.10.1...v10.10.2 [10.10.1]: https://github.com/MetaMask/metamask-extension/compare/v10.10.0...v10.10.1 diff --git a/package.json b/package.json index a5edf84d8..99824e2e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.11.0", + "version": "10.11.1", "private": true, "repository": { "type": "git", From 7ec8bd49c76482bcf75c8ca81925ecbb70be52d9 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 7 Mar 2022 09:28:30 -0600 Subject: [PATCH 02/10] [GridPlus] Updates Lattice dependencies (#13834) --- app/manifest/_base.json | 2 +- lavamoat/browserify/beta/policy.json | 2 ++ lavamoat/browserify/flask/policy.json | 2 ++ lavamoat/browserify/main/policy.json | 2 ++ package.json | 2 +- yarn.lock | 39 ++++++++++++++++++--------- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/app/manifest/_base.json b/app/manifest/_base.json index bc63ce27d..c2b20b4db 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -66,7 +66,7 @@ "clipboardWrite", "http://localhost:8545/", "https://*.infura.io/", - "https://wallet.gridplus.io/*", + "https://lattice.gridplus.io/*", "activeTab", "webRequest", "*://*.eth/", diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index fd9c5466a..bb6798360 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -2337,6 +2337,7 @@ "gridplus-sdk": { "globals": { "console.error": true, + "console.warn": true, "setTimeout": true }, "packages": { @@ -2350,6 +2351,7 @@ "crc-32": true, "elliptic": true, "eth-eip712-util-browser": true, + "hash.js": true, "js-sha3": true, "rlp-browser": true, "secp256k1": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index fc9b78a8e..d3c537308 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2356,6 +2356,7 @@ "gridplus-sdk": { "globals": { "console.error": true, + "console.warn": true, "setTimeout": true }, "packages": { @@ -2369,6 +2370,7 @@ "crc-32": true, "elliptic": true, "eth-eip712-util-browser": true, + "hash.js": true, "js-sha3": true, "rlp-browser": true, "secp256k1": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index fd9c5466a..bb6798360 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -2337,6 +2337,7 @@ "gridplus-sdk": { "globals": { "console.error": true, + "console.warn": true, "setTimeout": true }, "packages": { @@ -2350,6 +2351,7 @@ "crc-32": true, "elliptic": true, "eth-eip712-util-browser": true, + "hash.js": true, "js-sha3": true, "rlp-browser": true, "secp256k1": true, diff --git a/package.json b/package.json index 99824e2e4..fe00c5d76 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "eth-json-rpc-infura": "^5.1.0", "eth-json-rpc-middleware": "^8.0.0", "eth-keyring-controller": "^6.2.0", - "eth-lattice-keyring": "^0.4.0", + "eth-lattice-keyring": "^0.5.0", "eth-method-registry": "^2.0.0", "eth-query": "^2.1.2", "eth-rpc-errors": "^4.0.2", diff --git a/yarn.lock b/yarn.lock index 561e6bf79..a78c3288e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11084,16 +11084,16 @@ eth-keyring-controller@^6.2.0, eth-keyring-controller@^6.2.1: loglevel "^1.5.0" obs-store "^4.0.3" -eth-lattice-keyring@^0.4.0: - version "0.4.9" - resolved "https://registry.yarnpkg.com/eth-lattice-keyring/-/eth-lattice-keyring-0.4.9.tgz#327a41fa25ef28dfc9fe87f2ce11e95139adfd67" - integrity sha512-ZflOgYrbuGJGPSDWgDA6PndCIlYRS2M+/bxKsJupbPgz/O8XwQdTGttszp0mHwOqPdvUULUmW08QCqd8trnuVg== +eth-lattice-keyring@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/eth-lattice-keyring/-/eth-lattice-keyring-0.5.0.tgz#19dbbc2de31008dfd576531fa44a5d34061e61c8" + integrity sha512-+6iTQqrAqneUDfLR5aLVmYtys++a8C5N6F/9ibEtGT3YNYUE0NLZMI/DvFz/JhjpHhTjSXXtSb3yUajW6liAaQ== dependencies: "@ethereumjs/common" "^2.4.0" "@ethereumjs/tx" "^3.1.1" bignumber.js "^9.0.1" ethereumjs-util "^7.0.10" - gridplus-sdk "^0.9.7" + gridplus-sdk "^1.0.0" eth-lib@0.2.8: version "0.2.8" @@ -11405,10 +11405,10 @@ ethers@^4.0.20, ethers@^4.0.28: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.8, ethers@^5.4.0, ethers@^5.4.1, ethers@^5.4.5: - version "5.5.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.1.tgz#d3259a95a42557844aa543906c537106c0406fbf" - integrity sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw== +ethers@^5.0.8, ethers@^5.4.0, ethers@^5.4.1, ethers@^5.4.5, ethers@^5.5.1: + version "5.5.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.4.tgz#e1155b73376a2f5da448e4a33351b57a885f4352" + integrity sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw== dependencies: "@ethersproject/abi" "5.5.0" "@ethersproject/abstract-provider" "5.5.1" @@ -13456,10 +13456,22 @@ graphql-request@^1.8.2: dependencies: cross-fetch "2.2.2" -gridplus-sdk@^0.9.7: - version "0.9.10" - resolved "https://registry.yarnpkg.com/gridplus-sdk/-/gridplus-sdk-0.9.10.tgz#8835e8bc9a2ca7ae163520ddcc0b313350e67dd2" - integrity sha512-CNvhyaz3F8UvlHqihFJlOt+FenmFkb2dFrbBTyRth/nlzD8Tm0HjW+uyY1W0ekDp45Exz9l0VY0EmdvjphBe1w== +graphql-subscriptions@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" + integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== + dependencies: + iterall "^1.3.0" + +"graphql@^14.0.2 || ^15.5": + version "15.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + +gridplus-sdk@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gridplus-sdk/-/gridplus-sdk-1.0.0.tgz#008a24a8ec5b50a6fdb8005723a77f5d24fc88cd" + integrity sha512-vVyLyAY7Ockkf8hv+em1KkjPwvKkLmb7mYZFY2Vtt60+qpmPut1S2/WjrZGdNGGawWAKAmpw8WKdw5MSg2UkpA== dependencies: aes-js "^3.1.1" bech32 "^2.0.0" @@ -13471,6 +13483,7 @@ gridplus-sdk@^0.9.7: crc-32 "^1.2.0" elliptic "6.5.4" eth-eip712-util-browser "^0.0.3" + hash.js "^1.1.7" js-sha3 "^0.8.0" rlp-browser "^1.0.1" secp256k1 "4.0.2" From c3feabf4de3c978ecb25b5a960cbd2c919d9f20c Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 30 Jul 2021 19:07:40 -0230 Subject: [PATCH 03/10] Update SRP representation An array of integers is now used to represent the SRP in three cases: * In the import wallet flow, the UI uses it to pass the user-provided SRP to the background (which converts the array to a buffer). * In the create wallet flow, the UI uses it to retrieve the generated SRP from the background. * When persisting the wallet to state, the background uses it to serialize the SRP. Co-authored-by: Elliot Winkler --- app/scripts/lib/seed-phrase-verifier.js | 8 +- app/scripts/metamask-controller.js | 18 ++-- lavamoat/browserify/beta/policy.json | 5 ++ lavamoat/browserify/flask/policy.json | 5 ++ lavamoat/browserify/main/policy.json | 5 ++ patches/bip39+2.5.0.patch | 99 ++++++++++++++++++++++ patches/eth-hd-keyring+3.6.0.patch | 43 ++++++++++ patches/eth-keyring-controller+6.2.1.patch | 37 ++++++++ ui/store/actions.js | 65 ++++++++------ ui/store/actions.test.js | 12 ++- 10 files changed, 255 insertions(+), 42 deletions(-) create mode 100644 patches/bip39+2.5.0.patch create mode 100644 patches/eth-hd-keyring+3.6.0.patch create mode 100644 patches/eth-keyring-controller+6.2.1.patch diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 225a57896..e1c18c1eb 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -11,10 +11,10 @@ const seedPhraseVerifier = { * - The keyring always creates the accounts in the same sequence. * * @param {Array} createdAccounts - The accounts to restore - * @param {string} seedWords - The seed words to verify - * @returns {Promise} Promises undefined + * @param {Buffer} seedPhrase - The seed words to verify, encoded as a Buffer + * @returns {Promise} */ - async verifyAccounts(createdAccounts, seedWords) { + async verifyAccounts(createdAccounts, seedPhrase) { if (!createdAccounts || createdAccounts.length < 1) { throw new Error('No created accounts defined.'); } @@ -22,7 +22,7 @@ const seedPhraseVerifier = { const keyringController = new KeyringController({}); const Keyring = keyringController.getKeyringClassForType('HD Key Tree'); const opts = { - mnemonic: seedWords, + mnemonic: seedPhrase, numberOfAccounts: createdAccounts.length, }; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c378114a1..30a2bdc0b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1792,13 +1792,16 @@ export default class MetamaskController extends EventEmitter { * Create a new Vault and restore an existent keyring. * * @param {string} password - * @param {string} seed + * @param {number[]} encodedSeedPhrase - The seed phrase, encoded as an array + * of UTF-8 bytes. */ - async createNewVaultAndRestore(password, seed) { + async createNewVaultAndRestore(password, encodedSeedPhrase) { const releaseLock = await this.createVaultMutex.acquire(); try { let accounts, lastBalance; + const seedPhraseAsBuffer = Buffer.from(encodedSeedPhrase); + const { keyringController } = this; // clear known identities @@ -1819,7 +1822,7 @@ export default class MetamaskController extends EventEmitter { // create new vault const vault = await keyringController.createNewVaultAndRestore( password, - seed, + seedPhraseAsBuffer, ); const ethQuery = new EthQuery(this.provider); @@ -2279,7 +2282,8 @@ export default class MetamaskController extends EventEmitter { * * Called when the first account is created and on unlocking the vault. * - * @returns {Promise} Seed phrase to be confirmed by the user. + * @returns {Promise} The seed phrase to be confirmed by the user, + * encoded as an array of UTF-8 bytes. */ async verifySeedPhrase() { const primaryKeyring = this.keyringController.getKeyringsByType( @@ -2290,7 +2294,7 @@ export default class MetamaskController extends EventEmitter { } const serialized = await primaryKeyring.serialize(); - const seedWords = serialized.mnemonic; + const seedPhraseAsBuffer = Buffer.from(serialized.mnemonic); const accounts = await primaryKeyring.getAccounts(); if (accounts.length < 1) { @@ -2298,8 +2302,8 @@ export default class MetamaskController extends EventEmitter { } try { - await seedPhraseVerifier.verifyAccounts(accounts, seedWords); - return seedWords; + await seedPhraseVerifier.verifyAccounts(accounts, seedPhraseAsBuffer); + return Array.from(seedPhraseAsBuffer.values()); } catch (err) { log.error(err.message); throw err; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index bb6798360..e4d29eb88 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1175,6 +1175,9 @@ } }, "bip39": { + "globals": { + "console.log": true + }, "packages": { "buffer": true, "create-hash": true, @@ -1889,6 +1892,7 @@ "eth-hd-keyring": { "packages": { "bip39": true, + "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1947,6 +1951,7 @@ "packages": { "bip39": true, "browser-passworder": true, + "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index d3c537308..72fa6de24 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1194,6 +1194,9 @@ } }, "bip39": { + "globals": { + "console.log": true + }, "packages": { "buffer": true, "create-hash": true, @@ -1908,6 +1911,7 @@ "eth-hd-keyring": { "packages": { "bip39": true, + "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1966,6 +1970,7 @@ "packages": { "bip39": true, "browser-passworder": true, + "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index bb6798360..e4d29eb88 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1175,6 +1175,9 @@ } }, "bip39": { + "globals": { + "console.log": true + }, "packages": { "buffer": true, "create-hash": true, @@ -1889,6 +1892,7 @@ "eth-hd-keyring": { "packages": { "bip39": true, + "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1947,6 +1951,7 @@ "packages": { "bip39": true, "browser-passworder": true, + "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/patches/bip39+2.5.0.patch b/patches/bip39+2.5.0.patch new file mode 100644 index 000000000..2976f3bb2 --- /dev/null +++ b/patches/bip39+2.5.0.patch @@ -0,0 +1,99 @@ +diff --git a/node_modules/bip39/index.js b/node_modules/bip39/index.js +index aa0f29f..bee8008 100644 +--- a/node_modules/bip39/index.js ++++ b/node_modules/bip39/index.js +@@ -48,7 +48,9 @@ function salt (password) { + } + + function mnemonicToSeed (mnemonic, password) { +- var mnemonicBuffer = Buffer.from(unorm.nfkd(mnemonic), 'utf8') ++ var mnemonicBuffer = typeof mnemonic === 'string' ++ ? Buffer.from(unorm.nfkd(mnemonic), 'utf8') ++ : mnemonic + var saltBuffer = Buffer.from(salt(unorm.nfkd(password)), 'utf8') + + return pbkdf2(mnemonicBuffer, saltBuffer, 2048, 64, 'sha512') +@@ -61,12 +63,28 @@ function mnemonicToSeedHex (mnemonic, password) { + function mnemonicToEntropy (mnemonic, wordlist) { + wordlist = wordlist || DEFAULT_WORDLIST + +- var words = unorm.nfkd(mnemonic).split(' ') ++ var mnemonicAsBuffer = typeof mnemonic === 'string' ++ ? Buffer.from(unorm.nfkd(mnemonic), 'utf8') ++ : mnemonic ++ ++ var words = []; ++ var currentWord = []; ++ for (const byte of mnemonicAsBuffer.values()) { ++ // split at space or \u3000 (ideographic space, for Japanese wordlists) ++ if (byte === 0x20 || byte === 0x3000) { ++ words.push(Buffer.from(currentWord)); ++ currentWord = []; ++ } else { ++ currentWord.push(byte); ++ } ++ } ++ words.push(Buffer.from(currentWord)); ++ + if (words.length % 3 !== 0) throw new Error(INVALID_MNEMONIC) + + // convert word indices to 11 bit binary strings + var bits = words.map(function (word) { +- var index = wordlist.indexOf(word) ++ var index = wordlist.indexOf(word.toString('utf8')) + if (index === -1) throw new Error(INVALID_MNEMONIC) + + return lpad(index.toString(2), '0', 11) +@@ -104,12 +122,41 @@ function entropyToMnemonic (entropy, wordlist) { + + var bits = entropyBits + checksumBits + var chunks = bits.match(/(.{1,11})/g) +- var words = chunks.map(function (binary) { ++ var wordsAsBuffers = chunks.map(function (binary) { + var index = binaryToByte(binary) +- return wordlist[index] ++ return Buffer.from(wordlist[index], 'utf8') + }) + +- return wordlist === JAPANESE_WORDLIST ? words.join('\u3000') : words.join(' ') ++ var bufferSize = wordsAsBuffers.reduce(function (bufferSize, wordAsBuffer, i) { ++ var shouldAddSeparator = i < wordsAsBuffers.length - 1 ++ return ( ++ bufferSize + ++ wordAsBuffer.length + ++ (shouldAddSeparator ? 1 : 0) ++ ) ++ }, 0) ++ var separator = wordlist === JAPANESE_WORDLIST ? '\u3000' : ' ' ++ var result = wordsAsBuffers.reduce(function (result, wordAsBuffer, i) { ++ var shouldAddSeparator = i < wordsAsBuffers.length - 1 ++ result.workingBuffer.set(wordAsBuffer, result.offset) ++ if (shouldAddSeparator) { ++ result.workingBuffer.write( ++ separator, ++ result.offset + wordAsBuffer.length, ++ separator.length, ++ 'utf8' ++ ) ++ } ++ return { ++ workingBuffer: result.workingBuffer, ++ offset: ( ++ result.offset + ++ wordAsBuffer.length + ++ (shouldAddSeparator ? 1 : 0) ++ ) ++ } ++ }, { workingBuffer: Buffer.alloc(bufferSize), offset: 0 }) ++ return result.workingBuffer; + } + + function generateMnemonic (strength, rng, wordlist) { +@@ -124,6 +171,7 @@ function validateMnemonic (mnemonic, wordlist) { + try { + mnemonicToEntropy(mnemonic, wordlist) + } catch (e) { ++ console.log('could not validate mnemonic', e) + return false + } + diff --git a/patches/eth-hd-keyring+3.6.0.patch b/patches/eth-hd-keyring+3.6.0.patch new file mode 100644 index 000000000..211cb89dd --- /dev/null +++ b/patches/eth-hd-keyring+3.6.0.patch @@ -0,0 +1,43 @@ +diff --git a/node_modules/eth-hd-keyring/index.js b/node_modules/eth-hd-keyring/index.js +index 19d1d7f..350d6b8 100644 +--- a/node_modules/eth-hd-keyring/index.js ++++ b/node_modules/eth-hd-keyring/index.js +@@ -17,8 +17,11 @@ class HdKeyring extends SimpleKeyring { + } + + serialize () { ++ const mnemonicAsBuffer = typeof this.mnemonic === 'string' ++ ? Buffer.from(this.mnemonic, 'utf8') ++ : this.mnemonic + return Promise.resolve({ +- mnemonic: this.mnemonic, ++ mnemonic: Array.from(mnemonicAsBuffer.values()), + numberOfAccounts: this.wallets.length, + hdPath: this.hdPath, + }) +@@ -69,9 +72,22 @@ class HdKeyring extends SimpleKeyring { + + /* PRIVATE METHODS */ + +- _initFromMnemonic (mnemonic) { +- this.mnemonic = mnemonic +- const seed = bip39.mnemonicToSeed(mnemonic) ++ /** ++ * Sets appropriate properties for the keyring based on the given ++ * BIP39-compliant mnemonic. ++ * ++ * @param {string|Array|Buffer} mnemonic - A seed phrase represented ++ * as a string, an array of UTF-8 bytes, or a Buffer. ++ */ ++ _initFromMnemonic(mnemonic) { ++ if (typeof mnemonic === 'string') { ++ this.mnemonic = Buffer.from(mnemonic, 'utf8') ++ } else if (Array.isArray(mnemonic)) { ++ this.mnemonic = Buffer.from(mnemonic) ++ } else { ++ this.mnemonic = mnemonic ++ } ++ const seed = bip39.mnemonicToSeed(this.mnemonic) + this.hdWallet = hdkey.fromMasterSeed(seed) + this.root = this.hdWallet.derivePath(this.hdPath) + } diff --git a/patches/eth-keyring-controller+6.2.1.patch b/patches/eth-keyring-controller+6.2.1.patch new file mode 100644 index 000000000..aec0c7168 --- /dev/null +++ b/patches/eth-keyring-controller+6.2.1.patch @@ -0,0 +1,37 @@ +diff --git a/node_modules/eth-keyring-controller/index.js b/node_modules/eth-keyring-controller/index.js +index 250ab98..38615aa 100644 +--- a/node_modules/eth-keyring-controller/index.js ++++ b/node_modules/eth-keyring-controller/index.js +@@ -84,15 +84,20 @@ class KeyringController extends EventEmitter { + * + * @emits KeyringController#unlock + * @param {string} password - The password to encrypt the vault with +- * @param {string} seed - The BIP44-compliant seed phrase. ++ * @param {string|Array} seedPhrase - The BIP39-compliant seed phrase, ++ * either as a string or an array of UTF-8 bytes that represent the string. + * @returns {Promise} A Promise that resolves to the state. + */ +- createNewVaultAndRestore (password, seed) { ++ createNewVaultAndRestore(password, seedPhrase) { ++ const seedPhraseAsBuffer = typeof seedPhrase === 'string' ++ ? Buffer.from(seedPhrase, 'utf8') ++ : Buffer.from(seedPhrase) ++ + if (typeof password !== 'string') { + return Promise.reject(new Error('Password must be text.')) + } + +- if (!bip39.validateMnemonic(seed)) { ++ if (!bip39.validateMnemonic(seedPhraseAsBuffer)) { + return Promise.reject(new Error('Seed phrase is invalid.')) + } + +@@ -101,7 +106,7 @@ class KeyringController extends EventEmitter { + return this.persistAllKeyrings(password) + .then(() => { + return this.addNewKeyring('HD Key Tree', { +- mnemonic: seed, ++ mnemonic: seedPhraseAsBuffer, + numberOfAccounts: 1, + }) + }) diff --git a/ui/store/actions.js b/ui/store/actions.js index 7842b4b5d..71e0bf750 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -82,20 +82,39 @@ export function tryUnlockMetamask(password) { }; } -export function createNewVaultAndRestore(password, seed) { +/** + * Adds a new account where all data is encrypted using the given password and + * where all addresses are generated from a given seed phrase. + * + * @param {string} password - The password. + * @param {string} seedPhrase - The seed phrase. + * @returns {Object} The updated state of the keyring controller. + */ +export function createNewVaultAndRestore(password, seedPhrase) { return (dispatch) => { dispatch(showLoadingIndication()); log.debug(`background.createNewVaultAndRestore`); + + // Encode the secret recovery phrase as an array of integers so that it is + // serialized as JSON properly. + const encodedSeedPhrase = Array.from( + Buffer.from(seedPhrase, 'utf8').values(), + ); + let vault; return new Promise((resolve, reject) => { - background.createNewVaultAndRestore(password, seed, (err, _vault) => { - if (err) { - reject(err); - return; - } - vault = _vault; - resolve(); - }); + background.createNewVaultAndRestore( + password, + encodedSeedPhrase, + (err, _vault) => { + if (err) { + reject(err); + return; + } + vault = _vault; + resolve(); + }, + ); }) .then(() => dispatch(unMarkPasswordForgotten())) .then(() => { @@ -117,8 +136,8 @@ export function createNewVaultAndGetSeedPhrase(password) { try { await createNewVault(password); - const seedWords = await verifySeedPhrase(); - return seedWords; + const seedPhrase = await verifySeedPhrase(); + return seedPhrase; } catch (error) { dispatch(displayWarning(error.message)); throw new Error(error.message); @@ -134,9 +153,9 @@ export function unlockAndGetSeedPhrase(password) { try { await submitPassword(password); - const seedWords = await verifySeedPhrase(); + const seedPhrase = await verifySeedPhrase(); await forceUpdateMetamaskState(dispatch); - return seedWords; + return seedPhrase; } catch (error) { dispatch(displayWarning(error.message)); throw new Error(error.message); @@ -185,17 +204,9 @@ export function verifyPassword(password) { }); } -export function verifySeedPhrase() { - return new Promise((resolve, reject) => { - background.verifySeedPhrase((error, seedWords) => { - if (error) { - reject(error); - return; - } - - resolve(seedWords); - }); - }); +export async function verifySeedPhrase() { + const encodedSeedPhrase = await promisifiedBackground.verifySeedPhrase(); + return Buffer.from(encodedSeedPhrase).toString('utf8'); } export function requestRevealSeedWords(password) { @@ -205,11 +216,11 @@ export function requestRevealSeedWords(password) { try { await verifyPassword(password); - const seedWords = await verifySeedPhrase(); - return seedWords; + const seedPhrase = await verifySeedPhrase(); + return seedPhrase; } catch (error) { dispatch(displayWarning(error.message)); - throw new Error(error.message); + throw error; } finally { dispatch(hideLoadingIndication()); } diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 0866713b4..727835ecf 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -111,7 +111,9 @@ describe('Actions', () => { actions._setBackgroundConnection(background); - await store.dispatch(actions.createNewVaultAndRestore()); + await store.dispatch( + actions.createNewVaultAndRestore('password', 'test'), + ); expect(createNewVaultAndRestore.callCount).toStrictEqual(1); }); @@ -134,7 +136,9 @@ describe('Actions', () => { { type: 'HIDE_LOADING_INDICATION' }, ]; - await store.dispatch(actions.createNewVaultAndRestore()); + await store.dispatch( + actions.createNewVaultAndRestore('password', 'test'), + ); expect(store.getActions()).toStrictEqual(expectedActions); }); @@ -155,7 +159,7 @@ describe('Actions', () => { ]; await expect( - store.dispatch(actions.createNewVaultAndRestore()), + store.dispatch(actions.createNewVaultAndRestore('password', 'test')), ).rejects.toThrow('error'); expect(store.getActions()).toStrictEqual(expectedActions); @@ -174,7 +178,7 @@ describe('Actions', () => { cb(), ); const verifySeedPhrase = background.verifySeedPhrase.callsFake((cb) => - cb(), + cb(null, Array.from(Buffer.from('test').values())), ); actions._setBackgroundConnection(background); From 3f0fa89d8de5c347f83debfcbb75925c024107a2 Mon Sep 17 00:00:00 2001 From: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com> Date: Tue, 22 Feb 2022 12:59:13 -0500 Subject: [PATCH 04/10] Deleting transactions from currentNetworkTxnList based on unique address along with nonce and chainId (#13669) --- app/scripts/controllers/transactions/tx-state-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 879aac56c..d59b5a058 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -249,9 +249,9 @@ export default class TransactionStateManager extends EventEmitter { const txsToDelete = transactions .reverse() .filter((tx) => { - const { nonce } = tx.txParams; + const { nonce, from } = tx.txParams; const { chainId, metamaskNetworkId, status } = tx; - const key = `${nonce}-${chainId ?? metamaskNetworkId}`; + const key = `${nonce}-${chainId ?? metamaskNetworkId}-${from}`; if (nonceNetworkSet.has(key)) { return false; } else if ( From 8c9efb2a1fe5d20abc2ad9a5e940face2c2cc6cc Mon Sep 17 00:00:00 2001 From: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:51:33 -0500 Subject: [PATCH 05/10] Increase the txHistoryLimit in the transaction controller to 60 (#13743) --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 30a2bdc0b..a9f549bed 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -671,7 +671,7 @@ export default class MetamaskController extends EventEmitter { this.networkController, ), preferencesStore: this.preferencesController.store, - txHistoryLimit: 40, + txHistoryLimit: 60, signTransaction: this.keyringController.signTransaction.bind( this.keyringController, ), From e7bf63a6d6260552f50968815a55e30bd504f8fb Mon Sep 17 00:00:00 2001 From: Olusegun Akintayo Date: Mon, 7 Mar 2022 19:09:03 +0400 Subject: [PATCH 06/10] Fixes an issue where metamask popup is not loading on eth_accounts (#13840) (first time). Signed-off-by: Akintayo A. Olusegun --- .../lib/rpc-method-middleware/handlers/request-accounts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js b/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js index d9cb68f4b..5e071e9a2 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js @@ -72,7 +72,7 @@ async function requestEthereumAccountsHandler( // lock state when they were received. try { locks.add(origin); - await getUnlockPromise(); + await getUnlockPromise(true); res.result = await getAccounts(); end(); } catch (error) { From b879bf135979c45626f7a3e972eb87b3f945c524 Mon Sep 17 00:00:00 2001 From: Daniel <80175477+dan437@users.noreply.github.com> Date: Thu, 10 Mar 2022 04:17:57 +0100 Subject: [PATCH 07/10] Set up the right gasLimit for STX (#13891) * Set up the right gasLimit for STX * Trigger Build Co-authored-by: Dan J Miller --- ui/ducks/swaps/swaps.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 84d26b2a2..02d442951 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -915,6 +915,9 @@ export const signAndSendSwapsSmartTransaction = ({ const smartTransactionFees = await dispatch( fetchSwapsSmartTransactionFees(unsignedTransaction), ); + unsignedTransaction.gas = `0x${decimalToHex( + smartTransactionFees?.gasLimit || 0, + )}`; const uuid = await dispatch( signAndSendSmartTransaction({ unsignedTransaction, From 7931e607cbad1ee7451f2309036459fe6f2161d9 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Thu, 10 Mar 2022 00:00:16 -0330 Subject: [PATCH 08/10] Update changelog for v10.11.1 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64f6c27b4..e8665d9f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [10.11.1] +### Changed +- Fixes GridPlus Lattice bugs by upgrading to `gridplus-sdk` v1.0.0, `eth-lattice-keyring` v0.5.0 and to compatibility with v0.14.0 ([#13834](https://github.com/MetaMask/metamask-extension/pull/13834)) +- Increases transaction data in state logs + - Preserves fewer transactions with shared nonces across networks, decreasing number of old transactions that are not deleted ([#13669](https://github.com/MetaMask/metamask-extension/pull/13669)) + - Increase the number of transactions saved in state logs to 60 ([#13743](https://github.com/MetaMask/metamask-extension/pull/13743)) + +### Fixed +- Ensure that MetaMask popup is shown when a user attempts to connect to a dapp they are already connected to ([#13840](https://github.com/MetaMask/metamask-extension/pull/13840)) +- Submit correct gas limit for Swaps Smart Transactions ([#13891](https://github.com/MetaMask/metamask-extension/pull/13891)) ## [10.11.0] ### Added From 0361aa6a9381c943d656fc042fcfb592c0cb51ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ogle?= Date: Thu, 10 Mar 2022 23:42:35 +0200 Subject: [PATCH 09/10] Use pre-wrap instead of pre for signature content (#13828) --- ui/components/app/signature-request-original/index.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/signature-request-original/index.scss b/ui/components/app/signature-request-original/index.scss index e0e650b74..da6d3512e 100644 --- a/ui/components/app/signature-request-original/index.scss +++ b/ui/components/app/signature-request-original/index.scss @@ -222,7 +222,7 @@ overflow-wrap: break-word; border-bottom: 1px solid #d2d8dd; padding: 6px 18px 15px; - white-space: pre; + white-space: pre-wrap; } &__help-link { From d7713a70cece4eb5aa81a91a8d6ee70f906cd91f Mon Sep 17 00:00:00 2001 From: ryanml Date: Fri, 11 Mar 2022 13:26:37 -0700 Subject: [PATCH 10/10] Revert "Update SRP representation" This reverts commit c3feabf4de3c978ecb25b5a960cbd2c919d9f20c. --- app/scripts/lib/seed-phrase-verifier.js | 8 +- app/scripts/metamask-controller.js | 18 ++-- lavamoat/browserify/beta/policy.json | 5 -- lavamoat/browserify/flask/policy.json | 5 -- lavamoat/browserify/main/policy.json | 5 -- patches/bip39+2.5.0.patch | 99 ---------------------- patches/eth-hd-keyring+3.6.0.patch | 43 ---------- patches/eth-keyring-controller+6.2.1.patch | 37 -------- ui/store/actions.js | 65 ++++++-------- ui/store/actions.test.js | 12 +-- 10 files changed, 42 insertions(+), 255 deletions(-) delete mode 100644 patches/bip39+2.5.0.patch delete mode 100644 patches/eth-hd-keyring+3.6.0.patch delete mode 100644 patches/eth-keyring-controller+6.2.1.patch diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index e1c18c1eb..225a57896 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -11,10 +11,10 @@ const seedPhraseVerifier = { * - The keyring always creates the accounts in the same sequence. * * @param {Array} createdAccounts - The accounts to restore - * @param {Buffer} seedPhrase - The seed words to verify, encoded as a Buffer - * @returns {Promise} + * @param {string} seedWords - The seed words to verify + * @returns {Promise} Promises undefined */ - async verifyAccounts(createdAccounts, seedPhrase) { + async verifyAccounts(createdAccounts, seedWords) { if (!createdAccounts || createdAccounts.length < 1) { throw new Error('No created accounts defined.'); } @@ -22,7 +22,7 @@ const seedPhraseVerifier = { const keyringController = new KeyringController({}); const Keyring = keyringController.getKeyringClassForType('HD Key Tree'); const opts = { - mnemonic: seedPhrase, + mnemonic: seedWords, numberOfAccounts: createdAccounts.length, }; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ef6b9b86e..eb5381a6b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1838,16 +1838,13 @@ export default class MetamaskController extends EventEmitter { * Create a new Vault and restore an existent keyring. * * @param {string} password - * @param {number[]} encodedSeedPhrase - The seed phrase, encoded as an array - * of UTF-8 bytes. + * @param {string} seed */ - async createNewVaultAndRestore(password, encodedSeedPhrase) { + async createNewVaultAndRestore(password, seed) { const releaseLock = await this.createVaultMutex.acquire(); try { let accounts, lastBalance; - const seedPhraseAsBuffer = Buffer.from(encodedSeedPhrase); - const { keyringController } = this; // clear known identities @@ -1868,7 +1865,7 @@ export default class MetamaskController extends EventEmitter { // create new vault const vault = await keyringController.createNewVaultAndRestore( password, - seedPhraseAsBuffer, + seed, ); const ethQuery = new EthQuery(this.provider); @@ -2376,8 +2373,7 @@ export default class MetamaskController extends EventEmitter { * * Called when the first account is created and on unlocking the vault. * - * @returns {Promise} The seed phrase to be confirmed by the user, - * encoded as an array of UTF-8 bytes. + * @returns {Promise} Seed phrase to be confirmed by the user. */ async verifySeedPhrase() { const primaryKeyring = this.keyringController.getKeyringsByType( @@ -2388,7 +2384,7 @@ export default class MetamaskController extends EventEmitter { } const serialized = await primaryKeyring.serialize(); - const seedPhraseAsBuffer = Buffer.from(serialized.mnemonic); + const seedWords = serialized.mnemonic; const accounts = await primaryKeyring.getAccounts(); if (accounts.length < 1) { @@ -2396,8 +2392,8 @@ export default class MetamaskController extends EventEmitter { } try { - await seedPhraseVerifier.verifyAccounts(accounts, seedPhraseAsBuffer); - return Array.from(seedPhraseAsBuffer.values()); + await seedPhraseVerifier.verifyAccounts(accounts, seedWords); + return seedWords; } catch (err) { log.error(err.message); throw err; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 10a1dfc14..86a77a3df 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1178,9 +1178,6 @@ } }, "bip39": { - "globals": { - "console.log": true - }, "packages": { "buffer": true, "create-hash": true, @@ -1895,7 +1892,6 @@ "eth-hd-keyring": { "packages": { "bip39": true, - "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1954,7 +1950,6 @@ "packages": { "bip39": true, "browser-passworder": true, - "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index df637e627..9882d00ed 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1197,9 +1197,6 @@ } }, "bip39": { - "globals": { - "console.log": true - }, "packages": { "buffer": true, "create-hash": true, @@ -1914,7 +1911,6 @@ "eth-hd-keyring": { "packages": { "bip39": true, - "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1973,7 +1969,6 @@ "packages": { "bip39": true, "browser-passworder": true, - "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 10a1dfc14..86a77a3df 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1178,9 +1178,6 @@ } }, "bip39": { - "globals": { - "console.log": true - }, "packages": { "buffer": true, "create-hash": true, @@ -1895,7 +1892,6 @@ "eth-hd-keyring": { "packages": { "bip39": true, - "buffer": true, "eth-sig-util": true, "eth-simple-keyring": true, "ethereumjs-wallet": true @@ -1954,7 +1950,6 @@ "packages": { "bip39": true, "browser-passworder": true, - "buffer": true, "eth-hd-keyring": true, "eth-sig-util": true, "eth-simple-keyring": true, diff --git a/patches/bip39+2.5.0.patch b/patches/bip39+2.5.0.patch deleted file mode 100644 index 2976f3bb2..000000000 --- a/patches/bip39+2.5.0.patch +++ /dev/null @@ -1,99 +0,0 @@ -diff --git a/node_modules/bip39/index.js b/node_modules/bip39/index.js -index aa0f29f..bee8008 100644 ---- a/node_modules/bip39/index.js -+++ b/node_modules/bip39/index.js -@@ -48,7 +48,9 @@ function salt (password) { - } - - function mnemonicToSeed (mnemonic, password) { -- var mnemonicBuffer = Buffer.from(unorm.nfkd(mnemonic), 'utf8') -+ var mnemonicBuffer = typeof mnemonic === 'string' -+ ? Buffer.from(unorm.nfkd(mnemonic), 'utf8') -+ : mnemonic - var saltBuffer = Buffer.from(salt(unorm.nfkd(password)), 'utf8') - - return pbkdf2(mnemonicBuffer, saltBuffer, 2048, 64, 'sha512') -@@ -61,12 +63,28 @@ function mnemonicToSeedHex (mnemonic, password) { - function mnemonicToEntropy (mnemonic, wordlist) { - wordlist = wordlist || DEFAULT_WORDLIST - -- var words = unorm.nfkd(mnemonic).split(' ') -+ var mnemonicAsBuffer = typeof mnemonic === 'string' -+ ? Buffer.from(unorm.nfkd(mnemonic), 'utf8') -+ : mnemonic -+ -+ var words = []; -+ var currentWord = []; -+ for (const byte of mnemonicAsBuffer.values()) { -+ // split at space or \u3000 (ideographic space, for Japanese wordlists) -+ if (byte === 0x20 || byte === 0x3000) { -+ words.push(Buffer.from(currentWord)); -+ currentWord = []; -+ } else { -+ currentWord.push(byte); -+ } -+ } -+ words.push(Buffer.from(currentWord)); -+ - if (words.length % 3 !== 0) throw new Error(INVALID_MNEMONIC) - - // convert word indices to 11 bit binary strings - var bits = words.map(function (word) { -- var index = wordlist.indexOf(word) -+ var index = wordlist.indexOf(word.toString('utf8')) - if (index === -1) throw new Error(INVALID_MNEMONIC) - - return lpad(index.toString(2), '0', 11) -@@ -104,12 +122,41 @@ function entropyToMnemonic (entropy, wordlist) { - - var bits = entropyBits + checksumBits - var chunks = bits.match(/(.{1,11})/g) -- var words = chunks.map(function (binary) { -+ var wordsAsBuffers = chunks.map(function (binary) { - var index = binaryToByte(binary) -- return wordlist[index] -+ return Buffer.from(wordlist[index], 'utf8') - }) - -- return wordlist === JAPANESE_WORDLIST ? words.join('\u3000') : words.join(' ') -+ var bufferSize = wordsAsBuffers.reduce(function (bufferSize, wordAsBuffer, i) { -+ var shouldAddSeparator = i < wordsAsBuffers.length - 1 -+ return ( -+ bufferSize + -+ wordAsBuffer.length + -+ (shouldAddSeparator ? 1 : 0) -+ ) -+ }, 0) -+ var separator = wordlist === JAPANESE_WORDLIST ? '\u3000' : ' ' -+ var result = wordsAsBuffers.reduce(function (result, wordAsBuffer, i) { -+ var shouldAddSeparator = i < wordsAsBuffers.length - 1 -+ result.workingBuffer.set(wordAsBuffer, result.offset) -+ if (shouldAddSeparator) { -+ result.workingBuffer.write( -+ separator, -+ result.offset + wordAsBuffer.length, -+ separator.length, -+ 'utf8' -+ ) -+ } -+ return { -+ workingBuffer: result.workingBuffer, -+ offset: ( -+ result.offset + -+ wordAsBuffer.length + -+ (shouldAddSeparator ? 1 : 0) -+ ) -+ } -+ }, { workingBuffer: Buffer.alloc(bufferSize), offset: 0 }) -+ return result.workingBuffer; - } - - function generateMnemonic (strength, rng, wordlist) { -@@ -124,6 +171,7 @@ function validateMnemonic (mnemonic, wordlist) { - try { - mnemonicToEntropy(mnemonic, wordlist) - } catch (e) { -+ console.log('could not validate mnemonic', e) - return false - } - diff --git a/patches/eth-hd-keyring+3.6.0.patch b/patches/eth-hd-keyring+3.6.0.patch deleted file mode 100644 index 211cb89dd..000000000 --- a/patches/eth-hd-keyring+3.6.0.patch +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/node_modules/eth-hd-keyring/index.js b/node_modules/eth-hd-keyring/index.js -index 19d1d7f..350d6b8 100644 ---- a/node_modules/eth-hd-keyring/index.js -+++ b/node_modules/eth-hd-keyring/index.js -@@ -17,8 +17,11 @@ class HdKeyring extends SimpleKeyring { - } - - serialize () { -+ const mnemonicAsBuffer = typeof this.mnemonic === 'string' -+ ? Buffer.from(this.mnemonic, 'utf8') -+ : this.mnemonic - return Promise.resolve({ -- mnemonic: this.mnemonic, -+ mnemonic: Array.from(mnemonicAsBuffer.values()), - numberOfAccounts: this.wallets.length, - hdPath: this.hdPath, - }) -@@ -69,9 +72,22 @@ class HdKeyring extends SimpleKeyring { - - /* PRIVATE METHODS */ - -- _initFromMnemonic (mnemonic) { -- this.mnemonic = mnemonic -- const seed = bip39.mnemonicToSeed(mnemonic) -+ /** -+ * Sets appropriate properties for the keyring based on the given -+ * BIP39-compliant mnemonic. -+ * -+ * @param {string|Array|Buffer} mnemonic - A seed phrase represented -+ * as a string, an array of UTF-8 bytes, or a Buffer. -+ */ -+ _initFromMnemonic(mnemonic) { -+ if (typeof mnemonic === 'string') { -+ this.mnemonic = Buffer.from(mnemonic, 'utf8') -+ } else if (Array.isArray(mnemonic)) { -+ this.mnemonic = Buffer.from(mnemonic) -+ } else { -+ this.mnemonic = mnemonic -+ } -+ const seed = bip39.mnemonicToSeed(this.mnemonic) - this.hdWallet = hdkey.fromMasterSeed(seed) - this.root = this.hdWallet.derivePath(this.hdPath) - } diff --git a/patches/eth-keyring-controller+6.2.1.patch b/patches/eth-keyring-controller+6.2.1.patch deleted file mode 100644 index aec0c7168..000000000 --- a/patches/eth-keyring-controller+6.2.1.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/node_modules/eth-keyring-controller/index.js b/node_modules/eth-keyring-controller/index.js -index 250ab98..38615aa 100644 ---- a/node_modules/eth-keyring-controller/index.js -+++ b/node_modules/eth-keyring-controller/index.js -@@ -84,15 +84,20 @@ class KeyringController extends EventEmitter { - * - * @emits KeyringController#unlock - * @param {string} password - The password to encrypt the vault with -- * @param {string} seed - The BIP44-compliant seed phrase. -+ * @param {string|Array} seedPhrase - The BIP39-compliant seed phrase, -+ * either as a string or an array of UTF-8 bytes that represent the string. - * @returns {Promise} A Promise that resolves to the state. - */ -- createNewVaultAndRestore (password, seed) { -+ createNewVaultAndRestore(password, seedPhrase) { -+ const seedPhraseAsBuffer = typeof seedPhrase === 'string' -+ ? Buffer.from(seedPhrase, 'utf8') -+ : Buffer.from(seedPhrase) -+ - if (typeof password !== 'string') { - return Promise.reject(new Error('Password must be text.')) - } - -- if (!bip39.validateMnemonic(seed)) { -+ if (!bip39.validateMnemonic(seedPhraseAsBuffer)) { - return Promise.reject(new Error('Seed phrase is invalid.')) - } - -@@ -101,7 +106,7 @@ class KeyringController extends EventEmitter { - return this.persistAllKeyrings(password) - .then(() => { - return this.addNewKeyring('HD Key Tree', { -- mnemonic: seed, -+ mnemonic: seedPhraseAsBuffer, - numberOfAccounts: 1, - }) - }) diff --git a/ui/store/actions.js b/ui/store/actions.js index 5925120b0..6461f29da 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -80,39 +80,20 @@ export function tryUnlockMetamask(password) { }; } -/** - * Adds a new account where all data is encrypted using the given password and - * where all addresses are generated from a given seed phrase. - * - * @param {string} password - The password. - * @param {string} seedPhrase - The seed phrase. - * @returns {Object} The updated state of the keyring controller. - */ -export function createNewVaultAndRestore(password, seedPhrase) { +export function createNewVaultAndRestore(password, seed) { return (dispatch) => { dispatch(showLoadingIndication()); log.debug(`background.createNewVaultAndRestore`); - - // Encode the secret recovery phrase as an array of integers so that it is - // serialized as JSON properly. - const encodedSeedPhrase = Array.from( - Buffer.from(seedPhrase, 'utf8').values(), - ); - let vault; return new Promise((resolve, reject) => { - background.createNewVaultAndRestore( - password, - encodedSeedPhrase, - (err, _vault) => { - if (err) { - reject(err); - return; - } - vault = _vault; - resolve(); - }, - ); + background.createNewVaultAndRestore(password, seed, (err, _vault) => { + if (err) { + reject(err); + return; + } + vault = _vault; + resolve(); + }); }) .then(() => dispatch(unMarkPasswordForgotten())) .then(() => { @@ -134,8 +115,8 @@ export function createNewVaultAndGetSeedPhrase(password) { try { await createNewVault(password); - const seedPhrase = await verifySeedPhrase(); - return seedPhrase; + const seedWords = await verifySeedPhrase(); + return seedWords; } catch (error) { dispatch(displayWarning(error.message)); throw new Error(error.message); @@ -151,9 +132,9 @@ export function unlockAndGetSeedPhrase(password) { try { await submitPassword(password); - const seedPhrase = await verifySeedPhrase(); + const seedWords = await verifySeedPhrase(); await forceUpdateMetamaskState(dispatch); - return seedPhrase; + return seedWords; } catch (error) { dispatch(displayWarning(error.message)); throw new Error(error.message); @@ -202,9 +183,17 @@ export function verifyPassword(password) { }); } -export async function verifySeedPhrase() { - const encodedSeedPhrase = await promisifiedBackground.verifySeedPhrase(); - return Buffer.from(encodedSeedPhrase).toString('utf8'); +export function verifySeedPhrase() { + return new Promise((resolve, reject) => { + background.verifySeedPhrase((error, seedWords) => { + if (error) { + reject(error); + return; + } + + resolve(seedWords); + }); + }); } export function requestRevealSeedWords(password) { @@ -214,11 +203,11 @@ export function requestRevealSeedWords(password) { try { await verifyPassword(password); - const seedPhrase = await verifySeedPhrase(); - return seedPhrase; + const seedWords = await verifySeedPhrase(); + return seedWords; } catch (error) { dispatch(displayWarning(error.message)); - throw error; + throw new Error(error.message); } finally { dispatch(hideLoadingIndication()); } diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 727835ecf..0866713b4 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -111,9 +111,7 @@ describe('Actions', () => { actions._setBackgroundConnection(background); - await store.dispatch( - actions.createNewVaultAndRestore('password', 'test'), - ); + await store.dispatch(actions.createNewVaultAndRestore()); expect(createNewVaultAndRestore.callCount).toStrictEqual(1); }); @@ -136,9 +134,7 @@ describe('Actions', () => { { type: 'HIDE_LOADING_INDICATION' }, ]; - await store.dispatch( - actions.createNewVaultAndRestore('password', 'test'), - ); + await store.dispatch(actions.createNewVaultAndRestore()); expect(store.getActions()).toStrictEqual(expectedActions); }); @@ -159,7 +155,7 @@ describe('Actions', () => { ]; await expect( - store.dispatch(actions.createNewVaultAndRestore('password', 'test')), + store.dispatch(actions.createNewVaultAndRestore()), ).rejects.toThrow('error'); expect(store.getActions()).toStrictEqual(expectedActions); @@ -178,7 +174,7 @@ describe('Actions', () => { cb(), ); const verifySeedPhrase = background.verifySeedPhrase.callsFake((cb) => - cb(null, Array.from(Buffer.from('test').values())), + cb(), ); actions._setBackgroundConnection(background);