Merge pull request #13498 from MetaMask/Version-v10.10.0

Version v10.10.0 RC
feature/default_network_editable
ryanml 3 years ago committed by GitHub
commit 09c880d165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      .github/ISSUE_TEMPLATE/bug-report.md
  2. 97
      .github/ISSUE_TEMPLATE/bug-report.yml
  3. 2
      .github/workflows/crowdin_action.yml
  4. 1
      .metamaskrc.dist
  5. 2
      .storybook/test-data.js
  6. 38
      CHANGELOG.md
  7. 2
      LICENSE
  8. 12
      app/_locales/am/messages.json
  9. 32
      app/_locales/ar/messages.json
  10. 24
      app/_locales/bg/messages.json
  11. 24
      app/_locales/bn/messages.json
  12. 24
      app/_locales/ca/messages.json
  13. 18
      app/_locales/cs/messages.json
  14. 24
      app/_locales/da/messages.json
  15. 65
      app/_locales/de/messages.json
  16. 2324
      app/_locales/el/messages.json
  17. 111
      app/_locales/en/messages.json
  18. 43
      app/_locales/es/messages.json
  19. 57
      app/_locales/es_419/messages.json
  20. 24
      app/_locales/et/messages.json
  21. 24
      app/_locales/fa/messages.json
  22. 24
      app/_locales/fi/messages.json
  23. 21
      app/_locales/fil/messages.json
  24. 2344
      app/_locales/fr/messages.json
  25. 6
      app/_locales/gu/messages.json
  26. 24
      app/_locales/he/messages.json
  27. 1115
      app/_locales/hi/messages.json
  28. 12
      app/_locales/hn/messages.json
  29. 24
      app/_locales/hr/messages.json
  30. 21
      app/_locales/ht/messages.json
  31. 24
      app/_locales/hu/messages.json
  32. 1121
      app/_locales/id/messages.json
  33. 74
      app/_locales/it/messages.json
  34. 1115
      app/_locales/ja/messages.json
  35. 24
      app/_locales/kn/messages.json
  36. 1115
      app/_locales/ko/messages.json
  37. 26
      app/_locales/lt/messages.json
  38. 24
      app/_locales/lv/messages.json
  39. 6
      app/_locales/ml/messages.json
  40. 6
      app/_locales/mr/messages.json
  41. 21
      app/_locales/ms/messages.json
  42. 15
      app/_locales/nl/messages.json
  43. 24
      app/_locales/no/messages.json
  44. 12
      app/_locales/ph/messages.json
  45. 24
      app/_locales/pl/messages.json
  46. 12
      app/_locales/pt/messages.json
  47. 64
      app/_locales/pt_BR/messages.json
  48. 24
      app/_locales/ro/messages.json
  49. 1115
      app/_locales/ru/messages.json
  50. 24
      app/_locales/sk/messages.json
  51. 24
      app/_locales/sl/messages.json
  52. 24
      app/_locales/sr/messages.json
  53. 24
      app/_locales/sv/messages.json
  54. 24
      app/_locales/sw/messages.json
  55. 21
      app/_locales/ta/messages.json
  56. 6
      app/_locales/te/messages.json
  57. 18
      app/_locales/th/messages.json
  58. 1593
      app/_locales/tl/messages.json
  59. 3353
      app/_locales/tr/messages.json
  60. 24
      app/_locales/uk/messages.json
  61. 1115
      app/_locales/vi/messages.json
  62. 1522
      app/_locales/zh_CN/messages.json
  63. 12
      app/_locales/zh_TW/messages.json
  64. 2
      app/images/curve-high.svg
  65. 2
      app/images/curve-low.svg
  66. 2
      app/images/curve-medium.svg
  67. 116
      app/images/videos/recovery-onboarding/subtitles/de.vtt
  68. 4
      app/phishing.html
  69. 5
      app/scripts/background.js
  70. 24
      app/scripts/controllers/app-state.js
  71. 179
      app/scripts/controllers/metametrics.js
  72. 43
      app/scripts/controllers/metametrics.test.js
  73. 21
      app/scripts/controllers/preferences.js
  74. 360
      app/scripts/controllers/transactions/index.js
  75. 466
      app/scripts/controllers/transactions/index.test.js
  76. 2
      app/scripts/controllers/transactions/tx-state-manager.js
  77. 75
      app/scripts/lib/buy-eth-url.test.js
  78. 19
      app/scripts/lib/buy-url.js
  79. 117
      app/scripts/lib/buy-url.test.js
  80. 148
      app/scripts/metamask-controller.js
  81. 18
      app/scripts/metamask-controller.test.js
  82. 2
      development/build/scripts.js
  83. 12
      development/build/transforms/remove-fenced-code.js
  84. 11
      development/build/transforms/remove-fenced-code.test.js
  85. 4
      development/run-ganache.sh
  86. 8
      lavamoat/browserify/beta/policy.json
  87. 8
      lavamoat/browserify/flask/policy.json
  88. 8
      lavamoat/browserify/main/policy.json
  89. 80
      package.json
  90. 7
      shared/constants/hardware-wallets.js
  91. 40
      shared/constants/metametrics.js
  92. 58
      shared/constants/network.js
  93. 50
      shared/constants/transaction.js
  94. 145
      test/e2e/fixtures/eip-1559-v2-dapp/state.json
  95. 214
      test/e2e/fixtures/eip-1559-v2/state.json
  96. 40
      test/e2e/fixtures/navigate-transactions/state.json
  97. 214
      test/e2e/fixtures/send-edit-v2/state.json
  98. 13
      test/e2e/fixtures/send-edit/state.json
  99. 16
      test/e2e/ganache.js
  100. 52
      test/e2e/helpers.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,37 +0,0 @@
---
name: Bug Report
about: Using MetaMask, but it's not working as you expect?
---
<!--
BEFORE SUBMITTING:
1) Please search to make sure this issue has not been opened already
2) If this is an implementation question or trouble with your personal project, please post on StackExchange. This will get your question answered more quickly and make it easier for other devs to find the answer in the future.
-->
**Describe the bug**
A clear and concise description of what the bug is.
**Steps to reproduce (REQUIRED)**
Steps to reproduce the behavior, libraries used with version number, and/or any setup information to easily reproduce:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Browser details (please complete the following information):**
- OS: [e.g. OS X, Windows]
- Hardware Wallet: [e.g. Trezor Firmware version 1.8.3, Ledger Nano S Firmware version 1.6.0]
- Browser: [e.g. Chrome Version 79.0.3945.79 (Official Build) (64-bit), Firefox Browser 71.0 (64-bit)]
- MetaMask Version: [e.g. 5.0.2 - find it in Settings > About]
**Additional context (Error Messages, etc.)**
Add any other context about the problem here.

@ -0,0 +1,97 @@
name: Bug Report
description: Using MetaMask, but it's not working as you expect?
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
## **Before Submitting:**
* Please search to make sure this issue has not been opened already.
* If this is a question about how to integrate MetaMask with your project, please ask in our [Community forum](https://community.metamask.io/c/developer-questions/) instead. This will get your question answered more quickly and make it easier for other devs to find the answer in the future.
- type: textarea
id: what-happened
attributes:
label: Describe the bug
description: What happened? What did you expect to happen? Please include screenshots if applicable!
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: List all steps needed to reproduce the problem
value: |
1.
validations:
required: true
- type: textarea
id: error
attributes:
label: Error messages or log output
description: Please copy and paste any relevant error messages or log output. This will be automatically formatted, so there is no need for backticks.
render: shell
- type: input
id: version
attributes:
label: Version
description: What version of MetaMask are you running? You can find the version in "Settings" > "About"
validations:
required: true
- type: dropdown
id: build
attributes:
label: Build type
description: Are you using a testing or development build of MetaMask? If so, please select the type of build you are using.
options:
- Beta
- Flask
- Other (please specify exactly where you obtained this build in "Additional Context" section)
- type: dropdown
id: browsers
attributes:
label: Browser
description: Which browsers have you seen the problem on?
multiple: true
options:
- Chrome
- Firefox
- Microsoft Edge
- Brave
- Other (please elaborate in the "Additional Context" section)
validations:
required: true
- type: dropdown
id: os
attributes:
label: Operating system
description: Which operating systems have you seen the problem on?
multiple: true
options:
- Windows
- MacOS
- Linux
- Other (please elaborate in the "Additional Context" section)
validations:
required: true
- type: dropdown
id: hardware-wallet
attributes:
label: Hardware wallet
description: Are you using any of these hardware wallets? Please include the firmware version in the "Additional context" section below for any that you select here.
multiple: true
options:
- Ledger
- Trezor
- Keystone
- GridPlus Lattice1
- Other (please elaborate in the "Additional Context" section)
- type: textarea
id: additional
attributes:
label: Additional context
description: Add any other context about the problem here, e.g. related issues, additional error messages or logs, or any potentially relevant details about the environment or situation the bug occurred in.

@ -26,6 +26,6 @@ jobs:
upload_translations: true
download_translations: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.METAMASKBOT_CROWDIN_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

@ -3,6 +3,5 @@ PASSWORD=METAMASK PASSWORD
INFURA_PROJECT_ID=00000000000
SEGMENT_WRITE_KEY=
ONBOARDING_V2=
EIP_1559_V2=
SWAPS_USE_DEV_APIS=
COLLECTIBLES_V1=

@ -907,7 +907,7 @@ const state = {
'0xaD6D458402F60fD3Bd25163575031ACDce07538D': './sai.svg',
},
hiddenTokens: [],
suggestedAssets: {},
suggestedAssets: [],
useNonceField: false,
usePhishDetect: true,
lostIdentities: {},

@ -6,6 +6,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [10.10.0]
### Added
- Enable toggle to turn on the new gas fee customization UI ([#13481](https://github.com/MetaMask/metamask-extension/pull/13481))
- Select between new 'Low', 'Market', and 'Aggressive' gas options
- Improved advanced gas fee editing
- Adds the ability to save custom gas values as defaults
- More informative tooltips about suggested gas options
- More information about the status of the network
- Enable buying MATIC on Polygon, BNB on BSC, AVAX on Avalanche, FTM on Fantom, CELO on Celo, and respective stablecoins on Transak ([#13398](https://github.com/MetaMask/metamask-extension/pull/13398))
- Add German subtitles for SRP Video ([#13368](https://github.com/MetaMask/metamask-extension/pull/13368))
- Adding Brazilian Portuguese translation for some copy in Settings ([#13470](https://github.com/MetaMask/metamask-extension/pull/13470))
### Changed
- Hide 0 balance tokens in send screen dropdown if the "Hide Tokens Without Balance" toggle is on ([#13306](https://github.com/MetaMask/metamask-extension/pull/13306))
- Change the 'Connected Sites' removal icon to a button ([#13476](https://github.com/MetaMask/metamask-extension/pull/13476))
- Add specific hardware wallet names next to HW accounts in the account dropdown ([#13339](https://github.com/MetaMask/metamask-extension/pull/13339))
- Update title of phishing.html ([#13323](https://github.com/MetaMask/metamask-extension/pull/13323))
- Update language while importing an SRP to limit encouragement of copy-pasting seed phrases ([#12012](https://github.com/MetaMask/metamask-extension/pull/12012))
- Maintain leading whitespace in for data to be signed in the signature request popup ([#13340](https://github.com/MetaMask/metamask-extension/pull/13340))
- Update global link hover color from orange to blue ([#13344](https://github.com/MetaMask/metamask-extension/pull/13344))
- Adjust ordering of tokens in the Swaps token dropdown ([#13270](https://github.com/MetaMask/metamask-extension/pull/13270))
### Fixed
- Ensure a correct update of the gas limit upon editing of a transaction recipient ([#12784](https://github.com/MetaMask/metamask-extension/pull/12784))
- Ensure that the toggled display of currency in the send flow persists when editing a transaction ([#12813](https://github.com/MetaMask/metamask-extension/pull/12813))
- Ensure settings can be opened if browser zoom level > 100% ([#13460](https://github.com/MetaMask/metamask-extension/pull/13460))
- Ensure displayed balances of tokens are not incorrectly rounded down ([#13337](https://github.com/MetaMask/metamask-extension/pull/13337))
- Improve visual spacing on the wallet selection flow of onboarding ([#12799](https://github.com/MetaMask/metamask-extension/pull/12799))
## [10.9.3]
### Fixed
- Allow for scrolling when sign type data message is too long ([#13642](https://github.com/MetaMask/metamask-extension/pull/13642))
@ -429,7 +458,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#11093](https://github.com/MetaMask/metamask-extension/pull/11093): Update all uses of "Seed Phrase" to "Secret Recovery Phrase"
### Fixed
- [#11025](https://github.com/MetaMask/metamask-extension/pull/11025): Fixed redirection to the build quotes page from the swaps page when failure has occured
- [#11025](https://github.com/MetaMask/metamask-extension/pull/11025): Fixed redirection to the build quotes page from the swaps page when failure has occurred
- [#11015](https://github.com/MetaMask/metamask-extension/pull/11015): Prevent an undefined gas price from breaking the transaction list
- [#11013](https://github.com/MetaMask/metamask-extension/pull/11013): Prevent signature request component from canceling hardware wallet signing
- [#10982](https://github.com/MetaMask/metamask-extension/pull/10982): Re-validating chain id when rpc url changes [custom network form]
@ -483,7 +512,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [9.5.1]
### Fixed
- Fixed icon on approval screen ([#11048](https://github.com/MetaMask/metamask-extension/pull/11048))
- Fixed broken app state for some users with Chinese, Portugese or Spanish browser language settings. ([#11036](https://github.com/MetaMask/metamask-extension/pull/11036))
- Fixed broken app state for some users with Chinese, Portuguese or Spanish browser language settings. ([#11036](https://github.com/MetaMask/metamask-extension/pull/11036))
## [9.5.0] - 2021-04-28
### Added
@ -572,7 +601,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update Japanese translations. ([#10265](https://github.com/MetaMask/metamask-extension/pull/10265))
- Update Chinese(Simplified) translations. ([#9388](https://github.com/MetaMask/metamask-extension/pull/9388))
- Update Vietnamese translations. ([#10270](https://github.com/MetaMask/metamask-extension/pull/10270))
- Update Spanish and Spanish(Latin American and Carribean) translations. ([#10258](https://github.com/MetaMask/metamask-extension/pull/10258))
- Update Spanish and Spanish(Latin American and Caribbean) translations. ([#10258](https://github.com/MetaMask/metamask-extension/pull/10258))
- Update Russian translations. ([#10268](https://github.com/MetaMask/metamask-extension/pull/10268))
- Update Tagalog localized messages. ([#10269](https://github.com/MetaMask/metamask-extension/pull/10269))
- Fix 'imported' translation use case for Dutch. ([#10448](https://github.com/MetaMask/metamask-extension/pull/10448))
@ -2702,7 +2731,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Uncategorized
- Added the ability to restore accounts from seed words.
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.9.3...HEAD
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.10.0...HEAD
[10.10.0]: https://github.com/MetaMask/metamask-extension/compare/v10.9.3...v10.10.0
[10.9.3]: https://github.com/MetaMask/metamask-extension/compare/v10.9.2...v10.9.3
[10.9.2]: https://github.com/MetaMask/metamask-extension/compare/v10.9.1...v10.9.2
[10.9.1]: https://github.com/MetaMask/metamask-extension/compare/v10.9.0...v10.9.1

@ -1,4 +1,4 @@
Copyright ConsenSys Software Inc. 2020. All rights reserved.
Copyright ConsenSys Software Inc. 2022. All rights reserved.
You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form.

@ -283,18 +283,9 @@
"deleteNetworkDescription": {
"message": "ይህን አውታረ መረብ ለመሰረዝ እንደሚፈልጉ እርግጠኛ ነዎት?"
},
"depositEther": {
"message": "Ether አስቀምጥ"
},
"details": {
"message": "ዝርዝሮች"
},
"directDepositEther": {
"message": "Ether በቀጥታ ያስቀምጡ"
},
"directDepositEtherExplainer": {
"message": "ቀደም ሲል የተወሰነ Ether ካለዎት፣ በአዲሱ ቋትዎ Ether ለማግኘት ፈጣኑ መንገድ ቀጥተኛ ተቀማጭ ነው።"
},
"done": {
"message": "ተጠናቅቋል"
},
@ -581,9 +572,6 @@
"myAccounts": {
"message": "የእኔ መለያዎች"
},
"needEtherInWallet": {
"message": "MetaMask በመጠቀም ያልተማከሉ መተግበሪያዎች ጋር ግንኙነት ለማድረግ፣ በቋትዎ ውስጥ Ether ያስፈልግዎታል።"
},
"needImportFile": {
"message": "የሚያስመጡትን ፋይል መምረጥ አለብዎት።",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "رفض"
},
"QRHardwareWalletImporterTitle": {
"message": "مسح كود الاستجابة السريعة QR"
},
"about": {
"message": "حول"
},
@ -8,6 +14,14 @@
"acceleratingATransaction": {
"message": "* تسريع المعاملات باستخدام سعر عملة جاس أعلى يزيد من فرص معالجتها بواسطة الشبكة بشكلٍ أسرع، لكن ذلك غير مضمون دائماً."
},
"acceptTermsOfUse": {
"message": "لقد قرأت دولار واحد وأوافق عليه",
"description": "$1 is the `terms` message"
},
"accessAndSpendNotice": {
"message": "$1 يمكن الوصول إلى هذا المبلغ الأقصى وإنفاقه حتى",
"description": "$1 is the url of the site requesting ability to spend"
},
"accessingYourCamera": {
"message": "جاري استخدام كاميرتك..."
},
@ -256,6 +270,9 @@
"currentLanguage": {
"message": "اللغة الحالية"
},
"custom": {
"message": "إعدادات متقدمة"
},
"customGas": {
"message": "تخصيص الغاز"
},
@ -283,18 +300,9 @@
"deleteNetworkDescription": {
"message": "هل أنت متأكد أنك تريد حذف هذه الشبكة؟"
},
"depositEther": {
"message": "إيداع عملة إيثير"
},
"details": {
"message": "التفاصيل"
},
"directDepositEther": {
"message": "إيداع مباشرة لعملة الأثير"
},
"directDepositEtherExplainer": {
"message": "إذا كان لديك بالفعل بعض الأثير، فإن أسرع طريقة للحصول على الأثير في محفظتك الجديدة عن طريق الإيداع المباشر."
},
"done": {
"message": "تم"
},
@ -526,6 +534,9 @@
"learnMore": {
"message": "اكتشف المزيد"
},
"learnMoreUpperCase": {
"message": "اكتشف المزيد"
},
"ledgerAccountRestriction": {
"message": "أنت بحاجة إلى استخدام حسابك الأخير قبل أن تتمكن من إضافة حساب جديد."
},
@ -577,9 +588,6 @@
"myAccounts": {
"message": "حساباتي"
},
"needEtherInWallet": {
"message": "للتفاعل مع التطبيقات اللامركزية باستخدام MetaMask، ستحتاج إلى الإيثير في محفظتك."
},
"needImportFile": {
"message": "يلزم تحديد ملف للاستيراد.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Отхвърляне"
},
"QRHardwareWalletImporterTitle": {
"message": "Сканиране на QR код"
},
"about": {
"message": "Информация"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Настоящ език"
},
"custom": {
"message": "Разширени"
},
"customGas": {
"message": "Персонализирайте газ"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Наистина ли искате да изтриете тази мрежа?"
},
"depositEther": {
"message": "Депозирайте етер"
},
"details": {
"message": "Подробности"
},
"directDepositEther": {
"message": "Директно депозиране на етер"
},
"directDepositEtherExplainer": {
"message": "Ако вече имате някакъв етер, най-бързият начин да получите етер в новия си портфейл е чрез директен депозит."
},
"done": {
"message": "Готово"
},
@ -526,6 +526,9 @@
"learnMore": {
"message": "Научете повече"
},
"learnMoreUpperCase": {
"message": "Научете повече"
},
"ledgerAccountRestriction": {
"message": "Трябва да използвате последния си акаунт, преди да можете да добавите нов."
},
@ -580,9 +583,6 @@
"myAccounts": {
"message": "Моите акаунти"
},
"needEtherInWallet": {
"message": "За да взаимодействате с децентрализираните приложения, използвайки MetaMask, ще ви е необходим етер в портфейла ви."
},
"needImportFile": {
"message": "Трябва да изберете файл за импортиране.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "পরতন"
},
"QRHardwareWalletImporterTitle": {
"message": "QR কড সন করন"
},
"about": {
"message": "সমপর"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "বরতমন ভ"
},
"custom": {
"message": "উননত"
},
"customGas": {
"message": "গস কইজ করন"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "আপনিি এই নটওয়কটির বিষয়িিত?"
},
"depositEther": {
"message": "ইথর জম করন"
},
"details": {
"message": "বিশদ বিবরণ"
},
"directDepositEther": {
"message": "সরসরি ইথর জম করন"
},
"directDepositEtherExplainer": {
"message": "আপনর ইতিমধি ইথর থকল আপনর নতন ওয় ইথর পওয়র দততম উপয় হল সরসরি জম কর।"
},
"done": {
"message": "সমপনন "
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "আরও জন"
},
"learnMoreUpperCase": {
"message": "আরও জন"
},
"ledgerAccountRestriction": {
"message": "একটি নতন অউনট যগ করর আগ আপন আপনর শষ অউনট বযবহর করলত হব।"
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "আমর অউনটগি"
},
"needEtherInWallet": {
"message": "MetaMask বযবহর কর ছড়িিিিশনগির সগ করত, আপনর ওয় ইথর লগব।"
},
"needImportFile": {
"message": "আমদি করর জনয আপন অবশযই একটিইল নিচন করত হব।",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Rebutja"
},
"QRHardwareWalletImporterTitle": {
"message": "Escanejar Codi QR"
},
"about": {
"message": "Informació"
},
@ -253,6 +259,9 @@
"currentLanguage": {
"message": "Llengua Actual"
},
"custom": {
"message": "Configuració avançada"
},
"customGas": {
"message": "Customitza el gas"
},
@ -280,18 +289,9 @@
"deleteNetworkDescription": {
"message": "Estàs segur que vols eliminar aquesta xarxa?"
},
"depositEther": {
"message": "Diposita Ether"
},
"details": {
"message": "Detalls"
},
"directDepositEther": {
"message": "Diposita Ether directament"
},
"directDepositEtherExplainer": {
"message": "Si ja tens una mica d'Ether, la manera més ràpida de posar Ether al teu nou moneder és per dipòsit directe."
},
"done": {
"message": "Fet"
},
@ -517,6 +517,9 @@
"learnMore": {
"message": "Saber més"
},
"learnMoreUpperCase": {
"message": "Saber més"
},
"ledgerAccountRestriction": {
"message": "Has de fer servir el teu últim compte abans de poder afegir-ne un altre."
},
@ -568,9 +571,6 @@
"myAccounts": {
"message": "Els meus Comptes"
},
"needEtherInWallet": {
"message": "Per a interactuar amb aplicacions descentralitzades fent servir MetaMask, necessitaràs Ether al teu moneder."
},
"needImportFile": {
"message": "Has de seleccionar un arxiu per a importar.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "Odmítnout"
},
"account": {
"message": "Účet"
},
@ -105,18 +108,9 @@
"decimalsMustZerotoTen": {
"message": "Desetinných míst musí být od 0 do 36."
},
"depositEther": {
"message": "Vložit Ether"
},
"details": {
"message": "Podrobnosti"
},
"directDepositEther": {
"message": "Vložit Ether přímo"
},
"directDepositEtherExplainer": {
"message": "Pokud už vlastníte nějaký Ether, nejrychleji ho dostanete do peněženky přímým vkladem."
},
"done": {
"message": "Hotovo"
},
@ -213,6 +207,9 @@
"learnMore": {
"message": "Zjistěte více."
},
"learnMoreUpperCase": {
"message": "Zjistěte více."
},
"likeToImportTokens": {
"message": "Chcete přidat tyto tokeny?"
},
@ -240,9 +237,6 @@
"myAccounts": {
"message": "Moje účty"
},
"needEtherInWallet": {
"message": "Potřebujete Ether v peněžence, abyste mohli pomocí MetaMasku interagovat s decentralizovanými aplikacemi."
},
"needImportFile": {
"message": "Musíte zvolit soubor k importu.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Afvis"
},
"QRHardwareWalletImporterTitle": {
"message": "Scan QR-kode"
},
"about": {
"message": "Om"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Nuværende sprog"
},
"custom": {
"message": "Avanceret"
},
"customGas": {
"message": "Tilpas brændstof"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Er du sikker på, at du vil slette dette netværk?"
},
"depositEther": {
"message": "Indbetal Ether"
},
"details": {
"message": "Detaljer"
},
"directDepositEther": {
"message": "Indskyd Ether direkte"
},
"directDepositEtherExplainer": {
"message": "Hvis du allerede har Ether, er den hurtigste måde at få Ether i din nye tegnebog ved direkte indbetaling."
},
"done": {
"message": "Færdig"
},
@ -523,6 +523,9 @@
"learnMore": {
"message": "Lær mere"
},
"learnMoreUpperCase": {
"message": "Lær mere"
},
"ledgerAccountRestriction": {
"message": "Du skal benytte din tidligere konto, før du kan tilføje en ny."
},
@ -568,9 +571,6 @@
"myAccounts": {
"message": "Mine Konti"
},
"needEtherInWallet": {
"message": "Du skal have Ether i din tegnebog for at interagere med decentraliserede applikationer, der bruger MetaMask."
},
"needImportFile": {
"message": "Du skal vælge en fil, der skal importeres.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Ablehnen"
},
"QRHardwareWalletImporterTitle": {
"message": "QR-Code scannen"
},
"about": {
"message": "Über"
},
@ -247,6 +253,9 @@
"currentLanguage": {
"message": "Aktuelle Sprache"
},
"custom": {
"message": "Erweitert"
},
"customGas": {
"message": "Gas anpassen"
},
@ -274,14 +283,42 @@
"deleteNetworkDescription": {
"message": "Sind Sie sicher, dass Sie dieses Netzwerk löschen möchten?"
},
"depositEther": {
"message": "Ether einzahlen"
"description": {
"message": "Beschreibung"
},
"details": {
"message": "Details"
},
"disabledGasOptionToolTipMessage": {
"message": "“$1” ist deaktiviert, weil es nicht das Minimum einer zehnprozentigen Erhöhung gegenüber der ursprünglichen Gasgebühr erfüllt.",
"description": "$1 is gas estimate type which can be market or aggressive"
},
"disconnect": {
"message": "Verbindung trennen"
},
"disconnectAllAccounts": {
"message": "Alle Konten trennen"
},
"disconnectAllAccountsConfirmationDescription": {
"message": "Sind Sie sicher, dass Sie die Verbindung trennen möchten? Sie könnten die Site-Funktionalität verlieren."
},
"directDepositEther": {
"message": "Sofort Ether einzahlen"
"disconnectPrompt": {
"message": "$1 trennen"
},
"directDepositEtherExplainer": {
"message": "Wenn du bereits Ether besitzt, ist die sofortige Einzahlung die schnellste Methode Ether in deine neue Wallet zu bekommen."
"disconnectThisAccount": {
"message": "Dieses Konto trennen"
},
"dismiss": {
"message": "Verwerfen"
},
"dismissReminderDescriptionField": {
"message": "Aktivieren Sie diese Option, um die Erinnerungsmeldung zur Sicherung des Geheime Wiederherstellungsphrase zu deaktivieren. Wir empfehlen Ihnen dringend, eine Sicherungskopie Ihrer Geheime Wiederherstellungsphrase zu erstellen, um den Verlust von Geldern zu vermeiden"
},
"dismissReminderField": {
"message": "Erinnerung Geheime Wiederherstellungsphrase abweisen"
},
"domain": {
"message": "Domäne"
},
"done": {
"message": "Fertig"
@ -427,9 +464,6 @@
"happyToSeeYou": {
"message": "Wir freuen uns, Sie zu sehen."
},
"hardware": {
"message": "Hardware"
},
"hardwareWalletConnected": {
"message": "Hardware-Wallet verknüpft"
},
@ -518,6 +552,9 @@
"learnMore": {
"message": "Mehr erfahren"
},
"learnMoreUpperCase": {
"message": "Mehr erfahren"
},
"ledgerAccountRestriction": {
"message": "Sie müssen Ihr letztes Konto verwenden, ehe Sie ein neues hinzufügen können."
},
@ -539,9 +576,6 @@
"lock": {
"message": "Ausloggen"
},
"mainnet": {
"message": "Ethereum Mainnet"
},
"memo": {
"message": " Memo"
},
@ -563,9 +597,6 @@
"myAccounts": {
"message": "Meine Accounts"
},
"needEtherInWallet": {
"message": "Um dezentralisierte Applikationen mit MetaMask verwenden zu können, benötigst du Ether in deiner Wallet."
},
"needImportFile": {
"message": "Für den Import musst du eine Datei auswählen.",
"description": "User is important an account and needs to add a file to continue"
@ -591,10 +622,6 @@
"newAccountDetectedDialogMessage": {
"message": "Neue Adresse erkannt! Klicken Sie hier, um sie zu Ihrem Adressbuch hinzuzufügen."
},
"newAccountNumberName": {
"message": "Account $1",
"description": "Default name of next account to be created on create account screen"
},
"newContact": {
"message": "Neuer Kontakt"
},

File diff suppressed because it is too large Load Diff

@ -140,9 +140,6 @@
"addMemo": {
"message": "Add memo"
},
"addNFT": {
"message": "Add NFT"
},
"addNetwork": {
"message": "Add Network"
},
@ -392,11 +389,13 @@
"buy": {
"message": "Buy"
},
"buyWithTransak": {
"message": "Buy ETH with Transak"
"buyCryptoWithTransak": {
"message": "Buy $1 with Transak",
"description": "$1 represents the cypto symbol to be purchased"
},
"buyWithTransakDescription": {
"message": "Transak supports debit card and bank transfers (depending on location) in 59+ countries. ETH deposits into your MetaMask account."
"buyCryptoWithTransakDescription": {
"message": "Transak supports debit card and bank transfers (depending on location) in 59+ countries. $1 deposits into your MetaMask account.",
"description": "$1 represents the cypto symbol to be purchased"
},
"buyWithWyre": {
"message": "Buy ETH with Wyre"
@ -458,6 +457,10 @@
"close": {
"message": "Close"
},
"collectibleAddressError": {
"message": "This token is an NFT. Add on the $1",
"description": "$1 is a clickable link with text defined by the 'importNFTPage' key"
},
"confirm": {
"message": "Confirm"
},
@ -595,6 +598,9 @@
"contractInteraction": {
"message": "Contract Interaction"
},
"convertTokenToNFTDescription": {
"message": "We've detected that this asset is an NFT. Metamask now has full native support for NFTs. Would you like to remove it from your token list and add it as an NFT?"
},
"copiedExclamation": {
"message": "Copied!"
},
@ -652,6 +658,15 @@
"currentlyUnavailable": {
"message": "Unavailable on this network"
},
"curveHighGasEstimate": {
"message": "Aggressive gas estimate graph"
},
"curveLowGasEstimate": {
"message": "Low gas estimate graph"
},
"curveMediumGasEstimate": {
"message": "Market gas estimate graph"
},
"custom": {
"message": "Advanced"
},
@ -659,7 +674,7 @@
"message": "Customize Gas"
},
"customGasSettingToolTipMessage": {
"message": "Use $1 to customise the gas price. This can be confusing if you aren’t familiar. Interact at your own risk.",
"message": "Use $1 to customize the gas price. This can be confusing if you aren’t familiar. Interact at your own risk.",
"description": "$1 is key 'advanced' (text: 'Advanced') separated here so that it can be passed in with bold fontweight"
},
"customGasSubTitle": {
@ -732,8 +747,9 @@
"deleteNetworkDescription": {
"message": "Are you sure you want to delete this network?"
},
"depositEther": {
"message": "Deposit Ether"
"depositCrypto": {
"message": "Deposit $1",
"description": "$1 represents the cypto symbol to be purchased"
},
"description": {
"message": "Description"
@ -741,11 +757,11 @@
"details": {
"message": "Details"
},
"directDepositEther": {
"message": "Directly Deposit Ether"
"directDepositCrypto": {
"message": "Directly Deposit $1"
},
"directDepositEtherExplainer": {
"message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit."
"directDepositCryptoExplainer": {
"message": "If you already have some $1, the quickest way to get $1 in your new wallet by direct deposit."
},
"disabledGasOptionToolTipMessage": {
"message": "“$1” is disabled because it does not meet the minimum of a 10% increase from the original gas fee.",
@ -933,6 +949,22 @@
"enableAutoDetect": {
"message": " Enable Autodetect"
},
"enableEIP1559V2": {
"message": "Enable Enhanced Gas Fee UI"
},
"enableEIP1559V2AlertMessage": {
"message": "We've updated how gas fee estimation and customization works."
},
"enableEIP1559V2ButtonText": {
"message": "Turn on Enhanced Gas Fee UI in Settings"
},
"enableEIP1559V2Description": {
"message": "We've updated how gas estimation and customization works. Turn on if you'd like to use the new gas experience. $1",
"description": "$1 here is Learn More link"
},
"enableEIP1559V2Header": {
"message": "New gas experience"
},
"enableFromSettings": {
"message": " Enable it from Settings."
},
@ -1054,7 +1086,7 @@
"message": "Backup gas price is provided as the main gas estimation service is unavailable right now."
},
"eth_accounts": {
"message": "See address, account balance, activity and initiate transactions",
"message": "See address, account balance, activity and suggest transactions to approve",
"description": "The description for the `eth_accounts` permission"
},
"ethereumPublicAddress": {
@ -1190,6 +1222,9 @@
"gasLimitInfoTooltipContent": {
"message": "Gas limit is the maximum amount of units of gas you are willing to spend."
},
"gasLimitRecommended": {
"message": "Recommended gas limit is $1. If the gas limit is less than that, it may fail."
},
"gasLimitTooLow": {
"message": "Gas limit must be at least 21000"
},
@ -1337,11 +1372,8 @@
"high": {
"message": "Aggressive"
},
"highGasSettingToolTipDialog": {
"message": "High probability, even in volatile markets"
},
"highGasSettingToolTipMessage": {
"message": "Use $1 to cover surges in network traffic due to things like popular NFT drops.",
"message": "High probability, even in volatile markets. Use $1 to cover surges in network traffic due to things like popular NFT drops.",
"description": "$1 is key 'high' (text: 'Aggressive') separated here so that it can be passed in with bold fontweight"
},
"highLowercase": {
@ -1350,9 +1382,6 @@
"history": {
"message": "History"
},
"id": {
"message": "ID"
},
"import": {
"message": "Import",
"description": "Button to import an account from a selected file"
@ -1386,6 +1415,18 @@
"importMyWallet": {
"message": "Import My Wallet"
},
"importNFT": {
"message": "Import NFT"
},
"importNFTAddressToolTip": {
"message": "On OpenSea, for example, on the NFT's page under Details, there is a blue hyperlinked value labeled 'Contract Address'. If you click on this, it will take you to the contract's address on Etherscan; at the top-left of that page, there should be an icon labeled 'Contract', and to the right, a long string of letters and numbers. This is the address of the contract that created your NFT. Click on the 'copy' icon to the right of the address, and you'll have it on your clipboard."
},
"importNFTPage": {
"message": "Import NFT page"
},
"importNFTTokenIdToolTip": {
"message": "A collectible's ID is a unique identifier since no two NFTs are alike. Again, on OpenSea this number is under 'Details'. Make a note of it, or copy it onto your clipboard."
},
"importNFTs": {
"message": "Import NFTs"
},
@ -1439,6 +1480,9 @@
"invalidAddressRecipientNotEthNetwork": {
"message": "Not ETH network, set to lowercase"
},
"invalidAssetType": {
"message": "This asset is an NFT and needs to be re-added on the Import NFTs page found under the NFTs tab"
},
"invalidBlockExplorerURL": {
"message": "Invalid Block Explorer URL"
},
@ -1503,7 +1547,7 @@
"message": "Known contract address."
},
"knownTokenWarning": {
"message": "This action will edit tokens that are already listed in your wallet, which can be used to phish you. Only approve if you are certain that you mean to change what these tokens represent."
"message": "This action will edit tokens that are already listed in your wallet, which can be used to phish you. Only approve if you are certain that you mean to change what these tokens represent. Learn more about $1"
},
"kovan": {
"message": "Kovan Test Network"
@ -1596,6 +1640,9 @@
"loading": {
"message": "Loading..."
},
"loadingNFTs": {
"message": "Loading NFTs..."
},
"loadingTokens": {
"message": "Loading Tokens..."
},
@ -1612,14 +1659,14 @@
"message": "Low"
},
"lowGasSettingToolTipMessage": {
"message": "Use $1 to wait for a cheaper price. Time estimates are much less accurate as prices are somewhat unpredicible.",
"message": "Use $1 to wait for a cheaper price. Time estimates are much less accurate as prices are somewhat unpredictable.",
"description": "$1 is key 'low' separated here so that it can be passed in with bold fontweight"
},
"lowLowercase": {
"message": "low"
},
"lowPriorityMessage": {
"message": "Future transactions will queue after this one. This price was last seen was some time ago."
"message": "Future transactions will queue after this one."
},
"mainnet": {
"message": "Ethereum Mainnet"
@ -1755,8 +1802,9 @@
"name": {
"message": "Name"
},
"needEtherInWallet": {
"message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet."
"needCryptoInWallet": {
"message": "To interact with decentralized applications using MetaMask, you’ll need $1 in your wallet.",
"description": "$1 represents the cypto symbol to be purchased"
},
"needHelp": {
"message": "Need help? Contact $1",
@ -1891,7 +1939,7 @@
"description": "The next nonce according to MetaMask's internal logic"
},
"nftTokenIdPlaceholder": {
"message": "Enter the collectible ID"
"message": "Enter the Token ID"
},
"nfts": {
"message": "NFTs"
@ -2155,7 +2203,7 @@
"message": "Passwords Don't Match"
},
"pastePrivateKey": {
"message": "Paste your private key string here:",
"message": "Enter your private key string here:",
"description": "For importing an account from a private key"
},
"pending": {
@ -2467,7 +2515,7 @@
"message": "Separate each word with a single space"
},
"seedPhrasePlaceholderPaste": {
"message": "Paste Secret Recovery Phrase from clipboard"
"message": "Enter your Secret Recovery Phrase"
},
"seedPhraseReq": {
"message": "Secret Recovery Phrases contain 12, 15, 18, 21, or 24 words"
@ -3508,6 +3556,9 @@
"message": "$1 of $2 pending",
"description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total"
},
"yes": {
"message": "Yes"
},
"yesLetsTry": {
"message": "Yes, let's try"
},

@ -260,9 +260,6 @@
"buyWithWyreDescription": {
"message": "Wyre le permite usar una tarjeta de débito para depositar ETH directamente en su cuenta de MetaMask."
},
"bytes": {
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Puede volver a activar esta notificación desde Configuración -> Alertas."
},
@ -519,18 +516,9 @@
"deleteNetworkDescription": {
"message": "¿Está seguro de que quiere eliminar esta red?"
},
"depositEther": {
"message": "Depositar ether"
},
"details": {
"message": "Detalles"
},
"directDepositEther": {
"message": "Depositar ether directamente"
},
"directDepositEtherExplainer": {
"message": "Si ya tiene algunos ethers, la forma más rápida de tenerlos en la cartera nueva es mediante depósito directo."
},
"disconnect": {
"message": "Desconectar"
},
@ -696,9 +684,6 @@
"ethereumPublicAddress": {
"message": "Dirección pública de Ethereum"
},
"etherscan": {
"message": "Etherscan"
},
"etherscanView": {
"message": "Ver cuenta en Etherscan"
},
@ -802,9 +787,6 @@
"message": "Política de privacidad aquí",
"description": "this translation is intended to be exclusively used as the replacement for the $1 in the gdprMessage translation"
},
"general": {
"message": "General"
},
"generalSettingsDescription": {
"message": "Conversión de moneda, moneda principal, idioma, Blockies Identicon"
},
@ -824,16 +806,9 @@
"happyToSeeYou": {
"message": "Nos alegra verlo."
},
"hardware": {
"message": "Hardware"
},
"hardwareWalletConnected": {
"message": "Cartera de hardware conectada"
},
"hardwareWalletLegacyDescription": {
"message": "(legacy)",
"description": "Text representing the MEW path"
},
"hardwareWalletSupportLinkConversion": {
"message": "Haga clic aquí"
},
@ -1116,9 +1091,6 @@
"name": {
"message": "Nombre"
},
"needEtherInWallet": {
"message": "Para interactuar con aplicaciones descentralizadas mediante MetaMask, necesitará ethers en su cartera."
},
"needHelp": {
"message": "¿Necesita ayuda? Comuníquese con $1",
"description": "$1 represents `needHelpLinkText`, the text which goes in the help link"
@ -1139,15 +1111,9 @@
"networkName": {
"message": "Nombre de la red"
},
"networkNameBSC": {
"message": "BSC"
},
"networkNameDefinition": {
"message": "El nombre asociado a esta red."
},
"networkNameEthereum": {
"message": "Ethereum"
},
"networkNameTestnet": {
"message": "Red de prueba"
},
@ -1228,9 +1194,6 @@
"noWebcamFoundTitle": {
"message": "No se encontró cámara web"
},
"nonce": {
"message": "Nonce"
},
"nonceField": {
"message": "Personalizar nonce de transacción"
},
@ -2128,9 +2091,6 @@
"message": "Para: $1",
"description": "$1 is the address to include in the To label. It is typically shortened first using shortenAddress"
},
"token": {
"message": "Token"
},
"tokenAlreadyAdded": {
"message": "Ya se agregó el token."
},
@ -2146,9 +2106,6 @@
"tooltipApproveButton": {
"message": "Comprendo"
},
"total": {
"message": "Total"
},
"transaction": {
"message": "transacción"
},

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Rechazar"
},
"QRHardwareWalletImporterTitle": {
"message": "Escanear código QR"
},
"about": {
"message": "Acerca de"
},
@ -260,9 +266,6 @@
"buyWithWyreDescription": {
"message": "Wyre le permite usar una tarjeta de débito para depositar ETH directamente en su cuenta de MetaMask."
},
"bytes": {
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Puede volver a activar esta notificación desde Configuración -> Alertas."
},
@ -466,6 +469,9 @@
"currentLanguage": {
"message": "Idioma actual"
},
"custom": {
"message": "Avanzado"
},
"customGas": {
"message": "Personalizar gas"
},
@ -519,17 +525,12 @@
"deleteNetworkDescription": {
"message": "¿Está seguro de que quiere eliminar esta red?"
},
"depositEther": {
"message": "Depositar ether"
},
"details": {
"message": "Detalles"
},
"directDepositEther": {
"message": "Depositar ether directamente"
},
"directDepositEtherExplainer": {
"message": "Si ya tiene algunos ethers, la forma más rápida de tenerlos en la cartera nueva es mediante depósito directo."
"disabledGasOptionToolTipMessage": {
"message": "\"1$\" está desactivado porque no cumple el mínimo de un aumento del 10% respecto a la tarifa de gas original.",
"description": "$1 is gas estimate type which can be market or aggressive"
},
"disconnect": {
"message": "Desconectar"
@ -696,9 +697,6 @@
"ethereumPublicAddress": {
"message": "Dirección pública de Ethereum"
},
"etherscan": {
"message": "Etherscan"
},
"etherscanView": {
"message": "Ver cuenta en Etherscan"
},
@ -802,9 +800,6 @@
"message": "Política de privacidad aquí",
"description": "this translation is intended to be exclusively used as the replacement for the $1 in the gdprMessage translation"
},
"general": {
"message": "General"
},
"generalSettingsDescription": {
"message": "Conversión de moneda, moneda principal, idioma, Blockies Identicon"
},
@ -824,16 +819,9 @@
"happyToSeeYou": {
"message": "Nos alegra verlo."
},
"hardware": {
"message": "Hardware"
},
"hardwareWalletConnected": {
"message": "Cartera de hardware conectada"
},
"hardwareWalletLegacyDescription": {
"message": "(legacy)",
"description": "Text representing the MEW path"
},
"hardwareWalletSupportLinkConversion": {
"message": "Haga clic aquí"
},
@ -993,6 +981,9 @@
"learnMore": {
"message": "Más información"
},
"learnMoreUpperCase": {
"message": "Más información"
},
"ledgerAccountRestriction": {
"message": "Debe usar su última cuenta antes de poder agregar una nueva."
},
@ -1116,9 +1107,6 @@
"name": {
"message": "Nombre"
},
"needEtherInWallet": {
"message": "Para interactuar con aplicaciones descentralizadas mediante MetaMask, necesitará ethers en su cartera."
},
"needHelp": {
"message": "¿Necesita ayuda? Comuníquese con $1",
"description": "$1 represents `needHelpLinkText`, the text which goes in the help link"
@ -1139,15 +1127,9 @@
"networkName": {
"message": "Nombre de la red"
},
"networkNameBSC": {
"message": "BSC"
},
"networkNameDefinition": {
"message": "El nombre asociado a esta red."
},
"networkNameEthereum": {
"message": "Ethereum"
},
"networkNameTestnet": {
"message": "Red de prueba"
},
@ -1228,9 +1210,6 @@
"noWebcamFoundTitle": {
"message": "No se encontró cámara web"
},
"nonce": {
"message": "Nonce"
},
"nonceField": {
"message": "Personalizar nonce de transacción"
},
@ -2128,9 +2107,6 @@
"message": "Para: $1",
"description": "$1 is the address to include in the To label. It is typically shortened first using shortenAddress"
},
"token": {
"message": "Token"
},
"tokenAlreadyAdded": {
"message": "Ya se agregó el token."
},
@ -2146,9 +2122,6 @@
"tooltipApproveButton": {
"message": "Comprendo"
},
"total": {
"message": "Total"
},
"transaction": {
"message": "transacción"
},

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Lükka tagasi"
},
"QRHardwareWalletImporterTitle": {
"message": "Skannige QR-koos"
},
"about": {
"message": "Teave"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Praegune keel"
},
"custom": {
"message": "Täpsemad"
},
"customGas": {
"message": "Gaasi kohandamine"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Olete kindel, et soovite selle võrgu kustutada?"
},
"depositEther": {
"message": "Eetri sissemakse"
},
"details": {
"message": "Üksikasjad"
},
"directDepositEther": {
"message": "Eetri otsene sissemakse"
},
"directDepositEtherExplainer": {
"message": "Kui teil on juba veidi eetrit, on kiirem viis eetri rahakotti saamiseks otsene sissemakse."
},
"done": {
"message": "Valmis"
},
@ -526,6 +526,9 @@
"learnMore": {
"message": "Lisateave"
},
"learnMoreUpperCase": {
"message": "Lisateave"
},
"ledgerAccountRestriction": {
"message": "Enne uue konto loomist peate kasutama eelmist kontot."
},
@ -574,9 +577,6 @@
"myAccounts": {
"message": "Minu kontod"
},
"needEtherInWallet": {
"message": "Selleks, et suhelda MetaMaski abil detsentraliseeritud rakendustega, peab teil rahakotis eetrit olema."
},
"needImportFile": {
"message": "Peate importimiseks faili valima.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "عدم پذیرش"
},
"QRHardwareWalletImporterTitle": {
"message": "سکن کود QR"
},
"about": {
"message": "درباره"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "زبان فعلی"
},
"custom": {
"message": "پیشرفته"
},
"customGas": {
"message": "گاز دلخواه"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "آیا مطمئن هستید که این شبکه حذف شود؟"
},
"depositEther": {
"message": "پرداخت ایتر"
},
"details": {
"message": "جزئیات"
},
"directDepositEther": {
"message": "پرداخت مستقیم ایتر"
},
"directDepositEtherExplainer": {
"message": "در صورتیکه شما کدام ایتر داشته باشید، سریعترین روش برای گرفتن ایتر در کیف جدید تان توسط پرداخت مستقیم."
},
"done": {
"message": "تمام"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "بیشتر بدانید"
},
"learnMoreUpperCase": {
"message": "بیشتر بدانید"
},
"ledgerAccountRestriction": {
"message": "لازم است تا حساب قبلی تان را قبل از اینکه جدید اضافه کنید، مورد استفاده قرار دهید."
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "حساب های من"
},
"needEtherInWallet": {
"message": "برای تعامل با اپلیکیشن های غیر متمرکز شده با استفاده از MetaMask، شما نیاز به ایتر در کیف تان خواهید داشت."
},
"needImportFile": {
"message": "شما باید یک فایل برای وارد کردن را انتخاب کنید.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Hylkää"
},
"QRHardwareWalletImporterTitle": {
"message": "Lue QR-koodi"
},
"about": {
"message": "Tietoja asetuksista"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Nykyinen kieli"
},
"custom": {
"message": "Lisäasetukset"
},
"customGas": {
"message": "Mukauta bensa"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Haluatko varmasti poistaa tämän verkon?"
},
"depositEther": {
"message": "Talleta Etheriä"
},
"details": {
"message": "Tiedot"
},
"directDepositEther": {
"message": "Talleta etheriä suoraan"
},
"directDepositEtherExplainer": {
"message": "Jos sinulla on jo etheriä, nopein tapa hankkia etheriä uuteen lompakkoosi on suoratalletus."
},
"done": {
"message": "Valmis"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "Lisätietoa"
},
"learnMoreUpperCase": {
"message": "Lisätietoa"
},
"ledgerAccountRestriction": {
"message": "Sinun tarvitsee käyttää edellistä tiliäsi ennen kuin voit lisätä uuden."
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "Omat tilit"
},
"needEtherInWallet": {
"message": "Ollaksesi vuorovaikutuksessa hajautettujen sovellusten kanssa sinulla on oltava lompakossasi Ether."
},
"needImportFile": {
"message": "Sinun tarvitsee valita tuotava tiedosto.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Tanggihan"
},
"QRHardwareWalletImporterTitle": {
"message": "I-scan ang QR Code"
},
"about": {
"message": "Tungkol sa"
},
@ -262,18 +268,9 @@
"deleteNetworkDescription": {
"message": "Sigurado ka bang gusto mong i-delete ang network na ito?"
},
"depositEther": {
"message": "Magdeposito ng Ether"
},
"details": {
"message": "Mga Detalye"
},
"directDepositEther": {
"message": "Direktang Magdeposito ng Ether"
},
"directDepositEtherExplainer": {
"message": "Kung mayroon ka nang Ether, ang pinakamabilis na paraan para magkaroon ng Ether sa iyong bagong wallet ay sa pamamagitan ng direkang deposito."
},
"done": {
"message": "Tapos na"
},
@ -483,6 +480,9 @@
"learnMore": {
"message": "Matuto pa"
},
"learnMoreUpperCase": {
"message": "Matuto pa"
},
"ledgerAccountRestriction": {
"message": "Kailangan mong gamitin ang iyong dating account bago ka makapagdagdag ng bago."
},
@ -525,9 +525,6 @@
"myAccounts": {
"message": "Mga Account Ko"
},
"needEtherInWallet": {
"message": "Para gumamit ng mga decentralized na application gamit ang MetaMask, mangangailangan ka ng Ether sa iyong wallet."
},
"needImportFile": {
"message": "Dapat kang pumili ng file na ii-import.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "નક"
},
"about": {
"message": "વિ"
},
@ -44,6 +47,9 @@
"create": {
"message": "બન"
},
"custom": {
"message": "વિગતવર"
},
"delete": {
"message": "ક"
},

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "דחה"
},
"QRHardwareWalletImporterTitle": {
"message": "סריקת קוד QR"
},
"about": {
"message": "מידע כללי"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "שפה נוכחית"
},
"custom": {
"message": "מתקדם"
},
"customGas": {
"message": "התאמה אישית של דלק"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "הנך בטוח/ה שברצונך למחוק רשת זו?"
},
"depositEther": {
"message": "הפקדת את'ר"
},
"details": {
"message": "פרטים"
},
"directDepositEther": {
"message": "הפקד את'ר ישירות"
},
"directDepositEtherExplainer": {
"message": "אם כבר יש ברשותך את'ר (Ether) , הדרך המהירה ביותר להכניס את'ר לארנק החדש שלך היא באמצעות הפקדה ישירה."
},
"done": {
"message": "סיום"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "למדו עוד"
},
"learnMoreUpperCase": {
"message": "למדו עוד"
},
"ledgerAccountRestriction": {
"message": "עליך להשתמש בחשבון האחרון שלך לפני שתוכל/י להוסיף חשבון חדש."
},
@ -581,9 +584,6 @@
"myAccounts": {
"message": "החשבונות שלי"
},
"needEtherInWallet": {
"message": "כדי לתקשר עם אפליקציות מבוזרות באמצעות MetaMask, צריך להיות לך את'ר בארנק."
},
"needImportFile": {
"message": "יש לבחור קובץ לייצוא.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

@ -84,18 +84,9 @@
"decimalsMustZerotoTen": {
"message": "दशमलव कम स कम 0 हिए, और 36 स अधिक नहिए।"
},
"depositEther": {
"message": "जम - Ether"
},
"details": {
"message": "सश विवरण"
},
"directDepositEther": {
"message": "स ईथर जम कर"
},
"directDepositEtherExplainer": {
"message": "यदि आपकस पहलछ ईथर ह, त जम अपन नए बटए म ईथर पत करन तर।"
},
"done": {
"message": "सपनन"
},
@ -223,9 +214,6 @@
"myAccounts": {
"message": "म"
},
"needEtherInWallet": {
"message": "मक क उपयग करनित अनरयथ बतचत करनिए, आपक अपनट म ईथर क आवशयकत।"
},
"needImportFile": {
"message": "आयत करनिए आपक एक फइल क चयन करन।",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Odbaci"
},
"QRHardwareWalletImporterTitle": {
"message": "Skeniraj kôd QR"
},
"about": {
"message": "O opcijama"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Trenutačni jezik"
},
"custom": {
"message": "Napredno"
},
"customGas": {
"message": "Prilagodi gorivo"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Sigurno želite izbrisati ovu mrežu?"
},
"depositEther": {
"message": "Položi Ether"
},
"details": {
"message": "Detalji"
},
"directDepositEther": {
"message": "Izravan polog Ether"
},
"directDepositEtherExplainer": {
"message": "Ako imate nešto Ethera, najbrži je način prebacivanja Ethera u vaš novi novčanik izravan polog."
},
"done": {
"message": "Gotovo"
},
@ -526,6 +526,9 @@
"learnMore": {
"message": "Saznajte više"
},
"learnMoreUpperCase": {
"message": "Saznajte više"
},
"ledgerAccountRestriction": {
"message": "Treba se koristiti zadnjim računom kako biste dodali novi račun."
},
@ -577,9 +580,6 @@
"myAccounts": {
"message": "Moji računi"
},
"needEtherInWallet": {
"message": "Trebate Ether u svojem novčaniku kako biste ostvarili interakciju s decentraliziranim aplikacijama uporabom usluge MetaMask. "
},
"needImportFile": {
"message": "Morate odabrati datoteku za uvoz.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Rejte"
},
"QRHardwareWalletImporterTitle": {
"message": "Enspeksyon QR Kòd"
},
"accessingYourCamera": {
"message": "Aksè a Kamera"
},
@ -153,18 +159,9 @@
"decimalsMustZerotoTen": {
"message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36."
},
"depositEther": {
"message": "Depo Ether"
},
"details": {
"message": "Detay yo"
},
"directDepositEther": {
"message": "Dirèkteman Depo Ether"
},
"directDepositEtherExplainer": {
"message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk."
},
"done": {
"message": "Fini"
},
@ -307,6 +304,9 @@
"learnMore": {
"message": "Aprann plis"
},
"learnMoreUpperCase": {
"message": "Aprann plis"
},
"ledgerAccountRestriction": {
"message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo."
},
@ -346,9 +346,6 @@
"myAccounts": {
"message": "Kont mwen"
},
"needEtherInWallet": {
"message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou."
},
"needImportFile": {
"message": "Ou dwe chwazi yon dosye pou enpòte.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Elutasítás"
},
"QRHardwareWalletImporterTitle": {
"message": "QR-kód beolvasása"
},
"about": {
"message": "Névjegy"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Aktuális nyelv"
},
"custom": {
"message": "Speciális"
},
"customGas": {
"message": "Gáz testreszabása"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Biztosan törli ezt a hálózatot?"
},
"depositEther": {
"message": "Ether befizetése"
},
"details": {
"message": "Részletek"
},
"directDepositEther": {
"message": "Fizess be ethert közvetlenül"
},
"directDepositEtherExplainer": {
"message": "Amennyiben már rendelkezik némi Ether-rel, a közvetlen letéttel gyorsan elhelyezheti azt új pénztárcájában."
},
"done": {
"message": "Kész"
},
@ -526,6 +526,9 @@
"learnMore": {
"message": "Tudjon meg többet"
},
"learnMoreUpperCase": {
"message": "Tudjon meg többet"
},
"ledgerAccountRestriction": {
"message": "Használnia kell a korábbi fiókját, mielőtt újat adhat hozzá. "
},
@ -577,9 +580,6 @@
"myAccounts": {
"message": "Fiókjaim"
},
"needEtherInWallet": {
"message": "Ha a MetaMaskon keresztül szeretne interakcióba lépni decentralizált alkalmazással, ahhoz a tárcájában Ethernek kell lennie."
},
"needImportFile": {
"message": "Ki kell választania az importálni kívánt fájlt.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Annulla"
},
"QRHardwareWalletImporterTitle": {
"message": "Scansiona Codice QR"
},
"about": {
"message": "Informazioni"
},
@ -19,9 +25,6 @@
"accessingYourCamera": {
"message": "Accesso alla fotocamera..."
},
"account": {
"message": "Account"
},
"accountDetails": {
"message": "Dettagli Account"
},
@ -145,9 +148,6 @@
"approved": {
"message": "Approvato"
},
"asset": {
"message": "Asset"
},
"assets": {
"message": "Patrimonio"
},
@ -221,9 +221,6 @@
"buyWithWyreDescription": {
"message": "Wyre ti consente di usare la carta di credito per depositare ETH direttamente nel tuo account MetaMask."
},
"bytes": {
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Puoi riabilitare questa notifica in Impostazioni -> Avvisi."
},
@ -236,9 +233,6 @@
"cancelled": {
"message": "Annullata"
},
"chainId": {
"message": "Chain ID"
},
"chromeRequiredForHardwareWallets": {
"message": "Devi usare MetaMask con Google Chrome per connettere il tuo Portafoglio Hardware"
},
@ -400,6 +394,9 @@
"currentLanguage": {
"message": "Lingua Corrente"
},
"custom": {
"message": "Avanzate"
},
"customGas": {
"message": "Personalizza Gas"
},
@ -453,18 +450,9 @@
"deleteNetworkDescription": {
"message": "Sei sicuro di voler eliminare questa rete?"
},
"depositEther": {
"message": "Deposita Ether"
},
"details": {
"message": "Dettagli"
},
"directDepositEther": {
"message": "Deposita Direttamente Ether"
},
"directDepositEtherExplainer": {
"message": "Se possiedi già degli Ether, questa è la via più veloce per aggiungere Ether al tuo portafoglio con un deposito diretto."
},
"disconnect": {
"message": "Disconnetti"
},
@ -586,10 +574,6 @@
"message": "MetaMask ha riscontrato un errore",
"description": "Title of generic error page"
},
"errorStack": {
"message": "Stack:",
"description": "Title for error stack, which is displayed for debugging purposes"
},
"estimatedProcessingTimes": {
"message": "Tempi di Elaborazione Stimati"
},
@ -600,9 +584,6 @@
"ethereumPublicAddress": {
"message": "Indirizzo pubblico Ethereum "
},
"etherscan": {
"message": "Etherscan"
},
"etherscanView": {
"message": "Vedi account su Etherscan"
},
@ -858,6 +839,9 @@
"learnMore": {
"message": "Scopri di più"
},
"learnMoreUpperCase": {
"message": "Scopri di più"
},
"ledgerAccountRestriction": {
"message": "E' necessario utilizzare l'ultimo account prima di poterne aggiungere uno nuovo."
},
@ -879,9 +863,6 @@
"loadingTokens": {
"message": "Caricamento Tokens..."
},
"localhost": {
"message": "Localhost 8545"
},
"lock": {
"message": "Disconnetti"
},
@ -958,9 +939,6 @@
"myAccounts": {
"message": "Miei Account"
},
"needEtherInWallet": {
"message": "Per interagire con applicazioni decentralizzate con MetaMask, devi possedere Ether nel tuo portafoglio."
},
"needImportFile": {
"message": "Devi selezionare un file da importare.",
"description": "User is important an account and needs to add a file to continue"
@ -989,10 +967,6 @@
"newAccountDetectedDialogMessage": {
"message": "Rilevato un nuovo indirizzo! Clicca qui per aggiungerlo alla tua rubrica."
},
"newAccountNumberName": {
"message": "Account $1",
"description": "Default name of next account to be created on create account screen"
},
"newContact": {
"message": "Nuovo contatto"
},
@ -1060,18 +1034,9 @@
"ofTextNofM": {
"message": "di"
},
"off": {
"message": "Off"
},
"offlineForMaintenance": {
"message": "Offline per manutenzione"
},
"ok": {
"message": "Ok"
},
"on": {
"message": "On"
},
"onboardingReturnNotice": {
"message": "\"$1\" chiuderà questa tab e ritornerà a $2",
"description": "Return the user to the site that initiated onboarding"
@ -1094,9 +1059,6 @@
"participateInMetaMetricsDescription": {
"message": "Participa in MetaMetrics per aiutarci a rendere MetaMask migliore"
},
"password": {
"message": "Password"
},
"passwordNotLongEnough": {
"message": "Password non abbastanza lunga"
},
@ -1218,9 +1180,6 @@
"message": "È stato trovato un backup dei tuoi dati da $1. Vuoi ripristinare le preferenze del portafoglio?",
"description": "$1 is the date at which the data was backed up"
},
"retryTransaction": {
"message": "Retry Transaction"
},
"reusedTokenNameWarning": {
"message": "Un token usa un simbolo già usato da un altro token, ciò può confondere o ingannare."
},
@ -1384,9 +1343,6 @@
"signatureRequest": {
"message": "Firma Richiesta"
},
"signatureRequest1": {
"message": "Message"
},
"signed": {
"message": "Firmata"
},
@ -1647,9 +1603,6 @@
"message": "$1 $2 disponibili allo scambio",
"description": "Tells the user how much of a token they have in their balance. $1 is a decimal number amount of tokens, and $2 is a token symbol"
},
"swapZeroSlippage": {
"message": "0% Slippage"
},
"swapsAdvancedOptions": {
"message": "Impostazioni Avanzate"
},
@ -1730,9 +1683,6 @@
"message": "A: $1",
"description": "$1 is the address to include in the To label. It is typically shortened first using shortenAddress"
},
"token": {
"message": "Token"
},
"tokenAlreadyAdded": {
"message": "Il token è già stato aggiunto."
},

File diff suppressed because it is too large Load Diff

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "ತಿರಸಕರಿಿ"
},
"QRHardwareWalletImporterTitle": {
"message": "QR ಕಿ"
},
"about": {
"message": "ಕಿ"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "ಪರಸತ ಭ"
},
"custom": {
"message": "ಸಿತ"
},
"customGas": {
"message": "ಗ ಕಸಟಮಿ"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "ನ ಈ ನವರ ಅನ ಖಚಿತವಿ ಅಳಿಸಲ ಬಯಸ?"
},
"depositEther": {
"message": "ಎಥರವಣಿಿ"
},
"details": {
"message": "ವಿವರಗಳ"
},
"directDepositEther": {
"message": "ಎಥರರವಿವಣಿಿ"
},
"directDepositEtherExplainer": {
"message": "ನ ಈಗಗಲಲವ ಎಥರಿದರ, ನರ ಠವಣಿಲಕ ನಿಮ ಹಸ ವನಲಿ ಎಥರ ಅನ ಪಡವ ತವರಿತ ಮಗ."
},
"done": {
"message": "ಮಿಿ"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "ಇನನಷಿಿಿಿ"
},
"learnMoreUpperCase": {
"message": "ಇನನಷಿಿಿಿ"
},
"ledgerAccountRestriction": {
"message": "ನಸದನಿದರ ಮದಲಿಮ ಹಿಿನ ಖಯನ ಬಳಸಬ."
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "ನನನ ಖಗಳ"
},
"needEtherInWallet": {
"message": "MetaMask ಬಳಸಿಿತ ಖಗಳಿವಹನ ನಡಸಲ, ನಿಮ ವನಲಿಿಮಗ ಎಥರ ಅಗತಯವಿ."
},
"needImportFile": {
"message": "ಆಮದಡಲ ಅನ ಆಯಡಬ.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Atmesti"
},
"QRHardwareWalletImporterTitle": {
"message": "Nuskaityti QR kodą"
},
"about": {
"message": "Apie"
},
@ -67,7 +73,7 @@
"description": "The description of the application"
},
"appName": {
"message": "MetaMask",
"message": "MetaMask",
"description": "The name of the application"
},
"appNameBeta": {
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Dabartinė kalba"
},
"custom": {
"message": "Išplėstiniai"
},
"customGas": {
"message": "Pritaikyti dujas"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Ar tikrai norite panaikinti šį tinklą?"
},
"depositEther": {
"message": "Įnešti eterių"
},
"details": {
"message": "Išsami informacija"
},
"directDepositEther": {
"message": "Tiesiogiai įnešti eteriai"
},
"directDepositEtherExplainer": {
"message": "Jeigu jau turite šiek tiek eterių, sparčiausias būdas gauti eterių į naują piniginę yra tiesioginis įnašas."
},
"done": {
"message": "Atlikta"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "Sužinokite daugiau"
},
"learnMoreUpperCase": {
"message": "Sužinokite daugiau"
},
"ledgerAccountRestriction": {
"message": "Prieš įtraukdami naują, turite pasinaudoti paskutine paskyra."
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "Mano paskyros"
},
"needEtherInWallet": {
"message": "Norėdami dirbti su decentralizuotomis programomis „MetaMask“, savo piniginėje turite turėti eterių."
},
"needImportFile": {
"message": "Turite pasirinkti failą, kurį pageidaujate importuoti.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Noraidīt"
},
"QRHardwareWalletImporterTitle": {
"message": "Ieskenēt QR kodu"
},
"about": {
"message": "Par"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Pašreizējā valodā"
},
"custom": {
"message": "Papildu"
},
"customGas": {
"message": "Pielāgot Gas"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Vai tiešām vēlaties dzēst šo tīklu?"
},
"depositEther": {
"message": "Noguldīt Ether"
},
"details": {
"message": "Informācija"
},
"directDepositEther": {
"message": "Tiešā Ether iemaksa"
},
"directDepositEtherExplainer": {
"message": "Ja jums jau ir Ether, tad visātrāk Ether savā makā varat saņemt ar tiešo iemaksu."
},
"done": {
"message": "Pabeigts"
},
@ -526,6 +526,9 @@
"learnMore": {
"message": "Uzzināt vairāk"
},
"learnMoreUpperCase": {
"message": "Uzzināt vairāk"
},
"ledgerAccountRestriction": {
"message": "Jums jāizmanto pēdējais konts pirms varat pievienot jaunu."
},
@ -580,9 +583,6 @@
"myAccounts": {
"message": "Mani konti"
},
"needEtherInWallet": {
"message": "Lai izmantotu decentralizētas lietotnes ar MetaMask, jūsu makā jābūt Ether."
},
"needImportFile": {
"message": "Jums jāatlasa fails, ko importēt",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "നിരസിക"
},
"about": {
"message": "വിവര"
},
@ -44,6 +47,9 @@
"create": {
"message": "സിക"
},
"custom": {
"message": "നതന"
},
"delete": {
"message": "ഇലക"
},

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "न"
},
"about": {
"message": "बददल"
},
@ -44,6 +47,9 @@
"create": {
"message": "तयर कर"
},
"custom": {
"message": "परगत"
},
"delete": {
"message": "हटव"
},

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Tolak"
},
"QRHardwareWalletImporterTitle": {
"message": "Imbas Kod QR"
},
"about": {
"message": "Mengenai"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Bahasa Semasa"
},
"custom": {
"message": "Lanjutan"
},
"customGas": {
"message": "Suaikan Gas"
},
@ -286,12 +295,6 @@
"details": {
"message": "Butiran"
},
"directDepositEther": {
"message": "Deposit Ether Secara Terus"
},
"directDepositEtherExplainer": {
"message": "Jika anda sudah mempunyai Ether, cara paling cepat untuk mendapatkan Ether di dompet baru anda ialah dengan deposit langsung."
},
"done": {
"message": "Selesai"
},
@ -516,6 +519,9 @@
"learnMore": {
"message": "Maklumat lanjut"
},
"learnMoreUpperCase": {
"message": "Maklumat lanjut"
},
"ledgerAccountRestriction": {
"message": "Anda perlu menggunakan akaun terakhir anda sebelum anda boleh menambah yang baru."
},
@ -564,9 +570,6 @@
"myAccounts": {
"message": "Akaun Saya"
},
"needEtherInWallet": {
"message": "Untuk berinteraksi dengan aplikasi ternyahpusat menggunakan MetaMask, anda memerlukan Ether di dalam dompet anda."
},
"needImportFile": {
"message": "Anda mesti pilih fail untuk diimport.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "Afwijzen"
},
"accountDetails": {
"message": "Accountgegevens"
},
@ -81,15 +84,6 @@
"decimalsMustZerotoTen": {
"message": "Decimalen moeten minimaal 0 en niet meer dan 36 zijn."
},
"depositEther": {
"message": "Stort Ether"
},
"directDepositEther": {
"message": "Directe Ether storten"
},
"directDepositEtherExplainer": {
"message": "Als je al wat Ether hebt, de snelste manier om Ether in je nieuwe portemonnee te krijgen door een directe storting."
},
"done": {
"message": "Gedaan"
},
@ -214,9 +208,6 @@
"myAccounts": {
"message": "Mijn accounts"
},
"needEtherInWallet": {
"message": "Om te communiceren met gedecentraliseerde applicaties met MetaMask, heb je Ether nodig in je portemonnee."
},
"needImportFile": {
"message": "U moet een bestand selecteren om te importeren.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Avslå"
},
"QRHardwareWalletImporterTitle": {
"message": "Skann QR-kode"
},
"about": {
"message": "Info"
},
@ -253,6 +259,9 @@
"currentLanguage": {
"message": "Nåværende språk "
},
"custom": {
"message": "Avansert"
},
"customGas": {
"message": "Tilpass Gass"
},
@ -280,18 +289,9 @@
"deleteNetworkDescription": {
"message": "Er du sikker på at du vil slette dette nettverket?"
},
"depositEther": {
"message": "Sett inn Ether "
},
"details": {
"message": "Detaljer"
},
"directDepositEther": {
"message": "Sett Ether direkte inn"
},
"directDepositEtherExplainer": {
"message": "Hvis du allerede har noe Ether, er den raskeste måten å få Ether i den nye lommeboken din på ved hjelp av direkte innskudd."
},
"done": {
"message": "Ferdig"
},
@ -517,6 +517,9 @@
"learnMore": {
"message": "Lær mer"
},
"learnMoreUpperCase": {
"message": "Lær mer"
},
"ledgerAccountRestriction": {
"message": "Du må bruke den siste kontoen din før du kan legge til en ny."
},
@ -571,9 +574,6 @@
"myAccounts": {
"message": "Mine kontoer "
},
"needEtherInWallet": {
"message": "Du må ha Ether i lommeboken din for å samhandle med desentraliserte applikasjoner gjennom MateMask."
},
"needImportFile": {
"message": "Du må velge en fil å importere.",
"description": "User is important an account and needs to add a file to continue"

@ -519,18 +519,9 @@
"deleteNetworkDescription": {
"message": "Sigurado ka bang gusto mong i-delete ang network na ito?"
},
"depositEther": {
"message": "Mag-deposit ng Ether"
},
"details": {
"message": "Mga Detalye"
},
"directDepositEther": {
"message": "Direktang Mag-deposit ng Ether"
},
"directDepositEtherExplainer": {
"message": "Kung mayroon ka nang ilang Ether, ang pinakamabilis na paraan para makakuha ng Ether sa bago mong wallet ay sa pamamagitan ng direktang pag-deposit."
},
"disconnect": {
"message": "Idiskonekta"
},
@ -1116,9 +1107,6 @@
"name": {
"message": "Pangalan"
},
"needEtherInWallet": {
"message": "Para makaugnayan ang mga decentralized na application gamit ang MetaMask, kakailanganin mo ang Ether sa iyong wallet."
},
"needHelp": {
"message": "Kailangan ng tulong? Makipag-ugnayan sa $1",
"description": "$1 represents `needHelpLinkText`, the text which goes in the help link"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Odrzuć"
},
"QRHardwareWalletImporterTitle": {
"message": "Skanuj kod QR"
},
"about": {
"message": "Informacje"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Obecny język"
},
"custom": {
"message": "Zaawansowane"
},
"customGas": {
"message": "Ustaw gaz"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Czy na pewno chcesz usunąć tę sieć?"
},
"depositEther": {
"message": "Zdeponuj Eter"
},
"details": {
"message": "Szczegóły"
},
"directDepositEther": {
"message": "Zdeponuj Eter bezpośrednio"
},
"directDepositEtherExplainer": {
"message": "Jeśli już masz Eter, najszybciej umieścisz go w swoim nowym portfelu przy pomocy bezpośredniego depozytu."
},
"done": {
"message": "Gotowe"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "Dowiedz się więcej"
},
"learnMoreUpperCase": {
"message": "Dowiedz się więcej"
},
"ledgerAccountRestriction": {
"message": "Musisz użyć swojego poprzedniego konta zanim dodasz kolejne."
},
@ -581,9 +584,6 @@
"myAccounts": {
"message": "Moje konta"
},
"needEtherInWallet": {
"message": "Żeby skorzystać ze zdecentraliowanych aplikacji (dApps) przy pomocy MetaMask, potrzebujesz Eteru w swoim portfelu."
},
"needImportFile": {
"message": "Musisz wybrać plik do zaimportowania.",
"description": "User is important an account and needs to add a file to continue"

@ -84,18 +84,9 @@
"decimalsMustZerotoTen": {
"message": "Decimais devem ser no mínimo 0 e não passar de 36."
},
"depositEther": {
"message": "Depositar Ether"
},
"details": {
"message": "Detalhes"
},
"directDepositEther": {
"message": "Depositar Diretamente Ether"
},
"directDepositEtherExplainer": {
"message": "Se já tem Ether, a forma mais rápida de ficar com Ether na sua carteira é através de depósito direto."
},
"done": {
"message": "Finalizado"
},
@ -220,9 +211,6 @@
"myAccounts": {
"message": "As minhas contas"
},
"needEtherInWallet": {
"message": "Para interagir com applicações descentralizadas usando MetaMask tem de ter Ether na sua carteira."
},
"needImportFile": {
"message": "Deve selecionar um ficheiro para importar.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "Rejeitar"
},
"about": {
"message": "Sobre"
},
@ -251,6 +254,9 @@
"buildContactList": {
"message": "Crie sua lista de contatos"
},
"builtAroundTheWorld": {
"message": "MetaMask é projetado e construído em todo o mundo.."
},
"buy": {
"message": "Comprar"
},
@ -260,9 +266,6 @@
"buyWithWyreDescription": {
"message": "Com o Wyre, você pode usar um cartão de débito para depositar ETH diretamente na sua conta do MetaMask."
},
"bytes": {
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Você pode reabilitar essa notificação em Configurações -> Alertas."
},
@ -519,17 +522,12 @@
"deleteNetworkDescription": {
"message": "Tem certeza de que deseja excluir esta rede?"
},
"depositEther": {
"message": "Depositar ether"
},
"details": {
"message": "Detalhes"
},
"directDepositEther": {
"message": "Depositar ether diretamente"
},
"directDepositEtherExplainer": {
"message": "Se você já tiver alguns ethers, a forma mais rápida de colocar ethers na sua nova carteira é por depósito direto."
"disabledGasOptionToolTipMessage": {
"message": "“$1” está desativado porque não satisfaz o aumento mínimo de 10% em relação à taxa de gás original.",
"description": "$1 is gas estimate type which can be market or aggressive"
},
"disconnect": {
"message": "Desconectar"
@ -679,10 +677,6 @@
"message": "O MetaMask encontrou um erro",
"description": "Title of generic error page"
},
"errorStack": {
"message": "Stack:",
"description": "Title for error stack, which is displayed for debugging purposes"
},
"estimatedProcessingTimes": {
"message": "Tempo estimado de processamento"
},
@ -696,9 +690,6 @@
"ethereumPublicAddress": {
"message": "Endereço público do Ethereum"
},
"etherscan": {
"message": "Etherscan"
},
"etherscanView": {
"message": "Exibir conta no Etherscan"
},
@ -761,7 +752,7 @@
"message": "Tipo de função"
},
"gasLimit": {
"message": "Gas Limit"
"message": "Limite de Gas"
},
"gasLimitInfoTooltipContent": {
"message": "O Gas Limit é o valor máximo das unidades de gas que você está disposto a gastar."
@ -774,7 +765,7 @@
"description": "$1 is the custom gas limit, in decimal."
},
"gasPrice": {
"message": "Gas Price (GWEI)"
"message": "Preço Gas (GWEI)"
},
"gasPriceExcessive": {
"message": "Sua taxa de gas é desnecessariamente alta. Considere reduzir o valor."
@ -824,9 +815,6 @@
"happyToSeeYou": {
"message": "Ficamos felizes em ver você."
},
"hardware": {
"message": "Hardware"
},
"hardwareWalletConnected": {
"message": "Carteira de hardware conectada"
},
@ -1011,9 +999,6 @@
"likeToImportTokens": {
"message": "Você gostaria de adicionar esses tokens?"
},
"links": {
"message": "Links"
},
"loadMore": {
"message": "Carregar mais"
},
@ -1023,9 +1008,6 @@
"loadingTokens": {
"message": "Carregando tokens..."
},
"localhost": {
"message": "Localhost 8545"
},
"lock": {
"message": "Bloquear"
},
@ -1116,9 +1098,6 @@
"name": {
"message": "Nome"
},
"needEtherInWallet": {
"message": "Para interagir com aplicativos descentralizados usando o MetaMask, você precisará de ethers na sua carteira."
},
"needHelp": {
"message": "Precisa de ajuda? Contato $1",
"description": "$1 represents `needHelpLinkText`, the text which goes in the help link"
@ -1139,18 +1118,9 @@
"networkName": {
"message": "Nome da rede"
},
"networkNameBSC": {
"message": "BSC"
},
"networkNameDefinition": {
"message": "O nome associado com esta rede."
},
"networkNameEthereum": {
"message": "Ethereum"
},
"networkNameTestnet": {
"message": "Testnet"
},
"networkSettingsChainIdDescription": {
"message": "O ID da chain é usado para assinar transações. É preciso ser igual ao ID da chain retornado pela rede. Você pode informar um número decimal ou um número hexadecimal com prefixo “0x”, mas exibiremos o número em casas decimais."
},
@ -1228,9 +1198,6 @@
"noWebcamFoundTitle": {
"message": "Câmera não encontrada"
},
"nonce": {
"message": "Nonce"
},
"nonceField": {
"message": "Personalizar nonce da transação"
},
@ -1788,9 +1755,6 @@
"supportCenter": {
"message": "Visite nossa Central de Suporte"
},
"swap": {
"message": "Swap"
},
"swapAdvancedSlippageInfo": {
"message": "Quando o preço varia entre o momento em que seu pedido é feito e o momento em que é confirmado, isso recebe o nome de “slippage”. Seu swap será automaticamente cancelado se o slippage for superior à configuração “slippage máximo”."
},
@ -2128,9 +2092,6 @@
"message": "Até: $1",
"description": "$1 is the address to include in the To label. It is typically shortened first using shortenAddress"
},
"token": {
"message": "Token"
},
"tokenAlreadyAdded": {
"message": "O token já foi adicionado."
},
@ -2146,9 +2107,6 @@
"tooltipApproveButton": {
"message": "Eu entendo"
},
"total": {
"message": "Total"
},
"transaction": {
"message": "transação"
},

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Respingeți"
},
"QRHardwareWalletImporterTitle": {
"message": "Scanați codul QR"
},
"about": {
"message": "Despre"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Limba actuală"
},
"custom": {
"message": "Avansate"
},
"customGas": {
"message": "Particularizați Gas"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Sigur vreți să ștergeți această rețea?"
},
"depositEther": {
"message": "Depuneți Ether"
},
"details": {
"message": "Detalii"
},
"directDepositEther": {
"message": "Depuneți direct Ether"
},
"directDepositEtherExplainer": {
"message": "Dacă deja aveți Ether, cel mai rapid mod de a avea Ether în portofelul nou prin depunere directă."
},
"done": {
"message": "Efectuat"
},
@ -520,6 +520,9 @@
"learnMore": {
"message": "Aflați mai multe"
},
"learnMoreUpperCase": {
"message": "Aflați mai multe"
},
"ledgerAccountRestriction": {
"message": "Trebuie să folosiți ultimul cont înainte să adăugați altul."
},
@ -571,9 +574,6 @@
"myAccounts": {
"message": "Conturile mele"
},
"needEtherInWallet": {
"message": "Pentru a interacționa cu aplicațiile descentralizate prin intermediul MetaMask, trebuie să aveți Ether în portofel."
},
"needImportFile": {
"message": "Trebuie să selectați un fișier pentru importare.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Odmítnout"
},
"QRHardwareWalletImporterTitle": {
"message": "Skenovať QR kód"
},
"about": {
"message": "Informácie"
},
@ -250,6 +256,9 @@
"currentLanguage": {
"message": "Aktuálny jazyk"
},
"custom": {
"message": "Rozšírené"
},
"customGas": {
"message": "Nastavit palivo"
},
@ -277,18 +286,9 @@
"deleteNetworkDescription": {
"message": "Naozaj chcete túto sieť odstrániť?"
},
"depositEther": {
"message": "Vložit Ether"
},
"details": {
"message": "Podrobnosti"
},
"directDepositEther": {
"message": "Vložit Ether přímo"
},
"directDepositEtherExplainer": {
"message": "Pokud už vlastníte nějaký Ether, nejrychleji ho dostanete do peněženky přímým vkladem."
},
"done": {
"message": "Hotovo"
},
@ -514,6 +514,9 @@
"learnMore": {
"message": "Zjistěte více."
},
"learnMoreUpperCase": {
"message": "Zjistěte více."
},
"ledgerAccountRestriction": {
"message": "Skôr ako budete môcť pridať nový účet, musíte použiť svoj posledný účet."
},
@ -556,9 +559,6 @@
"myAccounts": {
"message": "Moje účty"
},
"needEtherInWallet": {
"message": "Potřebujete Ether v peněžence, abyste mohli pomocí MetaMasku interagovat s decentralizovanými aplikacemi."
},
"needImportFile": {
"message": "Musíte zvolit soubor k importu.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Zavrni"
},
"QRHardwareWalletImporterTitle": {
"message": "Skeniraj QR kodo"
},
"about": {
"message": "O možnostih"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Trenutni jezik"
},
"custom": {
"message": "Napredno"
},
"customGas": {
"message": "Prilagodi gas"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Ali ste prepričani, da želite izbrisati to omrežje?"
},
"depositEther": {
"message": "Vplačilo ethra"
},
"details": {
"message": "Podrobnosti"
},
"directDepositEther": {
"message": "Neposredno vplačilo ehera"
},
"directDepositEtherExplainer": {
"message": "Če že imate Ether, ga lahko najhitreje dobite v MetaMask z neposrednim vplačilom."
},
"done": {
"message": "Končano"
},
@ -524,6 +524,9 @@
"learnMore": {
"message": "Preberite več"
},
"learnMoreUpperCase": {
"message": "Preberite več"
},
"ledgerAccountRestriction": {
"message": "Za dodajanje novega računa morate uporabiti zadnji račun."
},
@ -572,9 +575,6 @@
"myAccounts": {
"message": "Moji računi"
},
"needEtherInWallet": {
"message": "Za interakcijo z decentraliziranimi aplikacijami boste v svoji denarnici potrebovali Eter."
},
"needImportFile": {
"message": "Za uvoz morate izbrati datoteko.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Одбиј"
},
"QRHardwareWalletImporterTitle": {
"message": "Skenirajte QR kod"
},
"about": {
"message": "Основни подаци"
},
@ -253,6 +259,9 @@
"currentLanguage": {
"message": "Trenutni jezik"
},
"custom": {
"message": "Напредне опције"
},
"customGas": {
"message": "Prilagodi gas"
},
@ -280,18 +289,9 @@
"deleteNetworkDescription": {
"message": "Da li ste sigurni da želite da izbrišete ovu mrežu?"
},
"depositEther": {
"message": "Dajte depozit Ether-u"
},
"details": {
"message": "Детаљи"
},
"directDepositEther": {
"message": "Direktno deponujte Ether"
},
"directDepositEtherExplainer": {
"message": "Ako već imate neki Ether, najbrži način da preuzmete Ether u svoj novi novčanik jeste direktnim deponovanjem."
},
"done": {
"message": "Gotovo"
},
@ -527,6 +527,9 @@
"learnMore": {
"message": "Nauči više"
},
"learnMoreUpperCase": {
"message": "Nauči više"
},
"ledgerAccountRestriction": {
"message": "Treba da koristite svoj poslednji nalog pre nego što budete mogli da dodate novi."
},
@ -575,9 +578,6 @@
"myAccounts": {
"message": "Moji nalozi"
},
"needEtherInWallet": {
"message": "Da biste stupili u interakciju sa decentralizovanim aplikacijama koristeći MetaMask, biće vam potreban Ether u vašem novčaniku."
},
"needImportFile": {
"message": "Morate izabrati fajl koji ćete uvesti.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Avvisa"
},
"QRHardwareWalletImporterTitle": {
"message": "Skanna QR-koden"
},
"about": {
"message": "Om"
},
@ -250,6 +256,9 @@
"currentLanguage": {
"message": "Aktuellt språk"
},
"custom": {
"message": "Avancerat"
},
"customGas": {
"message": "Anpassa gas"
},
@ -277,18 +286,9 @@
"deleteNetworkDescription": {
"message": "Är du säker på att du vill ta bort detta nätverk?"
},
"depositEther": {
"message": "Sätt in Ether"
},
"details": {
"message": "Info"
},
"directDepositEther": {
"message": "Sätt in Ether direkt"
},
"directDepositEtherExplainer": {
"message": "Om du redan har Ether är det snabbaste sättet att få Ether i din nya plånbok att göra en direktinsättning."
},
"done": {
"message": "Klart"
},
@ -520,6 +520,9 @@
"learnMore": {
"message": "Läs mer"
},
"learnMoreUpperCase": {
"message": "Läs mer"
},
"ledgerAccountRestriction": {
"message": "Du måste använda ditt senaste konto innan du kan lägga till ett nytt."
},
@ -568,9 +571,6 @@
"myAccounts": {
"message": "Mina konton"
},
"needEtherInWallet": {
"message": "För att interagera med decentraliserade applikationer med MetaMask behöver du Ether i din plånbok."
},
"needImportFile": {
"message": "Du måste välja en fil att importera.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Kataa"
},
"QRHardwareWalletImporterTitle": {
"message": "Kagua Msimbo wa QR"
},
"about": {
"message": "Kuhusu"
},
@ -250,6 +256,9 @@
"currentLanguage": {
"message": "Lugha ya Sasa"
},
"custom": {
"message": "Mipangilio ya kina"
},
"customGas": {
"message": "Weka Mipangilio ya Gesi Upendavyo"
},
@ -277,18 +286,9 @@
"deleteNetworkDescription": {
"message": "Una uhakika unataka kufuta mtandao huu?"
},
"depositEther": {
"message": "Weka Ether"
},
"details": {
"message": "Maelezo"
},
"directDepositEther": {
"message": "Weka Ether Moja kwa Moja"
},
"directDepositEtherExplainer": {
"message": "Ikiwa tayari una sarafu kadhaa za Ether, njia rahisi ya kupata Ether kwenye waleti yako mpya kupitia kuweka moja kwa moja."
},
"done": {
"message": "Imekamilika"
},
@ -517,6 +517,9 @@
"learnMore": {
"message": "Jifunze zaidi"
},
"learnMoreUpperCase": {
"message": "Jifunze zaidi"
},
"ledgerAccountRestriction": {
"message": "Unapaswa kutumia akaunti yako ya mwisho kabla hujaongeza mpya."
},
@ -562,9 +565,6 @@
"myAccounts": {
"message": "Akaunti zangu"
},
"needEtherInWallet": {
"message": "Ili kuingiliana na programu zilizosambazwa kwa kutumia MetaMask, utahitaji kuwa na Ether kwenye waleti yako."
},
"needImportFile": {
"message": "Unapaswa kuchagua faili la kuhamisha.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "நிகரி"
},
"about": {
"message": "அறிகம"
},
@ -108,6 +111,9 @@
"createAccount": {
"message": "உஙகள கணகவஙகள"
},
"custom": {
"message": "மபடடவ"
},
"customGas": {
"message": "எரி தனிபயனகள"
},
@ -123,18 +129,9 @@
"delete": {
"message": "ந"
},
"depositEther": {
"message": "வ எதி "
},
"details": {
"message": "விவரஙகள"
},
"directDepositEther": {
"message": "நரடிக வ"
},
"directDepositEtherExplainer": {
"message": "நகள ஏறகனவ ஏத இர, நரடிலம உஙகளிய பணபி ஈததரற வின வழி."
},
"done": {
"message": "மிதத"
},
@ -250,6 +247,9 @@
"learnMore": {
"message": "ம அறிக"
},
"learnMoreUpperCase": {
"message": "ம அறிக"
},
"likeToImportTokens": {
"message": "இநத டகனகளக விிகள?"
},
@ -286,9 +286,6 @@
"myAccounts": {
"message": "எனத கணககள"
},
"needEtherInWallet": {
"message": "மடமஸ ஐ பயனபடி பரவலகபபடட பயனகளடனடரள, உஙகள பணபபரிறதி ஈதர."
},
"needImportFile": {
"message": "இறகமதிய ஒரகளக வ.",
"description": "User is important an account and needs to add a file to continue"

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "తిరసకరి"
},
"about": {
"message": "గిి"
},
@ -44,6 +47,9 @@
"create": {
"message": "సి"
},
"custom": {
"message": "ఆధిక"
},
"delete": {
"message": "తలగి"
},

@ -1,4 +1,7 @@
{
"QRHardwareSignRequestCancel": {
"message": "ปฏเสธ"
},
"about": {
"message": "เกยวกบ"
},
@ -129,18 +132,9 @@
"deleteNetwork": {
"message": "ลบเครอขาย?"
},
"depositEther": {
"message": "การฝากอเธอร"
},
"details": {
"message": "รายละเอยด"
},
"directDepositEther": {
"message": "ฝากอเธอรโดยตรง"
},
"directDepositEtherExplainer": {
"message": "ถาคณมเธอรอยแลววการทเรวทดในการเอาเงนเขากระเปาใหมอการโอนตรงๆ"
},
"done": {
"message": "เสรจสน"
},
@ -268,6 +262,9 @@
"learnMore": {
"message": "เรยนรเพมเตม"
},
"learnMoreUpperCase": {
"message": "เรยนรเพมเตม"
},
"likeToImportTokens": {
"message": "คณตองการเพมโทเคนเหลานหรอไม?"
},
@ -295,9 +292,6 @@
"myAccounts": {
"message": "บญชของฉน"
},
"needEtherInWallet": {
"message": "คณจะตองมเธอรในกระเปาเงนของคณในการใชงานกบแอพพลเคชนแบบกระจายดวย MetaMask"
},
"needImportFile": {
"message": "คณตองเลอกไฟลจะนำเขา",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,4 +1,10 @@
{
"QRHardwareSignRequestCancel": {
"message": "Відхилити"
},
"QRHardwareWalletImporterTitle": {
"message": "Сканувати QR-код"
},
"about": {
"message": "Про Google Chrome"
},
@ -256,6 +262,9 @@
"currentLanguage": {
"message": "Поточна мова"
},
"custom": {
"message": "Розширені"
},
"customGas": {
"message": "Налаштувати пальне"
},
@ -283,18 +292,9 @@
"deleteNetworkDescription": {
"message": "Ви впевнені, що хочете видалити цю мережу?"
},
"depositEther": {
"message": "Депонувати Ether"
},
"details": {
"message": "Деталі"
},
"directDepositEther": {
"message": "Внести безпосередньо Ефір"
},
"directDepositEtherExplainer": {
"message": "Якщо ви вже маєте ефір, пряме переведення – найшвидший спосіб передати ефір у свій гаманець."
},
"done": {
"message": "Готово"
},
@ -530,6 +530,9 @@
"learnMore": {
"message": "Дізнатись більше"
},
"learnMoreUpperCase": {
"message": "Дізнатись більше"
},
"ledgerAccountRestriction": {
"message": "Потрібно скористатися своїм останнім обліковим записом, перш ніж додавати новий."
},
@ -584,9 +587,6 @@
"myAccounts": {
"message": "Мої облікові записи"
},
"needEtherInWallet": {
"message": "Щоб взаємодіяти з децентралізованими застосунками використовуючи MetaMask, вам буде потрібен Ether у вашому гаманці."
},
"needImportFile": {
"message": "Потрібно вибрати файл для імпорту.",
"description": "User is important an account and needs to add a file to continue"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -292,18 +292,9 @@
"deleteNetworkDescription": {
"message": "你確定要刪除網路嗎?"
},
"depositEther": {
"message": "存入以太幣"
},
"details": {
"message": "詳情"
},
"directDepositEther": {
"message": "直接存入以太幣"
},
"directDepositEtherExplainer": {
"message": "如果您已經擁有以太幣,直接存入功能是讓新錢包最快取得以太幣的方式。"
},
"done": {
"message": "完成"
},
@ -590,9 +581,6 @@
"myAccounts": {
"message": "我的帳戶"
},
"needEtherInWallet": {
"message": "要使用 MetaMask 存取去中心化應用服務時,您的錢包中需要有以太幣。"
},
"needImportFile": {
"message": "您必須選擇一個檔案來匯入",
"description": "User is important an account and needs to add a file to continue"

@ -1 +1 @@
<svg width="136" height="31" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M91.201 8.705h1.03l2.39 5.65 2.4-5.65h1.01l-3.02 7.1h-.78l-3.03-7.1Zm9.327 7.2a2.73 2.73 0 0 1-1.06-.2 2.431 2.431 0 0 1-1.35-1.37 2.91 2.91 0 0 1-.18-1.03c0-.367.063-.707.19-1.02.126-.32.303-.597.53-.83.233-.234.51-.417.83-.55.32-.134.67-.2 1.05-.2.326 0 .633.056.92.17.286.106.536.27.75.49.22.213.393.476.52.79.126.306.19.66.19 1.06v.13c0 .033-.004.076-.01.13h-4.1c.006.233.053.45.14.65.093.2.213.373.36.52.153.146.333.263.54.35.213.08.443.12.69.12.386 0 .703-.077.95-.23a1.82 1.82 0 0 0 .61-.64l.68.47a2.48 2.48 0 0 1-.91.87c-.374.213-.82.32-1.34.32Zm1.51-3.13a1.601 1.601 0 0 0-.19-.55c-.087-.16-.2-.297-.34-.41a1.431 1.431 0 0 0-.46-.26 1.645 1.645 0 0 0-.54-.09 1.73 1.73 0 0 0-1.04.35 1.5 1.5 0 0 0-.38.41c-.107.16-.18.343-.22.55h3.17Zm2.1-1.97h.86v.97c.047-.16.12-.304.22-.43a1.556 1.556 0 0 1 .74-.52c.147-.047.294-.07.44-.07.134 0 .264.013.39.04v.89a.78.78 0 0 0-.23-.06 1.342 1.342 0 0 0-.24-.02c-.16 0-.32.036-.48.11-.153.066-.293.17-.42.31-.12.14-.22.32-.3.54-.08.213-.12.466-.12.76v2.48h-.86v-5Zm4.032 7.09 1.09-2.35-2.19-4.74h.95l1.72 3.8 1.71-3.8h.96l-3.28 7.09h-.96Zm7.287-2.09v-7.5h.86v3.27c.173-.3.4-.52.68-.66s.583-.21.91-.21c.28 0 .536.046.77.14.233.093.43.23.59.41.166.173.296.386.39.64.093.246.14.523.14.83v3.08h-.85v-2.95c0-.42-.11-.75-.33-.99-.214-.247-.497-.37-.85-.37-.2 0-.39.04-.57.12-.174.08-.327.2-.46.36-.127.153-.23.343-.31.57-.074.226-.11.486-.11.78v2.48h-.86Zm6.328-6.34a.599.599 0 0 1-.62-.61c0-.167.06-.31.18-.43s.267-.18.44-.18a.602.602 0 0 1 .6.61c0 .173-.056.32-.17.44a.581.581 0 0 1-.43.17Zm-.44 1.34h.86v5h-.86v-5Zm4.671 4.19c.246 0 .473-.044.68-.13.213-.087.393-.207.54-.36.146-.16.26-.347.34-.56.086-.214.13-.447.13-.7 0-.247-.044-.477-.13-.69a1.588 1.588 0 0 0-.34-.56 1.542 1.542 0 0 0-.54-.36 1.637 1.637 0 0 0-.68-.14c-.254 0-.484.046-.69.14a1.548 1.548 0 0 0-.53.36c-.147.153-.264.34-.35.56-.08.213-.12.443-.12.69 0 .253.04.486.12.7.086.213.203.4.35.56.146.153.323.273.53.36.206.086.436.13.69.13Zm-.05 3c-.54 0-1.014-.1-1.42-.3-.407-.2-.717-.44-.93-.72l.6-.6c.2.253.443.456.73.61.293.153.633.23 1.02.23.213 0 .42-.034.62-.1.2-.067.376-.174.53-.32.16-.14.286-.32.38-.54.093-.214.14-.47.14-.77v-.57a2.032 2.032 0 0 1-.72.63c-.307.166-.647.25-1.02.25-.347 0-.67-.064-.97-.19-.3-.134-.56-.314-.78-.54a2.623 2.623 0 0 1-.52-.81 2.8 2.8 0 0 1-.18-1.01c0-.354.06-.684.18-.99.126-.314.3-.584.52-.81.22-.234.48-.414.78-.54.3-.134.623-.2.97-.2.373 0 .713.083 1.02.25.306.16.546.366.72.62v-.77h.86v4.71c0 .42-.067.783-.2 1.09-.127.313-.304.57-.53.77-.227.206-.494.36-.8.46-.307.106-.64.16-1 .16Zm4.149-2.19v-7.5h.86v3.27c.173-.3.4-.52.68-.66s.583-.21.91-.21c.28 0 .537.046.77.14.233.093.43.23.59.41.167.173.297.386.39.64.093.246.14.523.14.83v3.08h-.85v-2.95c0-.42-.11-.75-.33-.99-.213-.247-.497-.37-.85-.37-.2 0-.39.04-.57.12-.173.08-.327.2-.46.36-.127.153-.23.343-.31.57-.073.226-.11.486-.11.78v2.48h-.86Z" fill="#F66A0A"/><path opacity=".3" d="M19.506 22.805c-10.763 7.42-19.416 8-19.416 8h110.25s-8.653-.58-19.417-8c-10.763-7.42-23.363-22-35.708-22-12.345 0-24.945 14.58-35.709 22Z" fill="#037DD6"/><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="111" height="31"><path d="M19.506 22.672c-10.763 7.42-19.416 8-19.416 8h110.25s-8.653-.58-19.417-8c-10.763-7.42-23.363-22-35.708-22-12.345 0-24.945 14.58-35.709 22Z" fill="#EAF6FF"/></mask><g mask="url(#a)"><path fill="#F66A0A" stroke="#fff" stroke-width="2" d="M91.986-5.143h20.706v39.25H91.986z"/></g></svg>
<svg width="162" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path fill="#fff" d="M.813.082h161v31h-161z"/><path d="M117.469 8.638h1.03l2.39 5.65 2.4-5.65h1.01l-3.02 7.1h-.78l-3.03-7.1ZM126.795 15.838c-.386 0-.74-.067-1.06-.2a2.436 2.436 0 0 1-1.35-1.37 2.91 2.91 0 0 1-.18-1.03c0-.367.064-.707.19-1.02.127-.32.304-.597.53-.83.234-.233.51-.417.83-.55.32-.133.67-.2 1.05-.2.327 0 .634.057.92.17.287.107.537.27.75.49.22.213.394.477.52.79.127.307.19.66.19 1.06v.13c0 .033-.003.077-.01.13h-4.1c.007.233.054.45.14.65.094.2.214.373.36.52.154.147.334.263.54.35.214.08.444.12.69.12.387 0 .704-.077.95-.23.254-.16.457-.373.61-.64l.68.47c-.226.367-.53.657-.91.87-.373.213-.82.32-1.34.32Zm1.51-3.13a1.56 1.56 0 0 0-.19-.55c-.086-.16-.2-.297-.34-.41a1.408 1.408 0 0 0-.46-.26 1.636 1.636 0 0 0-.54-.09 1.732 1.732 0 0 0-1.04.35 1.512 1.512 0 0 0-.38.41c-.106.16-.18.343-.22.55h3.17ZM130.406 10.738h.86v.97c.046-.16.12-.303.22-.43s.213-.233.34-.32a1.59 1.59 0 0 1 .4-.2c.146-.047.293-.07.44-.07.133 0 .263.013.39.04v.89a.782.782 0 0 0-.23-.06 1.348 1.348 0 0 0-.24-.02c-.16 0-.32.037-.48.11-.154.067-.294.17-.42.31-.12.14-.22.32-.3.54-.08.213-.12.467-.12.76v2.48h-.86v-5ZM134.438 17.828l1.09-2.35-2.19-4.74h.95l1.72 3.8 1.71-3.8h.96l-3.28 7.09h-.96ZM141.724 15.738v-7.5h.86v3.27c.173-.3.4-.52.68-.66s.583-.21.91-.21c.28 0 .537.047.77.14.233.093.43.23.59.41.167.173.297.387.39.64.093.247.14.523.14.83v3.08h-.85v-2.95c0-.42-.11-.75-.33-.99-.213-.247-.497-.37-.85-.37-.2 0-.39.04-.57.12-.173.08-.327.2-.46.36-.127.153-.23.343-.31.57-.073.227-.11.487-.11.78v2.48h-.86ZM148.053 9.398a.599.599 0 0 1-.62-.61c0-.167.06-.31.18-.43s.266-.18.44-.18c.173 0 .316.06.43.18.113.12.17.263.17.43 0 .173-.057.32-.17.44a.584.584 0 0 1-.43.17Zm-.44 1.34h.86v5h-.86v-5ZM152.283 14.928c.247 0 .473-.043.68-.13.213-.087.393-.207.54-.36a1.7 1.7 0 0 0 .34-.56c.087-.213.13-.447.13-.7a1.81 1.81 0 0 0-.13-.69 1.573 1.573 0 0 0-.34-.56 1.54 1.54 0 0 0-.54-.36 1.632 1.632 0 0 0-.68-.14c-.253 0-.483.047-.69.14a1.554 1.554 0 0 0-.53.36 1.7 1.7 0 0 0-.35.56c-.08.213-.12.443-.12.69 0 .253.04.487.12.7.087.213.203.4.35.56.147.153.323.273.53.36.207.087.437.13.69.13Zm-.05 3c-.54 0-1.013-.1-1.42-.3-.407-.2-.717-.44-.93-.72l.6-.6c.2.253.443.457.73.61.293.153.633.23 1.02.23.213 0 .42-.033.62-.1s.377-.173.53-.32c.16-.14.287-.32.38-.54.093-.213.14-.47.14-.77v-.57a2.015 2.015 0 0 1-.72.63c-.307.167-.647.25-1.02.25-.347 0-.67-.063-.97-.19-.3-.133-.56-.313-.78-.54a2.643 2.643 0 0 1-.52-.81 2.8 2.8 0 0 1-.18-1.01c0-.353.06-.683.18-.99.127-.313.3-.583.52-.81.22-.233.48-.413.78-.54.3-.133.623-.2.97-.2.373 0 .713.083 1.02.25.307.16.547.367.72.62v-.77h.86v4.71c0 .42-.067.783-.2 1.09-.127.313-.303.57-.53.77a2.17 2.17 0 0 1-.8.46c-.307.107-.64.16-1 .16ZM156.382 15.738v-7.5h.86v3.27c.174-.3.4-.52.68-.66s.584-.21.91-.21c.28 0 .537.047.77.14.234.093.43.23.59.41.167.173.297.387.39.64.094.247.14.523.14.83v3.08h-.85v-2.95c0-.42-.11-.75-.33-.99-.213-.247-.496-.37-.85-.37-.2 0-.39.04-.57.12-.173.08-.326.2-.46.36-.126.153-.23.343-.31.57-.073.227-.11.487-.11.78v2.48h-.86Z" fill="#F66A0A"/><path opacity=".3" d="M45.774 22.738c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#037DD6"/><mask id="b" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="26" y="0" width="111" height="31"><path d="M45.774 22.605c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#EAF6FF"/></mask><g mask="url(#b)"><path fill="#F66A0A" stroke="#fff" stroke-width="2" d="M118.254-5.209h20.706v39.25h-20.706z"/></g></g><defs><clipPath id="a"><path fill="#fff" transform="translate(.813 .082)" d="M0 0h161v31H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

@ -1 +1 @@
<svg width="125" height="31" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.233 8.738h.93v6.22h3.43v.88h-4.36v-7.1Zm7.412 7.2c-.38 0-.73-.067-1.05-.2a2.679 2.679 0 0 1-.83-.56 2.569 2.569 0 0 1-.55-.82c-.126-.32-.19-.66-.19-1.02s.064-.697.19-1.01a2.54 2.54 0 0 1 .55-.83c.234-.233.51-.417.83-.55.32-.14.67-.21 1.05-.21.374 0 .72.07 1.04.21.32.133.597.317.83.55.234.233.414.51.54.83.134.313.2.65.2 1.01s-.066.7-.2 1.02a2.44 2.44 0 0 1-.54.82 2.68 2.68 0 0 1-.83.56c-.32.133-.666.2-1.04.2Zm0-.8c.26 0 .497-.047.71-.14.214-.093.394-.22.54-.38.154-.167.27-.357.35-.57.087-.22.13-.457.13-.71 0-.247-.043-.48-.13-.7-.08-.22-.196-.41-.35-.57a1.52 1.52 0 0 0-.54-.39 1.754 1.754 0 0 0-.71-.14c-.26 0-.496.047-.71.14a1.619 1.619 0 0 0-.55.39c-.153.16-.273.35-.36.57-.08.22-.12.453-.12.7 0 .253.04.49.12.71.087.213.207.403.36.57.154.16.337.287.55.38.214.093.45.14.71.14Zm6.825-2.89-1.23 3.59h-.76l-1.7-5h.9l1.21 3.65 1.25-3.65h.66l1.25 3.65 1.21-3.65h.91l-1.7 5h-.76l-1.24-3.59Z" fill="#F66A0A"/><path opacity=".3" d="M33.96 22.838c-10.764 7.42-19.417 8-19.417 8h110.25s-8.653-.58-19.416-8c-10.764-7.42-23.364-22-35.709-22-12.345 0-24.945 14.58-35.709 22Z" fill="#037DD6"/><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="14" y="0" width="111" height="31"><path d="M33.96 22.705c-10.764 7.42-19.417 8-19.417 8h110.25s-8.653-.58-19.416-8c-10.764-7.42-23.364-22-35.709-22-12.345 0-24.945 14.58-35.709 22Z" fill="#EAF6FF"/></mask><g mask="url(#a)"><path fill="#F66A0A" stroke="#fff" stroke-width="2" d="M12.793 16.838h20.706v17.303H12.793z"/></g></svg>
<svg width="162" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path fill="#fff" d="M.813.082h161v31h-161z"/><path d="M26.047 8.638h.93v6.22h3.43v.88h-4.36v-7.1ZM33.46 15.838c-.38 0-.73-.067-1.05-.2a2.573 2.573 0 0 1-1.38-1.38c-.127-.32-.19-.66-.19-1.02s.063-.697.19-1.01c.133-.32.316-.597.55-.83.233-.233.51-.417.83-.55.32-.14.67-.21 1.05-.21.373 0 .72.07 1.04.21.32.133.596.317.83.55.233.233.413.51.54.83.133.313.2.65.2 1.01s-.068.7-.2 1.02a2.438 2.438 0 0 1-.54.82c-.234.233-.51.42-.83.56-.32.133-.667.2-1.04.2Zm0-.8c.26 0 .496-.047.71-.14.212-.093.392-.22.54-.38.152-.167.27-.357.35-.57.086-.22.13-.457.13-.71 0-.247-.044-.48-.13-.7-.08-.22-.198-.41-.35-.57a1.518 1.518 0 0 0-.54-.39 1.752 1.752 0 0 0-.71-.14c-.26 0-.498.047-.71.14a1.62 1.62 0 0 0-.55.39 1.73 1.73 0 0 0-.36.57c-.08.22-.12.453-.12.7 0 .253.04.49.12.71.086.213.206.403.36.57.152.16.336.287.55.38.212.093.45.14.71.14ZM40.284 12.148l-1.23 3.59h-.76l-1.7-5h.9l1.21 3.65 1.25-3.65h.66l1.25 3.65 1.21-3.65h.91l-1.7 5h-.76l-1.24-3.59Z" fill="#F66A0A"/><path opacity=".3" d="M45.774 22.738c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#037DD6"/><mask id="b" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="26" y="0" width="111" height="31"><path d="M45.774 22.605c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#EAF6FF"/></mask><g mask="url(#b)"><path fill="#F66A0A" stroke="#fff" stroke-width="2" d="M24.607 16.738h20.706v17.303H24.607z"/></g></g><defs><clipPath id="a"><path fill="#fff" transform="translate(.813 .082)" d="M0 0h161v31H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -1 +1 @@
<svg width="111" height="49" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="m38 4.334 2.63 3.54 2.65-3.54h.84v7.1h-.92v-5.52l-2.56 3.44-2.56-3.44v5.52h-.93v-7.1H38Zm9.99 7.2a2.73 2.73 0 0 1-1.06-.2 2.431 2.431 0 0 1-1.35-1.37 2.91 2.91 0 0 1-.18-1.03c0-.367.063-.707.19-1.02.126-.32.303-.597.53-.83.233-.234.51-.417.83-.55.32-.134.67-.2 1.05-.2.326 0 .633.056.92.17.286.106.536.27.75.49.22.213.393.476.52.79.126.306.19.66.19 1.06v.13c0 .033-.004.076-.01.13h-4.1c.006.233.053.45.14.65.093.2.213.373.36.52.153.146.333.263.54.35.213.08.443.12.69.12.386 0 .703-.077.95-.23.253-.16.456-.374.61-.64l.68.47c-.227.366-.53.656-.91.87-.374.213-.82.32-1.34.32Zm1.51-3.13a1.579 1.579 0 0 0-.19-.55c-.087-.16-.2-.297-.34-.41a1.419 1.419 0 0 0-.46-.26 1.639 1.639 0 0 0-.54-.09 1.729 1.729 0 0 0-1.04.35 1.5 1.5 0 0 0-.38.41c-.107.16-.18.343-.22.55h3.17Zm4.16 3.13c-.353 0-.68-.067-.98-.2a2.57 2.57 0 0 1-.77-.56 2.73 2.73 0 0 1-.52-.83 2.8 2.8 0 0 1-.18-1.01c0-.36.06-.697.18-1.01.127-.314.3-.587.52-.82a2.359 2.359 0 0 1 1.75-.77c.38 0 .727.086 1.04.26.314.166.554.37.72.61v-3.27h.86v7.5h-.86v-.77a2.08 2.08 0 0 1-.72.62 2.18 2.18 0 0 1-1.04.25Zm.13-.79a1.607 1.607 0 0 0 1.22-.52c.154-.167.27-.36.35-.58.087-.22.13-.457.13-.71 0-.254-.043-.49-.13-.71-.08-.22-.196-.41-.35-.57a1.544 1.544 0 0 0-.53-.39 1.658 1.658 0 0 0-.69-.14c-.253 0-.486.046-.7.14a1.648 1.648 0 0 0-.54.39 1.82 1.82 0 0 0-.35.57c-.08.22-.12.456-.12.71 0 .253.04.49.12.71.087.22.204.413.35.58.154.16.334.286.54.38.214.093.447.14.7.14Zm4.55-5.65a.599.599 0 0 1-.62-.61c0-.167.06-.31.18-.43s.266-.18.44-.18c.172 0 .316.06.43.18.112.12.17.263.17.43 0 .173-.058.32-.17.44a.583.583 0 0 1-.43.17Zm-.44 1.34h.86v5h-.86v-5Zm4.26 5.1c-.274 0-.524-.047-.75-.14-.227-.1-.42-.237-.58-.41a1.917 1.917 0 0 1-.38-.63 2.617 2.617 0 0 1-.13-.85v-3.07h.86v2.94c0 .42.1.753.3 1 .206.246.483.37.83.37.193 0 .373-.04.54-.12.173-.087.32-.207.44-.36.126-.16.226-.354.3-.58.073-.227.11-.484.11-.77v-2.48h.86v5h-.86v-.77a1.654 1.654 0 0 1-.66.66c-.267.14-.56.21-.88.21Zm10.46-3.04c0-.407-.083-.737-.25-.99-.166-.254-.413-.38-.74-.38-.4 0-.726.156-.98.47-.246.313-.376.74-.39 1.28v2.56h-.86v-2.94c0-.407-.083-.737-.25-.99-.16-.254-.403-.38-.73-.38-.406 0-.74.163-1 .49-.253.326-.38.773-.38 1.34v2.48h-.86v-5h.86v.77a1.63 1.63 0 0 1 .61-.63c.26-.16.56-.24.9-.24.374 0 .69.096.95.29.267.186.464.446.59.78.134-.327.344-.587.63-.78.294-.194.63-.29 1.01-.29.274 0 .517.05.73.15.22.093.404.23.55.41.154.173.27.386.35.64.08.246.12.523.12.83v3.07h-.86v-2.94Z" fill="#037DD6"/><path opacity=".3" d="M19.506 40.566c-10.763 7.42-19.416 8-19.416 8h110.25s-8.653-.58-19.417-8c-10.763-7.42-23.363-22-35.708-22-12.345 0-24.945 14.58-35.709 22Z" fill="#037DD6"/><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="18" width="111" height="31"><path d="M19.506 40.434c-10.763 7.42-19.416 8-19.416 8h110.25s-8.653-.58-19.417-8c-10.763-7.42-23.363-22-35.708-22-12.345 0-24.945 14.58-35.709 22Z" fill="#EAF6FF"/></mask><g mask="url(#a)"><path fill="#037DD6" stroke="#fff" stroke-width="2" d="M36.047 12.619H73.39v39.25H36.047z"/></g></svg>
<svg width="162" height="47" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M.813.082h161v46h-161z"/><path d="m64.268 1.505 2.63 3.54 2.65-3.54h.84v7.1h-.92v-5.52l-2.56 3.44-2.56-3.44v5.52h-.93v-7.1h.85ZM74.257 8.705a2.73 2.73 0 0 1-1.06-.2 2.432 2.432 0 0 1-1.35-1.37 2.91 2.91 0 0 1-.18-1.03c0-.367.064-.707.19-1.02.127-.32.304-.596.53-.83.234-.233.51-.417.83-.55.32-.133.67-.2 1.05-.2.327 0 .634.057.92.17.287.107.537.27.75.49.22.213.394.477.52.79.127.307.19.66.19 1.06v.13c0 .034-.003.077-.01.13h-4.1c.007.233.054.45.14.65.094.2.214.373.36.52.154.147.334.263.54.35.214.08.444.12.69.12.387 0 .704-.077.95-.23.254-.16.457-.373.61-.64l.68.47c-.226.367-.53.657-.91.87-.373.213-.82.32-1.34.32Zm1.51-3.13a1.58 1.58 0 0 0-.19-.55c-.086-.16-.2-.296-.34-.41a1.42 1.42 0 0 0-.46-.26 1.639 1.639 0 0 0-.54-.09 1.728 1.728 0 0 0-1.04.35 1.498 1.498 0 0 0-.38.41 1.49 1.49 0 0 0-.22.55h3.17ZM79.928 8.705c-.353 0-.68-.066-.98-.2a2.57 2.57 0 0 1-.77-.56 2.732 2.732 0 0 1-.52-.83 2.8 2.8 0 0 1-.18-1.01c0-.36.06-.697.18-1.01.127-.313.3-.587.52-.82a2.36 2.36 0 0 1 1.75-.77c.38 0 .727.087 1.04.26.313.167.553.37.72.61v-3.27h.86v7.5h-.86v-.77c-.167.24-.407.447-.72.62a2.18 2.18 0 0 1-1.04.25Zm.13-.79a1.606 1.606 0 0 0 1.22-.52c.153-.167.27-.36.35-.58.087-.22.13-.457.13-.71 0-.253-.043-.49-.13-.71-.08-.22-.197-.41-.35-.57a1.542 1.542 0 0 0-.53-.39 1.657 1.657 0 0 0-.69-.14c-.253 0-.487.047-.7.14a1.65 1.65 0 0 0-.54.39c-.147.16-.263.35-.35.57-.08.22-.12.457-.12.71 0 .253.04.49.12.71.087.22.203.413.35.58.153.16.333.287.54.38.213.093.447.14.7.14ZM84.607 2.265a.599.599 0 0 1-.62-.61c0-.167.06-.31.18-.43s.266-.18.44-.18c.173 0 .317.06.43.18.113.12.17.263.17.43 0 .173-.057.32-.17.44a.583.583 0 0 1-.43.17Zm-.44 1.34h.86v5h-.86v-5ZM88.427 8.705c-.273 0-.523-.046-.75-.14-.227-.1-.42-.236-.58-.41a1.916 1.916 0 0 1-.38-.63 2.614 2.614 0 0 1-.13-.85v-3.07h.86v2.94c0 .42.1.753.3 1 .207.247.483.37.83.37.193 0 .373-.04.54-.12.173-.087.32-.207.44-.36.127-.16.227-.353.3-.58.073-.227.11-.483.11-.77v-2.48h.86v5h-.86v-.77a1.654 1.654 0 0 1-.66.66c-.267.14-.56.21-.88.21ZM98.888 5.665c0-.407-.083-.737-.25-.99-.166-.253-.413-.38-.74-.38-.4 0-.727.157-.98.47-.247.314-.377.74-.39 1.28v2.56h-.86v-2.94c0-.407-.083-.737-.25-.99-.16-.253-.403-.38-.73-.38-.407 0-.74.163-1 .49-.253.327-.38.774-.38 1.34v2.48h-.86v-5h.86v.77a1.63 1.63 0 0 1 .61-.63c.26-.16.56-.24.9-.24.374 0 .69.097.95.29.267.187.463.447.59.78.133-.327.343-.587.63-.78.293-.193.63-.29 1.01-.29.273 0 .517.05.73.15.22.094.404.23.55.41.153.173.27.387.35.64.08.247.12.524.12.83v3.07h-.86v-2.94Z" fill="#037DD6"/><path opacity=".3" d="M45.774 37.738c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#037DD6"/><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="26" y="15" width="111" height="31"><path d="M45.774 37.605c-10.764 7.42-19.417 8-19.417 8h110.251s-8.653-.58-19.417-8c-10.764-7.42-23.364-22-35.709-22-12.344 0-24.944 14.58-35.708 22Z" fill="#EAF6FF"/></mask><g mask="url(#a)"><path fill="#037DD6" stroke="#fff" stroke-width="2" d="M62.313 9.791h37.343v39.25H62.313z"/></g></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

@ -0,0 +1,116 @@
WEBVTT
1
00:00:00.780 --> 00:00:04.580
MetaMask ist eine neue Möglichkeit, sich mit
Webseiten und Anwendungen zu verbinden.
2
00:00:04.580 --> 00:00:08.860
Auf traditionellen Webseiten ist eine
zentrale Datenbank für die Steuerung und
3
00:00:08.860 --> 00:00:10.179
Wiederherstellung der Konten zuständig.
4
00:00:10.179 --> 00:00:15.050
Bei MetaMask gehört all diese Macht dem
Besitzer eines „Hauptschlüssels“.
5
00:00:15.050 --> 00:00:18.460
Wer den Schlüssel besitzt, kontrolliert
das Wallet und damit die Konten.
6
00:00:18.460 --> 00:00:21.110
Der geheime Satz zur Wiederherstellung
Deines Wallets ist der „Hauptschlüssel“.
7
00:00:21.110 --> 00:00:26.070
Es ist eine Reihe von 12 Wörtern, welche generiert werden,
wenn MetaMask zum ersten Mal eingerichtet wird, diese erlauben dir
8
00:00:26.070 --> 00:00:30.120
Deinen „Hauptschlüssel“ zu Deinem Wallet wieder herzustellen,
solltest Du jemals den Zugriff darauf verlieren.
9
00:00:30.120 --> 00:00:33.451
Es ist wichtig, dass Du Dein Wallet sicherst,
indem Du Deinen geheimen
10
00:00:33.451 --> 00:00:37.510
Wiederherstellungssatz sicher
und geheim verwahrst.
11
00:00:37.510 --> 00:00:41.429
Wenn jemand Zugriff darauf erhält, hat er
den „Hauptschlüssel“ für Dein Wallet und kann
12
00:00:41.429 --> 00:00:45.190
frei auf Deine Konten zugreifen und alle Gelder stehlen.
13
00:00:45.190 --> 00:00:50.109
Um Dein MetaMask-Wallet zu sichern, musst Du Deinen
geheimen Wiederherstellungssatz sicher speichern.
14
00:00:50.109 --> 00:00:54.930
Du kannst ihn aufschreiben, irgendwo verstecken,
in ein Schließfach legen
15
00:00:54.930 --> 00:00:57.729
oder in einen sicheren Passwort-Manager speichern.
16
00:00:57.729 --> 00:01:01.050
Einige Benutzer gravieren ihren
Satz sogar auf eine Metallplatte.
17
00:01:01.050 --> 00:01:04.440
Niemand, nicht einmal das Team von MetaMask,
kann Dir dabei helfen
18
00:01:04.440 --> 00:01:07.820
Dein Wallet wiederherzustellen, wenn Du Deinen
geheimen Wiederherstellungssatz verlierst.
19
00:01:07.820 --> 00:01:12.072
Wenn Du Deinen geheimen Wiederherstellungssatz noch nicht
aufgeschrieben und an einem sicheren Ort aufbewahrt hast,
20
00:01:12.072 --> 00:01:15.492
mach es jetzt. Wir warten solange.
21
00:01:15.500 --> 00:01:20.780
Und denk daran, teilen Deinen geheimen Wiederherstellungssatz
niemals: nicht einmal mit uns.
22
00:01:20.780 --> 00:01:24.910
Wenn dich jemals jemand danach fragt,
versucht er dich zu betrügen.
23
00:01:24.910 --> 00:01:26.250
Das ist alles!
24
00:01:26.250 --> 00:01:31.020
Jetzt weist Du, was ein geheimer Wiederherstellungssatz ist
und wie Du dafür sorgst, das Dein Wallete sicher bleibt.

@ -1,7 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<title>Ethereum Phishing Detection - MetaMask</title>
<title>MetaMask Phishing Detection</title>
<script src="./globalthis.js" type="text/javascript" charset="utf-8"></script>
<script src="./lockdown-install.js" type="text/javascript" charset="utf-8"></script>
<script src="./lockdown-run.js" type="text/javascript" charset="utf-8"></script>
@ -37,7 +37,7 @@
<img src="./images/info-logo.png" alt="">
<h1>
<i class="fa fa-exclamation-circle" aria-hidden="true"></i>
Ethereum Phishing Detection
MetaMask Phishing Detection
</h1>
</div>
<div class="content__body">

@ -414,7 +414,10 @@ function setupController(initState, initLangCode) {
// communication with page or other extension
function connectExternal(remotePort) {
const portStream = new PortStream(remotePort);
controller.setupUntrustedCommunication(portStream, remotePort.sender);
controller.setupUntrustedCommunication({
connectionStream: portStream,
sender: remotePort.sender,
});
}
//

@ -31,10 +31,12 @@ export default class AppStateController extends EventEmitter {
recoveryPhraseReminderHasBeenShown: false,
recoveryPhraseReminderLastShown: new Date().getTime(),
collectiblesDetectionNoticeDismissed: false,
enableEIP1559V2NoticeDismissed: false,
showTestnetMessageInDropdown: true,
trezorModel: null,
...initState,
qrHardware: {},
collectiblesDropdownState: {},
});
this.timer = null;
@ -270,4 +272,26 @@ export default class AppStateController extends EventEmitter {
collectiblesDetectionNoticeDismissed,
});
}
/**
* A setter for the `enableEIP1559V2NoticeDismissed` property
*
* @param enableEIP1559V2NoticeDismissed
*/
setEnableEIP1559V2NoticeDismissed(enableEIP1559V2NoticeDismissed) {
this.store.updateState({
enableEIP1559V2NoticeDismissed,
});
}
/**
* A setter for the `collectiblesDropdownState` property
*
* @param collectiblesDropdownState
*/
updateCollectibleDropDownState(collectiblesDropdownState) {
this.store.updateState({
collectiblesDropdownState,
});
}
}

@ -1,15 +1,17 @@
import { merge, omit } from 'lodash';
import { merge, omit, omitBy } from 'lodash';
import { ObservableStore } from '@metamask/obs-store';
import { bufferToHex, keccak } from 'ethereumjs-util';
import { generateUUID } from 'pubnub';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import {
METAMETRICS_ANONYMOUS_ID,
METAMETRICS_BACKGROUND_PAGE_OBJECT,
} from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time';
const defaultCaptureException = (err) => {
// throw error on clean stack so its captured by platform integrations (eg sentry)
// but does not interupt the call stack
// but does not interrupt the call stack
setTimeout(() => {
throw err;
});
@ -27,15 +29,18 @@ const exceptionsToFilter = {
* @typedef {import('../../../shared/constants/metametrics').SegmentInterface} SegmentInterface
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsPagePayload} MetaMetricsPagePayload
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsPageOptions} MetaMetricsPageOptions
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsEventFragment} MetaMetricsEventFragment
*/
/**
* @typedef {Object} MetaMetricsControllerState
* @property {?string} metaMetricsId - The user's metaMetricsId that will be
* @property {string} [metaMetricsId] - The user's metaMetricsId that will be
* attached to all non-anonymized event payloads
* @property {?boolean} participateInMetaMetrics - The user's preference for
* @property {boolean} [participateInMetaMetrics] - The user's preference for
* participating in the MetaMetrics analytics program. This setting controls
* whether or not events are tracked
* @property {{[string]: MetaMetricsEventFragment}} [fragments] - Object keyed
* by UUID with stored fragments as values.
*/
export default class MetaMetricsController {
@ -81,10 +86,15 @@ export default class MetaMetricsController {
this.version =
environment === 'production' ? version : `${version}-${environment}`;
const abandonedFragments = omitBy(initState?.fragments, 'persist');
this.store = new ObservableStore({
participateInMetaMetrics: null,
metaMetricsId: null,
...initState,
fragments: {
...initState?.fragments,
},
});
preferencesStore.subscribe(({ currentLocale }) => {
@ -96,6 +106,32 @@ export default class MetaMetricsController {
this.network = getNetworkIdentifier();
});
this.segment = segment;
// Track abandoned fragments that weren't properly cleaned up.
// Abandoned fragments are those that were stored in persistent memory
// and are available at controller instance creation, but do not have the
// 'persist' flag set. This means anytime the extension is unlocked, any
// fragments that are not marked as persistent will be purged and the
// failure event will be emitted.
Object.values(abandonedFragments).forEach((fragment) => {
this.finalizeEventFragment(fragment.id, { abandoned: true });
});
// Close out event fragments that were created but not progressed. An
// interval is used to routinely check if a fragment has not been updated
// within the fragment's timeout window. When creating a new event fragment
// a timeout can be specified that will cause an abandoned event to be
// tracked if the event isn't progressed within that amount of time.
setInterval(() => {
Object.values(this.store.getState().fragments).forEach((fragment) => {
if (
fragment.timeout &&
Date.now() - fragment.lastUpdated / 1000 > fragment.timeout
) {
this.finalizeEventFragment(fragment.id, { abandoned: true });
}
});
}, SECOND * 30);
}
generateMetaMetricsId() {
@ -109,6 +145,141 @@ export default class MetaMetricsController {
);
}
/**
* Create an event fragment in state and returns the event fragment object.
*
* @param {MetaMetricsEventFragment} options - Fragment settings and properties
* to initiate the fragment with.
* @returns {MetaMetricsEventFragment}
*/
createEventFragment(options) {
if (!options.successEvent || !options.category) {
throw new Error(
`Must specify success event and category. Success event was: ${
options.event
}. Category was: ${options.category}. Payload keys were: ${Object.keys(
options,
)}. ${
typeof options.properties === 'object'
? `Payload property keys were: ${Object.keys(options.properties)}`
: ''
}`,
);
}
const { fragments } = this.store.getState();
const id = options.uniqueIdentifier ?? generateUUID();
const fragment = {
id,
...options,
lastUpdated: Date.now(),
};
this.store.updateState({
fragments: {
...fragments,
[id]: fragment,
},
});
if (options.initialEvent) {
this.trackEvent({
event: fragment.initialEvent,
category: fragment.category,
properties: fragment.properties,
sensitiveProperties: fragment.sensitiveProperties,
page: fragment.page,
referrer: fragment.referrer,
revenue: fragment.revenue,
value: fragment.value,
currency: fragment.currency,
environmentType: fragment.environmentType,
});
}
return fragment;
}
/**
* Returns the fragment stored in memory with provided id or undefined if it
* does not exist.
*
* @param {string} id - id of fragment to retrieve
* @returns {[MetaMetricsEventFragment]}
*/
getEventFragmentById(id) {
const { fragments } = this.store.getState();
const fragment = fragments[id];
return fragment;
}
/**
* Updates an event fragment in state
*
* @param {string} id - The fragment id to update
* @param {MetaMetricsEventFragment} payload - Fragment settings and
* properties to initiate the fragment with.
*/
updateEventFragment(id, payload) {
const { fragments } = this.store.getState();
const fragment = fragments[id];
if (!fragment) {
throw new Error(`Event fragment with id ${id} does not exist.`);
}
this.store.updateState({
fragments: {
...fragments,
[id]: merge(fragments[id], {
...payload,
lastUpdated: Date.now(),
}),
},
});
}
/**
* Finalizes a fragment, tracking either a success event or failure Event
* and then removes the fragment from state.
*
* @param {string} id - UUID of the event fragment to be closed
* @param {object} options
* @param {boolean} [options.abandoned] - if true track the failure
* event instead of the success event
* @param {MetaMetricsContext.page} [options.page] - page the final event
* occurred on. This will override whatever is set on the fragment
* @param {MetaMetricsContext.referrer} [options.referrer] - Dapp that
* originated the fragment. This is for fallback only, the fragment referrer
* property will take precedence.
*/
finalizeEventFragment(id, { abandoned = false, page, referrer } = {}) {
const fragment = this.store.getState().fragments[id];
if (!fragment) {
throw new Error(`Funnel with id ${id} does not exist.`);
}
const eventName = abandoned ? fragment.failureEvent : fragment.successEvent;
this.trackEvent({
event: eventName,
category: fragment.category,
properties: fragment.properties,
sensitiveProperties: fragment.sensitiveProperties,
page: page ?? fragment.page,
referrer: fragment.referrer ?? referrer,
revenue: fragment.revenue,
value: fragment.value,
currency: fragment.currency,
environmentType: fragment.environmentType,
});
const { fragments } = this.store.getState();
delete fragments[id];
this.store.updateState({ fragments });
}
/**
* Setter for the `participateInMetaMetrics` property
*

@ -81,6 +81,28 @@ function getMockPreferencesStore({ currentLocale = LOCALE } = {}) {
};
}
const SAMPLE_PERSISTED_EVENT = {
id: 'testid',
persist: true,
category: 'Unit Test',
successEvent: 'sample persisted event success',
failureEvent: 'sample persisted event failure',
properties: {
test: true,
},
};
const SAMPLE_NON_PERSISTED_EVENT = {
id: 'testid2',
persist: false,
category: 'Unit Test',
successEvent: 'sample non-persisted event success',
failureEvent: 'sample non-persisted event failure',
properties: {
test: true,
},
};
function getMetaMetricsController({
participateInMetaMetrics = true,
metaMetricsId = TEST_META_METRICS_ID,
@ -105,12 +127,29 @@ function getMetaMetricsController({
initState: {
participateInMetaMetrics,
metaMetricsId,
fragments: {
testid: SAMPLE_PERSISTED_EVENT,
testid2: SAMPLE_NON_PERSISTED_EVENT,
},
},
});
}
describe('MetaMetricsController', function () {
describe('constructor', function () {
it('should properly initialize', function () {
const mock = sinon.mock(segment);
mock
.expects('track')
.once()
.withArgs({
event: 'sample non-persisted event failure',
userId: TEST_META_METRICS_ID,
context: DEFAULT_TEST_CONTEXT,
properties: {
...DEFAULT_EVENT_PROPERTIES,
test: true,
},
});
const metaMetricsController = getMetaMetricsController();
assert.strictEqual(metaMetricsController.version, VERSION);
assert.strictEqual(metaMetricsController.network, NETWORK);
@ -127,6 +166,10 @@ describe('MetaMetricsController', function () {
metaMetricsController.locale,
LOCALE.replace('_', '-'),
);
assert.deepStrictEqual(metaMetricsController.state.fragments, {
testid: SAMPLE_PERSISTED_EVENT,
});
mock.verify();
});
it('should update when network changes', function () {

@ -134,16 +134,10 @@ export default class PreferencesController {
/**
* Setter for the `useCollectibleDetection` property
*
* @param {boolean} val - Whether or not the user prefers to autodetect collectibles.
* @param {boolean} useCollectibleDetection - Whether or not the user prefers to autodetect collectibles.
*/
setUseCollectibleDetection(val) {
const { openSeaEnabled } = this.store.getState();
if (val && !openSeaEnabled) {
throw new Error(
'useCollectibleDetection cannot be enabled if openSeaEnabled is false',
);
}
this.store.updateState({ useCollectibleDetection: val });
setUseCollectibleDetection(useCollectibleDetection) {
this.store.updateState({ useCollectibleDetection });
}
/**
@ -167,6 +161,15 @@ export default class PreferencesController {
this.store.updateState({ advancedGasFee: val });
}
/**
* Setter for the `eip1559V2Enabled` property
*
* @param {object} val - holds the eip1559V2Enabled that the user set as experimental settings.
*/
setEIP1559V2Enabled(val) {
this.store.updateState({ eip1559V2Enabled: val });
}
/**
* Add new methodData to state, to avoid requesting this information again through Infura
*

@ -25,6 +25,7 @@ import {
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
TRANSACTION_ENVELOPE_TYPES,
TRANSACTION_EVENTS,
} from '../../../../shared/constants/transaction';
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
@ -54,13 +55,15 @@ const hstInterface = new ethers.utils.Interface(abi);
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
export const TRANSACTION_EVENTS = {
ADDED: 'Transaction Added',
APPROVED: 'Transaction Approved',
FINALIZED: 'Transaction Finalized',
REJECTED: 'Transaction Rejected',
SUBMITTED: 'Transaction Submitted',
};
const SWAP_TRANSACTION_TYPES = [
TRANSACTION_TYPES.SWAP,
TRANSACTION_TYPES.SWAP_APPROVAL,
];
/**
* @typedef {import('../../../../shared/constants/transaction').TransactionMeta} TransactionMeta
* @typedef {import('../../../../shared/constants/transaction').TransactionMetaMetricsEventString} TransactionMetaMetricsEventString
*/
/**
* @typedef {Object} CustomGasSettings
@ -118,6 +121,10 @@ export default class TransactionController extends EventEmitter {
this._trackMetaMetricsEvent = opts.trackMetaMetricsEvent;
this._getParticipateInMetrics = opts.getParticipateInMetrics;
this._getEIP1559GasFeeEstimates = opts.getEIP1559GasFeeEstimates;
this.createEventFragment = opts.createEventFragment;
this.updateEventFragment = opts.updateEventFragment;
this.finalizeEventFragment = opts.finalizeEventFragment;
this.getEventFragmentById = opts.getEventFragmentById;
this.memStore = new ObservableStore({});
this.query = new EthQuery(this.provider);
@ -335,9 +342,19 @@ export default class TransactionController extends EventEmitter {
*
* @param txParams
* @param origin
* @param transactionType
* @returns {txMeta}
*/
async addUnapprovedTransaction(txParams, origin) {
async addUnapprovedTransaction(txParams, origin, transactionType) {
if (
transactionType !== undefined &&
!SWAP_TRANSACTION_TYPES.includes(transactionType)
) {
throw new Error(
`TransactionController - invalid transactionType value: ${transactionType}`,
);
}
// validate
const normalizedTxParams = txUtils.normalizeTxParams(txParams);
const eip1559Compatibility = await this.getEIP1559Compatibility();
@ -379,7 +396,7 @@ export default class TransactionController extends EventEmitter {
const { type, getCodeResponse } = await this._determineTransactionType(
txParams,
);
txMeta.type = type;
txMeta.type = transactionType || type;
// ensure value
txMeta.txParams.value = txMeta.txParams.value
@ -432,7 +449,6 @@ export default class TransactionController extends EventEmitter {
gasLimit: defaultGasLimit,
simulationFails,
} = await this._getDefaultGasLimit(txMeta, getCodeResponse);
const advancedGasFeeDefaultValues = this.getAdvancedGasFee();
// eslint-disable-next-line no-param-reassign
txMeta = this.txStateManager.getTransaction(txMeta.id);
@ -441,7 +457,13 @@ export default class TransactionController extends EventEmitter {
}
if (eip1559Compatibility) {
if (process.env.EIP_1559_V2 && Boolean(advancedGasFeeDefaultValues)) {
const { eip1559V2Enabled } = this.preferencesStore.getState();
const advancedGasFeeDefaultValues = this.getAdvancedGasFee();
if (
eip1559V2Enabled &&
Boolean(advancedGasFeeDefaultValues) &&
!SWAP_TRANSACTION_TYPES.includes(txMeta.type)
) {
txMeta.userFeeLevel = CUSTOM_GAS_ESTIMATE;
txMeta.txParams.maxFeePerGas = decGWEIToHexWEI(
advancedGasFeeDefaultValues.maxBaseFee,
@ -458,7 +480,7 @@ export default class TransactionController extends EventEmitter {
// then we set maxFeePerGas and maxPriorityFeePerGas to the suggested gasPrice.
txMeta.txParams.maxFeePerGas = txMeta.txParams.gasPrice;
txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.gasPrice;
if (process.env.EIP_1559_V2) {
if (eip1559V2Enabled && txMeta.origin !== 'metamask') {
txMeta.userFeeLevel = PRIORITY_LEVELS.DAPP_SUGGESTED;
} else {
txMeta.userFeeLevel = CUSTOM_GAS_ESTIMATE;
@ -472,7 +494,7 @@ export default class TransactionController extends EventEmitter {
txMeta.origin === 'metamask'
) {
txMeta.userFeeLevel = GAS_RECOMMENDATIONS.MEDIUM;
} else if (process.env.EIP_1559_V2) {
} else if (eip1559V2Enabled) {
txMeta.userFeeLevel = PRIORITY_LEVELS.DAPP_SUGGESTED;
} else {
txMeta.userFeeLevel = CUSTOM_GAS_ESTIMATE;
@ -538,7 +560,15 @@ export default class TransactionController extends EventEmitter {
if (defaultGasLimit && !txMeta.txParams.gas) {
txMeta.txParams.gas = defaultGasLimit;
txMeta.originalGasEstimate = defaultGasLimit;
}
txMeta.defaultGasEstimates = {
estimateType: txMeta.userFeeLevel,
gas: txMeta.txParams.gas,
gasPrice: txMeta.txParams.gasPrice,
maxFeePerGas: txMeta.txParams.maxFeePerGas,
maxPriorityFeePerGas: txMeta.txParams.maxPriorityFeePerGas,
};
return txMeta;
}
@ -661,9 +691,8 @@ export default class TransactionController extends EventEmitter {
* which is defined by specifying a numerator. 11 is a 10% bump, 12 would be
* a 20% bump, and so on.
*
* @param {import(
* '../../../../shared/constants/transaction'
* ).TransactionMeta} originalTxMeta - Original transaction to use as base
* @param {TransactionMeta} originalTxMeta - Original transaction to use as
* base
* @param {CustomGasSettings} [customGasSettings] - overrides for the gas
* fields to use instead of the multiplier
* @param {number} [incrementNumerator] - Numerator from which to generate a
@ -1119,6 +1148,28 @@ export default class TransactionController extends EventEmitter {
this.txStateManager.updateTransaction(txMeta, 'transactions#setTxHash');
}
/**
* Convenience method for the UI to easily create event fragments when the
* fragment does not exist in state.
*
* @param {number} transactionId - The transaction id to create the event
* fragment for
* @param {valueOf<TRANSACTION_EVENTS>} event - event type to create
*/
async createTransactionEventFragment(transactionId, event) {
const txMeta = this.txStateManager.getTransaction(transactionId);
const {
properties,
sensitiveProperties,
} = await this._buildEventFragmentProperties(txMeta);
this._createTransactionEventFragment(
txMeta,
event,
properties,
sensitiveProperties,
);
}
//
// PRIVATE METHODS
//
@ -1449,20 +1500,7 @@ export default class TransactionController extends EventEmitter {
}
}
/**
* Extracts relevant properties from a transaction meta
* object and uses them to create and send metrics for various transaction
* events.
*
* @param {Object} txMeta - the txMeta object
* @param {string} event - the name of the transaction event
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
*/
_trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
if (!txMeta) {
return;
}
async _buildEventFragmentProperties(txMeta, extraParams) {
const {
type,
time,
@ -1477,6 +1515,7 @@ export default class TransactionController extends EventEmitter {
estimateSuggested,
estimateUsed,
},
defaultGasEstimates,
metamaskNetworkId: network,
} = txMeta;
const source = referrer === 'metamask' ? 'user' : 'dapp';
@ -1490,6 +1529,43 @@ export default class TransactionController extends EventEmitter {
gasParams.gas_price = gasPrice;
}
if (defaultGasEstimates) {
const { estimateType } = defaultGasEstimates;
if (estimateType) {
gasParams.default_estimate = estimateType;
let defaultMaxFeePerGas = txMeta.defaultGasEstimates.maxFeePerGas;
let defaultMaxPriorityFeePerGas =
txMeta.defaultGasEstimates.maxPriorityFeePerGas;
if (
[
GAS_RECOMMENDATIONS.LOW,
GAS_RECOMMENDATIONS.MEDIUM,
GAS_RECOMMENDATIONS.MEDIUM.HIGH,
].includes(estimateType)
) {
const { gasFeeEstimates } = await this._getEIP1559GasFeeEstimates();
if (gasFeeEstimates?.[estimateType]?.suggestedMaxFeePerGas) {
defaultMaxFeePerGas =
gasFeeEstimates[estimateType]?.suggestedMaxFeePerGas;
gasParams.default_max_fee_per_gas = defaultMaxFeePerGas;
}
if (gasFeeEstimates?.[estimateType]?.suggestedMaxPriorityFeePerGas) {
defaultMaxPriorityFeePerGas =
gasFeeEstimates[estimateType]?.suggestedMaxPriorityFeePerGas;
gasParams.default_max_priority_fee_per_gas = defaultMaxPriorityFeePerGas;
}
}
}
if (txMeta.defaultGasEstimates.gas) {
gasParams.default_gas = txMeta.defaultGasEstimates.gas;
}
if (txMeta.defaultGasEstimates.gasPrice) {
gasParams.default_gas_price = txMeta.defaultGasEstimates.gasPrice;
}
}
if (estimateSuggested) {
gasParams.estimate_suggested = estimateSuggested;
}
@ -1500,27 +1576,211 @@ export default class TransactionController extends EventEmitter {
const gasParamsInGwei = this._getGasValuesInGWEI(gasParams);
this._trackMetaMetricsEvent({
let eip1559Version = '0';
if (txMeta.txParams.maxFeePerGas) {
const { eip1559V2Enabled } = this.preferencesStore.getState();
eip1559Version = eip1559V2Enabled ? '2' : '1';
}
const properties = {
chain_id: chainId,
referrer,
source,
network,
type,
eip_1559_version: eip1559Version,
gas_edit_type: 'none',
gas_edit_attempted: 'none',
};
const sensitiveProperties = {
status,
transaction_envelope_type: isEIP1559Transaction(txMeta)
? TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET
: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
first_seen: time,
gas_limit: gasLimit,
...gasParamsInGwei,
...extraParams,
};
return { properties, sensitiveProperties };
}
/**
* Helper method that checks for the presence of an existing fragment by id
* appropriate for the type of event that triggered fragment creation. If the
* appropriate fragment exists, then nothing is done. If it does not exist a
* new event fragment is created with the appropriate payload.
*
* @param {TransactionMeta} txMeta - Transaction meta object
* @param {TransactionMetaMetricsEventString} event - The event type that
* triggered fragment creation
* @param {Object} properties - properties to include in the fragment
* @param {Object} [sensitiveProperties] - sensitive properties to include in
* the fragment
*/
_createTransactionEventFragment(
txMeta,
event,
properties,
sensitiveProperties,
) {
const isSubmitted = [
TRANSACTION_EVENTS.FINALIZED,
TRANSACTION_EVENTS.SUBMITTED,
].includes(event);
const uniqueIdentifier = `transaction-${
isSubmitted ? 'submitted' : 'added'
}-${txMeta.id}`;
const fragment = this.getEventFragmentById(uniqueIdentifier);
if (typeof fragment !== 'undefined') {
return;
}
switch (event) {
// When a transaction is added to the controller, we know that the user
// will be presented with a confirmation screen. The user will then
// either confirm or reject that transaction. Each has an associated
// event we want to track. While we don't necessarily need an event
// fragment to model this, having one allows us to record additional
// properties onto the event from the UI. For example, when the user
// edits the transactions gas params we can record that property and
// then get analytics on the number of transactions in which gas edits
// occur.
case TRANSACTION_EVENTS.ADDED:
this.createEventFragment({
category: 'Transactions',
initialEvent: TRANSACTION_EVENTS.ADDED,
successEvent: TRANSACTION_EVENTS.APPROVED,
failureEvent: TRANSACTION_EVENTS.REJECTED,
properties,
sensitiveProperties,
persist: true,
uniqueIdentifier,
});
break;
// If for some reason an approval or rejection occurs without the added
// fragment existing in memory, we create the added fragment but without
// the initialEvent firing. This is to prevent possible duplication of
// events. A good example why this might occur is if the user had
// unapproved transactions in memory when updating to the version that
// includes this change. A migration would have also helped here but this
// implementation hardens against other possible bugs where a fragment
// does not exist.
case TRANSACTION_EVENTS.APPROVED:
case TRANSACTION_EVENTS.REJECTED:
this.createEventFragment({
category: 'Transactions',
successEvent: TRANSACTION_EVENTS.APPROVED,
failureEvent: TRANSACTION_EVENTS.REJECTED,
properties,
sensitiveProperties,
persist: true,
uniqueIdentifier,
});
break;
// When a transaction is submitted it will always result in updating
// to a finalized state (dropped, failed, confirmed) -- eventually.
// However having a fragment started at this stage allows augmenting
// analytics data with user interactions such as speeding up and
// canceling the transactions. From this controllers perspective a new
// transaction with a new id is generated for speed up and cancel
// transactions, but from the UI we could augment the previous ID with
// supplemental data to show user intent. Such as when they open the
// cancel UI but don't submit. We can record that this happened and add
// properties to the transaction event.
case TRANSACTION_EVENTS.SUBMITTED:
this.createEventFragment({
category: 'Transactions',
initialEvent: TRANSACTION_EVENTS.SUBMITTED,
successEvent: TRANSACTION_EVENTS.FINALIZED,
properties,
sensitiveProperties,
persist: true,
uniqueIdentifier,
});
break;
// If for some reason a transaction is finalized without the submitted
// fragment existing in memory, we create the submitted fragment but
// without the initialEvent firing. This is to prevent possible
// duplication of events. A good example why this might occur is if th
// user had pending transactions in memory when updating to the version
// that includes this change. A migration would have also helped here but
// this implementation hardens against other possible bugs where a
// fragment does not exist.
case TRANSACTION_EVENTS.FINALIZED:
this.createEventFragment({
category: 'Transactions',
successEvent: TRANSACTION_EVENTS.FINALIZED,
properties,
sensitiveProperties,
persist: true,
uniqueIdentifier,
});
break;
default:
break;
}
}
/**
* Extracts relevant properties from a transaction meta
* object and uses them to create and send metrics for various transaction
* events.
*
* @param {Object} txMeta - the txMeta object
* @param {TransactionMetaMetricsEventString} event - the name of the transaction event
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
*/
async _trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
if (!txMeta) {
return;
}
const {
properties,
sensitiveProperties,
} = await this._buildEventFragmentProperties(txMeta, extraParams);
// Create event fragments for event types that spawn fragments, and ensure
// existence of fragments for event types that act upon them.
this._createTransactionEventFragment(
txMeta,
event,
category: 'Transactions',
properties: {
chain_id: chainId,
referrer,
source,
network,
type,
},
sensitiveProperties: {
status,
transaction_envelope_type: isEIP1559Transaction(txMeta)
? TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET
: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
first_seen: time,
gas_limit: gasLimit,
...gasParamsInGwei,
...extraParams,
},
});
properties,
sensitiveProperties,
);
let id;
switch (event) {
// If the user approves a transaction, finalize the transaction added
// event fragment.
case TRANSACTION_EVENTS.APPROVED:
id = `transaction-added-${txMeta.id}`;
this.updateEventFragment(id, { properties, sensitiveProperties });
this.finalizeEventFragment(id);
break;
// If the user rejects a transaction, finalize the transaction added
// event fragment. with the abandoned flag set.
case TRANSACTION_EVENTS.REJECTED:
id = `transaction-added-${txMeta.id}`;
this.updateEventFragment(id, { properties, sensitiveProperties });
this.finalizeEventFragment(id, {
abandoned: true,
});
break;
// When a transaction is finalized, also finalize the transaction
// submitted event fragment.
case TRANSACTION_EVENTS.FINALIZED:
id = `transaction-submitted-${txMeta.id}`;
this.updateEventFragment(id, { properties, sensitiveProperties });
this.finalizeEventFragment(`transaction-submitted-${txMeta.id}`);
break;
default:
break;
}
}
_getTransactionCompletionTime(submittedTime) {

@ -9,10 +9,12 @@ import {
createTestProviderTools,
getTestAccounts,
} from '../../../../test/stub/provider';
import mockEstimates from '../../../../test/data/mock-estimates.json';
import {
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
TRANSACTION_ENVELOPE_TYPES,
TRANSACTION_EVENTS,
} from '../../../../shared/constants/transaction';
import { SECOND } from '../../../../shared/constants/time';
@ -22,7 +24,7 @@ import {
} from '../../../../shared/constants/gas';
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import TransactionController, { TRANSACTION_EVENTS } from '.';
import TransactionController from '.';
const noop = () => true;
const currentNetworkId = '42';
@ -35,17 +37,21 @@ const VALID_ADDRESS = '0x0000000000000000000000000000000000000000';
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
describe('Transaction Controller', function () {
let txController, provider, providerResultStub, fromAccount;
let txController, provider, providerResultStub, fromAccount, fragmentExists;
beforeEach(function () {
fragmentExists = false;
providerResultStub = {
// 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000',
// by default, all accounts are external accounts (not contracts)
eth_getCode: '0x',
};
provider = createTestProviderTools({ scaffold: providerResultStub })
.provider;
provider = createTestProviderTools({
scaffold: providerResultStub,
networkId: currentNetworkId,
chainId: currentNetworkId,
}).provider;
fromAccount = getTestAccounts()[0];
const blockTrackerStub = new EventEmitter();
@ -70,6 +76,11 @@ describe('Transaction Controller', function () {
getCurrentChainId: () => currentChainId,
getParticipateInMetrics: () => false,
trackMetaMetricsEvent: () => undefined,
createEventFragment: () => undefined,
updateEventFragment: () => undefined,
finalizeEventFragment: () => undefined,
getEventFragmentById: () =>
fragmentExists === false ? undefined : { id: 0 },
getEIP1559GasFeeEstimates: () => undefined,
});
txController.nonceTracker.getNonceLock = () =>
@ -1536,66 +1547,357 @@ describe('Transaction Controller', function () {
describe('#_trackTransactionMetricsEvent', function () {
let trackMetaMetricsEventSpy;
let createEventFragmentSpy;
let finalizeEventFragmentSpy;
beforeEach(function () {
trackMetaMetricsEventSpy = sinon.spy(
txController,
'_trackMetaMetricsEvent',
);
createEventFragmentSpy = sinon.spy(txController, 'createEventFragment');
finalizeEventFragmentSpy = sinon.spy(
txController,
'finalizeEventFragment',
);
sinon
.stub(txController, '_getEIP1559GasFeeEstimates')
.resolves(mockEstimates['fee-market']);
});
afterEach(function () {
trackMetaMetricsEventSpy.restore();
createEventFragmentSpy.restore();
finalizeEventFragmentSpy.restore();
});
it('should call _trackMetaMetricsEvent with the correct payload (user source)', function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TRANSACTION_TYPES.SIMPLE_SEND,
origin: 'metamask',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
category: 'Transactions',
properties: {
chain_id: '0x2a',
network: '42',
referrer: 'metamask',
source: 'user',
describe('On transaction created by the user', function () {
let txMeta;
before(function () {
txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TRANSACTION_TYPES.SIMPLE_SEND,
},
sensitiveProperties: {
gas_price: '2',
gas_limit: '0x7b0d',
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
},
};
origin: 'metamask',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
gas: '0x7b0d',
gasPrice: '0x77359400',
},
};
});
txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
expectedPayload,
);
it('should create an event fragment when transaction added', async function () {
const expectedPayload = {
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: 'Transactions',
persist: true,
properties: {
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'metamask',
source: 'user',
type: TRANSACTION_TYPES.SIMPLE_SEND,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.REJECTED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], {
abandoned: true,
});
});
it('Should finalize the transaction added fragment if user approves transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.APPROVED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
it('should create an event fragment when transaction is submitted', async function () {
const expectedPayload = {
initialEvent: 'Transaction Submitted',
successEvent: 'Transaction Finalized',
uniqueIdentifier: 'transaction-submitted-1',
category: 'Transactions',
persist: true,
properties: {
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'metamask',
source: 'user',
type: TRANSACTION_TYPES.SIMPLE_SEND,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.SUBMITTED,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction submitted fragment when transaction finalizes', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.FINALIZED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-submitted-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
});
describe('On transaction suggested by dapp', function () {
let txMeta;
before(function () {
txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TRANSACTION_TYPES.SIMPLE_SEND,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
gas: '0x7b0d',
gasPrice: '0x77359400',
},
};
});
it('should create an event fragment when transaction added', async function () {
const expectedPayload = {
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: 'Transactions',
persist: true,
properties: {
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'other',
source: 'dapp',
type: TRANSACTION_TYPES.SIMPLE_SEND,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.REJECTED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], {
abandoned: true,
});
});
it('Should finalize the transaction added fragment if user approves transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.APPROVED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
it('should create an event fragment when transaction is submitted', async function () {
const expectedPayload = {
initialEvent: 'Transaction Submitted',
successEvent: 'Transaction Finalized',
uniqueIdentifier: 'transaction-submitted-1',
category: 'Transactions',
persist: true,
properties: {
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'other',
source: 'dapp',
type: TRANSACTION_TYPES.SIMPLE_SEND,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.SUBMITTED,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction submitted fragment when transaction finalizes', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.FINALIZED,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-submitted-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
});
it('should call _trackMetaMetricsEvent with the correct payload (dapp source)', function () {
it('should create missing fragments when events happen out of order or are missing', async function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
@ -1612,11 +1914,18 @@ describe('Transaction Controller', function () {
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: 'Transactions',
persist: true,
properties: {
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'other',
source: 'dapp',
@ -1630,19 +1939,24 @@ describe('Transaction Controller', function () {
status: 'unapproved',
},
};
txController._trackTransactionMetricsEvent(
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
TRANSACTION_EVENTS.APPROVED,
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], undefined);
});
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', function () {
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', async function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
@ -1660,7 +1974,11 @@ describe('Transaction Controller', function () {
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: 'Transactions',
properties: {
network: '42',
@ -1668,6 +1986,9 @@ describe('Transaction Controller', function () {
source: 'dapp',
type: TRANSACTION_TYPES.SIMPLE_SEND,
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
},
sensitiveProperties: {
baz: 3.0,
@ -1680,7 +2001,7 @@ describe('Transaction Controller', function () {
},
};
txController._trackTransactionMetricsEvent(
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
{
@ -1688,14 +2009,15 @@ describe('Transaction Controller', function () {
foo: 'bar',
},
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (EIP-1559)', function () {
it('should call _trackMetaMetricsEvent with the correct payload (EIP-1559)', async function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
@ -1714,12 +2036,24 @@ describe('Transaction Controller', function () {
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
estimateType: 'medium',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x77359400',
},
};
const expectedPayload = {
event: 'Transaction Added',
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: 'Transactions',
properties: {
chain_id: '0x2a',
eip_1559_version: '1',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '42',
referrer: 'other',
source: 'dapp',
@ -1736,10 +2070,13 @@ describe('Transaction Controller', function () {
status: 'unapproved',
estimate_suggested: GAS_RECOMMENDATIONS.MEDIUM,
estimate_used: GAS_RECOMMENDATIONS.HIGH,
default_estimate: 'medium',
default_max_fee_per_gas: '70',
default_max_priority_fee_per_gas: '7',
},
};
txController._trackTransactionMetricsEvent(
await txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
{
@ -1747,9 +2084,10 @@ describe('Transaction Controller', function () {
foo: 'bar',
},
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});

@ -117,6 +117,8 @@ export default class TransactionStateManager extends EventEmitter {
time: new Date().getTime(),
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: netId,
originalGasEstimate: opts.txParams?.gas,
userEditedGasLimit: false,
chainId,
loadingDefaults: true,
dappSuggestedGasFees,

@ -1,75 +0,0 @@
import nock from 'nock';
import {
KOVAN_CHAIN_ID,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import { TRANSAK_API_KEY } from '../constants/on-ramp';
import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps';
import getBuyEthUrl from './buy-eth-url';
const WYRE_ACCOUNT_ID = 'AC-7AG3W4XH4N2';
const ETH_ADDRESS = '0x0dcd5d886577d5581b0c524242ef2ee70be3e7bc';
const MAINNET = {
chainId: MAINNET_CHAIN_ID,
amount: 5,
address: ETH_ADDRESS,
};
const ROPSTEN = {
chainId: ROPSTEN_CHAIN_ID,
};
const RINKEBY = {
chainId: RINKEBY_CHAIN_ID,
};
const KOVAN = {
chainId: KOVAN_CHAIN_ID,
};
describe('buy-eth-url', () => {
it('returns Wyre url with an ETH address for Ethereum mainnet', async () => {
nock(SWAPS_API_V2_BASE_URL)
.get(
`/networks/1/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}`,
)
.reply(200, {
url: `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=ETH&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
});
const wyreUrl = await getBuyEthUrl(MAINNET);
expect(wyreUrl).toStrictEqual(
`https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=ETH&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
);
nock.cleanAll();
});
it('returns a fallback Wyre url if /orders/reserve API call fails', async () => {
const wyreUrl = await getBuyEthUrl(MAINNET);
expect(wyreUrl).toStrictEqual(
`https://pay.sendwyre.com/purchase?dest=ethereum:${ETH_ADDRESS}&destCurrency=ETH&accountId=${WYRE_ACCOUNT_ID}&paymentMethod=debit-card`,
);
});
it('returns Transak url with an ETH address for Ethereum mainnet', async () => {
const transakUrl = await getBuyEthUrl({ ...MAINNET, service: 'transak' });
expect(transakUrl).toStrictEqual(
`https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=ETH&walletAddress=${ETH_ADDRESS}`,
);
});
it('returns metamask ropsten faucet for network 3', async () => {
const ropstenUrl = await getBuyEthUrl(ROPSTEN);
expect(ropstenUrl).toStrictEqual('https://faucet.metamask.io/');
});
it('returns rinkeby dapp for network 4', async () => {
const rinkebyUrl = await getBuyEthUrl(RINKEBY);
expect(rinkebyUrl).toStrictEqual('https://www.rinkeby.io/');
});
it('returns kovan github test faucet for network 42', async () => {
const kovanUrl = await getBuyEthUrl(KOVAN);
expect(kovanUrl).toStrictEqual('https://github.com/kovan-testnet/faucet');
});
});

@ -8,6 +8,7 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
MAINNET_NETWORK_ID,
BUYABLE_CHAINS_MAP,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
@ -47,16 +48,22 @@ const createWyrePurchaseUrl = async (address) => {
* Create a Transak Checkout URL.
* API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238
*
* @param {string} address - Ethereum destination address
* @param {string} walletAddress - Ethereum destination address
* @param {string} chainId - Current chain ID
* @returns String
*/
const createTransakUrl = (address) => {
const createTransakUrl = (walletAddress, chainId) => {
const { transakCurrencies, network } = BUYABLE_CHAINS_MAP[chainId];
const queryParams = new URLSearchParams({
apiKey: TRANSAK_API_KEY,
hostURL: 'https://metamask.io',
defaultCryptoCurrency: 'ETH',
walletAddress: address,
cryptoCurrencyList: transakCurrencies.join(','),
defaultCryptoCurrency: transakCurrencies[0],
networks: network,
walletAddress,
});
return `https://global.transak.com/?${queryParams}`;
};
@ -70,7 +77,7 @@ const createTransakUrl = (address) => {
* @returns {string|undefined} The url at which the user can access ETH, while in the given chain. If the passed
* chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
*/
export default async function getBuyEthUrl({ chainId, address, service }) {
export default async function getBuyUrl({ chainId, address, service }) {
// default service by network if not specified
if (!service) {
// eslint-disable-next-line no-param-reassign
@ -81,7 +88,7 @@ export default async function getBuyEthUrl({ chainId, address, service }) {
case 'wyre':
return await createWyrePurchaseUrl(address);
case 'transak':
return createTransakUrl(address);
return createTransakUrl(address, chainId);
case 'metamask-faucet':
return 'https://faucet.metamask.io/';
case 'rinkeby-faucet':

@ -0,0 +1,117 @@
import nock from 'nock';
import {
KOVAN_CHAIN_ID,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
BSC_CHAIN_ID,
POLYGON_CHAIN_ID,
ETH_SYMBOL,
BUYABLE_CHAINS_MAP,
} from '../../../shared/constants/network';
import { TRANSAK_API_KEY } from '../constants/on-ramp';
import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps';
import getBuyUrl from './buy-url';
const WYRE_ACCOUNT_ID = 'AC-7AG3W4XH4N2';
const ETH_ADDRESS = '0x0dcd5d886577d5581b0c524242ef2ee70be3e7bc';
const MAINNET = {
chainId: MAINNET_CHAIN_ID,
amount: 5,
address: ETH_ADDRESS,
};
const ROPSTEN = {
chainId: ROPSTEN_CHAIN_ID,
};
const RINKEBY = {
chainId: RINKEBY_CHAIN_ID,
};
const KOVAN = {
chainId: KOVAN_CHAIN_ID,
};
const BSC = {
chainId: BSC_CHAIN_ID,
amount: 5,
address: ETH_ADDRESS,
};
const POLYGON = {
chainId: POLYGON_CHAIN_ID,
amount: 5,
address: ETH_ADDRESS,
};
describe('buy-url', () => {
it('returns Wyre url with an ETH address for Ethereum mainnet', async () => {
nock(SWAPS_API_V2_BASE_URL)
.get(
`/networks/1/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}`,
)
.reply(200, {
url: `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=${ETH_SYMBOL}&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
});
const wyreUrl = await getBuyUrl(MAINNET);
expect(wyreUrl).toStrictEqual(
`https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=${ETH_SYMBOL}&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
);
nock.cleanAll();
});
it('returns a fallback Wyre url if /orders/reserve API call fails', async () => {
const wyreUrl = await getBuyUrl(MAINNET);
expect(wyreUrl).toStrictEqual(
`https://pay.sendwyre.com/purchase?dest=ethereum:${ETH_ADDRESS}&destCurrency=${ETH_SYMBOL}&accountId=${WYRE_ACCOUNT_ID}&paymentMethod=debit-card`,
);
});
it('returns Transak url with an ETH address for Ethereum mainnet', async () => {
const transakUrl = await getBuyUrl({ ...MAINNET, service: 'transak' });
const buyableChain = BUYABLE_CHAINS_MAP[MAINNET.chainId];
const buyableCurrencies = encodeURIComponent(
buyableChain.transakCurrencies.join(','),
);
expect(transakUrl).toStrictEqual(
`https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&cryptoCurrencyList=${buyableCurrencies}&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`,
);
});
it('returns Transak url with an BNB address for Binance Smart Chain', async () => {
const transakUrl = await getBuyUrl({ ...BSC, service: 'transak' });
const buyableChain = BUYABLE_CHAINS_MAP[BSC.chainId];
const buyableCurrencies = encodeURIComponent(
buyableChain.transakCurrencies.join(','),
);
expect(transakUrl).toStrictEqual(
`https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&cryptoCurrencyList=${buyableCurrencies}&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`,
);
});
it('returns Transak url with an MATIC address for Polygon', async () => {
const transakUrl = await getBuyUrl({ ...POLYGON, service: 'transak' });
const buyableChain = BUYABLE_CHAINS_MAP[POLYGON.chainId];
const buyableCurrencies = encodeURIComponent(
buyableChain.transakCurrencies.join(','),
);
expect(transakUrl).toStrictEqual(
`https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&cryptoCurrencyList=${buyableCurrencies}&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`,
);
});
it('returns metamask ropsten faucet for network 3', async () => {
const ropstenUrl = await getBuyUrl(ROPSTEN);
expect(ropstenUrl).toStrictEqual('https://faucet.metamask.io/');
});
it('returns rinkeby dapp for network 4', async () => {
const rinkebyUrl = await getBuyUrl(RINKEBY);
expect(rinkebyUrl).toStrictEqual('https://www.rinkeby.io/');
});
it('returns kovan github test faucet for network 42', async () => {
const kovanUrl = await getBuyUrl(KOVAN);
expect(kovanUrl).toStrictEqual('https://github.com/kovan-testnet/faucet');
});
});

@ -220,22 +220,22 @@ export default class MetamaskController extends EventEmitter {
onNetworkStateChange: this.networkController.store.subscribe.bind(
this.networkController.store,
),
getAssetName: this.assetsContractController.getAssetName.bind(
getERC721AssetName: this.assetsContractController.getERC721AssetName.bind(
this.assetsContractController,
),
getAssetSymbol: this.assetsContractController.getAssetSymbol.bind(
getERC721AssetSymbol: this.assetsContractController.getERC721AssetSymbol.bind(
this.assetsContractController,
),
getCollectibleTokenURI: this.assetsContractController.getCollectibleTokenURI.bind(
getERC721TokenURI: this.assetsContractController.getERC721TokenURI.bind(
this.assetsContractController,
),
getOwnerOf: this.assetsContractController.getOwnerOf.bind(
getERC721OwnerOf: this.assetsContractController.getERC721OwnerOf.bind(
this.assetsContractController,
),
balanceOfERC1155Collectible: this.assetsContractController.balanceOfERC1155Collectible.bind(
getERC1155BalanceOf: this.assetsContractController.getERC1155BalanceOf.bind(
this.assetsContractController,
),
uriERC1155Collectible: this.assetsContractController.uriERC1155Collectible.bind(
getERC1155TokenURI: this.assetsContractController.getERC1155TokenURI.bind(
this.assetsContractController,
),
},
@ -243,6 +243,8 @@ export default class MetamaskController extends EventEmitter {
initState.CollectiblesController,
);
this.collectiblesController.setApiKey(process.env.OPENSEA_KEY);
process.env.COLLECTIBLES_V1 &&
(this.collectibleDetectionController = new CollectibleDetectionController(
{
@ -601,6 +603,18 @@ export default class MetamaskController extends EventEmitter {
),
provider: this.provider,
blockTracker: this.blockTracker,
createEventFragment: this.metaMetricsController.createEventFragment.bind(
this.metaMetricsController,
),
updateEventFragment: this.metaMetricsController.updateEventFragment.bind(
this.metaMetricsController,
),
finalizeEventFragment: this.metaMetricsController.finalizeEventFragment.bind(
this.metaMetricsController,
),
getEventFragmentById: this.metaMetricsController.getEventFragmentById.bind(
this.metaMetricsController,
),
trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind(
this.metaMetricsController,
),
@ -660,8 +674,7 @@ export default class MetamaskController extends EventEmitter {
this.collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus(
knownCollectible,
false,
// TODO add this when checkAndUpdateSingleCollectibleOwnershipStatus is updated
// { userAddress, chainId },
{ userAddress, chainId },
);
}
}
@ -1064,6 +1077,7 @@ export default class MetamaskController extends EventEmitter {
appStateController,
collectiblesController,
collectibleDetectionController,
assetsContractController,
currencyRateController,
detectTokensController,
ensController,
@ -1212,6 +1226,14 @@ export default class MetamaskController extends EventEmitter {
setAdvancedGasFee: preferencesController.setAdvancedGasFee.bind(
preferencesController,
),
setEIP1559V2Enabled: preferencesController.setEIP1559V2Enabled.bind(
preferencesController,
),
// AssetsContractController
getTokenStandardAndDetails: assetsContractController.getTokenStandardAndDetails.bind(
assetsContractController,
),
// CollectiblesController
addCollectible: collectiblesController.addCollectible.bind(
@ -1270,6 +1292,12 @@ export default class MetamaskController extends EventEmitter {
setCollectiblesDetectionNoticeDismissed: appStateController.setCollectiblesDetectionNoticeDismissed.bind(
appStateController,
),
setEnableEIP1559V2NoticeDismissed: appStateController.setEnableEIP1559V2NoticeDismissed.bind(
appStateController,
),
updateCollectibleDropDownState: appStateController.updateCollectibleDropDownState.bind(
appStateController,
),
// EnsController
tryReverseResolveAddress: ensController.reverseResolveAddress.bind(
ensController,
@ -1294,6 +1322,9 @@ export default class MetamaskController extends EventEmitter {
addUnapprovedTransaction: txController.addUnapprovedTransaction.bind(
txController,
),
createTransactionEventFragment: txController.createTransactionEventFragment.bind(
txController,
),
// messageManager
signMessage: this.signMessage.bind(this),
@ -1426,6 +1457,15 @@ export default class MetamaskController extends EventEmitter {
trackMetaMetricsPage: metaMetricsController.trackPage.bind(
metaMetricsController,
),
createEventFragment: metaMetricsController.createEventFragment.bind(
metaMetricsController,
),
updateEventFragment: metaMetricsController.updateEventFragment.bind(
metaMetricsController,
),
finalizeEventFragment: metaMetricsController.finalizeEventFragment.bind(
metaMetricsController,
),
// approval controller
resolvePendingApproval: approvalController.accept.bind(
@ -2634,28 +2674,47 @@ export default class MetamaskController extends EventEmitter {
* Used to create a multiplexed stream for connecting to an untrusted context
* like a Dapp or other extension.
*
* @param {*} connectionStream - The Duplex stream to connect to.
* @param {MessageSender} sender - The sender of the messages on this stream
* @param options - Options bag.
* @param {ReadableStream} options.connectionStream - The Duplex stream to connect to.
* @param {MessageSender | SnapSender} options.sender - The sender of the messages on this stream.
* @param {string} [options.subjectType] - The type of the sender, i.e. subject.
*/
setupUntrustedCommunication(connectionStream, sender) {
setupUntrustedCommunication({ connectionStream, sender, subjectType }) {
const { usePhishDetect } = this.preferencesController.store.getState();
const { hostname } = new URL(sender.url);
// Check if new connection is blocked if phishing detection is on
if (usePhishDetect && this.phishingController.test(hostname)) {
log.debug('MetaMask - sending phishing warning for', hostname);
this.sendPhishingWarning(connectionStream, hostname);
return;
let _subjectType;
if (subjectType) {
_subjectType = subjectType;
} else if (sender.id && sender.id !== this.extension.runtime.id) {
_subjectType = SUBJECT_TYPES.EXTENSION;
} else {
_subjectType = SUBJECT_TYPES.WEBSITE;
}
if (sender.url) {
const { hostname } = new URL(sender.url);
// Check if new connection is blocked if phishing detection is on
if (usePhishDetect && this.phishingController.test(hostname)) {
log.debug('MetaMask - sending phishing warning for', hostname);
this.sendPhishingWarning(connectionStream, hostname);
return;
}
}
// setup multiplexing
const mux = setupMultiplex(connectionStream);
// messages between inpage and background
this.setupProviderConnection(mux.createStream('metamask-provider'), sender);
this.setupProviderConnection(
mux.createStream('metamask-provider'),
sender,
_subjectType,
);
// TODO:LegacyProvider: Delete
// legacy streams
this.setupPublicConfig(mux.createStream('publicConfig'));
if (sender.url) {
// legacy streams
this.setupPublicConfig(mux.createStream('publicConfig'));
}
}
/**
@ -2672,7 +2731,11 @@ export default class MetamaskController extends EventEmitter {
const mux = setupMultiplex(connectionStream);
// connect features
this.setupControllerConnection(mux.createStream('controller'));
this.setupProviderConnection(mux.createStream('provider'), sender, true);
this.setupProviderConnection(
mux.createStream('provider'),
sender,
SUBJECT_TYPES.INTERNAL,
);
}
/**
@ -2731,17 +2794,19 @@ export default class MetamaskController extends EventEmitter {
*
* @param {*} outStream - The stream to provide over.
* @param {MessageSender} sender - The sender of the messages on this stream
* @param {boolean} isInternal - True if this is a connection with an internal process
* @param {string} subjectType - The type of the sender, i.e. subject.
*/
setupProviderConnection(outStream, sender, isInternal) {
const origin = isInternal ? 'metamask' : new URL(sender.url).origin;
let subjectType = isInternal
? SUBJECT_TYPES.INTERNAL
: SUBJECT_TYPES.WEBSITE;
setupProviderConnection(outStream, sender, subjectType) {
let origin;
if (subjectType === SUBJECT_TYPES.INTERNAL) {
origin = 'metamask';
} else {
origin = new URL(sender.url).origin;
}
if (sender.id !== this.extension.runtime.id) {
subjectType = SUBJECT_TYPES.EXTENSION;
this.subjectMetadataController.addSubjectMetadata(origin, {
if (sender.id && sender.id !== this.extension.runtime.id) {
this.subjectMetadataController.addSubjectMetadata({
origin,
extensionId: sender.id,
subjectType: SUBJECT_TYPES.EXTENSION,
});
@ -2754,8 +2819,8 @@ export default class MetamaskController extends EventEmitter {
const engine = this.setupProviderEngine({
origin,
location: sender.url,
tabId,
sender,
subjectType,
});
@ -2783,14 +2848,14 @@ export default class MetamaskController extends EventEmitter {
*
* @param {Object} options - Provider engine options
* @param {string} options.origin - The origin of the sender
* @param {string} options.location - The full URL of the sender
* @param {MessageSender | SnapSender} options.sender - The sender object.
* @param {string} options.subjectType - The type of the sender subject.
* @param {tabId} [options.tabId] - The tab ID of the sender - if the sender is within a tab
*/
setupProviderEngine({ origin, location, subjectType, tabId }) {
setupProviderEngine({ origin, subjectType, sender, tabId }) {
// setup json rpc engine stack
const engine = new JsonRpcEngine();
const { provider, blockTracker } = this;
const { blockTracker, provider } = this;
// create filter polyfill middleware
const filterMiddleware = createFilterMiddleware({ provider, blockTracker });
@ -2812,13 +2877,16 @@ export default class MetamaskController extends EventEmitter {
}
// logging
engine.push(createLoggerMiddleware({ origin }));
engine.push(
createOnboardingMiddleware({
location,
registerOnboarding: this.onboardingController.registerOnboarding,
}),
);
engine.push(this.permissionLogController.createMiddleware());
// onboarding
if (subjectType === SUBJECT_TYPES.WEBSITE) {
engine.push(
createOnboardingMiddleware({
location: sender.url,
registerOnboarding: this.onboardingController.registerOnboarding,
}),
);
}
engine.push(
createMethodMiddleware({
origin,

@ -995,10 +995,10 @@ describe('MetaMaskController', function () {
cb();
});
metamaskController.setupUntrustedCommunication(
streamTest,
phishingMessageSender,
);
metamaskController.setupUntrustedCommunication({
connectionStream: streamTest,
sender: phishingMessageSender,
});
await promise;
streamTest.end();
});
@ -1016,7 +1016,10 @@ describe('MetaMaskController', function () {
cb();
});
metamaskController.setupUntrustedCommunication(streamTest, messageSender);
metamaskController.setupUntrustedCommunication({
connectionStream: streamTest,
sender: messageSender,
});
const message = {
id: 1999133338649204,
@ -1055,7 +1058,10 @@ describe('MetaMaskController', function () {
cb();
});
metamaskController.setupUntrustedCommunication(streamTest, messageSender);
metamaskController.setupUntrustedCommunication({
connectionStream: streamTest,
sender: messageSender,
});
const message = {
id: 1999133338649204,

@ -34,7 +34,6 @@ const metamaskrc = require('rc')('metamask', {
INFURA_PROD_PROJECT_ID: process.env.INFURA_PROD_PROJECT_ID,
ONBOARDING_V2: process.env.ONBOARDING_V2,
COLLECTIBLES_V1: process.env.COLLECTIBLES_V1,
EIP_1559_V2: process.env.EIP_1559_V2,
SEGMENT_HOST: process.env.SEGMENT_HOST,
SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY,
SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY,
@ -797,7 +796,6 @@ function getEnvironmentVariables({ buildType, devMode, testing }) {
SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS === '1',
ONBOARDING_V2: metamaskrc.ONBOARDING_V2 === '1',
COLLECTIBLES_V1: metamaskrc.COLLECTIBLES_V1 === '1',
EIP_1559_V2: metamaskrc.EIP_1559_V2 === '1',
};
}

@ -200,9 +200,19 @@ const directiveParsingRegex = /^([A-Z]+):([A-Z_]+)(?:\(((?:\w+,)*\w+)\))?$/u;
* a boolean indicating whether they were modified.
*/
function removeFencedCode(filePath, typeOfCurrentBuild, fileContent) {
const matchedLines = [...fileContent.matchAll(linesWithFenceRegex)];
// Do not modify the file if we detect an inline sourcemap. For reasons
// yet to be determined, the transform receives every file twice while in
// watch mode, the second after Babel has transpiled the file. Babel adds
// inline source maps to the file, something we will never do in our own
// source files, so we use the existence of inline source maps to determine
// whether we should ignore the file.
if (/^\/\/# sourceMappingURL=/gmu.test(fileContent)) {
return [fileContent, false];
}
// If we didn't match any lines, return the unmodified file contents.
const matchedLines = [...fileContent.matchAll(linesWithFenceRegex)];
if (matchedLines.length === 0) {
return [fileContent, false];
}

@ -610,6 +610,17 @@ describe('build/transforms/remove-fenced-code', () => {
});
});
it('ignores files with inline source maps', () => {
// This is so that there isn't an unnecessary second execution of
// removeFencedCode with a transpiled version of the same file
const input = getTestData().validInputs.extraContentWithFences.concat(
'\n//# sourceMappingURL=as32e32wcwc2234f2ew32cnin4243f4nv9nsdoivnxzoivnd',
);
expect(
removeFencedCode(mockFileName, BuildType.flask, input),
).toStrictEqual([input, false]);
});
// We can't do this until there's more than one command
it.todo('rejects directive pairs with mismatched commands');
});

@ -4,7 +4,7 @@ set -e
set -u
set -o pipefail
ganache_cli="$(yarn bin)/ganache-cli"
ganache_cli="$(yarn bin)/ganache"
seed_phrase="${GANACHE_SEED_PHRASE:-phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent}"
_term () {
@ -23,7 +23,7 @@ trap _term SIGTERM
trap _int SIGINT
# shellcheck disable=SC2086
$ganache_cli --noVMErrorsOnRPCResponse --networkId 1337 --mnemonic "$seed_phrase" ${GANACHE_ARGS:-} &
$ganache_cli --chain.vmErrorsOnRPCResponse false --networkId 1337 --mnemonic "$seed_phrase" ${GANACHE_ARGS:-} &
child=$!
wait "$child"

@ -955,7 +955,10 @@
},
"abstract-leveldown": {
"packages": {
"buffer": true,
"immediate": true,
"is-buffer": true,
"level-supports": true,
"process": true,
"xtend": true
}
@ -3042,6 +3045,11 @@
"xtend": true
}
},
"level-supports": {
"packages": {
"xtend": true
}
},
"levelup": {
"packages": {
"assert": true,

@ -955,7 +955,10 @@
},
"abstract-leveldown": {
"packages": {
"buffer": true,
"immediate": true,
"is-buffer": true,
"level-supports": true,
"process": true,
"xtend": true
}
@ -3042,6 +3045,11 @@
"xtend": true
}
},
"level-supports": {
"packages": {
"xtend": true
}
},
"levelup": {
"packages": {
"assert": true,

@ -955,7 +955,10 @@
},
"abstract-leveldown": {
"packages": {
"buffer": true,
"immediate": true,
"is-buffer": true,
"level-supports": true,
"process": true,
"xtend": true
}
@ -3042,6 +3045,11 @@
"xtend": true
}
},
"level-supports": {
"packages": {
"xtend": true
}
},
"levelup": {
"packages": {
"assert": true,

@ -1,6 +1,6 @@
{
"name": "metamask-crx",
"version": "10.9.3",
"version": "10.10.0",
"private": true,
"repository": {
"type": "git",
@ -87,7 +87,6 @@
"3box/**/libp2p-keychain/node-forge": "^1.0.0",
"3box/ipfs/libp2p-webrtc-star/socket.io/engine.io": "^4.0.0",
"analytics-node/axios": "^0.21.2",
"analytics-node/axios/follow-redirects": "^1.14.7",
"ganache-core/lodash": "^4.17.21",
"netmask": "^2.0.1",
"pubnub/superagent-proxy": "^3.0.0",
@ -110,9 +109,9 @@
"@keystonehq/metamask-airgapped-keyring": "0.2.1",
"@material-ui/core": "^4.11.0",
"@metamask/contract-metadata": "^1.31.0",
"@metamask/controllers": "^24.0.0",
"@metamask/controllers": "^25.0.0",
"@metamask/eth-ledger-bridge-keyring": "^0.10.0",
"@metamask/eth-token-tracker": "^3.0.1",
"@metamask/eth-token-tracker": "^4.0.0",
"@metamask/etherscan-link": "^2.1.0",
"@metamask/jazzicon": "^2.0.0",
"@metamask/logo": "^3.1.1",
@ -233,7 +232,7 @@
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.5.5",
"@lavamoat/allow-scripts": "^1.0.6",
"@lavamoat/allow-scripts": "^2.0.0",
"@lavamoat/lavapack": "^2.0.4",
"@metamask/auto-changelog": "^2.1.0",
"@metamask/eslint-config": "^9.0.0",
@ -293,8 +292,7 @@
"fancy-log": "^1.3.3",
"fast-glob": "^3.2.2",
"fs-extra": "^8.1.0",
"ganache-cli": "^6.12.1",
"ganache-core": "^2.13.1",
"ganache": "^v7.0.0-rc.0",
"geckodriver": "^1.21.0",
"globby": "^11.0.4",
"gulp": "^4.0.2",
@ -365,30 +363,54 @@
},
"lavamoat": {
"allowScripts": {
"gridplus-sdk": false,
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>leveldown": false,
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto-secp256k1>secp256k1": false,
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto>libp2p-crypto-secp256k1>secp256k1": false,
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto>ursa-optional": false,
"3box>ipfs-postmsg-proxy>peer-id>libp2p-crypto>libp2p-crypto-secp256k1>secp256k1": false,
"3box>ipfs>ipfs-mfs>ipfs-unixfs-exporter>ipfs-unixfs-importer>rabin-wasm>assemblyscript": false,
"3box>ipfs>ipfs-repo>datastore-level>leveldown": false,
"3box>ipfs>ipld-bitcoin>bitcoinjs-lib>bip32>tiny-secp256k1": false,
"3box>ipfs>ipld-ethereum>ethereumjs-account>ethereumjs-util>keccak": false,
"3box>ipfs>ipld-ethereum>ethereumjs-account>ethereumjs-util>secp256k1": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-tx>ethereumjs-util>ethereum-cryptography>keccak": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-tx>ethereumjs-util>ethereum-cryptography>secp256k1": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-util>keccak": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-util>secp256k1": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>merkle-patricia-tree>ethereumjs-util>keccak": false,
"3box>ipfs>ipld-ethereum>ethereumjs-block>merkle-patricia-tree>ethereumjs-util>secp256k1": false,
"3box>ipfs>ipld-ethereum>ethereumjs-tx>ethereumjs-util>keccak": false,
"3box>ipfs>ipld-ethereum>ethereumjs-tx>ethereumjs-util>secp256k1": false,
"3box>ipfs>ipld-ethereum>merkle-patricia-tree>ethereumjs-util>keccak": false,
"3box>ipfs>ipld-ethereum>merkle-patricia-tree>ethereumjs-util>secp256k1": false,
"3box>orbit-db>orbit-db-cache>leveldown": false,
"@lavamoat/allow-scripts>@lavamoat/preinstall-always-fail": false,
"@metamask/controllers>babel-runtime>core-js": false,
"@metamask/controllers>eth-json-rpc-infura>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
"@metamask/controllers>eth-json-rpc-infura>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
"@metamask/controllers>eth-keyring-controller>eth-hd-keyring>eth-sig-util>ethereumjs-util>keccak": false,
"@metamask/controllers>eth-keyring-controller>eth-hd-keyring>eth-sig-util>ethereumjs-util>secp256k1": false,
"@metamask/controllers>web3-provider-engine>eth-json-rpc-filters>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
"@metamask/controllers>web3-provider-engine>eth-json-rpc-filters>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
"@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
"@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
"@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>keccak": false,
"@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>secp256k1": false,
"@sentry/cli": true,
"@storybook/addon-a11y>@storybook/addons>@storybook/api>@storybook/channels>core-js": false,
"@storybook/addon-essentials>@storybook/addon-docs>@storybook/builder-webpack4>@storybook/ui>core-js-pure": false,
"chromedriver": true,
"eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
"eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
"eth-lattice-keyring>gridplus-sdk": false,
"eth-trezor-keyring>hdkey>secp256k1": false,
"eth-trezor-keyring>trezor-connect>@trezor/utxo-lib>blake-hash": false,
"eth-trezor-keyring>trezor-connect>trezor-link>protobufjs": false,
"ganache>@trufflesuite/bigint-buffer": false,
"ganache>keccak": false,
"ganache>leveldown": false,
"geckodriver": true,
"@sentry/cli": true,
"electron": true,
"core-js": false,
"core-js-pure": false,
"keccak": false,
"secp256k1": false,
"web3": false,
"sha3": false,
"bufferutil": false,
"utf-8-validate": false,
"leveldown": false,
"ursa-optional": false,
"gc-stats": false,
"github:assemblyscript/assemblyscript": false,
"tiny-secp256k1": false,
"@lavamoat/preinstall-always-fail": false,
"fsevents": false,
"node-hid": false,
"usb": false,
"blake-hash": false,
"protobufjs": false
"react-devtools>electron": true
}
}
}

@ -17,6 +17,13 @@ export const DEVICE_NAMES = {
LATTICE: 'lattice',
};
export const KEYRING_NAMES = {
LEDGER: 'Ledger',
TREZOR: 'Trezor',
QR: 'QR',
LATTICE: 'Lattice1',
};
/**
* Used for setting the users preference for ledger transport type
*/

@ -82,6 +82,46 @@
* segment source that marks the event data as not conforming to our schema
*/
/**
* @typedef {Object} MetaMetricsEventFragment
* @property {string} successEvent - The event name to fire when the fragment
* is closed in an affirmative action.
* @property {string} [failureEvent] - The event name to fire when the fragment
* is closed with a rejection.
* @property {string} [initialEvent] - An event name to fire immediately upon
* fragment creation. This is useful for building funnels in mixpanel and for
* reduction of code duplication.
* @property {string} category - the event category to use for both the success
* and failure events
* @property {boolean} [persist] - Should this fragment be persisted in
* state and progressed after the extension is locked and unlocked.
* @property {number} [timeout] - Time in seconds the event should be persisted
* for. After the timeout the fragment will be closed as abandoned. if not
* supplied the fragment is stored indefinitely.
* @property {number} [lastUpdated] - Date.now() when the fragment was last
* updated. Used to determine if the timeout has expired and the fragment
* should be closed.
* @property {object} [properties] - Object of custom values to track, keys in
* this object must be in snake_case.
* @property {object} [sensitiveProperties] - Object of sensitive values to
* track. Keys in this object must be in snake_case. These properties will be
* sent in an additional event that excludes the user's metaMetricsId
* @property {number} [revenue] - amount of currency that event creates in
* revenue for MetaMask if fragment is successful.
* @property {string} [currency] - ISO 4127 format currency for events with
* revenue, defaults to US dollars
* @property {number} [value] - Abstract business "value" attributable to
* customers who successfully complete this fragment
* @property {MetaMetricsPageObject} [page] - the page/route that the event
* occurred on
* @property {MetaMetricsReferrerObject} [referrer] - the origin of the dapp
* that initiated the event fragment.
* @property {string} [uniqueIdentifier] - optional argument to override the
* automatic generation of UUID for the event fragment. This is useful when
* tracking events for subsystems that already generate UUIDs so to avoid
* unnecessary lookups and reduce accidental duplication.
*/
/**
* Represents the shape of data sent to the segment.track method.
*

@ -23,6 +23,9 @@ export const BSC_CHAIN_ID = '0x38';
export const OPTIMISM_CHAIN_ID = '0xa';
export const OPTIMISM_TESTNET_CHAIN_ID = '0x45';
export const POLYGON_CHAIN_ID = '0x89';
export const AVALANCHE_CHAIN_ID = '0xa86a';
export const FANTOM_CHAIN_ID = '0xfa';
export const CELO_CHAIN_ID = '0xa4ec';
/**
* The largest possible chain ID we can handle.
@ -53,6 +56,9 @@ export const WETH_SYMBOL = 'WETH';
export const TEST_ETH_SYMBOL = 'TESTETH';
export const BNB_SYMBOL = 'BNB';
export const MATIC_SYMBOL = 'MATIC';
export const AVALANCHE_SYMBOL = 'AVAX';
export const FANTOM_SYMBOL = 'FTM';
export const CELO_SYMBOL = 'CELO';
export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.svg';
export const TEST_ETH_TOKEN_IMAGE_URL = './images/black-eth-logo.svg';
@ -173,3 +179,55 @@ export const UNSUPPORTED_RPC_METHODS = new Set([
]);
export const IPFS_DEFAULT_GATEWAY_URL = 'dweb.link';
// The first item in transakCurrencies must be the
// default crypto currency for the network
const BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME = 'ethereum';
export const BUYABLE_CHAINS_MAP = {
[MAINNET_CHAIN_ID]: {
nativeCurrency: ETH_SYMBOL,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
transakCurrencies: [ETH_SYMBOL, 'USDT', 'USDC', 'DAI'],
},
[ROPSTEN_CHAIN_ID]: {
nativeCurrency: ETH_SYMBOL,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[RINKEBY_CHAIN_ID]: {
nativeCurrency: ETH_SYMBOL,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[GOERLI_CHAIN_ID]: {
nativeCurrency: ETH_SYMBOL,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[KOVAN_CHAIN_ID]: {
nativeCurrency: ETH_SYMBOL,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[BSC_CHAIN_ID]: {
nativeCurrency: BNB_SYMBOL,
network: 'bsc',
transakCurrencies: [BNB_SYMBOL, 'BUSD'],
},
[POLYGON_CHAIN_ID]: {
nativeCurrency: MATIC_SYMBOL,
network: 'polygon',
transakCurrencies: [MATIC_SYMBOL, 'USDT', 'USDC', 'DAI'],
},
[AVALANCHE_CHAIN_ID]: {
nativeCurrency: AVALANCHE_SYMBOL,
network: 'avaxcchain',
transakCurrencies: [AVALANCHE_SYMBOL],
},
[FANTOM_CHAIN_ID]: {
nativeCurrency: FANTOM_SYMBOL,
network: 'fantom',
transakCurrencies: [FANTOM_SYMBOL],
},
[CELO_CHAIN_ID]: {
nativeCurrency: CELO_SYMBOL,
network: 'celo',
transakCurrencies: [CELO_SYMBOL],
},
};

@ -226,6 +226,10 @@ export const TRANSACTION_GROUP_CATEGORIES = {
* TransactionMeta object.
* @property {string} origin - A string representing the interface that
* suggested the transaction.
* @property {string} originalGasEstimate - A string representing the original
* gas estimation on the transaction metadata.
* @property {boolean} userEditedGasLimit - A boolean representing when the
* user manually edited the gas limit.
* @property {Object} nonceDetails - A metadata object containing information
* used to derive the suggested nonce, useful for debugging nonce issues.
* @property {string} rawTx - A hex string of the final signed transaction,
@ -236,3 +240,49 @@ export const TRANSACTION_GROUP_CATEGORIES = {
* the network, in Unix epoch time (ms).
* @property {TxError} [err] - The error encountered during the transaction
*/
/**
* Defines the possible types
*
* @typedef {Object} TransactionMetaMetricsEvents
* @property {'Transaction Added'} ADDED - All transactions, except incoming
* ones, are added to the controller state in an unapproved status. When this
* happens we fire the Transaction Added event to show that the transaction
* has been added to the user's MetaMask.
* @property {'Transaction Approved'} APPROVED - When an unapproved transaction
* is in the controller state, MetaMask will render a confirmation screen for
* that transaction. If the user approves the transaction we fire this event
* to indicate that the user has approved the transaction for submission to
* the network.
* @property {'Transaction Rejected'} REJECTED - When an unapproved transaction
* is in the controller state, MetaMask will render a confirmation screen for
* that transaction. If the user rejects the transaction we fire this event
* to indicate that the user has rejected the transaction. It will be removed
* from state as a result.
* @property {'Transaction Submitted'} SUBMITTED - After a transaction is
* approved by the user, it is then submitted to the network for inclusion in
* a block. When this happens we fire the Transaction Submitted event to
* indicate that MetaMask is submitting a transaction at the user's request.
* @property {'Transaction Finalized'} FINALIZED - All transactions that are
* submitted will finalized (eventually) by either being dropped, failing
* or being confirmed. When this happens we track this event, along with the
* status.
*/
/**
* This type will work anywhere you expect a string that can be one of the
* above transaction event types.
*
* @typedef {TransactionMetaMetricsEvents[keyof TransactionMetaMetricsEvents]} TransactionMetaMetricsEventString
*/
/**
* @type {TransactionMetaMetricsEvents}
*/
export const TRANSACTION_EVENTS = {
ADDED: 'Transaction Added',
APPROVED: 'Transaction Approved',
FINALIZED: 'Transaction Finalized',
REJECTED: 'Transaction Rejected',
SUBMITTED: 'Transaction Submitted',
};

@ -0,0 +1,145 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
},
"CachedBalancesController": {
"cachedBalances": {
"4": {}
}
},
"CurrencyController": {
"conversionDate": 1575697244.188,
"conversionRate": 149.61,
"currentCurrency": "usd",
"nativeCurrency": "ETH"
},
"IncomingTransactionsController": {
"incomingTransactions": {},
"incomingTxLastFetchedBlocksByNetwork": {
"goerli": null,
"kovan": null,
"mainnet": null,
"rinkeby": 5570536
}
},
"KeyringController": {
"vault": "{\"data\":\"s6TpYjlUNsn7ifhEFTkuDGBUM1GyOlPrim7JSjtfIxgTt8/6MiXgiR/CtFfR4dWW2xhq85/NGIBYEeWrZThGdKGarBzeIqBfLFhw9n509jprzJ0zc2Rf+9HVFGLw+xxC4xPxgCS0IIWeAJQ+XtGcHmn0UZXriXm8Ja4kdlow6SWinB7sr/WM3R0+frYs4WgllkwggDf2/Tv6VHygvLnhtzp6hIJFyTjh+l/KnyJTyZW1TkZhDaNDzX3SCOHT\",\"iv\":\"FbeHDAW5afeWNORfNJBR0Q==\",\"salt\":\"TxZ+WbCW6891C9LK/hbMAoUsSEW1E8pyGLVBU6x5KR8=\"}"
},
"NetworkController": {
"network": "1337",
"provider": {
"nickname": "Localhost 8545",
"rpcUrl": "http://localhost:8545",
"chainId": "0x539",
"ticker": "ETH",
"type": "rpc"
}
},
"NotificationController": {
"notifications": {
"1": {
"isShown": true
},
"3": {
"isShown": true
},
"5": {
"isShown": true
},
"6": {
"isShown": true
},
"8": {
"isShown": true
}
}
},
"OnboardingController": {
"onboardingTabs": {},
"seedPhraseBackedUp": false
},
"PermissionsMetadata": {
"domainMetadata": {
"metamask.github.io": {
"icon": null,
"name": "M E T A M A S K M E S H T E S T"
}
},
"permissionsHistory": {},
"permissionsLog": [
{
"id": 746677923,
"method": "eth_accounts",
"methodType": "restricted",
"origin": "metamask.github.io",
"request": {
"id": 746677923,
"jsonrpc": "2.0",
"method": "eth_accounts",
"origin": "metamask.github.io",
"params": []
},
"requestTime": 1575697241368,
"response": {
"id": 746677923,
"jsonrpc": "2.0",
"result": []
},
"responseTime": 1575697241370,
"success": true
}
]
},
"PreferencesController": {
"accountTokens": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"rinkeby": [],
"ropsten": []
}
},
"assetImages": {},
"completedOnboarding": true,
"eip1559V2Enabled": true,
"currentLocale": "en",
"featureFlags": {
"showIncomingTransactions": true,
"transactionTime": false
},
"firstTimeFlowType": "create",
"forgottenPassword": false,
"frequentRpcListDetail": [],
"identities": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"address": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"name": "Account 1"
}
},
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true
},
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"suggestedTokens": {},
"tokens": [],
"useBlockie": false,
"useNonceField": false,
"usePhishDetect": true
},
"TransactionController": {
"transactions": {}
},
"config": {},
"firstTimeInfo": {
"date": 1575697234195,
"version": "7.7.0"
}
},
"meta": {
"version": 40
}
}

@ -0,0 +1,214 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
},
"CachedBalancesController": {
"cachedBalances": {
"4": {}
}
},
"CurrencyController": {
"conversionDate": 1575697244.188,
"conversionRate": 149.61,
"currentCurrency": "usd",
"nativeCurrency": "ETH"
},
"IncomingTransactionsController": {
"incomingTransactions": {},
"incomingTxLastFetchedBlocksByNetwork": {
"goerli": null,
"kovan": null,
"mainnet": null,
"rinkeby": 5570536
}
},
"KeyringController": {
"vault": "{\"data\":\"s6TpYjlUNsn7ifhEFTkuDGBUM1GyOlPrim7JSjtfIxgTt8/6MiXgiR/CtFfR4dWW2xhq85/NGIBYEeWrZThGdKGarBzeIqBfLFhw9n509jprzJ0zc2Rf+9HVFGLw+xxC4xPxgCS0IIWeAJQ+XtGcHmn0UZXriXm8Ja4kdlow6SWinB7sr/WM3R0+frYs4WgllkwggDf2/Tv6VHygvLnhtzp6hIJFyTjh+l/KnyJTyZW1TkZhDaNDzX3SCOHT\",\"iv\":\"FbeHDAW5afeWNORfNJBR0Q==\",\"salt\":\"TxZ+WbCW6891C9LK/hbMAoUsSEW1E8pyGLVBU6x5KR8=\"}"
},
"NetworkController": {
"network": "1337",
"provider": {
"nickname": "Localhost 8545",
"rpcUrl": "http://localhost:8545",
"chainId": "0x539",
"ticker": "ETH",
"type": "rpc"
}
},
"NotificationController": {
"notifications": {
"1": {
"isShown": true
},
"3": {
"isShown": true
},
"5": {
"isShown": true
},
"6": {
"isShown": true
},
"8": {
"isShown": true
}
}
},
"OnboardingController": {
"onboardingTabs": {},
"seedPhraseBackedUp": false
},
"PermissionsMetadata": {
"domainMetadata": {
"metamask.github.io": {
"icon": null,
"name": "M E T A M A S K M E S H T E S T"
}
},
"permissionsHistory": {},
"permissionsLog": [
{
"id": 746677923,
"method": "eth_accounts",
"methodType": "restricted",
"origin": "metamask.github.io",
"request": {
"id": 746677923,
"jsonrpc": "2.0",
"method": "eth_accounts",
"origin": "metamask.github.io",
"params": []
},
"requestTime": 1575697241368,
"response": {
"id": 746677923,
"jsonrpc": "2.0",
"result": []
},
"responseTime": 1575697241370,
"success": true
}
]
},
"PreferencesController": {
"accountTokens": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"rinkeby": [],
"ropsten": []
}
},
"assetImages": {},
"completedOnboarding": true,
"eip1559V2Enabled": true,
"currentLocale": "en",
"featureFlags": {
"showIncomingTransactions": true,
"transactionTime": false
},
"firstTimeFlowType": "create",
"forgottenPassword": false,
"frequentRpcListDetail": [],
"identities": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"address": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"name": "Account 1"
}
},
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true
},
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"suggestedTokens": {},
"tokens": [],
"useBlockie": false,
"useNonceField": false,
"usePhishDetect": true
},
"TransactionController": {
"transactions": {
"4046084157914634": {
"chainId": "0x539",
"primaryTransaction": {
"chainId": "0x539",
"id": 4046084157914634,
"loadingDefaults": true,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0x1e87F85809dc0000"
},
"type": "sentEther"
},
"history": [
{
"chainId": "0x539",
"id": 4046084157914634,
"loadingDefaults": true,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0x1e87F85809dc0000"
},
"type": "simpleSend"
},
[
{
"note": "Added new unapproved transaction.",
"op": "replace",
"path": "/loadingDefaults",
"timestamp": 1617228030069,
"value": false
}
]
],
"id": 4046084157914634,
"loadingDefaults": false,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0x1e87F85809dc0000"
},
"type": "simpleSend"
}
}
},
"config": {},
"firstTimeInfo": {
"date": 1575697234195,
"version": "7.7.0"
}
},
"meta": {
"version": 40
}
}

@ -485,6 +485,46 @@
"usePhishDetect": true,
"useTokenDetection": true
},
"MetaMetricsController": {
"fragments": {
"transaction-added-7911313280012623": {
"category": "Transactions",
"initialEvent": "Transaction Added",
"successEvent": "Transaction Approved",
"failureEvent": "Transaction Rejected",
"properties": {},
"persist": true,
"uniqueIdentifier": "transaction-added-7911313280012623"
},
"transaction-added-7911313280012624": {
"category": "Transactions",
"initialEvent": "Transaction Added",
"successEvent": "Transaction Approved",
"failureEvent": "Transaction Rejected",
"properties": {},
"persist": true,
"uniqueIdentifier": "transaction-added-7911313280012624"
},
"transaction-added-7911313280012625": {
"category": "Transactions",
"initialEvent": "Transaction Added",
"successEvent": "Transaction Approved",
"failureEvent": "Transaction Rejected",
"properties": {},
"persist": true,
"uniqueIdentifier": "transaction-added-7911313280012625"
},
"transaction-added-7911313280012626": {
"category": "Transactions",
"initialEvent": "Transaction Added",
"successEvent": "Transaction Approved",
"failureEvent": "Transaction Rejected",
"properties": {},
"persist": true,
"uniqueIdentifier": "transaction-added-7911313280012626"
}
}
},
"TransactionController": {
"transactions": {
"7911313280012623": {

@ -0,0 +1,214 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
},
"CachedBalancesController": {
"cachedBalances": {
"4": {}
}
},
"CurrencyController": {
"conversionDate": 1575697244.188,
"conversionRate": 149.61,
"currentCurrency": "usd",
"nativeCurrency": "ETH"
},
"IncomingTransactionsController": {
"incomingTransactions": {},
"incomingTxLastFetchedBlocksByNetwork": {
"goerli": null,
"kovan": null,
"mainnet": null,
"rinkeby": 5570536
}
},
"KeyringController": {
"vault": "{\"data\":\"s6TpYjlUNsn7ifhEFTkuDGBUM1GyOlPrim7JSjtfIxgTt8/6MiXgiR/CtFfR4dWW2xhq85/NGIBYEeWrZThGdKGarBzeIqBfLFhw9n509jprzJ0zc2Rf+9HVFGLw+xxC4xPxgCS0IIWeAJQ+XtGcHmn0UZXriXm8Ja4kdlow6SWinB7sr/WM3R0+frYs4WgllkwggDf2/Tv6VHygvLnhtzp6hIJFyTjh+l/KnyJTyZW1TkZhDaNDzX3SCOHT\",\"iv\":\"FbeHDAW5afeWNORfNJBR0Q==\",\"salt\":\"TxZ+WbCW6891C9LK/hbMAoUsSEW1E8pyGLVBU6x5KR8=\"}"
},
"NetworkController": {
"network": "1337",
"provider": {
"nickname": "Localhost 8545",
"rpcUrl": "http://localhost:8545",
"chainId": "0x539",
"ticker": "ETH",
"type": "rpc"
}
},
"NotificationController": {
"notifications": {
"1": {
"isShown": true
},
"3": {
"isShown": true
},
"5": {
"isShown": true
},
"6": {
"isShown": true
},
"8": {
"isShown": true
}
}
},
"OnboardingController": {
"onboardingTabs": {},
"seedPhraseBackedUp": false
},
"PermissionsMetadata": {
"domainMetadata": {
"metamask.github.io": {
"icon": null,
"name": "M E T A M A S K M E S H T E S T"
}
},
"permissionsHistory": {},
"permissionsLog": [
{
"id": 746677923,
"method": "eth_accounts",
"methodType": "restricted",
"origin": "metamask.github.io",
"request": {
"id": 746677923,
"jsonrpc": "2.0",
"method": "eth_accounts",
"origin": "metamask.github.io",
"params": []
},
"requestTime": 1575697241368,
"response": {
"id": 746677923,
"jsonrpc": "2.0",
"result": []
},
"responseTime": 1575697241370,
"success": true
}
]
},
"PreferencesController": {
"accountTokens": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"rinkeby": [],
"ropsten": []
}
},
"assetImages": {},
"completedOnboarding": true,
"eip1559V2Enabled": true,
"currentLocale": "en",
"featureFlags": {
"showIncomingTransactions": true,
"transactionTime": false
},
"firstTimeFlowType": "create",
"forgottenPassword": false,
"frequentRpcListDetail": [],
"identities": {
"0x5cfe73b6021e818b776b421b1c4db2474086a7e1": {
"address": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"name": "Account 1"
}
},
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true
},
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"suggestedTokens": {},
"tokens": [],
"useBlockie": false,
"useNonceField": false,
"usePhishDetect": true
},
"TransactionController": {
"transactions": {
"4046084157914634": {
"chainId": "0x539",
"primaryTransaction": {
"chainId": "0x539",
"id": 4046084157914634,
"loadingDefaults": true,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0xde0b6b3a7640000"
},
"type": "sentEther"
},
"history": [
{
"chainId": "0x539",
"id": 4046084157914634,
"loadingDefaults": true,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0xde0b6b3a7640000"
},
"type": "simpleSend"
},
[
{
"note": "Added new unapproved transaction.",
"op": "replace",
"path": "/loadingDefaults",
"timestamp": 1617228030069,
"value": false
}
]
],
"id": 4046084157914634,
"loadingDefaults": false,
"metamaskNetworkId": "1337",
"origin": "metamask",
"status": "unapproved",
"time": 1617228030067,
"txParams": {
"from": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1",
"gas": "0x61a8",
"maxFeePerGas": "0x59682f0c",
"maxPriorityFeePerGas": "0x59682f00",
"type": "0x2",
"to": "0x2f318C334780961FB129D2a6c30D0763d9a5C970",
"value": "0xde0b6b3a7640000"
},
"type": "simpleSend"
}
}
},
"config": {},
"firstTimeInfo": {
"date": 1575697234195,
"version": "7.7.0"
}
},
"meta": {
"version": 40
}
}

@ -129,6 +129,19 @@
"useNonceField": false,
"usePhishDetect": true
},
"MetaMetricsController": {
"fragments": {
"transaction-added-4046084157914634": {
"category": "Transactions",
"initialEvent": "Transaction Added",
"successEvent": "Transaction Approved",
"failureEvent": "Transaction Rejected",
"properties": {},
"persist": true,
"uniqueIdentifier": "transaction-added-4046084157914634"
}
}
},
"TransactionController": {
"transactions": {
"4046084157914634": {

@ -1,5 +1,4 @@
const { promisify } = require('util');
const ganache = require('ganache-core');
const ganache = require('ganache');
const defaultOptions = {
blockTime: 2,
@ -8,6 +7,7 @@ const defaultOptions = {
'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent',
port: 8545,
vmErrorsOnRPCResponse: false,
hardfork: 'muirGlacier',
};
class Ganache {
@ -15,22 +15,14 @@ class Ganache {
const options = { ...defaultOptions, ...opts };
const { port } = options;
this._server = ganache.server(options);
const listen = promisify(this._server.listen).bind(this._server);
const blockchain = await listen(port);
return {
...blockchain,
port,
};
await this._server.listen(port);
}
async quit() {
if (!this._server) {
throw new Error('Server not running yet');
}
const close = promisify(this._server.close).bind(this._server);
await close();
await this._server.close();
}
}

@ -1,5 +1,6 @@
const path = require('path');
const sinon = require('sinon');
const BigNumber = require('bignumber.js');
const createStaticServer = require('../../development/create-static-server');
const {
createSegmentServer,
@ -12,9 +13,10 @@ const { ensureXServerIsRunning } = require('./x-server');
const tinyDelayMs = 200;
const regularDelayMs = tinyDelayMs * 2;
const largeDelayMs = regularDelayMs * 2;
const dappPort = 8080;
const convertToHexValue = (val) => `0x${new BigNumber(val, 10).toString(16)}`;
async function withFixtures(options, testSuite) {
const {
dapp,
@ -42,7 +44,7 @@ async function withFixtures(options, testSuite) {
secondaryGanacheServer = new Ganache();
await secondaryGanacheServer.start({
blockTime: 2,
_chainIdRpc: chainId,
chain: { chainId },
port,
vmErrorsOnRPCResponse: false,
});
@ -147,9 +149,55 @@ async function withFixtures(options, testSuite) {
}
}
/**
* @param {*} driver - selinium driver
* @param {*} handlesCount - total count of windows that should be loaded
* @returns handles - an object with window handles, properties in object represent windows:
* 1. extension: metamask extension window
* 2. dapp: test-app window
* 3. popup: metsmask extension popup window
*/
const getWindowHandles = async (driver, handlesCount) => {
await driver.waitUntilXWindowHandles(handlesCount);
const windowHandles = await driver.getAllWindowHandles();
const extension = windowHandles[0];
const dapp = await driver.switchToWindowWithTitle(
'E2E Test Dapp',
windowHandles,
);
const popup = windowHandles.find(
(handle) => handle !== extension && handle !== dapp,
);
return { extension, dapp, popup };
};
const connectDappWithExtensionPopup = async (driver) => {
await driver.openNewPage(`http://127.0.0.1:${dappPort}/`);
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Connect', tag: 'button' });
await driver.delay(regularDelayMs);
const windowHandles = await getWindowHandles(driver, 3);
// open extension popup and confirm connect
await driver.switchToWindow(windowHandles.popup);
await driver.delay(largeDelayMs);
await driver.clickElement({ text: 'Next', tag: 'button' });
await driver.clickElement({ text: 'Connect', tag: 'button' });
// send from dapp
await driver.waitUntilXWindowHandles(2);
await driver.switchToWindow(windowHandles.dapp);
await driver.delay(regularDelayMs);
};
module.exports = {
getWindowHandles,
convertToHexValue,
tinyDelayMs,
regularDelayMs,
largeDelayMs,
withFixtures,
connectDappWithExtensionPopup,
};

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save