From 023b5c84c4d3427973770f2b7d2c18b3ac61f12d Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 22 Dec 2017 10:15:38 -0800 Subject: [PATCH 01/47] deps - eth-json-rpc-filters@1.2.5 fix case sensitive address check in filters --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7184e3ea8..b47f45fd4 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "eth-block-tracker": "^2.2.0", "eth-contract-metadata": "^1.1.4", "eth-hd-keyring": "^1.2.1", - "eth-json-rpc-filters": "^1.2.4", + "eth-json-rpc-filters": "^1.2.5", "eth-json-rpc-infura": "^1.0.2", "eth-keyring-controller": "^2.1.2", "eth-phishing-detect": "^1.1.4", From 20aa135ad87231694ead2fe65a3124b719b8fc4d Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 3 Jan 2018 16:06:46 -0800 Subject: [PATCH 02/47] Add fix for infinite spinner for incorrect seed phrase. --- app/scripts/metamask-controller.js | 13 +++++++++---- ui/app/keychains/hd/restore-vault.js | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 23f2a1598..8d8c1d094 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -513,10 +513,15 @@ module.exports = class MetamaskController extends EventEmitter { async createNewVaultAndRestore (password, seed) { const release = await this.createVaultMutex.acquire() - const vault = await this.keyringController.createNewVaultAndRestore(password, seed) - this.selectFirstIdentity(vault) - release() - return vault + try { + const vault = await this.keyringController.createNewVaultAndRestore(password, seed) + this.selectFirstIdentity(vault) + release() + return vault + } catch (err) { + release() + throw err + } } selectFirstIdentity (vault) { diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index 06e51d9b3..24b37a83d 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -149,4 +149,8 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { this.warning = null this.props.dispatch(actions.displayWarning(this.warning)) this.props.dispatch(actions.createNewVaultAndRestore(password, seed)) + .catch((err) => { + log.error(err.message) + }) + } From 4b63ec8f1daaba11e66322fbdfb045ba1ea5319d Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 3 Jan 2018 16:44:14 -0800 Subject: [PATCH 03/47] Test for failure of the async methods. --- test/unit/metamask-controller-test.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index fd420a70f..873b8d17d 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -39,17 +39,19 @@ describe('MetaMaskController', function () { beforeEach(function () { sinon.spy(metamaskController.keyringController, 'createNewVaultAndKeychain') + sinon.spy(metamaskController.keyringController, 'createNewVaultAndRestore') }) afterEach(function () { metamaskController.keyringController.createNewVaultAndKeychain.restore() + metamaskController.keyringController.createNewVaultAndRestore.restore() }) describe('#createNewVaultAndKeychain', function () { it('can only create new vault on keyringController once', async function () { - const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity') + const password = 'a-fake-password' const first = await metamaskController.createNewVaultAndKeychain(password) @@ -60,6 +62,22 @@ describe('MetaMaskController', function () { selectStub.reset() }) }) + + describe('#createNewVaultAndRestore', function () { + it('should be able to call newVaultAndRestore despite a mistake.', async function () { + // const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity') + + const password = 'what-what-what' + const wrongSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadiu' + const rightSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + const first = await metamaskController.createNewVaultAndRestore(password, wrongSeed) + .catch((e) => { + return + }) + const second = await metamaskController.createNewVaultAndRestore(password, rightSeed) + + assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice) + }) + }) }) }) - From a6760fca256f7e988a01482a1d83e01a875e0873 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 4 Jan 2018 06:40:38 -0600 Subject: [PATCH 04/47] Update vinyl-buffer to version 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 871ed204e..1d76585b3 100644 --- a/package.json +++ b/package.json @@ -216,7 +216,7 @@ "tape": "^4.5.1", "testem": "^1.10.3", "uglifyify": "^4.0.2", - "vinyl-buffer": "^1.0.0", + "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", "watchify": "^3.9.0" }, From 5312ed9a20d06339c98a9e488cdede405f3c9c49 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Thu, 4 Jan 2018 17:10:40 +0300 Subject: [PATCH 05/47] info.js Remove width element to fix email layout --- ui/app/info.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/info.js b/ui/app/info.js index 24c211c1f..110678a46 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -138,7 +138,6 @@ InfoScreen.prototype.render = function () { h('div.fa.fa-envelope', [ h('a.info', { target: '_blank', - style: { width: '85vw' }, href: 'mailto:help@metamask.io?subject=Feedback', }, 'Email us!'), ]), From dcd589788e58f4d0b02fd6bf0df30a917f06ae1b Mon Sep 17 00:00:00 2001 From: wbt Date: Thu, 4 Jan 2018 14:31:49 -0500 Subject: [PATCH 06/47] Cut statement about test network default Removing inaccurate statement that default is test network, because most users now connect to the main network by default. See also https://github.com/MetaMask/metamask-extension/commit/f6e551ef5f3773cf5637c2ae0e11fdeb5f40645b --- notices/archive/notice_2.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/notices/archive/notice_2.md b/notices/archive/notice_2.md index 76e9bd8fb..4cea97b4f 100644 --- a/notices/archive/notice_2.md +++ b/notices/archive/notice_2.md @@ -4,5 +4,3 @@ When you log in to MetaMask, your current account is visible to every new site y For your privacy, for now, please sign out of MetaMask when you're done using a site. -Also, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu. - From 7d2edbc18b5c52a865ef26cad9db8c4cc2190a7a Mon Sep 17 00:00:00 2001 From: wbt Date: Thu, 4 Jan 2018 14:31:52 -0500 Subject: [PATCH 07/47] Cut statement about test network default Removing inaccurate statement that default is test network, because most users now connect to the main network by default. See also https://github.com/MetaMask/metamask-extension/commit/f6e551ef5f3773cf5637c2ae0e11fdeb5f40645b --- notices/notices.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notices/notices.json b/notices/notices.json index c1fe64f4e..ddadea1b0 100644 --- a/notices/notices.json +++ b/notices/notices.json @@ -1 +1 @@ -[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at legal-opt@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2},{"read":false,"date":"Tue Nov 28 2017","title":"Seed Phrase Alert","firstVersion":"<=3.12.0","body":"Please take a moment to [back up your seed phrase again](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up).\n\nMetaMask has become aware of a previous issue where a very small number of users were shown the wrong seed phrase to back up. The only way to protect yourself from this issue, is to back up your seed phrase again now.\n\nYou can follow the guide at this link:\n\n[https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up)\n\nWe have fixed the known issue, but will be issuing ongoing bug bounties to help prevent this kind of problem in the future.\n\nFor more information on this issue, [see this blog post](https://medium.com/metamask/seed-phrase-issue-bounty-awarded-e1986e811021)","id":3}] +[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at legal-opt@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\n","id":2},{"read":false,"date":"Tue Nov 28 2017","title":"Seed Phrase Alert","firstVersion":"<=3.12.0","body":"Please take a moment to [back up your seed phrase again](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up).\n\nMetaMask has become aware of a previous issue where a very small number of users were shown the wrong seed phrase to back up. The only way to protect yourself from this issue, is to back up your seed phrase again now.\n\nYou can follow the guide at this link:\n\n[https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up](https://support.metamask.io/kb/article/28-abbu-always-be-backed-up-how-to-make-sure-your-12-word-metamask-seed-phrase-is-backed-up)\n\nWe have fixed the known issue, but will be issuing ongoing bug bounties to help prevent this kind of problem in the future.\n\nFor more information on this issue, [see this blog post](https://medium.com/metamask/seed-phrase-issue-bounty-awarded-e1986e811021)","id":3}] From 571f6723a64f28f22b7a7439d1f16bcbc9345320 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 5 Jan 2018 21:24:10 -0800 Subject: [PATCH 08/47] Add test for better gas estimation --- test/unit/metamask-controller-test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index fd420a70f..293a45eef 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -3,6 +3,8 @@ const sinon = require('sinon') const clone = require('clone') const MetaMaskController = require('../../app/scripts/metamask-controller') const firstTimeState = require('../../app/scripts/first-time-state') +const BN = require('ethereumjs-util').BN +const GWEI_BN = new BN('1000000000') describe('MetaMaskController', function () { const noop = () => {} @@ -45,6 +47,29 @@ describe('MetaMaskController', function () { metamaskController.keyringController.createNewVaultAndKeychain.restore() }) + describe('#getGasPrice', function () { + it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () { + const realRecentBlocksController = metamaskController.recentBlocksController + metamaskController.recentBlocksController = { + store: { + getState: () => { + return { + recentBlocks: [ + { transactions: [ new BN('50000000000'), new BN('100000000000') ] }, + { transactions: [ new BN('60000000000'), new BN('100000000000') ] }, + ] + } + } + } + } + + const gasPrice = metamaskController.getGasPrice() + assert.equal(gasPrice, 50, 'accurately estimates 50th percentile accepted gas price') + + metamaskController.recentBlocksController = realRecentBlocksController + }) + }) + describe('#createNewVaultAndKeychain', function () { it('can only create new vault on keyringController once', async function () { From 4bca98d588869fb58796a6b2f29dca48605ceeba Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 5 Jan 2018 21:24:20 -0800 Subject: [PATCH 09/47] Derive gas price estimate from previous transactions Return the 50th percentile lowest gas price of the previous 20 blocks. --- app/scripts/controllers/blacklist.js | 1 + app/scripts/controllers/transactions.js | 3 ++- app/scripts/metamask-controller.js | 21 ++++++++++++++++++++- package.json | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js index dd671943f..33c31dab9 100644 --- a/app/scripts/controllers/blacklist.js +++ b/app/scripts/controllers/blacklist.js @@ -57,3 +57,4 @@ class BlacklistController { } module.exports = BlacklistController + diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 7c7efb84d..be7e7221f 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -32,6 +32,7 @@ module.exports = class TransactionController extends EventEmitter { this.provider = opts.provider this.blockTracker = opts.blockTracker this.signEthTx = opts.signTransaction + this.getGasPrice = opts.getGasPrice this.memStore = new ObservableStore({}) this.query = new EthQuery(this.provider) @@ -179,7 +180,7 @@ module.exports = class TransactionController extends EventEmitter { // ensure value txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) txMeta.nonceSpecified = Boolean(txParams.nonce) - const gasPrice = txParams.gasPrice || await this.query.gasPrice() + const gasPrice = txParams.gasPrice || this.getGasPrice() txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' // set gasLimit diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 23f2a1598..7ffa653e4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -35,13 +35,15 @@ const accountImporter = require('./account-import-strategies') const getBuyEthUrl = require('./lib/buy-eth-url') const Mutex = require('await-semaphore').Mutex const version = require('../manifest.json').version +const BN = require('ethereumjs-util').BN +const GWEI_BN = new BN('1000000000') +const percentile = require('percentile') module.exports = class MetamaskController extends EventEmitter { constructor (opts) { super() - this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) this.opts = opts @@ -139,6 +141,7 @@ module.exports = class MetamaskController extends EventEmitter { provider: this.provider, blockTracker: this.blockTracker, ethQuery: this.ethQuery, + getGasPrice: this.getGasPrice.bind(this), }) this.txController.on('newUnapprovedTx', opts.showUnapprovedTx.bind(opts)) @@ -484,6 +487,22 @@ module.exports = class MetamaskController extends EventEmitter { this.emit('update', this.getState()) } + getGasPrice () { + const { recentBlocksController } = this + console.dir(recentBlocksController) + const { recentBlocks } = recentBlocksController.store.getState() + console.dir(recentBlocks) + const lowestPrices = recentBlocks.map((block) => { + return block.transactions + .sort((a, b) => { + return a.gt(b) ? 1 : -1 + })[0] + }) + .map(number => number.div(GWEI_BN).toNumber()) + console.dir({ lowestPrices }) + return percentile(50, lowestPrices) + } + // // Vault Management // diff --git a/package.json b/package.json index 871ed204e..07ef76b0a 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "obj-multiplex": "^1.0.0", "obs-store": "^3.0.0", "once": "^1.3.3", + "percentile": "^1.2.0", "ping-pong-stream": "^1.0.0", "pojo-migrator": "^2.1.0", "polyfill-crypto.getrandomvalues": "^1.0.0", From 121596bfb4269ca0c2cf11b600dbb1884885b943 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 5 Jan 2018 21:25:28 -0800 Subject: [PATCH 10/47] Bump changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc96203be..dd9379ba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- Improve gas price suggestion to be closer to the lowest that will be accepted. - Throw an error if a application tries to submit a tx whose value is a decimal, and inform that it should be in wei. - Fix bug that prevented updating custom token details. - No longer mark long-pending transactions as failed, since we now have button to retry with higher gas. From 447682d1fbb07309c696217fba3839455721d003 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 5 Jan 2018 21:34:35 -0800 Subject: [PATCH 11/47] Linted --- app/scripts/metamask-controller.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 7ffa653e4..79ad2ff05 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -489,9 +489,7 @@ module.exports = class MetamaskController extends EventEmitter { getGasPrice () { const { recentBlocksController } = this - console.dir(recentBlocksController) const { recentBlocks } = recentBlocksController.store.getState() - console.dir(recentBlocks) const lowestPrices = recentBlocks.map((block) => { return block.transactions .sort((a, b) => { @@ -499,7 +497,6 @@ module.exports = class MetamaskController extends EventEmitter { })[0] }) .map(number => number.div(GWEI_BN).toNumber()) - console.dir({ lowestPrices }) return percentile(50, lowestPrices) } From aec24ec81e4785ceea93375d562458f62be69266 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 5 Jan 2018 22:08:03 -0800 Subject: [PATCH 12/47] Fix feature to work --- app/scripts/controllers/transactions.js | 3 ++- app/scripts/metamask-controller.js | 11 +++++++++-- test/unit/metamask-controller-test.js | 8 +++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index be7e7221f..469deb670 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -180,7 +180,8 @@ module.exports = class TransactionController extends EventEmitter { // ensure value txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) txMeta.nonceSpecified = Boolean(txParams.nonce) - const gasPrice = txParams.gasPrice || this.getGasPrice() + const gasPrice = txParams.gasPrice || this.getGasPrice ? this.getGasPrice() + : await this.query.gasPrice() txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' // set gasLimit diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 79ad2ff05..1b13f6567 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -491,13 +491,20 @@ module.exports = class MetamaskController extends EventEmitter { const { recentBlocksController } = this const { recentBlocks } = recentBlocksController.store.getState() const lowestPrices = recentBlocks.map((block) => { - return block.transactions + if (!block.gasPrices) { + return new BN(0) + } + return block.gasPrices + .map(hexPrefix => hexPrefix.substr(2)) + .map(hex => new BN(hex, 16)) .sort((a, b) => { return a.gt(b) ? 1 : -1 })[0] }) .map(number => number.div(GWEI_BN).toNumber()) - return percentile(50, lowestPrices) + const percentileNum = percentile(50, lowestPrices) + const percentileNumBn = new BN(percentileNum) + return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) } // diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index 293a45eef..3deb5a1c7 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -55,8 +55,10 @@ describe('MetaMaskController', function () { getState: () => { return { recentBlocks: [ - { transactions: [ new BN('50000000000'), new BN('100000000000') ] }, - { transactions: [ new BN('60000000000'), new BN('100000000000') ] }, + { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, + { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, + { gasPrices: [ '0x174876e800', '0x174876e800' ]}, + { gasPrices: [ '0x174876e800', '0x174876e800' ]}, ] } } @@ -64,7 +66,7 @@ describe('MetaMaskController', function () { } const gasPrice = metamaskController.getGasPrice() - assert.equal(gasPrice, 50, 'accurately estimates 50th percentile accepted gas price') + assert.equal(gasPrice, '0x3b9aca00', 'accurately estimates 50th percentile accepted gas price') metamaskController.recentBlocksController = realRecentBlocksController }) From 39b700bf87f213d2fb06dcde85f4e6173a6ce70c Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 8 Jan 2018 03:16:20 -0800 Subject: [PATCH 13/47] Account for 0x/empty string address and contract creation --- CHANGELOG.md | 1 + app/scripts/lib/tx-gas-utils.js | 11 +++++++++++ test/unit/tx-gas-util-test.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 test/unit/tx-gas-util-test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index dc96203be..568d1b7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. - Throw an error if a application tries to submit a tx whose value is a decimal, and inform that it should be in wei. - Fix bug that prevented updating custom token details. - No longer mark long-pending transactions as failed, since we now have button to retry with higher gas. diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index ccf8bb1b1..5e49fdb22 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -81,6 +81,7 @@ module.exports = class txProvideUtil { } async validateTxParams (txParams) { + this.validateRecipient(txParams) if ('value' in txParams) { const value = txParams.value.toString() if (value.includes('-')) { @@ -92,4 +93,14 @@ module.exports = class txProvideUtil { } } } + validateRecipient (txParams) { + if (txParams.to === '0x') { + if (txParams.data) { + delete txParams.to + } else { + throw new Error('Invalid recipient address') + } + } + return txParams + } } diff --git a/test/unit/tx-gas-util-test.js b/test/unit/tx-gas-util-test.js new file mode 100644 index 000000000..ccef31359 --- /dev/null +++ b/test/unit/tx-gas-util-test.js @@ -0,0 +1,32 @@ +const assert = require('assert') +const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils') +const { createStubedProvider } = require('../stub/provider') + +describe('Tx Gas Util', function () { + let txGasUtil, provider, providerResultStub + beforeEach(function () { + providerResultStub = {} + provider = createStubedProvider(providerResultStub) + txGasUtil = new TxGasUtils({ + provider, + }) + }) + + it('removes recipient for txParams with 0x when contract data is provided', function () { + const zeroRecipientandDataTxParams = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0x', + data: 'bytecode', + } + const sanitizedTxParams = txGasUtil.validateRecipient(zeroRecipientandDataTxParams) + assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x') + }) + + it('should error when recipient is 0x', function () { + const zeroRecipientTxParams = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0x', + } + assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address') + }) +}) From 52bb711fa99611678d2a2e9b4098f9a6ece8adda Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 8 Jan 2018 11:26:35 -0800 Subject: [PATCH 14/47] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfcd0d1b9..49d92cd1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fix bug that prevented updating custom token details. - No longer mark long-pending transactions as failed, since we now have button to retry with higher gas. - Fix rounding error when specifying an ether amount that has too much precision. +- Fix bug where incorrectly inputting seed phrase would prevent any future attempts from succeeding. ## 3.13.3 2017-12-14 From 9a8670309d2791b212d04ee795f70040cc5f40fc Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 8 Jan 2018 13:19:18 -0800 Subject: [PATCH 15/47] bugfix - transactions controller - breakout logic and fix order of operations bug --- app/scripts/controllers/transactions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 469deb670..ded9739a8 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -180,8 +180,10 @@ module.exports = class TransactionController extends EventEmitter { // ensure value txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) txMeta.nonceSpecified = Boolean(txParams.nonce) - const gasPrice = txParams.gasPrice || this.getGasPrice ? this.getGasPrice() - : await this.query.gasPrice() + let gasPrice = txParams.gasPrice + if (!gasPrice) { + gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice() + } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' // set gasLimit From 63ae7fb589b43d2af87f31d51f5b5f96669dabe0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 8 Jan 2018 13:19:18 -0800 Subject: [PATCH 16/47] bugfix - transactions controller - breakout logic and fix order of operations bug --- app/scripts/controllers/transactions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 469deb670..ded9739a8 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -180,8 +180,10 @@ module.exports = class TransactionController extends EventEmitter { // ensure value txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) txMeta.nonceSpecified = Boolean(txParams.nonce) - const gasPrice = txParams.gasPrice || this.getGasPrice ? this.getGasPrice() - : await this.query.gasPrice() + let gasPrice = txParams.gasPrice + if (!gasPrice) { + gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice() + } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' // set gasLimit From ab7701efb35f39e73fcccc2110a754384e23d695 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 8 Jan 2018 14:57:57 -0800 Subject: [PATCH 17/47] provider - infura - use infura REST api --- app/scripts/controllers/network.js | 7 +++++-- package.json | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js index 377ba6eca..a1db8946a 100644 --- a/app/scripts/controllers/network.js +++ b/app/scripts/controllers/network.js @@ -1,6 +1,7 @@ const assert = require('assert') const EventEmitter = require('events') const createMetamaskProvider = require('web3-provider-engine/zero.js') +const SubproviderFromProvider = require('web3-provider-engine/subproviders/web3.js') const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider') const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') @@ -133,15 +134,17 @@ module.exports = class NetworkController extends EventEmitter { _configureInfuraProvider (opts) { log.info('_configureInfuraProvider', opts) - const blockTrackerProvider = createInfuraProvider({ + const infuraProvider = createInfuraProvider({ network: opts.type, }) + const infuraSubprovider = new SubproviderFromProvider(infuraProvider) const providerParams = extend(this._baseProviderParams, { rpcUrl: opts.rpcUrl, engineParams: { pollingInterval: 8000, - blockTrackerProvider, + blockTrackerProvider: infuraProvider, }, + dataSubprovider: infuraSubprovider, }) const provider = createMetamaskProvider(providerParams) this._setProvider(provider) diff --git a/package.json b/package.json index df532b01e..71a3268a4 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "eth-contract-metadata": "^1.1.4", "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.4", - "eth-json-rpc-infura": "^1.0.2", + "eth-json-rpc-infura": "^2.0.3", "eth-keyring-controller": "^2.1.2", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", @@ -154,7 +154,7 @@ "valid-url": "^1.0.9", "vreme": "^3.0.2", "web3": "^0.20.1", - "web3-provider-engine": "^13.4.0", + "web3-provider-engine": "^13.5.0", "web3-stream-provider": "^3.0.1", "xtend": "^4.0.1" }, From 34826d18aa0acbe06d5c27013f249fa7c664d072 Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Mon, 8 Jan 2018 14:58:38 -0800 Subject: [PATCH 18/47] Default to estimating 1 gwei for empty blocks. To avoid estimating 0 gwei on low-traffic private networks. --- 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 66738db51..aa2dddf3d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -492,7 +492,7 @@ module.exports = class MetamaskController extends EventEmitter { const { recentBlocks } = recentBlocksController.store.getState() const lowestPrices = recentBlocks.map((block) => { if (!block.gasPrices) { - return new BN(0) + return GWEI_BN } return block.gasPrices .map(hexPrefix => hexPrefix.substr(2)) From 0275231e13d49a9b71b85af389d2a9850229eacb Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 8 Jan 2018 15:08:05 -0800 Subject: [PATCH 19/47] Default gas estimate to 1 gwei for networks with no block activity --- app/scripts/metamask-controller.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 66738db51..9462af494 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -490,6 +490,12 @@ module.exports = class MetamaskController extends EventEmitter { getGasPrice () { const { recentBlocksController } = this const { recentBlocks } = recentBlocksController.store.getState() + + // Return 1 gwei if no blocks have been observed: + if (recentBlocks.length === 0) { + return '0x' + GWEI_BN.toString(16) + } + const lowestPrices = recentBlocks.map((block) => { if (!block.gasPrices) { return new BN(0) From 943befef91cd725579c4bf4e7024734f02ef98f5 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 8 Jan 2018 15:16:08 -0800 Subject: [PATCH 20/47] Add test for gas estimate default --- test/unit/metamask-controller-test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index 9ec7cd0af..3fc7f9a98 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -72,6 +72,25 @@ describe('MetaMaskController', function () { metamaskController.recentBlocksController = realRecentBlocksController }) + + it('gives the 1 gwei price if no blocks have been seen.', async function () { + const realRecentBlocksController = metamaskController.recentBlocksController + metamaskController.recentBlocksController = { + store: { + getState: () => { + return { + recentBlocks: [] + } + } + } + } + + const gasPrice = metamaskController.getGasPrice() + assert.equal(gasPrice, '0x' + GWEI_BN.toString(16), 'defaults to 1 gwei') + + metamaskController.recentBlocksController = realRecentBlocksController + }) + }) describe('#createNewVaultAndKeychain', function () { From d829fb91b889f35a3e1043dec56d8f0ff6faa09d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 8 Jan 2018 15:41:57 -0800 Subject: [PATCH 21/47] Default to 1 gwei for empty blocks --- app/scripts/metamask-controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 9462af494..f62b5e5cd 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -497,8 +497,8 @@ module.exports = class MetamaskController extends EventEmitter { } const lowestPrices = recentBlocks.map((block) => { - if (!block.gasPrices) { - return new BN(0) + if (!block.gasPrices || block.gasPrices.length < 1) { + return GWEI_BN } return block.gasPrices .map(hexPrefix => hexPrefix.substr(2)) @@ -508,6 +508,7 @@ module.exports = class MetamaskController extends EventEmitter { })[0] }) .map(number => number.div(GWEI_BN).toNumber()) + const percentileNum = percentile(50, lowestPrices) const percentileNumBn = new BN(percentileNum) return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) From cc49e637dd85f1946e606634a5fc8c126c7cc04d Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 9 Jan 2018 08:18:58 -0800 Subject: [PATCH 22/47] deps - bump eth-json-infura --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 71a3268a4..3b64c14c1 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "eth-contract-metadata": "^1.1.4", "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.4", - "eth-json-rpc-infura": "^2.0.3", + "eth-json-rpc-infura": "^2.0.5", "eth-keyring-controller": "^2.1.2", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", From 330ae020287f4178b493619ede17ee0b1b67b7af Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 9 Jan 2018 10:13:25 -0800 Subject: [PATCH 23/47] Version 3.13.4 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cacc4b522..4b4218210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 3.13.4 2018-1-9 + - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. - Improve gas price suggestion to be closer to the lowest that will be accepted. - Throw an error if a application tries to submit a tx whose value is a decimal, and inform that it should be in wei. diff --git a/app/manifest.json b/app/manifest.json index d6c57d681..df7b1f1aa 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.13.3", + "version": "3.13.4", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From e5b34b3d044e8c414b2a390c302dd01ce6ed45e4 Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Tue, 9 Jan 2018 14:09:29 -0800 Subject: [PATCH 24/47] Update support links for helpscout --- ui/app/info.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/info.js b/ui/app/info.js index 110678a46..2e59db890 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -103,9 +103,9 @@ InfoScreen.prototype.render = function () { [ h('div.fa.fa-support', [ h('a.info', { - href: 'https://support.metamask.io', + href: 'http://metamask.helpscoutdocs.com/', target: '_blank', - }, 'Visit our Support Center'), + }, 'Visit our Knowledge Base'), ]), h('div', [ @@ -138,7 +138,7 @@ InfoScreen.prototype.render = function () { h('div.fa.fa-envelope', [ h('a.info', { target: '_blank', - href: 'mailto:help@metamask.io?subject=Feedback', + href: 'mailto:support@metamask.io?subject=MetaMask Support', }, 'Email us!'), ]), ]), From 9c42216c4e6059af131820fbd12e3b2df2d8edec Mon Sep 17 00:00:00 2001 From: x86kernel Date: Wed, 10 Jan 2018 21:06:20 +0900 Subject: [PATCH 25/47] ci(ko/messages.json): add korean localization file --- app/_locales/ko/messages.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 app/_locales/ko/messages.json diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json new file mode 100644 index 000000000..c58af4b80 --- /dev/null +++ b/app/_locales/ko/messages.json @@ -0,0 +1,10 @@ +{ + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "appDescription": { + "message": "이더리움 계좌 관리", + "description": "The description of the application" + } +} From 9a603606a6d4276ee07d412bc0ad9de3baa6b722 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 10 Jan 2018 13:51:25 -0800 Subject: [PATCH 26/47] deps - gulp in dev deps only --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index df532b01e..b679ab95f 100644 --- a/package.json +++ b/package.json @@ -93,8 +93,6 @@ "extensionizer": "^1.0.0", "fast-json-patch": "^2.0.4", "fast-levenshtein": "^2.0.6", - "gulp": "github:gulpjs/gulp#4.0", - "gulp-eslint": "^4.0.0", "hat": "0.0.3", "human-standard-token-abi": "^1.0.2", "idb-global": "^2.1.0", @@ -190,6 +188,7 @@ "gulp-util": "^3.0.7", "gulp-watch": "^4.3.5", "gulp-zip": "^4.0.0", + "gulp-eslint": "^4.0.0", "isomorphic-fetch": "^2.2.1", "jsdom": "^11.1.0", "jsdom-global": "^3.0.2", From 27ace69a7fb24b5ac4346f15f8397cf2e45f807d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 10 Jan 2018 13:54:29 -0800 Subject: [PATCH 27/47] build - add 'deps' step that records output of 'npm ls' into build --- gulpfile.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index 293179892..4c36ff7d4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -19,6 +19,8 @@ var manifest = require('./app/manifest.json') var gulpif = require('gulp-if') var replace = require('gulp-replace') var mkdirp = require('mkdirp') +var asyncEach = require('async/each') +var exec = require('child_process').exec var disableDebugTools = gutil.env.disableDebugTools var debug = gutil.env.debug @@ -153,6 +155,18 @@ gulp.task('copy:watch', function(){ gulp.watch(['./app/{_locales,images}/*', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy')) }) +// record deps + +gulp.task('deps', function (cb) { + exec('npm ls', (err, stdoutOutput, stderrOutput) => { + if (err) return cb(err) + const browsers = ['firefox','chrome','edge','opera'] + asyncEach(browsers, (target, done) => { + fs.writeFile(`./dist/${target}/deps.txt`, stdoutOutput, done) + }, cb) + }) +}) + // lint js gulp.task('lint', function () { @@ -234,7 +248,7 @@ gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:ope gulp.task('dev', gulp.series('dev:js', 'copy', gulp.parallel('copy:watch', 'dev:reload'))) -gulp.task('build', gulp.series('clean', gulp.parallel('build:js', 'copy'))) +gulp.task('build', gulp.series('clean', gulp.parallel('build:js', 'copy', 'deps'))) gulp.task('dist', gulp.series('build', 'zip')) // task generators From 60a52b260863e62b1717581e0fa6fb8dd91e1234 Mon Sep 17 00:00:00 2001 From: tmashuang Date: Wed, 10 Jan 2018 21:54:43 -0800 Subject: [PATCH 28/47] Add one px to address for Firefox clipping --- ui/app/account-detail.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index d4f707e0b..c9a8a774d 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -161,6 +161,7 @@ AccountDetailScreen.prototype.render = function () { textOverflow: 'ellipsis', paddingTop: '3px', width: '5em', + height: '15px', fontSize: '13px', fontFamily: 'Montserrat Light', textRendering: 'geometricPrecision', From be604391d0b3bbd3a2cae3aef79889130850f472 Mon Sep 17 00:00:00 2001 From: tmashuang Date: Wed, 10 Jan 2018 21:56:07 -0800 Subject: [PATCH 29/47] Add max height for Firefox addon overflow and hide horizontal scroll --- ui/app/css/index.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/app/css/index.css b/ui/app/css/index.css index c0bf18c23..b40d48b5d 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -441,7 +441,9 @@ input.large-input { .account-detail-section { display: flex; flex-wrap: wrap; + overflow-x: hidden; overflow-y: auto; + max-height: 465px; flex-direction: inherit; } From 4a9dad7c40b97f1e625931d6b57fc9d7fdc5080d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 11 Jan 2018 15:00:48 -0800 Subject: [PATCH 30/47] Improve gas price estimation by backfilling recent-blocks When first initializing, recent-block controller now back-fills up to its desired history length. This makes estimated gas prices reflect a longer recent history, even when first switching to a new network. Fixes #2925 --- CHANGELOG.md | 2 + app/scripts/controllers/recent-blocks.js | 79 +++++++++++++++++++++--- app/scripts/metamask-controller.js | 6 +- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4218210..30ddb3531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Further improve gas price estimation. + ## 3.13.4 2018-1-9 - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 4a906261e..c65c2b1c4 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -1,11 +1,13 @@ const ObservableStore = require('obs-store') const extend = require('xtend') +const BN = require('ethereumjs-util').BN class RecentBlocksController { constructor (opts = {}) { - const { blockTracker } = opts + const { blockTracker, ethQuery } = opts this.blockTracker = blockTracker + this.ethQuery = ethQuery this.historyLength = opts.historyLength || 40 const initState = extend({ @@ -14,6 +16,7 @@ class RecentBlocksController { this.store = new ObservableStore(initState) this.blockTracker.on('block', this.processBlock.bind(this)) + this.backfill() } resetState () { @@ -23,12 +26,7 @@ class RecentBlocksController { } processBlock (newBlock) { - const block = extend(newBlock, { - gasPrices: newBlock.transactions.map((tx) => { - return tx.gasPrice - }), - }) - delete block.transactions + const block = this.mapTransactionsToPrices(newBlock) const state = this.store.getState() state.recentBlocks.push(block) @@ -39,6 +37,73 @@ class RecentBlocksController { this.store.updateState(state) } + + backfillBlock (newBlock) { + const block = this.mapTransactionsToPrices(newBlock) + + const state = this.store.getState() + + if (state.recentBlocks.length < this.historyLength) { + state.recentBlocks.unshift(block) + } + + this.store.updateState(state) + } + + mapTransactionsToPrices (newBlock) { + const block = extend(newBlock, { + gasPrices: newBlock.transactions.map((tx) => { + return tx.gasPrice + }), + }) + delete block.transactions + return block + } + + async backfill() { + this.blockTracker.once('block', async (block) => { + let blockNum = block.number + let recentBlocks + let state = this.store.getState() + recentBlocks = state.recentBlocks + + while (recentBlocks.length < this.historyLength) { + try { + let blockNumBn = new BN(blockNum.substr(2), 16) + const newNum = blockNumBn.subn(1).toString(10) + const newBlock = await this.getBlockByNumber(newNum) + + if (newBlock) { + this.backfillBlock(newBlock) + blockNum = newBlock.number + } + + state = this.store.getState() + recentBlocks = state.recentBlocks + } catch (e) { + log.error(e) + } + await this.wait() + } + }) + } + + async wait () { + return new Promise((resolve) => { + setTimeout(resolve, 100) + }) + } + + async getBlockByNumber (number) { + const bn = new BN(number) + return new Promise((resolve, reject) => { + this.ethQuery.getBlockByNumber('0x' + bn.toString(16), true, (err, block) => { + if (err) reject(err) + resolve(block) + }) + }) + } + } module.exports = RecentBlocksController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f62b5e5cd..81d70797a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -94,12 +94,14 @@ module.exports = class MetamaskController extends EventEmitter { this.provider = this.initializeProvider() this.blockTracker = this.provider._blockTracker + // eth data query tools + this.ethQuery = new EthQuery(this.provider) + this.recentBlocksController = new RecentBlocksController({ blockTracker: this.blockTracker, + ethQuery: this.ethQuery, }) - // eth data query tools - this.ethQuery = new EthQuery(this.provider) // account tracker watches balances, nonces, and any code at their address. this.accountTracker = new AccountTracker({ provider: this.provider, From 7cb66ce4cba446f8149c4a8872dbdfbc53f72f7c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 12 Jan 2018 10:25:36 -0800 Subject: [PATCH 31/47] Prefer passing a provider over an ethQuery instance --- app/scripts/controllers/recent-blocks.js | 5 +++-- app/scripts/metamask-controller.js | 7 +------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index c65c2b1c4..4ae3810eb 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -1,13 +1,14 @@ const ObservableStore = require('obs-store') const extend = require('xtend') const BN = require('ethereumjs-util').BN +const EthQuery = require('eth-query') class RecentBlocksController { constructor (opts = {}) { - const { blockTracker, ethQuery } = opts + const { blockTracker, provider } = opts this.blockTracker = blockTracker - this.ethQuery = ethQuery + this.ethQuery = new EthQuery(provider) this.historyLength = opts.historyLength || 40 const initState = extend({ diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 81d70797a..000e17b9e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -5,7 +5,6 @@ const Dnode = require('dnode') const ObservableStore = require('obs-store') const asStream = require('obs-store/lib/asStream') const AccountTracker = require('./lib/account-tracker') -const EthQuery = require('eth-query') const RpcEngine = require('json-rpc-engine') const debounce = require('debounce') const createEngineStream = require('json-rpc-middleware-stream/engineStream') @@ -94,12 +93,9 @@ module.exports = class MetamaskController extends EventEmitter { this.provider = this.initializeProvider() this.blockTracker = this.provider._blockTracker - // eth data query tools - this.ethQuery = new EthQuery(this.provider) - this.recentBlocksController = new RecentBlocksController({ blockTracker: this.blockTracker, - ethQuery: this.ethQuery, + provider: this.provider, }) // account tracker watches balances, nonces, and any code at their address. @@ -142,7 +138,6 @@ module.exports = class MetamaskController extends EventEmitter { signTransaction: this.keyringController.signTransaction.bind(this.keyringController), provider: this.provider, blockTracker: this.blockTracker, - ethQuery: this.ethQuery, getGasPrice: this.getGasPrice.bind(this), }) this.txController.on('newUnapprovedTx', opts.showUnapprovedTx.bind(opts)) From 3a27332cf6b0285e529db4d958c6ea035da81b79 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 12 Jan 2018 11:01:39 -0800 Subject: [PATCH 32/47] Update support link on readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 913723ad5..c9893d14a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Support -If you're a user seeking support, [here is our support site](http://metamask.consensyssupport.happyfox.com). +If you're a user seeking support, [here is our support site](http://metamask.helpscoutdocs.com/). ## Developing Compatible Dapps From 429db74508cd5c0cd275d4872d9553bd29c6ea38 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 12 Jan 2018 11:03:03 -0800 Subject: [PATCH 33/47] Use https --- README.md | 2 +- ui/app/info.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c9893d14a..d45b73778 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Support -If you're a user seeking support, [here is our support site](http://metamask.helpscoutdocs.com/). +If you're a user seeking support, [here is our support site](https://metamask.helpscoutdocs.com/). ## Developing Compatible Dapps diff --git a/ui/app/info.js b/ui/app/info.js index 2e59db890..49ff9f24a 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -103,7 +103,7 @@ InfoScreen.prototype.render = function () { [ h('div.fa.fa-support', [ h('a.info', { - href: 'http://metamask.helpscoutdocs.com/', + href: 'https://metamask.helpscoutdocs.com/', target: '_blank', }, 'Visit our Knowledge Base'), ]), From 6df3261debfa63dc7c667d8051000260dbde9570 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Sat, 13 Jan 2018 13:38:55 -0800 Subject: [PATCH 34/47] Fix signTypedData bytes signing Fixes #2826 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4218210..e90134613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix bug that prevented eth_signTypedData from signing bytes. + ## 3.13.4 2018-1-9 - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. diff --git a/package.json b/package.json index 8b846803b..fcccfd4ef 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "eth-keyring-controller": "^2.1.2", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", - "eth-sig-util": "^1.4.0", + "eth-sig-util": "^1.4.2", "eth-simple-keyring": "^1.2.0", "eth-token-tracker": "^1.1.4", "ethereumjs-tx": "^1.3.0", From d5c311b13e6a9399252c4617b07ad463f6ead9b0 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 14 Jan 2018 13:56:54 -0800 Subject: [PATCH 35/47] add a loading spinner to conf-tx view --- ui/app/conf-tx.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index cb1afedfe..ce4d153b5 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -4,6 +4,7 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('./actions') const NetworkIndicator = require('./components/network') +const LoadingIndicator = require('./components/loading') const txHelper = require('../lib/tx-helper') const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notification') @@ -60,6 +61,11 @@ ConfirmTxScreen.prototype.render = function () { h('.flex-column.flex-grow', [ + h(LoadingIndicator, { + isLoading: txData.loadingDefaults, + loadingMessage: 'Estimating transaction cost…', + }), + // subtitle and nav h('.section-title.flex-row.flex-center', [ !isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { From f0dd4f19238d63875fbdfa3a9b31fa7b9d8925ed Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 14 Jan 2018 14:00:17 -0800 Subject: [PATCH 36/47] transactions - emit 'newUnapprovedTx' before estimateGas finishes --- app/scripts/controllers/transactions.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index ded9739a8..bb9253175 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -139,7 +139,6 @@ module.exports = class TransactionController extends EventEmitter { async newUnapprovedTransaction (txParams) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) - this.emit('newUnapprovedTx', initialTxMeta) // listen for tx completion (success, fail) return new Promise((resolve, reject) => { this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => { @@ -167,11 +166,16 @@ module.exports = class TransactionController extends EventEmitter { status: 'unapproved', metamaskNetworkId: this.getNetwork(), txParams: txParams, + loadingDefaults: true, } + this.addTx(txMeta) + this.emit('newUnapprovedTx', txMeta) // add default tx params await this.addTxDefaults(txMeta) + + txMeta.loadingDefaults = false // save txMeta - this.addTx(txMeta) + this.txStateManager.updateTx(txMeta) return txMeta } From 409b49b411fee4c3f6f9106d99e2bba915bb5f0f Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 14 Jan 2018 14:00:59 -0800 Subject: [PATCH 37/47] test - create ethJsQuery stub --- test/stub/provider.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/stub/provider.js b/test/stub/provider.js index 8a306f6d9..85e1da707 100644 --- a/test/stub/provider.js +++ b/test/stub/provider.js @@ -5,7 +5,8 @@ module.exports = { createEngineForTestData, providerFromEngine, scaffoldMiddleware, - createStubedProvider + createEthJsQueryStub, + createStubedProvider, } @@ -18,6 +19,18 @@ function providerFromEngine (engine) { return provider } +function createEthJsQueryStub (stubProvider) { + return new Proxy({}, { + get: (obj, method) => { + return (...params) => { + return new Promise((resolve, reject) => { + stubProvider.sendAsync({ method: `eth_${method}`, params }, (err, ress) => resolve(ress.result)) + }) + } + }, + }) +} + function createStubedProvider (resultStub) { const engine = createEngineForTestData() engine.push(scaffoldMiddleware(resultStub)) From 7a30950e4dd31a2e4b1807bf3d1e2a09a25da323 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 14 Jan 2018 14:01:37 -0800 Subject: [PATCH 38/47] test - fix to match expected behavior --- test/unit/tx-controller-test.js | 42 ++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index aeefd5ec6..36f3e1c68 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -5,7 +5,7 @@ const ObservableStore = require('obs-store') const sinon = require('sinon') const TransactionController = require('../../app/scripts/controllers/transactions') const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils') -const { createStubedProvider } = require('../stub/provider') +const { createStubedProvider, createEthJsQueryStub } = require('../stub/provider') const noop = () => true const currentNetworkId = 42 @@ -30,6 +30,8 @@ describe('Transaction Controller', function () { resolve() }), }) + txController.query = createEthJsQueryStub(provider) + txController.txGasUtil.query = createEthJsQueryStub(provider) txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop }) txController.txProviderUtils = new TxGasUtils(txController.provider) }) @@ -110,23 +112,16 @@ describe('Transaction Controller', function () { history: [], } txController.txStateManager._saveTxList([txMeta]) - stub = sinon.stub(txController, 'addUnapprovedTransaction').returns(Promise.resolve(txController.txStateManager.addTx(txMeta))) + stub = sinon.stub(txController, 'addUnapprovedTransaction').callsFake(() => { + txController.emit('newUnapprovedTx', txMeta) + return Promise.resolve(txController.txStateManager.addTx(txMeta)) }) afterEach(function () { txController.txStateManager._saveTxList([]) stub.restore() }) - - it('should emit newUnapprovedTx event and pass txMeta as the first argument', function (done) { - txController.once('newUnapprovedTx', (txMetaFromEmit) => { - assert(txMetaFromEmit, 'txMeta is falsey') - assert.equal(txMetaFromEmit.id, 1, 'the right txMeta was passed') - done() - }) - txController.newUnapprovedTransaction(txParams) - .catch(done) - }) + }) it('should resolve when finished and status is submitted and resolve with the hash', function (done) { txController.once('newUnapprovedTx', (txMetaFromEmit) => { @@ -160,8 +155,17 @@ describe('Transaction Controller', function () { }) describe('#addUnapprovedTransaction', function () { + let addTxDefaults + beforeEach(() => { + addTxDefaults = txController.addTxDefaults + txController.addTxDefaults = function addTxDefaultsStub () { return Promise.resolve() } + + }) + afterEach(() => { + txController.addTxDefaults = addTxDefaults + }) + it('should add an unapproved transaction and return a valid txMeta', function (done) { - const addTxDefaultsStub = sinon.stub(txController, 'addTxDefaults').callsFake(() => Promise.resolve()) txController.addUnapprovedTransaction({}) .then((txMeta) => { assert(('id' in txMeta), 'should have a id') @@ -172,10 +176,20 @@ describe('Transaction Controller', function () { const memTxMeta = txController.txStateManager.getTx(txMeta.id) assert.deepEqual(txMeta, memTxMeta, `txMeta should be stored in txController after adding it\n expected: ${txMeta} \n got: ${memTxMeta}`) - addTxDefaultsStub.restore() done() }).catch(done) }) + + it('should emit newUnapprovedTx event and pass txMeta as the first argument', function (done) { + providerResultStub.eth_gasPrice = '4a817c800' + txController.once('newUnapprovedTx', (txMetaFromEmit) => { + assert(txMetaFromEmit, 'txMeta is falsey') + done() + }) + txController.addUnapprovedTransaction({}) + .catch(done) + }) + }) describe('#addTxDefaults', function () { From cab22163432f5d93a208b6702dd20098d1901884 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 15 Jan 2018 10:07:50 -0800 Subject: [PATCH 39/47] Bump Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4218210..f1ecd4bd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Current Master +- Add an extra px to address for Firefox clipping. +- Adjust max height for account detail section for Firefox. + ## 3.13.4 2018-1-9 - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. From 93d4b223631802d05830c2ce60e5d4e303330429 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 15 Jan 2018 14:11:59 -0800 Subject: [PATCH 40/47] Bump keyringController version --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index fcccfd4ef..fa83c980e 100644 --- a/package.json +++ b/package.json @@ -72,14 +72,12 @@ "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^2.2.0", "eth-contract-metadata": "^1.1.4", - "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.5", "eth-json-rpc-infura": "^1.0.2", - "eth-keyring-controller": "^2.1.2", + "eth-keyring-controller": "^2.1.4", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", "eth-sig-util": "^1.4.2", - "eth-simple-keyring": "^1.2.0", "eth-token-tracker": "^1.1.4", "ethereumjs-tx": "^1.3.0", "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", From 23a928bc9d6ebc0a7baf4a9e0800453cce87f9cc Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Mon, 15 Jan 2018 14:18:32 -0800 Subject: [PATCH 41/47] Edit: Fix Firefox scrollbar Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ecd4bd7..6e421b4b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Current Master - Add an extra px to address for Firefox clipping. -- Adjust max height for account detail section for Firefox. +- Fix Firefox scrollbar. ## 3.13.4 2018-1-9 From cd7eaaa735aa084cec0c4a647edf89bc5e4b2ec7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 15 Jan 2018 15:08:07 -0800 Subject: [PATCH 42/47] Set gas limit to 21k for recipients with no code Fixes #2907 --- CHANGELOG.md | 2 ++ app/scripts/lib/tx-gas-utils.js | 27 ++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4218210..a60e1245c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Estimating gas limit for simple ether sends now faster & cheaper, by avoiding VM usage on recipients with no code. + ## 3.13.4 2018-1-9 - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 5e49fdb22..d57c70b10 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -4,6 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('./util') +const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. /* tx-utils are utility methods for Transaction manager @@ -37,14 +38,30 @@ module.exports = class txProvideUtil { async estimateTxGas (txMeta, blockGasLimitHex) { const txParams = txMeta.txParams + // check if gasLimit is already specified txMeta.gasLimitSpecified = Boolean(txParams.gas) - // if not, fallback to block gasLimit - if (!txMeta.gasLimitSpecified) { - const blockGasLimitBN = hexToBn(blockGasLimitHex) - const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20) - txParams.gas = bnToHex(saferGasLimitBN) + + // if it is, use that value + if (txMeta.gasLimitSpecified) { + return txParams.gas } + + // if recipient has no code, gas is 21k max: + const recipient = txParams.to + const hasRecipient = Boolean(recipient) + const code = await this.query.getCode(recipient) + if (hasRecipient && (!code || code === '0x')) { + txParams.gas = SIMPLE_GAS_COST + txMeta.gasLimitSpecified = true // Prevents buffer addition + return SIMPLE_GAS_COST + } + + // if not, fall back to block gasLimit + const blockGasLimitBN = hexToBn(blockGasLimitHex) + const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20) + txParams.gas = bnToHex(saferGasLimitBN) + // run tx return await this.query.estimateGas(txParams) } From 724197b95f30931e17edaf86c7391687b2922457 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 15 Jan 2018 15:23:11 -0800 Subject: [PATCH 43/47] add to CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4218210..b681ebcb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Open metamask popup for transaction confirmation before gas estimation finishes and add a loading screen over transaction confirmation. + ## 3.13.4 2018-1-9 - Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. From 58be1742e1fbfc6ae73e50256849f2e673989446 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 15 Jan 2018 16:04:49 -0800 Subject: [PATCH 44/47] Rename lock to log out Fixes #2475 --- ui/app/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/app.js b/ui/app/app.js index bc198b482..f0dfef34f 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -395,7 +395,7 @@ App.prototype.renderDropdown = function () { h(DropdownMenuItem, { closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), onClick: () => { this.props.dispatch(actions.lockMetamask()) }, - }, 'Lock'), + }, 'Log Out'), h(DropdownMenuItem, { closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), From 8fb62b97c5b0901c7e4402d49538db87396c8579 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 16 Jan 2018 11:05:11 -0800 Subject: [PATCH 45/47] Create new flag for simple sends to avoid overloading other flag --- app/scripts/lib/tx-gas-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index d57c70b10..e80e0467e 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -53,7 +53,7 @@ module.exports = class txProvideUtil { const code = await this.query.getCode(recipient) if (hasRecipient && (!code || code === '0x')) { txParams.gas = SIMPLE_GAS_COST - txMeta.gasLimitSpecified = true // Prevents buffer addition + txMeta.simpleSend = true // Prevents buffer addition return SIMPLE_GAS_COST } @@ -72,7 +72,7 @@ module.exports = class txProvideUtil { // if gasLimit was specified and doesnt OOG, // use original specified amount - if (txMeta.gasLimitSpecified) { + if (txMeta.gasLimitSpecified || txMeta.simpleSend) { txMeta.estimatedGas = txParams.gas return } From 41fdff41cd83f9c954be0f8b8bd66586a8b8a968 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 16 Jan 2018 12:20:15 -0800 Subject: [PATCH 46/47] Version 3.13.5 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da6da219..e5f85dbb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 3.13.5 2018-1-16 + - Estimating gas limit for simple ether sends now faster & cheaper, by avoiding VM usage on recipients with no code. - Add an extra px to address for Firefox clipping. - Fix Firefox scrollbar. diff --git a/app/manifest.json b/app/manifest.json index df7b1f1aa..3b6fc6b20 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.13.4", + "version": "3.13.5", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From aa08d1a09dce7324eaa3b3df568df43f8c55cc63 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 16 Jan 2018 18:34:24 -0800 Subject: [PATCH 47/47] Fix merge conflicts --- old-ui/app/app.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/old-ui/app/app.js b/old-ui/app/app.js index e5fc5b9e9..6eb1e487f 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -403,6 +403,14 @@ App.prototype.renderDropdown = function () { closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), onClick: () => { this.props.dispatch(actions.showInfoPage()) }, }, 'Info/Help'), + + h(DropdownMenuItem, { + closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), + onClick: () => { + this.props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL')) + .then(() => this.props.dispatch(actions.setNetworkEndpoints(BETA_UI_NETWORK_TYPE))) + }, + }, 'Try Beta!'), ]) } @@ -462,11 +470,6 @@ App.prototype.renderPrimary = function () { }) } - if (props.seedWords) { - log.debug('rendering seed words') - return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) - } - // show initialize screen if (!props.isInitialized || props.forgottenPassword) { // show current view @@ -501,6 +504,12 @@ App.prototype.renderPrimary = function () { } } + // show seed words screen + if (props.seedWords) { + log.debug('rendering seed words') + return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) + } + // show current view switch (props.currentView.name) {