Merge remote-tracking branch 'origin/develop' into sync-master

* origin/develop: (45 commits)
  eth-block-tracker@5.0.1 (#10737)
  Allow 11 characters in symbol for RPC (#10670)
  security - update SES lockdown (#10663)
  build - refactor build system for easier configuration (#10718)
  ci - cache deps before patch-package (#10735)
  Additional swaps network support (#10721)
  Update @metamask/controllers to v6.2.1 (#10701)
  Fix 10562 - Hide the suggested token pane when not on Mainnet or test network (#10702)
  Fix mismatchedChain typo in custom network approval screen (#10723)
  Fix 10706 - Prevent autocomplete from add token input (#10700)
  fix: remove unused `metamask.rpcUrl` from redux state + fix tests to reflect that (#10714)
  rule out empty string for symbol (#10712)
  Removing hard references to 12 word seed phrases in copy (#10704)
  Add MetaMask to list of BIP44 HD path examples (#10703)
  resolve issue with missing template error (#10692)
  Delete setupFetchDebugging.js (#10636)
  Excluding sourcemaps comment in production builds (#10695)
  deps - remove "remotedev-server" (#10687)
  Adding default properties to NetworkForm (#10682)
  make migration more safe (#10689)
  ...
feature/default_network_editable
Mark Stacey 4 years ago
commit 68d3756528
  1. 6
      .eslintrc.js
  2. 1
      .storybook/test-data.js
  3. 9
      app/_locales/am/messages.json
  4. 9
      app/_locales/ar/messages.json
  5. 9
      app/_locales/bg/messages.json
  6. 9
      app/_locales/bn/messages.json
  7. 9
      app/_locales/ca/messages.json
  8. 6
      app/_locales/cs/messages.json
  9. 9
      app/_locales/da/messages.json
  10. 9
      app/_locales/de/messages.json
  11. 9
      app/_locales/el/messages.json
  12. 12
      app/_locales/en/messages.json
  13. 9
      app/_locales/es/messages.json
  14. 9
      app/_locales/es_419/messages.json
  15. 9
      app/_locales/et/messages.json
  16. 9
      app/_locales/fa/messages.json
  17. 9
      app/_locales/fi/messages.json
  18. 9
      app/_locales/fil/messages.json
  19. 9
      app/_locales/fr/messages.json
  20. 9
      app/_locales/he/messages.json
  21. 9
      app/_locales/hi/messages.json
  22. 6
      app/_locales/hn/messages.json
  23. 9
      app/_locales/hr/messages.json
  24. 6
      app/_locales/ht/messages.json
  25. 9
      app/_locales/hu/messages.json
  26. 9
      app/_locales/id/messages.json
  27. 9
      app/_locales/it/messages.json
  28. 9
      app/_locales/ja/messages.json
  29. 9
      app/_locales/kn/messages.json
  30. 9
      app/_locales/ko/messages.json
  31. 9
      app/_locales/lt/messages.json
  32. 9
      app/_locales/lv/messages.json
  33. 9
      app/_locales/ms/messages.json
  34. 6
      app/_locales/nl/messages.json
  35. 6
      app/_locales/no/messages.json
  36. 9
      app/_locales/pl/messages.json
  37. 6
      app/_locales/pt/messages.json
  38. 9
      app/_locales/pt_BR/messages.json
  39. 9
      app/_locales/ro/messages.json
  40. 9
      app/_locales/ru/messages.json
  41. 9
      app/_locales/sk/messages.json
  42. 9
      app/_locales/sl/messages.json
  43. 9
      app/_locales/sr/messages.json
  44. 9
      app/_locales/sv/messages.json
  45. 9
      app/_locales/sw/messages.json
  46. 6
      app/_locales/ta/messages.json
  47. 6
      app/_locales/th/messages.json
  48. 9
      app/_locales/tl/messages.json
  49. 6
      app/_locales/tr/messages.json
  50. 9
      app/_locales/uk/messages.json
  51. 9
      app/_locales/vi/messages.json
  52. 9
      app/_locales/zh_CN/messages.json
  53. 9
      app/_locales/zh_TW/messages.json
  54. BIN
      app/images/bnb.png
  55. 2
      app/scripts/account-import-strategies/account-import-strategies.test.js
  56. 22
      app/scripts/background.js
  57. 4
      app/scripts/controllers/cached-balances.test.js
  58. 8
      app/scripts/controllers/detect-tokens.test.js
  59. 2
      app/scripts/controllers/ens/index.test.js
  60. 293
      app/scripts/controllers/incoming-transactions.js
  61. 902
      app/scripts/controllers/incoming-transactions.test.js
  62. 12
      app/scripts/controllers/metametrics.test.js
  63. 4
      app/scripts/controllers/network/createInfuraClient.js
  64. 4
      app/scripts/controllers/network/createJsonRpcClient.js
  65. 4
      app/scripts/controllers/network/network-controller.test.js
  66. 4
      app/scripts/controllers/network/pending-middleware.test.js
  67. 18
      app/scripts/controllers/permissions/permissions-controller.test.js
  68. 18
      app/scripts/controllers/permissions/permissions-log-controller.test.js
  69. 15
      app/scripts/controllers/permissions/permissions-middleware.test.js
  70. 6
      app/scripts/controllers/permissions/permissionsLog.js
  71. 2
      app/scripts/controllers/permissions/restricted-methods.test.js
  72. 11
      app/scripts/controllers/preferences.js
  73. 25
      app/scripts/controllers/preferences.test.js
  74. 73
      app/scripts/controllers/swaps.js
  75. 25
      app/scripts/controllers/swaps.test.js
  76. 2
      app/scripts/controllers/token-rates-controller.test.js
  77. 63
      app/scripts/controllers/transactions/index.js
  78. 59
      app/scripts/controllers/transactions/index.test.js
  79. 4
      app/scripts/controllers/transactions/lib/tx-state-history-helpers.test.js
  80. 2
      app/scripts/controllers/transactions/lib/util.test.js
  81. 4
      app/scripts/controllers/transactions/pending-tx-tracker.test.js
  82. 4
      app/scripts/controllers/transactions/tx-gas-utils.test.js
  83. 2
      app/scripts/controllers/transactions/tx-state-manager.js
  84. 8
      app/scripts/controllers/transactions/tx-state-manager.test.js
  85. 2
      app/scripts/lib/ComposableObservableStore.test.js
  86. 36
      app/scripts/lib/buy-eth-url.js
  87. 16
      app/scripts/lib/buy-eth-url.test.js
  88. 2
      app/scripts/lib/cleanErrorStack.test.js
  89. 33
      app/scripts/lib/createMetaRPCHandler.js
  90. 61
      app/scripts/lib/createMetaRPCHandler.test.js
  91. 2
      app/scripts/lib/decrypt-message-manager.js
  92. 2
      app/scripts/lib/encryption-public-key-manager.js
  93. 2
      app/scripts/lib/message-manager.js
  94. 2
      app/scripts/lib/message-manager.test.js
  95. 81
      app/scripts/lib/metaRPCClientFactory.js
  96. 88
      app/scripts/lib/metaRPCClientFactory.test.js
  97. 8
      app/scripts/lib/migrator/index.test.js
  98. 2
      app/scripts/lib/nodeify.test.js
  99. 2
      app/scripts/lib/personal-message-manager.js
  100. 2
      app/scripts/lib/personal-message-manager.test.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -180,7 +180,11 @@ module.exports = {
}, },
}, },
{ {
files: ['development/**/*.js', 'test/e2e/benchmark.js', 'test/helper.js'], files: [
'development/**/*.js',
'test/e2e/benchmark.js',
'test/helpers/setup-helper.js',
],
rules: { rules: {
'node/no-process-exit': 'off', 'node/no-process-exit': 'off',
'node/shebang': 'off', 'node/shebang': 'off',

@ -5,7 +5,6 @@ const state = {
isInitialized: true, isInitialized: true,
isUnlocked: true, isUnlocked: true,
featureFlags: { sendHexData: true }, featureFlags: { sendHexData: true },
rpcUrl: 'https://rawtestrpc.metamask.io/',
identities: { identities: {
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "ቋት አስመጣ" "message": "ቋት አስመጣ"
}, },
"importYourExisting": {
"message": "ባለ 12 ቃል የዘር ሐረግን በመጠቀም ነባር ቋትዎን ያስመጡ"
},
"imported": { "imported": {
"message": "ከውጭ የመጣ", "message": "ከውጭ የመጣ",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -892,9 +889,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ማስጠንቀቂያ፡ የመጠባበቂያ ምዕራፍዎን በጭራሽ አይግለጹ። ይህን ሐረገ የያዘ ማንኛውም ሰው የእርስዎን Ether እስከወዲያኛው ሊወስደው ይችላል።" "message": "ማስጠንቀቂያ፡ የመጠባበቂያ ምዕራፍዎን በጭራሽ አይግለጹ። ይህን ሐረገ የያዘ ማንኛውም ሰው የእርስዎን Ether እስከወዲያኛው ሊወስደው ይችላል።"
}, },
"secretPhrase": {
"message": "ካዝናዎን ወደነበረበት ለመመለስ ሚስጥራዊ ባለ አስራ ሁለት ቃል ሐረግዎን ያስገቡ።"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "ደህንነት እና ግላዊነት" "message": "ደህንነት እና ግላዊነት"
}, },
@ -934,9 +928,6 @@
"sendAmount": { "sendAmount": {
"message": "መጠኑን ላክ" "message": "መጠኑን ላክ"
}, },
"sendETH": {
"message": "ETH ላክ"
},
"sendTokens": { "sendTokens": {
"message": "ተለዋጭ ስሞችን ላክ" "message": "ተለዋጭ ስሞችን ላክ"
}, },

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "استيراد المحفظة" "message": "استيراد المحفظة"
}, },
"importYourExisting": {
"message": "قم باستيراد محفظتك الحالية باستخدام جملة بذرية مكونة من 12 كلمة"
},
"imported": { "imported": {
"message": "المستوردة", "message": "المستوردة",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -888,9 +885,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "تحذير: لا تكشف مطلقاً عن عبارة الدعم الخاصة بك. يمكن لأي شخص بهذه العبارة أن يستحوذ على الأثير الخاص بك إلى الأبد." "message": "تحذير: لا تكشف مطلقاً عن عبارة الدعم الخاصة بك. يمكن لأي شخص بهذه العبارة أن يستحوذ على الأثير الخاص بك إلى الأبد."
}, },
"secretPhrase": {
"message": "أدخل جملتك السرية المكونة من اثني عشر كلمة هنا لاستعادة خزنتك."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "الأمن والخصوصية" "message": "الأمن والخصوصية"
}, },
@ -930,9 +924,6 @@
"sendAmount": { "sendAmount": {
"message": "إرسال المبلغ" "message": "إرسال المبلغ"
}, },
"sendETH": {
"message": "إرسال عملة إيثيريوم"
},
"sendTokens": { "sendTokens": {
"message": "إرسال عملات رمزية" "message": "إرسال عملات رمزية"
}, },

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "Импортиране на портфейла" "message": "Импортиране на портфейла"
}, },
"importYourExisting": {
"message": "Импортирайте съществуващия си портфейл с помощта на фраза зародиш с 12 думи"
},
"imported": { "imported": {
"message": "Импортирани", "message": "Импортирани",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -891,9 +888,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ВНИМАНИЕ: Никога не разкривайте резервната си фраза. Всеки с тази фраза може да вземе вашия етер завинаги." "message": "ВНИМАНИЕ: Никога не разкривайте резервната си фраза. Всеки с тази фраза може да вземе вашия етер завинаги."
}, },
"secretPhrase": {
"message": "Въведете своята тайна фраза от дванадесет думи тук, за да възстановите портфейла си."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Сигурност и поверителност" "message": "Сигурност и поверителност"
}, },
@ -933,9 +927,6 @@
"sendAmount": { "sendAmount": {
"message": "Изпратете сумата" "message": "Изпратете сумата"
}, },
"sendETH": {
"message": "Изпрати ETH"
},
"sendTokens": { "sendTokens": {
"message": "Изпращане на жетони" "message": "Изпращане на жетони"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "ওয়ট আমদি করন" "message": "ওয়ট আমদি করন"
}, },
"importYourExisting": {
"message": "একটি 12 শবর সড ফজ বযবহর কর আপনর বিযমন ওয়ট আমদি করন"
},
"imported": { "imported": {
"message": "আমদিত", "message": "আমদিত",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -895,9 +892,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "সতরকত: কখনও আপনর বকআপ ফজ পরকশ করবন ন। এই ফজ পউ আপনর ইথর চিরকর জনয নিিরবন।" "message": "সতরকত: কখনও আপনর বকআপ ফজ পরকশ করবন ন। এই ফজ পউ আপনর ইথর চিরকর জনয নিিরবন।"
}, },
"secretPhrase": {
"message": "আপনর ভলট রির করত এখ আপনর গপন ব শবর ফজ লিন।"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "নিপত এবপনয়ত" "message": "নিপত এবপনয়ত"
}, },
@ -937,9 +931,6 @@
"sendAmount": { "sendAmount": {
"message": "প অরথরি" "message": "প অরথরি"
}, },
"sendETH": {
"message": "ETH পন"
},
"sendTokens": { "sendTokens": {
"message": "টনগিন" "message": "টনগিন"
}, },

@ -492,9 +492,6 @@
"importWallet": { "importWallet": {
"message": "Importar Moneder" "message": "Importar Moneder"
}, },
"importYourExisting": {
"message": "Importa el teu moneder utilitzant la frase de recuperació de 12 paraules"
},
"imported": { "imported": {
"message": "Importats", "message": "Importats",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -873,9 +870,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ATENCIÓ: No divulguis mai la teva frase de recuperació. Qualsevol amb aquesta frase pot utilitzar el teu Ether per sempre." "message": "ATENCIÓ: No divulguis mai la teva frase de recuperació. Qualsevol amb aquesta frase pot utilitzar el teu Ether per sempre."
}, },
"secretPhrase": {
"message": "Introdueix aquí la teva frase secreta de dotze paraules per a recuperar la teva caixa forta."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Seguretat i privacitat" "message": "Seguretat i privacitat"
}, },
@ -915,9 +909,6 @@
"sendAmount": { "sendAmount": {
"message": "Enviar Quantitat" "message": "Enviar Quantitat"
}, },
"sendETH": {
"message": "Envia ETH"
},
"sendTokens": { "sendTokens": {
"message": "Enviar Fitxes" "message": "Enviar Fitxes"
}, },

@ -344,9 +344,6 @@
"searchTokens": { "searchTokens": {
"message": "Hledat tokeny" "message": "Hledat tokeny"
}, },
"secretPhrase": {
"message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "klíčové fráze mají 12 slov" "message": "klíčové fráze mají 12 slov"
}, },
@ -356,9 +353,6 @@
"send": { "send": {
"message": "Odeslat" "message": "Odeslat"
}, },
"sendETH": {
"message": "Odeslat ETH"
},
"sendTokens": { "sendTokens": {
"message": "Odeslat tokeny" "message": "Odeslat tokeny"
}, },

@ -498,9 +498,6 @@
"importWallet": { "importWallet": {
"message": "Importér pung" "message": "Importér pung"
}, },
"importYourExisting": {
"message": "Importér din eksisterende pung med en 12-ords seedfrase"
},
"imported": { "imported": {
"message": "Importeret", "message": "Importeret",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -876,9 +873,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ADVARSEL: Afslør aldrig din backup-frase. Enhver med denne frase kan tage din Ether for altid." "message": "ADVARSEL: Afslør aldrig din backup-frase. Enhver med denne frase kan tage din Ether for altid."
}, },
"secretPhrase": {
"message": "Indtast din hemmelige tolv ord lange sætning for at gendanne din vault."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sikkerhed & Privatliv" "message": "Sikkerhed & Privatliv"
}, },
@ -915,9 +909,6 @@
"sendAmount": { "sendAmount": {
"message": "Send Beløb" "message": "Send Beløb"
}, },
"sendETH": {
"message": "Vælg ETH"
},
"sendTokens": { "sendTokens": {
"message": "Send tokens" "message": "Send tokens"
}, },

@ -493,9 +493,6 @@
"importWallet": { "importWallet": {
"message": "Wallet importieren" "message": "Wallet importieren"
}, },
"importYourExisting": {
"message": "Importieren Sie Ihre bestehende Wallet mit einem 12-Wort-Seed-Schlüssel"
},
"imported": { "imported": {
"message": "Importiert", "message": "Importiert",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -864,9 +861,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "WARNUNG: Legen Sie niemals Ihre Sicherungsphrase offen. Mit dieser Phrase kann sich jeder Ihr Ether für immer aneignen." "message": "WARNUNG: Legen Sie niemals Ihre Sicherungsphrase offen. Mit dieser Phrase kann sich jeder Ihr Ether für immer aneignen."
}, },
"secretPhrase": {
"message": "Gib die 12 Wörter deiner geheimem Wörterfolge ein um deinen Vault wiederherzustellen."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sicherheit & Datenschutz" "message": "Sicherheit & Datenschutz"
}, },
@ -906,9 +900,6 @@
"sendAmount": { "sendAmount": {
"message": "Betrag senden" "message": "Betrag senden"
}, },
"sendETH": {
"message": "ETH senden"
},
"sendTokens": { "sendTokens": {
"message": "Token senden" "message": "Token senden"
}, },

@ -502,9 +502,6 @@
"importWallet": { "importWallet": {
"message": "Εισαγωγή Πορτοφολιού" "message": "Εισαγωγή Πορτοφολιού"
}, },
"importYourExisting": {
"message": "Εισαγάγετε το υπάρχον πορτοφόλι σας χρησιμοποιώντας μια φράση φύτρου 12 λέξεων"
},
"imported": { "imported": {
"message": "Έγινε εισαγωγή", "message": "Έγινε εισαγωγή",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -892,9 +889,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Ποτέ μην αποκαλύπτετε την εφεδρική φράση. Όποιος έχει αυτή τη φράση μπορεί να πάρει τα Ether σας για πάντα." "message": "ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Ποτέ μην αποκαλύπτετε την εφεδρική φράση. Όποιος έχει αυτή τη φράση μπορεί να πάρει τα Ether σας για πάντα."
}, },
"secretPhrase": {
"message": "Εισαγάγετε εδώ τη μυστική φράση δώδεκα λέξεων για να επαναφέρετε το χρηματοκιβώτιό σας."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Ασφάλεια και Απόρρητο" "message": "Ασφάλεια και Απόρρητο"
}, },
@ -934,9 +928,6 @@
"sendAmount": { "sendAmount": {
"message": "Αποστολή Ποσού" "message": "Αποστολή Ποσού"
}, },
"sendETH": {
"message": "Στείλτε ETH"
},
"sendTokens": { "sendTokens": {
"message": "Στείλτε Tokens" "message": "Στείλτε Tokens"
}, },

@ -873,7 +873,7 @@
"message": "Import wallet" "message": "Import wallet"
}, },
"importYourExisting": { "importYourExisting": {
"message": "Import your existing wallet using a 12 word seed phrase" "message": "Import your existing wallet using a seed phrase"
}, },
"imported": { "imported": {
"message": "Imported", "message": "Imported",
@ -1064,7 +1064,7 @@
"message": "MetaMask would like to gather usage data to better understand how our users interact with the extension. This data will be used to continually improve the usability and user experience of our product and the Ethereum ecosystem." "message": "MetaMask would like to gather usage data to better understand how our users interact with the extension. This data will be used to continually improve the usability and user experience of our product and the Ethereum ecosystem."
}, },
"mismatchedChain": { "mismatchedChain": {
"message": "This network details for this Chain ID do not match our records. We recommend that you $1 before proceeding.", "message": "The network details for this chain ID do not match our records. We recommend that you $1 before proceeding.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
}, },
"mismatchedChainLinkText": { "mismatchedChainLinkText": {
@ -1455,7 +1455,7 @@
"message": "WARNING: Never disclose your backup phrase. Anyone with this phrase can take your Ether forever." "message": "WARNING: Never disclose your backup phrase. Anyone with this phrase can take your Ether forever."
}, },
"secretPhrase": { "secretPhrase": {
"message": "Enter your secret twelve word phrase here to restore your vault." "message": "Enter your secret phrase here to restore your vault."
}, },
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Security & Privacy" "message": "Security & Privacy"
@ -1511,9 +1511,6 @@
"sendAmount": { "sendAmount": {
"message": "Send Amount" "message": "Send Amount"
}, },
"sendETH": {
"message": "Send ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Send $1", "message": "Send $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"
@ -2221,6 +2218,9 @@
"walletSeed": { "walletSeed": {
"message": "Seed phrase" "message": "Seed phrase"
}, },
"walletSeedRestore": {
"message": "Wallet Seed"
},
"web3ShimUsageNotification": { "web3ShimUsageNotification": {
"message": "We noticed that the current website tried to use the removed window.web3 API. If the site appears to be broken, please click $1 for more information.", "message": "We noticed that the current website tried to use the removed window.web3 API. If the site appears to be broken, please click $1 for more information.",
"description": "$1 is a clickable link." "description": "$1 is a clickable link."

@ -800,9 +800,6 @@
"importWallet": { "importWallet": {
"message": "Importar Monedero" "message": "Importar Monedero"
}, },
"importYourExisting": {
"message": "Importa tu monedero existente usando la frase semilla de 12 palabras"
},
"imported": { "imported": {
"message": "Importado", "message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1359,9 +1356,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ADVERTENCIA: Nunca revele su frase de respaldo. Cualquiera con esta frase puede tomar su Ether para siempre." "message": "ADVERTENCIA: Nunca revele su frase de respaldo. Cualquiera con esta frase puede tomar su Ether para siempre."
}, },
"secretPhrase": {
"message": "Ingresa tu frase de doce (12) palabras para restaurar tu bóveda."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Seguridad y Privacidad" "message": "Seguridad y Privacidad"
}, },
@ -1413,9 +1407,6 @@
"sendAmount": { "sendAmount": {
"message": "Enviar cantidad" "message": "Enviar cantidad"
}, },
"sendETH": {
"message": "Enviar ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Enviar $1", "message": "Enviar $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -800,9 +800,6 @@
"importWallet": { "importWallet": {
"message": "Importar billetera" "message": "Importar billetera"
}, },
"importYourExisting": {
"message": "Importa tu billetera existente con una frase semilla de 12 palabras"
},
"imported": { "imported": {
"message": "Importado", "message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1359,9 +1356,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ADVERTENCIA: Nunca reveles tu frase de respaldo. Cualquier persona que tenga acceso a esta frase puede llevarse tus Ether permanentemente." "message": "ADVERTENCIA: Nunca reveles tu frase de respaldo. Cualquier persona que tenga acceso a esta frase puede llevarse tus Ether permanentemente."
}, },
"secretPhrase": {
"message": "Ingresa tu frase secreta de doce palabras para restaurar tu almacén."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Seguridad y privacidad" "message": "Seguridad y privacidad"
}, },
@ -1413,9 +1407,6 @@
"sendAmount": { "sendAmount": {
"message": "Enviar monto" "message": "Enviar monto"
}, },
"sendETH": {
"message": "Enviar ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Enviar $1", "message": "Enviar $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "Importige rahakott" "message": "Importige rahakott"
}, },
"importYourExisting": {
"message": "Importige 12-sõnalise seemnefraasi abil olemasolev rahakott"
},
"imported": { "imported": {
"message": "Imporditud", "message": "Imporditud",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -885,9 +882,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "HOIATUS! Ärge avaldage kunagi oma varundusfraasi. Selle fraasiga on võimalik teie eeter igaveseks ära võtta." "message": "HOIATUS! Ärge avaldage kunagi oma varundusfraasi. Selle fraasiga on võimalik teie eeter igaveseks ära võtta."
}, },
"secretPhrase": {
"message": "Sisestage hoidla taastamiseks oma salajane 12-sõnaline fraas."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Turvalisus ja privaatsus" "message": "Turvalisus ja privaatsus"
}, },
@ -927,9 +921,6 @@
"sendAmount": { "sendAmount": {
"message": "Saatke kogus" "message": "Saatke kogus"
}, },
"sendETH": {
"message": "Saada ETH"
},
"sendTokens": { "sendTokens": {
"message": "Saada lube" "message": "Saada lube"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "وارد سازی کیف" "message": "وارد سازی کیف"
}, },
"importYourExisting": {
"message": "کیف موجود تان را با استفاده از عبارت رمزیاب 12 کلمه یی وارد کنید"
},
"imported": { "imported": {
"message": "وارد شده", "message": "وارد شده",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -895,9 +892,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "هشدار: هرگز عبارت پشتیبان تان را به کسی فاش نسازید. هرکسیکه این عبارت را داشته باشد ایتر شما را برای همیشه خواهد گرفت." "message": "هشدار: هرگز عبارت پشتیبان تان را به کسی فاش نسازید. هرکسیکه این عبارت را داشته باشد ایتر شما را برای همیشه خواهد گرفت."
}, },
"secretPhrase": {
"message": "جهت بازیابی خزانه تان عبارت دوازده کلمه یی تان را اینجا وارد کنید."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "امنیت و حریم خصوصی" "message": "امنیت و حریم خصوصی"
}, },
@ -937,9 +931,6 @@
"sendAmount": { "sendAmount": {
"message": "ارسال مبلغ" "message": "ارسال مبلغ"
}, },
"sendETH": {
"message": "ارسال ETH"
},
"sendTokens": { "sendTokens": {
"message": "رمزیاب ها را ارسال کنید" "message": "رمزیاب ها را ارسال کنید"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "Tuo kukkaro" "message": "Tuo kukkaro"
}, },
"importYourExisting": {
"message": "Tuo nykyinen lompakkosi käyttäen 12 sanan \n siemenlausetta"
},
"imported": { "imported": {
"message": "Tuotu", "message": "Tuotu",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -892,9 +889,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "VAROITUS: älä koskaan kerro varmuuskopiolausettasi kenellekään. Kuka tahansa tämän lauseen omaava voi napata Etherisi pysyvästi." "message": "VAROITUS: älä koskaan kerro varmuuskopiolausettasi kenellekään. Kuka tahansa tämän lauseen omaava voi napata Etherisi pysyvästi."
}, },
"secretPhrase": {
"message": "Palauta holvisi syöttämällä tähän salainen kahdentoista sanan tekstisi."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Turva & yksityisyys" "message": "Turva & yksityisyys"
}, },
@ -934,9 +928,6 @@
"sendAmount": { "sendAmount": {
"message": "Lähetä summa" "message": "Lähetä summa"
}, },
"sendETH": {
"message": "Lähetä ETH:iä"
},
"sendTokens": { "sendTokens": {
"message": "Lähetä tietueita" "message": "Lähetä tietueita"
}, },

@ -462,9 +462,6 @@
"importWallet": { "importWallet": {
"message": "Mag-import ng Wallet" "message": "Mag-import ng Wallet"
}, },
"importYourExisting": {
"message": "I-import ang kasalukuyan mong wallet gamit ang isang seed phrase na may 12 salita"
},
"imported": { "imported": {
"message": "Na-import", "message": "Na-import",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -807,9 +804,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "BABALA: Huwag ibunyag ang iyong backup phrase. Mananakaw ng kahit sinong may ganitong parirala ang iyong Ether at hindi na ito maibabalik." "message": "BABALA: Huwag ibunyag ang iyong backup phrase. Mananakaw ng kahit sinong may ganitong parirala ang iyong Ether at hindi na ito maibabalik."
}, },
"secretPhrase": {
"message": "Ilagay ang iyong lihim na pariralang may labindalawang salita para ma-restore ang iyong vault."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Seguridad at Privacy" "message": "Seguridad at Privacy"
}, },
@ -849,9 +843,6 @@
"sendAmount": { "sendAmount": {
"message": "Magpadala ng Halaga" "message": "Magpadala ng Halaga"
}, },
"sendETH": {
"message": "Magpadala ng ETH"
},
"sendTokens": { "sendTokens": {
"message": "Magpadala ng Mga Token" "message": "Magpadala ng Mga Token"
}, },

@ -496,9 +496,6 @@
"importWallet": { "importWallet": {
"message": "Importer le portefeuille" "message": "Importer le portefeuille"
}, },
"importYourExisting": {
"message": "Importez votre portefeuille existant à l'aide d'une phrase mnémotechnique de 12 mots"
},
"imported": { "imported": {
"message": "Importé", "message": "Importé",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -877,9 +874,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "AVERTISSEMENT : ne révélez jamais votre phrase de sauvegarde. N'importe qui avec cette phrase peut voler votre Ether pour toujours." "message": "AVERTISSEMENT : ne révélez jamais votre phrase de sauvegarde. N'importe qui avec cette phrase peut voler votre Ether pour toujours."
}, },
"secretPhrase": {
"message": "Entrez vos 12 mots secrets de votre phrase Seed pour restaurer votre coffre."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sécurité et confidentialité" "message": "Sécurité et confidentialité"
}, },
@ -919,9 +913,6 @@
"sendAmount": { "sendAmount": {
"message": "Envoyer le montant" "message": "Envoyer le montant"
}, },
"sendETH": {
"message": "Envoyer des ETH"
},
"sendTokens": { "sendTokens": {
"message": "Envoyer des jetons" "message": "Envoyer des jetons"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "ייבא ארנק" "message": "ייבא ארנק"
}, },
"importYourExisting": {
"message": "יבא/י את הארנק הקיים שלך באמצעות seed phrase בן 12 מילים"
},
"imported": { "imported": {
"message": "מיובאות", "message": "מיובאות",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -889,9 +886,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "אזהרה: לעולם אין לחשוף את צירוף הגיבוי שלך. כל מי שברשותו צירוף זה יכול לקחת את האת'ר שלך לצמיתות." "message": "אזהרה: לעולם אין לחשוף את צירוף הגיבוי שלך. כל מי שברשותו צירוף זה יכול לקחת את האת'ר שלך לצמיתות."
}, },
"secretPhrase": {
"message": "הזנ/י את הצירוף הסודי שלך של שתים-עשרה המילים כאן כדי לשחזר את הכספת שלך."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "אבטחה ופרטיות" "message": "אבטחה ופרטיות"
}, },
@ -931,9 +925,6 @@
"sendAmount": { "sendAmount": {
"message": "שלח סכום" "message": "שלח סכום"
}, },
"sendETH": {
"message": "שלח/י ETH"
},
"sendTokens": { "sendTokens": {
"message": "שלח טוקנים" "message": "שלח טוקנים"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "वट आयत कर" "message": "वट आयत कर"
}, },
"importYourExisting": {
"message": "12 शबद कडफ उपयग करक अपनट क आयत कर"
},
"imported": { "imported": {
"message": "आयित", "message": "आयित",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1350,9 +1347,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "चवन: कभ अपनकअप वश क न कर। इस वश कथ कई भ आपक Ether क हमिए ल सकत।" "message": "चवन: कभ अपनकअप वश क न कर। इस वश कथ कई भ आपक Ether क हमिए ल सकत।"
}, },
"secretPhrase": {
"message": "अपनिनरित करनिए अपनत बरह शबद वश क यह दरज कर।"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "सरक और गपनयत" "message": "सरक और गपनयत"
}, },
@ -1404,9 +1398,6 @@
"sendAmount": { "sendAmount": {
"message": "रि" "message": "रि"
}, },
"sendETH": {
"message": "ETH भ"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "$1 भ", "message": "$1 भ",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -324,9 +324,6 @@
"search": { "search": {
"message": "खज कर" "message": "खज कर"
}, },
"secretPhrase": {
"message": "अपनत बरह शबद वश यह अपनिनरित करनिए दरज कर।"
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "बज वश 12 शबद ल" "message": "बज वश 12 शबद ल"
}, },
@ -336,9 +333,6 @@
"send": { "send": {
"message": "भ" "message": "भ"
}, },
"sendETH": {
"message": "भ ETH"
},
"sendTokens": { "sendTokens": {
"message": "भकन" "message": "भकन"
}, },

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "Uvezi novčanik" "message": "Uvezi novčanik"
}, },
"importYourExisting": {
"message": "Uvezite svoj postojeći novčanik početnom rečenicom od 12 riječi"
},
"imported": { "imported": {
"message": "Uvezeno", "message": "Uvezeno",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -888,9 +885,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "UPOZORENJE: nikada ne otkrivajte svoju alternativnu rečenicu. Bilo tko ovom rečenicom može zauvijek preuzeti vaš Ether." "message": "UPOZORENJE: nikada ne otkrivajte svoju alternativnu rečenicu. Bilo tko ovom rečenicom može zauvijek preuzeti vaš Ether."
}, },
"secretPhrase": {
"message": "Ovdje upišite svoju tajnu rečenicu od 12 riječi kako biste obnovili svoj sef."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sigurnost i privatnost" "message": "Sigurnost i privatnost"
}, },
@ -930,9 +924,6 @@
"sendAmount": { "sendAmount": {
"message": "Odaberi iznos" "message": "Odaberi iznos"
}, },
"sendETH": {
"message": "Pošalji ETH"
},
"sendTokens": { "sendTokens": {
"message": "Pošalji tokene" "message": "Pošalji tokene"
}, },

@ -561,9 +561,6 @@
"searchTokens": { "searchTokens": {
"message": "Rechèch Tokens" "message": "Rechèch Tokens"
}, },
"secretPhrase": {
"message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "Seed fraz yo se 12 long mo" "message": "Seed fraz yo se 12 long mo"
}, },
@ -585,9 +582,6 @@
"send": { "send": {
"message": "Voye" "message": "Voye"
}, },
"sendETH": {
"message": "Voye ETH"
},
"sendTokens": { "sendTokens": {
"message": "Voye Tokens" "message": "Voye Tokens"
}, },

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "Pénztárca importálása" "message": "Pénztárca importálása"
}, },
"importYourExisting": {
"message": "Importálja meglévő pénztárcáját a 12 szóból álló seed mondat segítségével"
},
"imported": { "imported": {
"message": "Importált", "message": "Importált",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -888,9 +885,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "FIGYELEM: Senkise se adja meg a biztonsági szakaszát. Ennek tulajdonosa örökre elviheti Ether-jeit." "message": "FIGYELEM: Senkise se adja meg a biztonsági szakaszát. Ennek tulajdonosa örökre elviheti Ether-jeit."
}, },
"secretPhrase": {
"message": "Tárolód helyreállításához írd be titkos tizenkét szavas szókapcsolatodat ide."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Biztonság és adatvédelem" "message": "Biztonság és adatvédelem"
}, },
@ -930,9 +924,6 @@
"sendAmount": { "sendAmount": {
"message": "Összeg küldése" "message": "Összeg küldése"
}, },
"sendETH": {
"message": "ETH küldése"
},
"sendTokens": { "sendTokens": {
"message": "Token küldése" "message": "Token küldése"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "Impor dompet" "message": "Impor dompet"
}, },
"importYourExisting": {
"message": "Impor dompet Anda yang ada menggunakan frasa pemulihan 12 kata"
},
"imported": { "imported": {
"message": "Diimpor", "message": "Diimpor",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1350,9 +1347,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "PERINGATAN: Jangan pernah ungkapkan frasa cadangan Anda. Siapa pun yang memiliki frasa ini dapat mengambil Ether Anda selamanya." "message": "PERINGATAN: Jangan pernah ungkapkan frasa cadangan Anda. Siapa pun yang memiliki frasa ini dapat mengambil Ether Anda selamanya."
}, },
"secretPhrase": {
"message": "Masukkan frasa kata dua belas rahasia Anda di sini untuk memulihkan vault Anda."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Keamanan & Privasi" "message": "Keamanan & Privasi"
}, },
@ -1404,9 +1398,6 @@
"sendAmount": { "sendAmount": {
"message": "Kirim Jumlah" "message": "Kirim Jumlah"
}, },
"sendETH": {
"message": "Kirim ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Kirim $1", "message": "Kirim $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -803,9 +803,6 @@
"importWallet": { "importWallet": {
"message": "Importa Portafoglio" "message": "Importa Portafoglio"
}, },
"importYourExisting": {
"message": "Importa il tuo portafoglio esistente usando la tua frase seed a 12 parole"
},
"imported": { "imported": {
"message": "Importato", "message": "Importato",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1365,9 +1362,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ATTENZIONE: Non dire mai a nessuno questa frase di backup. Chiunque con questa frase può rubare i tuoi Ether per sempre." "message": "ATTENZIONE: Non dire mai a nessuno questa frase di backup. Chiunque con questa frase può rubare i tuoi Ether per sempre."
}, },
"secretPhrase": {
"message": "Inserisci la tua frase segreta di dodici parole per ripristinare la cassaforte."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sicurezza & Privacy" "message": "Sicurezza & Privacy"
}, },
@ -1419,9 +1413,6 @@
"sendAmount": { "sendAmount": {
"message": "Invia Importo" "message": "Invia Importo"
}, },
"sendETH": {
"message": "Invia ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Invia $1", "message": "Invia $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -800,9 +800,6 @@
"importWallet": { "importWallet": {
"message": "ウォレットのインポート" "message": "ウォレットのインポート"
}, },
"importYourExisting": {
"message": "12単語のシードフレーズを使用して既存のウォレットをインポートします"
},
"imported": { "imported": {
"message": "インポート済", "message": "インポート済",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1359,9 +1356,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "警告:シードフレーズは絶対に公開しないでください。シードフレーズを使うと、誰でもアカウントからETHを盗み出せます。" "message": "警告:シードフレーズは絶対に公開しないでください。シードフレーズを使うと、誰でもアカウントからETHを盗み出せます。"
}, },
"secretPhrase": {
"message": "アカウント情報を復元するには、12単語で構成されたシードフレーズを入力してください。"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "セキュリティとプライバシー" "message": "セキュリティとプライバシー"
}, },
@ -1413,9 +1407,6 @@
"sendAmount": { "sendAmount": {
"message": "送金額" "message": "送金額"
}, },
"sendETH": {
"message": "ETHの送金"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "$1 を送る", "message": "$1 を送る",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "ವ ಅನ ಆಮದಿ" "message": "ವ ಅನ ಆಮದಿ"
}, },
"importYourExisting": {
"message": "12 ಪದದ ಸ ಅನ ಬಳಸಿಿಮ ಅಸಿವದಲಿವ ವ ಅನ ಆಮದಿ"
},
"imported": { "imported": {
"message": "ಆಮದಡಲಿ", "message": "ಆಮದಡಲಿ",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -895,9 +892,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ಎಚಚರಿ: ನಿಮ ಬಕಪ ಅನಿ ಬಹಿರಗಪಡಿಸಬಿ. ಈ ಫ ಅನಿವ ಯದರಿಮ ಎಥರ ಅನವತವಿಳಬಹ." "message": "ಎಚಚರಿ: ನಿಮ ಬಕಪ ಅನಿ ಬಹಿರಗಪಡಿಸಬಿ. ಈ ಫ ಅನಿವ ಯದರಿಮ ಎಥರ ಅನವತವಿಳಬಹ."
}, },
"secretPhrase": {
"message": "ನಿಮ ವ ಅನ ಮರಿಸಲಿಮ ರಹಸಯ ಹನರಡ ಪದದ ಫ ಅನ ಇಲಿ ನಮಿಿ."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "ಭದರತ ಮತಯತ" "message": "ಭದರತ ಮತಯತ"
}, },
@ -937,9 +931,6 @@
"sendAmount": { "sendAmount": {
"message": "ಮತವನ ಕಳಿಿ" "message": "ಮತವನ ಕಳಿಿ"
}, },
"sendETH": {
"message": "ETH ಕಳಿಿ"
},
"sendTokens": { "sendTokens": {
"message": "ಟಕನಗಳನ ಕಳಿಿ" "message": "ಟಕನಗಳನ ಕಳಿಿ"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "지갑 가져오기" "message": "지갑 가져오기"
}, },
"importYourExisting": {
"message": "12단어 시드 구문을 사용하여 지갑 가져오기"
},
"imported": { "imported": {
"message": "가져옴", "message": "가져옴",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1347,9 +1344,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "경고: 백업 구문은 절대로 공개하지 마세요. 이 구문이 있는 사람은 귀하의 Ether를 영원히 소유할 수 있습니다." "message": "경고: 백업 구문은 절대로 공개하지 마세요. 이 구문이 있는 사람은 귀하의 Ether를 영원히 소유할 수 있습니다."
}, },
"secretPhrase": {
"message": "금고를 복구하려면 비밀 12단어 구문을 여기에 입력하세요."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "보안 및 개인정보 보호" "message": "보안 및 개인정보 보호"
}, },
@ -1401,9 +1395,6 @@
"sendAmount": { "sendAmount": {
"message": "금액 보내기" "message": "금액 보내기"
}, },
"sendETH": {
"message": "ETH 보내기"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "$1 보내기", "message": "$1 보내기",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "Importuoti slaptažodinę" "message": "Importuoti slaptažodinę"
}, },
"importYourExisting": {
"message": "Importuoti turimą piniginę naudojant 12 žodžių atkūrimo frazę"
},
"imported": { "imported": {
"message": "Importuota", "message": "Importuota",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -895,9 +892,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ĮSPĖJIMAS. Niekada neatskleiskite savo atsarginės frazės. Bet kas, žinantis šią frazę, gali visiems laikams pasiimti jūsų eterius." "message": "ĮSPĖJIMAS. Niekada neatskleiskite savo atsarginės frazės. Bet kas, žinantis šią frazę, gali visiems laikams pasiimti jūsų eterius."
}, },
"secretPhrase": {
"message": "Savo saugyklai atkurti įveskite slaptą dvylikos žodžių frazę."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sauga ir privatumas" "message": "Sauga ir privatumas"
}, },
@ -937,9 +931,6 @@
"sendAmount": { "sendAmount": {
"message": "Siųsti sumą" "message": "Siųsti sumą"
}, },
"sendETH": {
"message": "Siųsti ETH"
},
"sendTokens": { "sendTokens": {
"message": "Siųsti žetonus" "message": "Siųsti žetonus"
}, },

@ -501,9 +501,6 @@
"importWallet": { "importWallet": {
"message": "Importēt maku" "message": "Importēt maku"
}, },
"importYourExisting": {
"message": "Importējiet esošo maku, izmantojot 12 vārdu atkopšanas frāzi"
},
"imported": { "imported": {
"message": "Importēts", "message": "Importēts",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -891,9 +888,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "BRĪDINĀJUMS! Nekādā gadījumā neizpaudiet savu rezerves frāzi. Ikviens, kam pieejama šī frāze, var uz visiem laikiem pārņemt jūsu Ether." "message": "BRĪDINĀJUMS! Nekādā gadījumā neizpaudiet savu rezerves frāzi. Ikviens, kam pieejama šī frāze, var uz visiem laikiem pārņemt jūsu Ether."
}, },
"secretPhrase": {
"message": "Ievadiet šeit slepeno divpadsmit vārdu frāzi, lai atjaunotu savu seifu."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Drošība un konfidencialitāte" "message": "Drošība un konfidencialitāte"
}, },
@ -933,9 +927,6 @@
"sendAmount": { "sendAmount": {
"message": "Nosūtītā summa" "message": "Nosūtītā summa"
}, },
"sendETH": {
"message": "Sūtīt ETH"
},
"sendTokens": { "sendTokens": {
"message": "Nosūtīt marķierus" "message": "Nosūtīt marķierus"
}, },

@ -491,9 +491,6 @@
"importWallet": { "importWallet": {
"message": "Import Dompet" "message": "Import Dompet"
}, },
"importYourExisting": {
"message": "Import dompet sedia ada anda menggunakan frasa benih 12 perkataan"
},
"imported": { "imported": {
"message": "Diimport", "message": "Diimport",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -872,9 +869,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "AMARAN: Jangan sesekali dedahkan frasa sandaran anda. Sesiapa yang memperoleh frasa ini boleh mengambil Ether anda selama-lamanya." "message": "AMARAN: Jangan sesekali dedahkan frasa sandaran anda. Sesiapa yang memperoleh frasa ini boleh mengambil Ether anda selama-lamanya."
}, },
"secretPhrase": {
"message": "Masukkan ungkapan rahsia dua belas perkataan di sini untuk memulihkan kekubah anda."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Keselamatan & Privasi" "message": "Keselamatan & Privasi"
}, },
@ -914,9 +908,6 @@
"sendAmount": { "sendAmount": {
"message": "Hantar Amaun" "message": "Hantar Amaun"
}, },
"sendETH": {
"message": "Hantar ETH"
},
"sendTokens": { "sendTokens": {
"message": "Hantar Token" "message": "Hantar Token"
}, },

@ -311,9 +311,6 @@
"search": { "search": {
"message": "Zoeken" "message": "Zoeken"
}, },
"secretPhrase": {
"message": "Voer hier je geheime twaalfwoordfrase in om je kluis te herstellen."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "Back-up woorden zijn 12 woorden lang" "message": "Back-up woorden zijn 12 woorden lang"
}, },
@ -323,9 +320,6 @@
"send": { "send": {
"message": "Sturen" "message": "Sturen"
}, },
"sendETH": {
"message": "Verzend ETH"
},
"sendTokens": { "sendTokens": {
"message": "Stuur tokens" "message": "Stuur tokens"
}, },

@ -492,9 +492,6 @@
"importWallet": { "importWallet": {
"message": "Importér lommebok " "message": "Importér lommebok "
}, },
"importYourExisting": {
"message": "Importer din eksisterende lommebok ved å bruk en tolvords seed-frase."
},
"imported": { "imported": {
"message": "Importert", "message": "Importert",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -879,9 +876,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ADVARSEL: Du må aldri avsløre gjenopprettingsfrasen din. Alle som har denne frasen kan ta fra deg Etheren din for alltid." "message": "ADVARSEL: Du må aldri avsløre gjenopprettingsfrasen din. Alle som har denne frasen kan ta fra deg Etheren din for alltid."
}, },
"secretPhrase": {
"message": "Skriv inn den tolv ord lange frasen her for å gjenopprette hvelvet ditt. "
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sikkerhet og personvern" "message": "Sikkerhet og personvern"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "Importuj portfel" "message": "Importuj portfel"
}, },
"importYourExisting": {
"message": "Zaimportuj istniejący portfel, wprowadzając 12 słów frazy seed"
},
"imported": { "imported": {
"message": "Zaimportowane", "message": "Zaimportowane",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -889,9 +886,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "OSTRZEŻENIE: Nigdy nie ujawniaj swojej frazy zapasowej. Każdy, kto pozna tę frazę, może bezpowrotnie odebrać Ci kryptowalutę Ether." "message": "OSTRZEŻENIE: Nigdy nie ujawniaj swojej frazy zapasowej. Każdy, kto pozna tę frazę, może bezpowrotnie odebrać Ci kryptowalutę Ether."
}, },
"secretPhrase": {
"message": "Żeby otworzyć schowek, wpisz tutaj swoją frazę dwunastu słów."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Bezpieczeństwo i prywatność" "message": "Bezpieczeństwo i prywatność"
}, },
@ -931,9 +925,6 @@
"sendAmount": { "sendAmount": {
"message": "Wyślij kwotę" "message": "Wyślij kwotę"
}, },
"sendETH": {
"message": "Wyślij ETH"
},
"sendTokens": { "sendTokens": {
"message": "Wyślij tokeny" "message": "Wyślij tokeny"
}, },

@ -321,9 +321,6 @@
"search": { "search": {
"message": "Procurar" "message": "Procurar"
}, },
"secretPhrase": {
"message": "Introduza a sua frase secreta de 12 palavras para recuperar o seu ."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "seed phrases are 12 words long" "message": "seed phrases are 12 words long"
}, },
@ -333,9 +330,6 @@
"send": { "send": {
"message": "Enviar" "message": "Enviar"
}, },
"sendETH": {
"message": "Enviar ETH"
},
"sendTokens": { "sendTokens": {
"message": "Enviar Tokens" "message": "Enviar Tokens"
}, },

@ -499,9 +499,6 @@
"importWallet": { "importWallet": {
"message": "Importar Carteira" "message": "Importar Carteira"
}, },
"importYourExisting": {
"message": "Importe sua carteira existente usando uma frase-semente de 12 palavras"
},
"imported": { "imported": {
"message": "Importado", "message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -883,9 +880,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ATENÇÃO: Nunca revele sua frase de backup a ninguém. Qualquer pessoa com essa frase pode obter seu Ether para sempre." "message": "ATENÇÃO: Nunca revele sua frase de backup a ninguém. Qualquer pessoa com essa frase pode obter seu Ether para sempre."
}, },
"secretPhrase": {
"message": "Digite sua frase secreta de doze palavras aqui para restaurar seu cofre."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Segurança & Privacidade" "message": "Segurança & Privacidade"
}, },
@ -925,9 +919,6 @@
"sendAmount": { "sendAmount": {
"message": "Enviar Quantia" "message": "Enviar Quantia"
}, },
"sendETH": {
"message": "Enviar ETH"
},
"sendTokens": { "sendTokens": {
"message": "Enviar Tokens" "message": "Enviar Tokens"
}, },

@ -495,9 +495,6 @@
"importWallet": { "importWallet": {
"message": "Importați portofel" "message": "Importați portofel"
}, },
"importYourExisting": {
"message": "Importați portofelul existent folosind o frază seed de 12 cuvinte"
},
"imported": { "imported": {
"message": "Importate", "message": "Importate",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -882,9 +879,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ATENȚIE: Nu dezvăluiți niciodată expresia dvs. de rezervă. Oricine are această expresie vă poate lua Ether-ul pentru totdeauna." "message": "ATENȚIE: Nu dezvăluiți niciodată expresia dvs. de rezervă. Oricine are această expresie vă poate lua Ether-ul pentru totdeauna."
}, },
"secretPhrase": {
"message": "Introduceți aici expresia dvs. secretă din 12 cuvinte pentru a restabili seiful."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Securitate și confidențialitate" "message": "Securitate și confidențialitate"
}, },
@ -924,9 +918,6 @@
"sendAmount": { "sendAmount": {
"message": "Suma trimisă" "message": "Suma trimisă"
}, },
"sendETH": {
"message": "Trimitere ETH"
},
"sendTokens": { "sendTokens": {
"message": "Trimiteți indicative" "message": "Trimiteți indicative"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "Импортировать кошелек" "message": "Импортировать кошелек"
}, },
"importYourExisting": {
"message": "Импортируйте существующий кошелек, используя начальную фразу из 12 слов"
},
"imported": { "imported": {
"message": "Импортированный", "message": "Импортированный",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1350,9 +1347,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ПРЕДУПРЕЖДЕНИЕ: Никогда не разглашайте резервную фразу. Любой, у кого есть эта фраза, может забрать ваш Ether навсегда." "message": "ПРЕДУПРЕЖДЕНИЕ: Никогда не разглашайте резервную фразу. Любой, у кого есть эта фраза, может забрать ваш Ether навсегда."
}, },
"secretPhrase": {
"message": "Введите здесь свою секретную фразу из двенадцати слов, чтобы восстановить свой сейф."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Безопасность и конфиденциальность" "message": "Безопасность и конфиденциальность"
}, },
@ -1404,9 +1398,6 @@
"sendAmount": { "sendAmount": {
"message": "Отправить сумму" "message": "Отправить сумму"
}, },
"sendETH": {
"message": "Отправить ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Отправить $1", "message": "Отправить $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -492,9 +492,6 @@
"importWallet": { "importWallet": {
"message": "Importovať Peňaženku" "message": "Importovať Peňaženku"
}, },
"importYourExisting": {
"message": "Importujte svoju existujúcu peňaženku pomocou 12-slovnej seed frázy"
},
"imported": { "imported": {
"message": "Importováno", "message": "Importováno",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -858,9 +855,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "UPOZORNENIE: Nikdy nezverejňujte svoju backup frázu. Každý, kto má túto frázu, môže navždy vziať váš Ether." "message": "UPOZORNENIE: Nikdy nezverejňujte svoju backup frázu. Každý, kto má túto frázu, môže navždy vziať váš Ether."
}, },
"secretPhrase": {
"message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Bezpečnosť a súkromie" "message": "Bezpečnosť a súkromie"
}, },
@ -900,9 +894,6 @@
"sendAmount": { "sendAmount": {
"message": "Poslať sumu" "message": "Poslať sumu"
}, },
"sendETH": {
"message": "Odeslat ETH"
},
"sendTokens": { "sendTokens": {
"message": "Odeslat tokeny" "message": "Odeslat tokeny"
}, },

@ -496,9 +496,6 @@
"importWallet": { "importWallet": {
"message": "Uvozi denarnico" "message": "Uvozi denarnico"
}, },
"importYourExisting": {
"message": "Uvozite svojo obstoječo denarnico s pomočjo 12-besednega gesla seed phrase"
},
"imported": { "imported": {
"message": "Uvoženo", "message": "Uvoženo",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -877,9 +874,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "OPOZORILO: Nikoli nikomur ne razkrijte varnostne kopije. Kdorkoli lahko tem geslom vedno prevzame vaš Ether." "message": "OPOZORILO: Nikoli nikomur ne razkrijte varnostne kopije. Kdorkoli lahko tem geslom vedno prevzame vaš Ether."
}, },
"secretPhrase": {
"message": "Vnesite vaših dvanajst besed za obnovitev vaših računov."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Varnost in zasebnost" "message": "Varnost in zasebnost"
}, },
@ -919,9 +913,6 @@
"sendAmount": { "sendAmount": {
"message": "Pošlji znesek" "message": "Pošlji znesek"
}, },
"sendETH": {
"message": "Pošlji ETH"
},
"sendTokens": { "sendTokens": {
"message": "Pošlji žetone" "message": "Pošlji žetone"
}, },

@ -502,9 +502,6 @@
"importWallet": { "importWallet": {
"message": "Uvezite novčanik" "message": "Uvezite novčanik"
}, },
"importYourExisting": {
"message": "Uvezite vaš postojeći novčanik koristeći seed frazu sa 12 reči"
},
"imported": { "imported": {
"message": "Увезени", "message": "Увезени",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -886,9 +883,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "UPOZORENJE: Nikada ne otkrivajte svoju rezervnu frazu. Svako sa ovom frazom može zauvek da Vam uzme Vaš Ether." "message": "UPOZORENJE: Nikada ne otkrivajte svoju rezervnu frazu. Svako sa ovom frazom može zauvek da Vam uzme Vaš Ether."
}, },
"secretPhrase": {
"message": "Unesite ovde svoj tajni izraz od dvanaest reči kako biste povratili svoj trezor."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Bezbednost i privatnost" "message": "Bezbednost i privatnost"
}, },
@ -928,9 +922,6 @@
"sendAmount": { "sendAmount": {
"message": "Pošaljite iznos" "message": "Pošaljite iznos"
}, },
"sendETH": {
"message": "Pošalji ETH"
},
"sendTokens": { "sendTokens": {
"message": "Pošalji tokene" "message": "Pošalji tokene"
}, },

@ -495,9 +495,6 @@
"importWallet": { "importWallet": {
"message": "Importera plånbok" "message": "Importera plånbok"
}, },
"importYourExisting": {
"message": "Importera din existerande plånbok med hjälp av en 12 ord lång seedfras"
},
"imported": { "imported": {
"message": "Importerade", "message": "Importerade",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -879,9 +876,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "VARNING: avslöja aldrig din backup-fras. Någon som känner till denna fras kan ta dina Ether för alltid." "message": "VARNING: avslöja aldrig din backup-fras. Någon som känner till denna fras kan ta dina Ether för alltid."
}, },
"secretPhrase": {
"message": "Ange din tolv ord långa hemliga fras här för att återställa ditt valv."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Säkerhet och integritet" "message": "Säkerhet och integritet"
}, },
@ -921,9 +915,6 @@
"sendAmount": { "sendAmount": {
"message": "Skicka belopp" "message": "Skicka belopp"
}, },
"sendETH": {
"message": "Skicka ETH"
},
"sendTokens": { "sendTokens": {
"message": "Skicka tokens" "message": "Skicka tokens"
}, },

@ -492,9 +492,6 @@
"importWallet": { "importWallet": {
"message": "Hamisha Waleti" "message": "Hamisha Waleti"
}, },
"importYourExisting": {
"message": "Hamisha waleti iliyopo kwa kutumia kirai kianzio cha maneno 12"
},
"imported": { "imported": {
"message": "Zilizoingizwa", "message": "Zilizoingizwa",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -873,9 +870,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ONYO: Kamwe usiweke wazi kirai chako cha hifadhi mbadala. Mtu yeyote mwenye kirai hiki anaweza kuchukua Ether yako daima." "message": "ONYO: Kamwe usiweke wazi kirai chako cha hifadhi mbadala. Mtu yeyote mwenye kirai hiki anaweza kuchukua Ether yako daima."
}, },
"secretPhrase": {
"message": "Ingiza hapa kirai chako cha siri cha maneno kumi na mawili ili urejeshe vault yako."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Ulinzi na Faragha" "message": "Ulinzi na Faragha"
}, },
@ -915,9 +909,6 @@
"sendAmount": { "sendAmount": {
"message": "Tuma Kiasi" "message": "Tuma Kiasi"
}, },
"sendETH": {
"message": "Tuma ETH"
},
"sendTokens": { "sendTokens": {
"message": "Tuma Vianzio" "message": "Tuma Vianzio"
}, },

@ -426,9 +426,6 @@
"searchTokens": { "searchTokens": {
"message": "தடலகன" "message": "தடலகன"
}, },
"secretPhrase": {
"message": "உஙகளடகதபதறக இங உஙகள ரகசிய பனிரணடர உளிடவ."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "விியஙகள 12 வகளடவ" "message": "விியஙகள 12 வகளடவ"
}, },
@ -438,9 +435,6 @@
"send": { "send": {
"message": "அன" "message": "அன"
}, },
"sendETH": {
"message": "ETH ஐ அன"
},
"sendTokens": { "sendTokens": {
"message": "டகனகள அனபவ" "message": "டகனகள அனபவ"
}, },

@ -420,9 +420,6 @@
"search": { "search": {
"message": "คนหา" "message": "คนหา"
}, },
"secretPhrase": {
"message": "ปอนกลมคำสบสองคำเพอกนตเซฟของคณ"
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "กลมคำชดมความยาว 12 คำ" "message": "กลมคำชดมความยาว 12 คำ"
}, },
@ -441,9 +438,6 @@
"sendAmount": { "sendAmount": {
"message": "สงจำนวนเงนน" "message": "สงจำนวนเงนน"
}, },
"sendETH": {
"message": "สงอเธอร"
},
"sendTokens": { "sendTokens": {
"message": "สงโทเคน" "message": "สงโทเคน"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "I-import ang wallet" "message": "I-import ang wallet"
}, },
"importYourExisting": {
"message": "I-import ang iyong kasalukuyang wallet gamit ang 12 salita na seed phrase"
},
"imported": { "imported": {
"message": "Na-import", "message": "Na-import",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1347,9 +1344,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "BABALA: Huwag kailanman ipaalam ang iyong phrase sa pag-back up. Ang sinumang may phrase na ito ay maaaring angkinin ang iyong Ether." "message": "BABALA: Huwag kailanman ipaalam ang iyong phrase sa pag-back up. Ang sinumang may phrase na ito ay maaaring angkinin ang iyong Ether."
}, },
"secretPhrase": {
"message": "Ilagay ang iyong labindalawang lihim na phrase dito para ma-restore ang iyong vault."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Seguridad at Pagkapribado" "message": "Seguridad at Pagkapribado"
}, },
@ -1401,9 +1395,6 @@
"sendAmount": { "sendAmount": {
"message": "Halaga ng Ipapadala" "message": "Halaga ng Ipapadala"
}, },
"sendETH": {
"message": "Magpadala ng ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Magpadala ng $1", "message": "Magpadala ng $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -366,9 +366,6 @@
"searchTokens": { "searchTokens": {
"message": "Jeton ara" "message": "Jeton ara"
}, },
"secretPhrase": {
"message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
},
"seedPhraseReq": { "seedPhraseReq": {
"message": "Kaynak ifadeleri 12 kelimedir." "message": "Kaynak ifadeleri 12 kelimedir."
}, },
@ -378,9 +375,6 @@
"send": { "send": {
"message": "Gönder" "message": "Gönder"
}, },
"sendETH": {
"message": "ETH Gönder"
},
"sendTokens": { "sendTokens": {
"message": "Jeton Gönder" "message": "Jeton Gönder"
}, },

@ -505,9 +505,6 @@
"importWallet": { "importWallet": {
"message": "Імпортувати гаманець" "message": "Імпортувати гаманець"
}, },
"importYourExisting": {
"message": "Імпортуйте ваш гаманець, що існує, використовуючи початкову фразу з 12 слів"
},
"imported": { "imported": {
"message": "Імпортовано", "message": "Імпортовано",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -895,9 +892,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "ЗАСТЕРЕЖЕННЯ: Ніколи не розголошуйте вашу резервну фразу. Будь-хто з цією фразою зможе забрати ваш Ether назавжди." "message": "ЗАСТЕРЕЖЕННЯ: Ніколи не розголошуйте вашу резервну фразу. Будь-хто з цією фразою зможе забрати ваш Ether назавжди."
}, },
"secretPhrase": {
"message": "Введіть секретну фразу з дванадцяти слів, щоб відновити своє сховище."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Безпека й конфіденційність" "message": "Безпека й конфіденційність"
}, },
@ -937,9 +931,6 @@
"sendAmount": { "sendAmount": {
"message": "Надіслати суму" "message": "Надіслати суму"
}, },
"sendETH": {
"message": "Надіслати ETH"
},
"sendTokens": { "sendTokens": {
"message": "Надіслати токени" "message": "Надіслати токени"
}, },

@ -791,9 +791,6 @@
"importWallet": { "importWallet": {
"message": "Nhập ví" "message": "Nhập ví"
}, },
"importYourExisting": {
"message": "Nhập ví hiện có của bạn bằng cụm mật khẩu gốc gồm 12 từ"
},
"imported": { "imported": {
"message": "Đã nhập", "message": "Đã nhập",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1350,9 +1347,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "CẢNH BÁO: Tuyệt đối không để lộ cụm mật khẩu sao lưu của bạn. Bất kỳ ai có cụm mật khẩu này cũng có thể lấy Ether của bạn vĩnh viễn." "message": "CẢNH BÁO: Tuyệt đối không để lộ cụm mật khẩu sao lưu của bạn. Bất kỳ ai có cụm mật khẩu này cũng có thể lấy Ether của bạn vĩnh viễn."
}, },
"secretPhrase": {
"message": "Nhập cụm mật khẩu bí mật gồm 12 từ vào đây để khôi phục két của bạn."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Bảo mật và quyền riêng tư" "message": "Bảo mật và quyền riêng tư"
}, },
@ -1404,9 +1398,6 @@
"sendAmount": { "sendAmount": {
"message": "Gửi khoản tiền" "message": "Gửi khoản tiền"
}, },
"sendETH": {
"message": "Gửi ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Gửi $1", "message": "Gửi $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -800,9 +800,6 @@
"importWallet": { "importWallet": {
"message": "导入钱包" "message": "导入钱包"
}, },
"importYourExisting": {
"message": "使用 12 个单词的账户助记词导入您现有的钱包账户。"
},
"imported": { "imported": {
"message": "已导入", "message": "已导入",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -1359,9 +1356,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "警告:切勿向他人透露您的账户助记词。任何人一旦持有该账户助记词,即可控制您的 Ether。" "message": "警告:切勿向他人透露您的账户助记词。任何人一旦持有该账户助记词,即可控制您的 Ether。"
}, },
"secretPhrase": {
"message": "输入 12 个单词组成的账户助记词恢复您的账户。"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "安全与隐私" "message": "安全与隐私"
}, },
@ -1413,9 +1407,6 @@
"sendAmount": { "sendAmount": {
"message": "发送数额" "message": "发送数额"
}, },
"sendETH": {
"message": "发送 ETH"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "发送 $1", "message": "发送 $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"

@ -514,9 +514,6 @@
"importWallet": { "importWallet": {
"message": "匯入錢包" "message": "匯入錢包"
}, },
"importYourExisting": {
"message": "使用 12 字的助記詞來匯入你現有的錢包"
},
"imported": { "imported": {
"message": "已匯入私鑰", "message": "已匯入私鑰",
"description": "status showing that an account has been fully loaded into the keyring" "description": "status showing that an account has been fully loaded into the keyring"
@ -889,9 +886,6 @@
"secretBackupPhraseWarning": { "secretBackupPhraseWarning": {
"message": "警告: 絕對不要洩漏您的助憶詞。任何人只要得知助憶詞代表他可以竊取您所有的以太幣和代幣。" "message": "警告: 絕對不要洩漏您的助憶詞。任何人只要得知助憶詞代表他可以竊取您所有的以太幣和代幣。"
}, },
"secretPhrase": {
"message": "輸入您的12個助憶詞以回復金庫"
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "安全&隱私" "message": "安全&隱私"
}, },
@ -925,9 +919,6 @@
"sendAmount": { "sendAmount": {
"message": "發送數量" "message": "發送數量"
}, },
"sendETH": {
"message": "發送以太幣"
},
"sendTokens": { "sendTokens": {
"message": "發送代幣" "message": "發送代幣"
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import ethUtil from 'ethereumjs-util'; import ethUtil from 'ethereumjs-util';
import accountImporter from '../../../app/scripts/account-import-strategies'; import accountImporter from '.';
describe('Account Import Strategies', function () { describe('Account Import Strategies', function () {
const privkey = const privkey =

@ -1,12 +1,6 @@
/** /**
* @file The entry point for the web extension singleton process. * @file The entry point for the web extension singleton process.
*/ */
// these need to run before anything else
/* eslint-disable import/first,import/order */
import setupFetchDebugging from './lib/setupFetchDebugging';
/* eslint-enable import/order */
setupFetchDebugging();
// polyfills // polyfills
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'; import 'abortcontroller-polyfill/dist/polyfill-patch-fetch';
@ -70,21 +64,7 @@ if (inTest || process.env.METAMASK_DEBUG) {
initialize().catch(log.error); initialize().catch(log.error);
/** /**
* An object representing a transaction, in whatever state it is in. * @typedef {import('../../shared/constants/transaction').TransactionMeta} TransactionMeta
* @typedef TransactionMeta
*
* @property {number} id - An internally unique tx identifier.
* @property {number} time - Time the tx was first suggested, in unix epoch time (ms).
* @property {string} status - The current transaction status (unapproved, signed, submitted, dropped, failed, rejected), as defined in `tx-state-manager.js`.
* @property {string} metamaskNetworkId - The transaction's network ID, used for EIP-155 compliance.
* @property {boolean} loadingDefaults - TODO: Document
* @property {Object} txParams - The tx params as passed to the network provider.
* @property {Object[]} history - A history of mutations to this TransactionMeta object.
* @property {string} origin - A string representing the interface that suggested the transaction.
* @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, ready to submit to the network.
* @property {string} hash - A hex string of the transaction hash, used to identify the transaction on the network.
* @property {number} submittedTime - The time the transaction was submitted to the network, in Unix epoch time (ms).
*/ */
/** /**

@ -1,7 +1,7 @@
import assert from 'assert'; import assert from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import CachedBalancesController from '../../../../app/scripts/controllers/cached-balances'; import { KOVAN_CHAIN_ID } from '../../../shared/constants/network';
import { KOVAN_CHAIN_ID } from '../../../../shared/constants/network'; import CachedBalancesController from './cached-balances';
describe('CachedBalancesController', function () { describe('CachedBalancesController', function () {
describe('updateCachedBalances', function () { describe('updateCachedBalances', function () {

@ -4,10 +4,10 @@ import { ObservableStore } from '@metamask/obs-store';
import contracts from '@metamask/contract-metadata'; import contracts from '@metamask/contract-metadata';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import DetectTokensController from '../../../../app/scripts/controllers/detect-tokens'; import { MAINNET, ROPSTEN } from '../../../shared/constants/network';
import NetworkController from '../../../../app/scripts/controllers/network/network'; import DetectTokensController from './detect-tokens';
import PreferencesController from '../../../../app/scripts/controllers/preferences'; import NetworkController from './network';
import { MAINNET, ROPSTEN } from '../../../../shared/constants/network'; import PreferencesController from './preferences';
describe('DetectTokensController', function () { describe('DetectTokensController', function () {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import EnsController from '../../../../app/scripts/controllers/ens'; import EnsController from '.';
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
const ZERO_X_ERROR_ADDRESS = '0x'; const ZERO_X_ERROR_ADDRESS = '0x';

@ -1,32 +1,48 @@
import { ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel'; import log from 'loglevel';
import BN from 'bn.js'; import BN from 'bn.js';
import createId from '../lib/random-id'; import createId from '../../../shared/modules/random-id';
import { bnToHex } from '../lib/util'; import { bnToHex } from '../lib/util';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import { import {
TRANSACTION_CATEGORIES, TRANSACTION_TYPES,
TRANSACTION_STATUSES, TRANSACTION_STATUSES,
} from '../../../shared/constants/transaction'; } from '../../../shared/constants/transaction';
import { import {
CHAIN_ID_TO_NETWORK_ID_MAP, CHAIN_ID_TO_NETWORK_ID_MAP,
CHAIN_ID_TO_TYPE_MAP, CHAIN_ID_TO_TYPE_MAP,
GOERLI,
GOERLI_CHAIN_ID, GOERLI_CHAIN_ID,
KOVAN,
KOVAN_CHAIN_ID, KOVAN_CHAIN_ID,
MAINNET,
MAINNET_CHAIN_ID, MAINNET_CHAIN_ID,
RINKEBY,
RINKEBY_CHAIN_ID, RINKEBY_CHAIN_ID,
ROPSTEN,
ROPSTEN_CHAIN_ID, ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
import { NETWORK_EVENTS } from './network';
const fetchWithTimeout = getFetchWithTimeout(30000); const fetchWithTimeout = getFetchWithTimeout(30000);
/**
* @typedef {import('../../../shared/constants/transaction').TransactionMeta} TransactionMeta
*/
/**
* A transaction object in the format returned by the Etherscan API.
*
* Note that this is not an exhaustive type definiton; only the properties we use are defined
*
* @typedef {Object} EtherscanTransaction
* @property {string} blockNumber - The number of the block this transaction was found in, in decimal
* @property {string} from - The hex-prefixed address of the sender
* @property {string} gas - The gas limit, in decimal WEI
* @property {string} gasPrice - The gas price, in decimal WEI
* @property {string} hash - The hex-prefixed transaction hash
* @property {string} isError - Whether the transaction was confirmed or failed (0 for confirmed, 1 for failed)
* @property {string} nonce - The transaction nonce, in decimal
* @property {string} timeStamp - The timestamp for the transaction, in seconds
* @property {string} to - The hex-prefixed address of the recipient
* @property {string} value - The amount of ETH sent in this transaction, in decimal WEI
*/
/** /**
* This controller is responsible for retrieving incoming transactions. Etherscan is polled once every block to check * This controller is responsible for retrieving incoming transactions. Etherscan is polled once every block to check
* for new incoming transactions for the current selected account on the current network * for new incoming transactions for the current selected account on the current network
@ -44,35 +60,37 @@ const etherscanSupportedNetworks = [
export default class IncomingTransactionsController { export default class IncomingTransactionsController {
constructor(opts = {}) { constructor(opts = {}) {
const { blockTracker, networkController, preferencesController } = opts; const {
blockTracker,
onNetworkDidChange,
getCurrentChainId,
preferencesController,
} = opts;
this.blockTracker = blockTracker; this.blockTracker = blockTracker;
this.networkController = networkController; this.getCurrentChainId = getCurrentChainId;
this.preferencesController = preferencesController; this.preferencesController = preferencesController;
this._onLatestBlock = async (newBlockNumberHex) => { this._onLatestBlock = async (newBlockNumberHex) => {
const selectedAddress = this.preferencesController.getSelectedAddress(); const selectedAddress = this.preferencesController.getSelectedAddress();
const newBlockNumberDec = parseInt(newBlockNumberHex, 16); const newBlockNumberDec = parseInt(newBlockNumberHex, 16);
await this._update({ await this._update(selectedAddress, newBlockNumberDec);
address: selectedAddress,
newBlockNumberDec,
});
}; };
const initState = { const initState = {
incomingTransactions: {}, incomingTransactions: {},
incomingTxLastFetchedBlocksByNetwork: { incomingTxLastFetchedBlockByChainId: {
[GOERLI]: null, [GOERLI_CHAIN_ID]: null,
[KOVAN]: null, [KOVAN_CHAIN_ID]: null,
[MAINNET]: null, [MAINNET_CHAIN_ID]: null,
[RINKEBY]: null, [RINKEBY_CHAIN_ID]: null,
[ROPSTEN]: null, [ROPSTEN_CHAIN_ID]: null,
}, },
...opts.initState, ...opts.initState,
}; };
this.store = new ObservableStore(initState); this.store = new ObservableStore(initState);
this.preferencesController.store.subscribe( this.preferencesController.store.subscribe(
pairwise((prevState, currState) => { previousValueComparator((prevState, currState) => {
const { const {
featureFlags: { featureFlags: {
showIncomingTransactions: prevShowIncomingTransactions, showIncomingTransactions: prevShowIncomingTransactions,
@ -94,29 +112,24 @@ export default class IncomingTransactionsController {
} }
this.start(); this.start();
}), }, this.preferencesController.store.getState()),
); );
this.preferencesController.store.subscribe( this.preferencesController.store.subscribe(
pairwise(async (prevState, currState) => { previousValueComparator(async (prevState, currState) => {
const { selectedAddress: prevSelectedAddress } = prevState; const { selectedAddress: prevSelectedAddress } = prevState;
const { selectedAddress: currSelectedAddress } = currState; const { selectedAddress: currSelectedAddress } = currState;
if (currSelectedAddress === prevSelectedAddress) { if (currSelectedAddress === prevSelectedAddress) {
return; return;
} }
await this._update(currSelectedAddress);
await this._update({ }, this.preferencesController.store.getState()),
address: currSelectedAddress,
});
}),
); );
this.networkController.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, async () => { onNetworkDidChange(async () => {
const address = this.preferencesController.getSelectedAddress(); const address = this.preferencesController.getSelectedAddress();
await this._update({ await this._update(address);
address,
});
}); });
} }
@ -136,85 +149,79 @@ export default class IncomingTransactionsController {
this.blockTracker.removeListener('latest', this._onLatestBlock); this.blockTracker.removeListener('latest', this._onLatestBlock);
} }
async _update({ address, newBlockNumberDec } = {}) { /**
const chainId = this.networkController.getCurrentChainId(); * Determines the correct block number to begin looking for new transactions
if (!etherscanSupportedNetworks.includes(chainId)) { * from, fetches the transactions and then saves them and the next block
* number to begin fetching from in state. Block numbers and transactions are
* stored per chainId.
* @private
* @param {string} address - address to lookup transactions for
* @param {number} [newBlockNumberDec] - block number to begin fetching from
* @returns {void}
*/
async _update(address, newBlockNumberDec) {
const chainId = this.getCurrentChainId();
if (!etherscanSupportedNetworks.includes(chainId) || !address) {
return; return;
} }
try { try {
const dataForUpdate = await this._getDataForUpdate({ const currentState = this.store.getState();
const currentBlock = parseInt(this.blockTracker.getCurrentBlock(), 16);
const mostRecentlyFetchedBlock =
currentState.incomingTxLastFetchedBlockByChainId[chainId];
const blockToFetchFrom =
mostRecentlyFetchedBlock ?? newBlockNumberDec ?? currentBlock;
const newIncomingTxs = await this._getNewIncomingTransactions(
address, address,
blockToFetchFrom,
chainId, chainId,
newBlockNumberDec, );
let newMostRecentlyFetchedBlock = blockToFetchFrom;
newIncomingTxs.forEach((tx) => {
if (
tx.blockNumber &&
parseInt(newMostRecentlyFetchedBlock, 10) <
parseInt(tx.blockNumber, 10)
) {
newMostRecentlyFetchedBlock = parseInt(tx.blockNumber, 10);
}
});
this.store.updateState({
incomingTxLastFetchedBlockByChainId: {
...currentState.incomingTxLastFetchedBlockByChainId,
[chainId]: newMostRecentlyFetchedBlock + 1,
},
incomingTransactions: newIncomingTxs.reduce(
(transactions, tx) => {
transactions[tx.hash] = tx;
return transactions;
},
{
...currentState.incomingTransactions,
},
),
}); });
this._updateStateWithNewTxData(dataForUpdate);
} catch (err) { } catch (err) {
log.error(err); log.error(err);
} }
} }
async _getDataForUpdate({ address, chainId, newBlockNumberDec } = {}) { /**
const { * fetches transactions for the given address and chain, via etherscan, then
incomingTransactions: currentIncomingTxs, * processes the data into the necessary shape for usage in this controller.
incomingTxLastFetchedBlocksByNetwork: currentBlocksByNetwork, *
} = this.store.getState(); * @private
* @param {string} [address] - Address to fetch transactions for
const lastFetchBlockByCurrentNetwork = * @param {number} [fromBlock] - Block to look for transactions at
currentBlocksByNetwork[CHAIN_ID_TO_TYPE_MAP[chainId]]; * @param {string} [chainId] - The chainId for the current network
let blockToFetchFrom = lastFetchBlockByCurrentNetwork || newBlockNumberDec; * @returns {TransactionMeta[]}
if (blockToFetchFrom === undefined) { */
blockToFetchFrom = parseInt(this.blockTracker.getCurrentBlock(), 16); async _getNewIncomingTransactions(address, fromBlock, chainId) {
}
const { latestIncomingTxBlockNumber, txs: newTxs } = await this._fetchAll(
address,
blockToFetchFrom,
chainId,
);
return {
latestIncomingTxBlockNumber,
newTxs,
currentIncomingTxs,
currentBlocksByNetwork,
fetchedBlockNumber: blockToFetchFrom,
chainId,
};
}
_updateStateWithNewTxData({
latestIncomingTxBlockNumber,
newTxs,
currentIncomingTxs,
currentBlocksByNetwork,
fetchedBlockNumber,
chainId,
}) {
const newLatestBlockHashByNetwork = latestIncomingTxBlockNumber
? parseInt(latestIncomingTxBlockNumber, 10) + 1
: fetchedBlockNumber + 1;
const newIncomingTransactions = {
...currentIncomingTxs,
};
newTxs.forEach((tx) => {
newIncomingTransactions[tx.hash] = tx;
});
this.store.updateState({
incomingTxLastFetchedBlocksByNetwork: {
...currentBlocksByNetwork,
[CHAIN_ID_TO_TYPE_MAP[chainId]]: newLatestBlockHashByNetwork,
},
incomingTransactions: newIncomingTransactions,
});
}
async _fetchAll(address, fromBlock, chainId) {
const fetchedTxResponse = await this._fetchTxs(address, fromBlock, chainId);
return this._processTxFetchResponse(fetchedTxResponse);
}
async _fetchTxs(address, fromBlock, chainId) {
const etherscanSubdomain = const etherscanSubdomain =
chainId === MAINNET_CHAIN_ID chainId === MAINNET_CHAIN_ID
? 'api' ? 'api'
@ -227,16 +234,8 @@ export default class IncomingTransactionsController {
url += `&startBlock=${parseInt(fromBlock, 10)}`; url += `&startBlock=${parseInt(fromBlock, 10)}`;
} }
const response = await fetchWithTimeout(url); const response = await fetchWithTimeout(url);
const parsedResponse = await response.json(); const { status, result } = await response.json();
let newIncomingTxs = [];
return {
...parsedResponse,
address,
chainId,
};
}
_processTxFetchResponse({ status, result = [], address, chainId }) {
if (status === '1' && Array.isArray(result) && result.length > 0) { if (status === '1' && Array.isArray(result) && result.length > 0) {
const remoteTxList = {}; const remoteTxList = {};
const remoteTxs = []; const remoteTxs = [];
@ -247,70 +246,70 @@ export default class IncomingTransactionsController {
} }
}); });
const incomingTxs = remoteTxs.filter( newIncomingTxs = remoteTxs.filter(
(tx) => tx.txParams?.to?.toLowerCase() === address.toLowerCase(), (tx) => tx.txParams?.to?.toLowerCase() === address.toLowerCase(),
); );
incomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); newIncomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1));
let latestIncomingTxBlockNumber = null;
incomingTxs.forEach((tx) => {
if (
tx.blockNumber &&
(!latestIncomingTxBlockNumber ||
parseInt(latestIncomingTxBlockNumber, 10) <
parseInt(tx.blockNumber, 10))
) {
latestIncomingTxBlockNumber = tx.blockNumber;
}
});
return {
latestIncomingTxBlockNumber,
txs: incomingTxs,
};
} }
return { return newIncomingTxs;
latestIncomingTxBlockNumber: null,
txs: [],
};
} }
_normalizeTxFromEtherscan(txMeta, chainId) { /**
const time = parseInt(txMeta.timeStamp, 10) * 1000; * Transmutes a EtherscanTransaction into a TransactionMeta
* @param {EtherscanTransaction} etherscanTransaction - the transaction to normalize
* @param {string} chainId - The chainId of the current network
* @returns {TransactionMeta}
*/
_normalizeTxFromEtherscan(etherscanTransaction, chainId) {
const time = parseInt(etherscanTransaction.timeStamp, 10) * 1000;
const status = const status =
txMeta.isError === '0' etherscanTransaction.isError === '0'
? TRANSACTION_STATUSES.CONFIRMED ? TRANSACTION_STATUSES.CONFIRMED
: TRANSACTION_STATUSES.FAILED; : TRANSACTION_STATUSES.FAILED;
return { return {
blockNumber: txMeta.blockNumber, blockNumber: etherscanTransaction.blockNumber,
id: createId(), id: createId(),
chainId, chainId,
metamaskNetworkId: CHAIN_ID_TO_NETWORK_ID_MAP[chainId], metamaskNetworkId: CHAIN_ID_TO_NETWORK_ID_MAP[chainId],
status, status,
time, time,
txParams: { txParams: {
from: txMeta.from, from: etherscanTransaction.from,
gas: bnToHex(new BN(txMeta.gas)), gas: bnToHex(new BN(etherscanTransaction.gas)),
gasPrice: bnToHex(new BN(txMeta.gasPrice)), gasPrice: bnToHex(new BN(etherscanTransaction.gasPrice)),
nonce: bnToHex(new BN(txMeta.nonce)), nonce: bnToHex(new BN(etherscanTransaction.nonce)),
to: txMeta.to, to: etherscanTransaction.to,
value: bnToHex(new BN(txMeta.value)), value: bnToHex(new BN(etherscanTransaction.value)),
}, },
hash: txMeta.hash, hash: etherscanTransaction.hash,
transactionCategory: TRANSACTION_CATEGORIES.INCOMING, type: TRANSACTION_TYPES.INCOMING,
}; };
} }
} }
function pairwise(fn) { /**
* Returns a function with arity 1 that caches the argument that the function
* is called with and invokes the comparator with both the cached, previous,
* value and the current value. If specified, the initialValue will be passed
* in as the previous value on the first invocation of the returned method.
* @template A
* @params {A=} type of compared value
* @param {(prevValue: A, nextValue: A) => void} comparator - method to compare
* previous and next values.
* @param {A} [initialValue] - initial value to supply to prevValue
* on first call of the method.
* @returns {void}
*/
function previousValueComparator(comparator, initialValue) {
let first = true; let first = true;
let cache; let cache;
return (value) => { return (value) => {
try { try {
if (first) { if (first) {
first = false; first = false;
return fn(value, value); return comparator(initialValue ?? value, value);
} }
return fn(cache, value); return comparator(cache, value);
} finally { } finally {
cache = value; cache = value;
} }

@ -1,14 +1,14 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import MetaMetricsController from '../../../../app/scripts/controllers/metametrics'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../../shared/constants/app'; import { createSegmentMock } from '../lib/segment';
import { createSegmentMock } from '../../../../app/scripts/lib/segment';
import { import {
METAMETRICS_ANONYMOUS_ID, METAMETRICS_ANONYMOUS_ID,
METAMETRICS_BACKGROUND_PAGE_OBJECT, METAMETRICS_BACKGROUND_PAGE_OBJECT,
} from '../../../../shared/constants/metametrics'; } from '../../../shared/constants/metametrics';
import waitUntilCalled from '../../../lib/wait-until-called'; import waitUntilCalled from '../../../test/lib/wait-until-called';
import { NETWORK_EVENTS } from '../../../../app/scripts/controllers/network'; import MetaMetricsController from './metametrics';
import { NETWORK_EVENTS } from './network';
const segment = createSegmentMock(2, 10000); const segment = createSegmentMock(2, 10000);
const segmentLegacy = createSegmentMock(2, 10000); const segmentLegacy = createSegmentMock(2, 10000);

@ -6,7 +6,7 @@ import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache';
import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector'; import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector';
import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware'; import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware';
import createInfuraMiddleware from 'eth-json-rpc-infura'; import createInfuraMiddleware from 'eth-json-rpc-infura';
import BlockTracker from 'eth-block-tracker'; import { PollingBlockTracker } from 'eth-block-tracker';
import { NETWORK_TYPE_TO_ID_MAP } from '../../../../shared/constants/network'; import { NETWORK_TYPE_TO_ID_MAP } from '../../../../shared/constants/network';
@ -18,7 +18,7 @@ export default function createInfuraClient({ network, projectId }) {
source: 'metamask', source: 'metamask',
}); });
const infuraProvider = providerFromMiddleware(infuraMiddleware); const infuraProvider = providerFromMiddleware(infuraMiddleware);
const blockTracker = new BlockTracker({ provider: infuraProvider }); const blockTracker = new PollingBlockTracker({ provider: infuraProvider });
const networkMiddleware = mergeMiddleware([ const networkMiddleware = mergeMiddleware([
createNetworkAndChainIdMiddleware({ network }), createNetworkAndChainIdMiddleware({ network }),

@ -5,7 +5,7 @@ import createBlockCacheMiddleware from 'eth-json-rpc-middleware/block-cache';
import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache'; import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache';
import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector'; import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector';
import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware'; import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware';
import BlockTracker from 'eth-block-tracker'; import { PollingBlockTracker } from 'eth-block-tracker';
const inTest = process.env.IN_TEST === 'true'; const inTest = process.env.IN_TEST === 'true';
const blockTrackerOpts = inTest ? { pollingInterval: 1000 } : {}; const blockTrackerOpts = inTest ? { pollingInterval: 1000 } : {};
@ -16,7 +16,7 @@ const getTestMiddlewares = () => {
export default function createJsonRpcClient({ rpcUrl, chainId }) { export default function createJsonRpcClient({ rpcUrl, chainId }) {
const fetchMiddleware = createFetchMiddleware({ rpcUrl }); const fetchMiddleware = createFetchMiddleware({ rpcUrl });
const blockProvider = providerFromMiddleware(fetchMiddleware); const blockProvider = providerFromMiddleware(fetchMiddleware);
const blockTracker = new BlockTracker({ const blockTracker = new PollingBlockTracker({
...blockTrackerOpts, ...blockTrackerOpts,
provider: blockProvider, provider: blockProvider,
}); });

@ -1,7 +1,7 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import NetworkController from '../../../../../app/scripts/controllers/network'; import { getNetworkDisplayName } from './util';
import { getNetworkDisplayName } from '../../../../../app/scripts/controllers/network/util'; import NetworkController from './network';
describe('NetworkController', function () { describe('NetworkController', function () {
describe('controller', function () { describe('controller', function () {

@ -1,9 +1,9 @@
import assert from 'assert'; import assert from 'assert';
import { txMetaStub } from '../../../../test/stub/tx-meta-stub';
import { import {
createPendingNonceMiddleware, createPendingNonceMiddleware,
createPendingTxMiddleware, createPendingTxMiddleware,
} from '../../../../../app/scripts/controllers/network/middleware/pending'; } from './middleware/pending';
import { txMetaStub } from './stubs';
describe('PendingNonceMiddleware', function () { describe('PendingNonceMiddleware', function () {
describe('#createPendingNonceMiddleware', function () { describe('#createPendingNonceMiddleware', function () {

@ -2,22 +2,20 @@ import { strict as assert } from 'assert';
import { find } from 'lodash'; import { find } from 'lodash';
import sinon from 'sinon'; import sinon from 'sinon';
import {
METADATA_STORE_KEY,
METADATA_CACHE_MAX_SIZE,
} from '../../../../../app/scripts/controllers/permissions/enums';
import { PermissionsController } from '../../../../../app/scripts/controllers/permissions';
import { getRequestUserApprovalHelper, grantPermissions } from './helpers';
import { import {
constants, constants,
getters, getters,
getNotifyDomain, getNotifyDomain,
getNotifyAllDomains, getNotifyAllDomains,
getPermControllerOpts, getPermControllerOpts,
} from './mocks'; } from '../../../../test/mocks/permission-controller';
import {
getRequestUserApprovalHelper,
grantPermissions,
} from '../../../../test/helpers/permission-controller-helpers';
import { METADATA_STORE_KEY, METADATA_CACHE_MAX_SIZE } from './enums';
import { PermissionsController } from '.';
const { ERRORS, NOTIFICATIONS, PERMS } = getters; const { ERRORS, NOTIFICATIONS, PERMS } = getters;

@ -3,16 +3,14 @@ import { ObservableStore } from '@metamask/obs-store';
import nanoid from 'nanoid'; import nanoid from 'nanoid';
import { useFakeTimers } from 'sinon'; import { useFakeTimers } from 'sinon';
import PermissionsLogController from '../../../../../app/scripts/controllers/permissions/permissionsLog';
import { import {
LOG_LIMIT, constants,
LOG_METHOD_TYPES, getters,
} from '../../../../../app/scripts/controllers/permissions/enums'; noop,
} from '../../../../test/mocks/permission-controller';
import { validateActivityEntry } from './helpers'; import { validateActivityEntry } from '../../../../test/helpers/permission-controller-helpers';
import PermissionsLogController from './permissionsLog';
import { constants, getters, noop } from './mocks'; import { LOG_LIMIT, LOG_METHOD_TYPES } from './enums';
const { PERMS, RPC_REQUESTS } = getters; const { PERMS, RPC_REQUESTS } = getters;
@ -50,7 +48,7 @@ const initMiddleware = (permLog) => {
const initClock = () => { const initClock = () => {
// useFakeTimers, is in fact, not a react-hook // useFakeTimers, is in fact, not a react-hook
// eslint-disable-next-line // eslint-disable-next-line
clock = useFakeTimers(1) clock = useFakeTimers(1);
}; };
const tearDownClock = () => { const tearDownClock = () => {

@ -1,18 +1,19 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import { METADATA_STORE_KEY } from '../../../../../app/scripts/controllers/permissions/enums';
import { PermissionsController } from '../../../../../app/scripts/controllers/permissions';
import { getUserApprovalPromise, grantPermissions } from './helpers';
import { import {
constants, constants,
getters, getters,
getPermControllerOpts, getPermControllerOpts,
getPermissionsMiddleware, getPermissionsMiddleware,
} from './mocks'; } from '../../../../test/mocks/permission-controller';
import {
getUserApprovalPromise,
grantPermissions,
} from '../../../../test/helpers/permission-controller-helpers';
import { METADATA_STORE_KEY } from './enums';
import { PermissionsController } from '.';
const { CAVEATS, ERRORS, PERMS, RPC_REQUESTS } = getters; const { CAVEATS, ERRORS, PERMS, RPC_REQUESTS } = getters;

@ -1,4 +1,4 @@
import { cloneDeep } from 'lodash'; import stringify from 'fast-safe-stringify';
import { CAVEAT_NAMES } from '../../../../shared/constants/permissions'; import { CAVEAT_NAMES } from '../../../../shared/constants/permissions';
import { import {
HISTORY_STORE_KEY, HISTORY_STORE_KEY,
@ -151,7 +151,7 @@ export default class PermissionsLogController {
? LOG_METHOD_TYPES.internal ? LOG_METHOD_TYPES.internal
: LOG_METHOD_TYPES.restricted, : LOG_METHOD_TYPES.restricted,
origin: request.origin, origin: request.origin,
request: cloneDeep(request), request: stringify(request, null, 2),
requestTime: Date.now(), requestTime: Date.now(),
response: null, response: null,
responseTime: null, responseTime: null,
@ -174,7 +174,7 @@ export default class PermissionsLogController {
return; return;
} }
entry.response = cloneDeep(response); entry.response = stringify(response, null, 2);
entry.responseTime = time; entry.responseTime = time;
entry.success = !response.error; entry.success = !response.error;
} }

@ -1,7 +1,7 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import pify from 'pify'; import pify from 'pify';
import getRestrictedMethods from '../../../../../app/scripts/controllers/permissions/restrictedMethods'; import getRestrictedMethods from './restrictedMethods';
describe('restricted methods', function () { describe('restricted methods', function () {
describe('eth_accounts', function () { describe('eth_accounts', function () {

@ -378,7 +378,7 @@ export default class PreferencesController {
*/ */
async addToken(rawAddress, symbol, decimals, image) { async addToken(rawAddress, symbol, decimals, image) {
const address = normalizeAddress(rawAddress); const address = normalizeAddress(rawAddress);
const newEntry = { address, symbol, decimals }; const newEntry = { address, symbol, decimals: Number(decimals) };
const { tokens, hiddenTokens } = this.store.getState(); const { tokens, hiddenTokens } = this.store.getState();
const assetImages = this.getAssetImages(); const assetImages = this.getAssetImages();
const updatedHiddenTokens = hiddenTokens.filter( const updatedHiddenTokens = hiddenTokens.filter(
@ -793,9 +793,14 @@ export default class PreferencesController {
if (typeof symbol !== 'string') { if (typeof symbol !== 'string') {
throw ethErrors.rpc.invalidParams(`Invalid symbol: not a string.`); throw ethErrors.rpc.invalidParams(`Invalid symbol: not a string.`);
} }
if (!(symbol.length < 7)) { if (!(symbol.length > 0)) {
throw ethErrors.rpc.invalidParams( throw ethErrors.rpc.invalidParams(
`Invalid symbol "${symbol}": longer than 6 characters.`, `Invalid symbol "${symbol}": shorter than a character.`,
);
}
if (!(symbol.length < 12)) {
throw ethErrors.rpc.invalidParams(
`Invalid symbol "${symbol}": longer than 11 characters.`,
); );
} }
const numDecimals = parseInt(decimals, 10); const numDecimals = parseInt(decimals, 10);

@ -1,10 +1,10 @@
import assert from 'assert'; import assert from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import PreferencesController from '../../../../app/scripts/controllers/preferences';
import { import {
MAINNET_CHAIN_ID, MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID, RINKEBY_CHAIN_ID,
} from '../../../../shared/constants/network'; } from '../../../shared/constants/network';
import PreferencesController from './preferences';
describe('preferences controller', function () { describe('preferences controller', function () {
let preferencesController; let preferencesController;
@ -539,6 +539,14 @@ describe('preferences controller', function () {
decimals: 0, decimals: 0,
}), }),
); );
assert.doesNotThrow(() =>
validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: 'ABCDEFGHIJK',
decimals: 0,
}),
);
assert.throws( assert.throws(
() => validate({ symbol: 'ABC', decimals: 0 }), () => validate({ symbol: 'ABC', decimals: 0 }),
'missing address should fail', 'missing address should fail',
@ -563,10 +571,19 @@ describe('preferences controller', function () {
() => () =>
validate({ validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: 'ABCDEFGHI', symbol: 'ABCDEFGHIJKLM',
decimals: 0,
}),
'long symbol should fail',
);
assert.throws(
() =>
validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: '',
decimals: 0, decimals: 0,
}), }),
'invalid symbol should fail', 'empty symbol should fail',
); );
assert.throws( assert.throws(
() => () =>

@ -8,12 +8,13 @@ import { calcTokenAmount } from '../../../ui/app/helpers/utils/token-util';
import { calcGasTotal } from '../../../ui/app/pages/send/send.utils'; import { calcGasTotal } from '../../../ui/app/pages/send/send.utils';
import { conversionUtil } from '../../../ui/app/helpers/utils/conversion-util'; import { conversionUtil } from '../../../ui/app/helpers/utils/conversion-util';
import { import {
ETH_SWAPS_TOKEN_OBJECT,
DEFAULT_ERC20_APPROVE_GAS, DEFAULT_ERC20_APPROVE_GAS,
QUOTES_EXPIRED_ERROR, QUOTES_EXPIRED_ERROR,
QUOTES_NOT_AVAILABLE_ERROR, QUOTES_NOT_AVAILABLE_ERROR,
SWAPS_FETCH_ORDER_CONFLICT, SWAPS_FETCH_ORDER_CONFLICT,
} from '../../../ui/app/helpers/constants/swaps'; } from '../../../shared/constants/swaps';
import { isSwapsDefaultTokenAddress } from '../../../shared/modules/swaps.utils';
import { import {
fetchTradesInfo as defaultFetchTradesInfo, fetchTradesInfo as defaultFetchTradesInfo,
fetchSwapsFeatureLiveness as defaultFetchSwapsFeatureLiveness, fetchSwapsFeatureLiveness as defaultFetchSwapsFeatureLiveness,
@ -85,6 +86,7 @@ export default class SwapsController {
fetchTradesInfo = defaultFetchTradesInfo, fetchTradesInfo = defaultFetchTradesInfo,
fetchSwapsFeatureLiveness = defaultFetchSwapsFeatureLiveness, fetchSwapsFeatureLiveness = defaultFetchSwapsFeatureLiveness,
fetchSwapsQuoteRefreshTime = defaultFetchSwapsQuoteRefreshTime, fetchSwapsQuoteRefreshTime = defaultFetchSwapsQuoteRefreshTime,
getCurrentChainId,
}) { }) {
this.store = new ObservableStore({ this.store = new ObservableStore({
swapsState: { ...initialState.swapsState }, swapsState: { ...initialState.swapsState },
@ -93,6 +95,7 @@ export default class SwapsController {
this._fetchTradesInfo = fetchTradesInfo; this._fetchTradesInfo = fetchTradesInfo;
this._fetchSwapsFeatureLiveness = fetchSwapsFeatureLiveness; this._fetchSwapsFeatureLiveness = fetchSwapsFeatureLiveness;
this._fetchSwapsQuoteRefreshTime = fetchSwapsQuoteRefreshTime; this._fetchSwapsQuoteRefreshTime = fetchSwapsQuoteRefreshTime;
this._getCurrentChainId = getCurrentChainId;
this.getBufferedGasLimit = getBufferedGasLimit; this.getBufferedGasLimit = getBufferedGasLimit;
this.tokenRatesStore = tokenRatesStore; this.tokenRatesStore = tokenRatesStore;
@ -116,10 +119,11 @@ export default class SwapsController {
// Sets the refresh rate for quote updates from the MetaSwap API // Sets the refresh rate for quote updates from the MetaSwap API
async _setSwapsQuoteRefreshTime() { async _setSwapsQuoteRefreshTime() {
const chainId = this._getCurrentChainId();
// Default to fallback time unless API returns valid response // Default to fallback time unless API returns valid response
let swapsQuoteRefreshTime = FALLBACK_QUOTE_REFRESH_TIME; let swapsQuoteRefreshTime = FALLBACK_QUOTE_REFRESH_TIME;
try { try {
swapsQuoteRefreshTime = await this._fetchSwapsQuoteRefreshTime(); swapsQuoteRefreshTime = await this._fetchSwapsQuoteRefreshTime(chainId);
} catch (e) { } catch (e) {
console.error('Request for swaps quote refresh time failed: ', e); console.error('Request for swaps quote refresh time failed: ', e);
} }
@ -158,6 +162,8 @@ export default class SwapsController {
fetchParamsMetaData = {}, fetchParamsMetaData = {},
isPolledRequest, isPolledRequest,
) { ) {
const { chainId } = fetchParamsMetaData;
if (!fetchParams) { if (!fetchParams) {
return null; return null;
} }
@ -177,7 +183,7 @@ export default class SwapsController {
this.indexOfNewestCallInFlight = indexOfCurrentCall; this.indexOfNewestCallInFlight = indexOfCurrentCall;
let [newQuotes] = await Promise.all([ let [newQuotes] = await Promise.all([
this._fetchTradesInfo(fetchParams), this._fetchTradesInfo(fetchParams, fetchParamsMetaData),
this._setSwapsQuoteRefreshTime(), this._setSwapsQuoteRefreshTime(),
]); ]);
@ -191,7 +197,7 @@ export default class SwapsController {
let approvalRequired = false; let approvalRequired = false;
if ( if (
fetchParams.sourceToken !== ETH_SWAPS_TOKEN_OBJECT.address && !isSwapsDefaultTokenAddress(fetchParams.sourceToken, chainId) &&
Object.values(newQuotes).length Object.values(newQuotes).length
) { ) {
const allowance = await this._getERC20Allowance( const allowance = await this._getERC20Allowance(
@ -490,6 +496,7 @@ export default class SwapsController {
const { const {
swapsState: { customGasPrice }, swapsState: { customGasPrice },
} = this.store.getState(); } = this.store.getState();
const chainId = this._getCurrentChainId();
const numQuotes = Object.keys(quotes).length; const numQuotes = Object.keys(quotes).length;
if (!numQuotes) { if (!numQuotes) {
@ -533,8 +540,8 @@ export default class SwapsController {
// trade.value is a sum of different values depending on the transaction. // trade.value is a sum of different values depending on the transaction.
// It always includes any external fees charged by the quote source. In // It always includes any external fees charged by the quote source. In
// addition, if the source asset is ETH, trade.value includes the amount // addition, if the source asset is the selected chain's default token, trade.value
// of swapped ETH. // includes the amount of that token.
const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16).plus( const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16).plus(
trade.value, trade.value,
16, 16,
@ -549,21 +556,21 @@ export default class SwapsController {
}); });
// The total fee is aggregator/exchange fees plus gas fees. // The total fee is aggregator/exchange fees plus gas fees.
// If the swap is from ETH, subtract the sourceAmount from the total cost. // If the swap is from the selected chain's default token, subtract
// Otherwise, the total fee is simply trade.value plus gas fees. // the sourceAmount from the total cost. Otherwise, the total fee
const ethFee = // is simply trade.value plus gas fees.
sourceToken === ETH_SWAPS_TOKEN_OBJECT.address const ethFee = isSwapsDefaultTokenAddress(sourceToken, chainId)
? conversionUtil( ? conversionUtil(
totalWeiCost.minus(sourceAmount, 10), // sourceAmount is in wei totalWeiCost.minus(sourceAmount, 10), // sourceAmount is in wei
{ {
fromCurrency: 'ETH', fromCurrency: 'ETH',
fromDenomination: 'WEI', fromDenomination: 'WEI',
toDenomination: 'ETH', toDenomination: 'ETH',
fromNumericBase: 'BN', fromNumericBase: 'BN',
numberOfDecimals: 6, numberOfDecimals: 6,
}, },
) )
: totalEthCost; : totalEthCost;
const decimalAdjustedDestinationAmount = calcTokenAmount( const decimalAdjustedDestinationAmount = calcTokenAmount(
destinationAmount, destinationAmount,
@ -588,10 +595,12 @@ export default class SwapsController {
10, 10,
); );
const conversionRateForCalculations = const conversionRateForCalculations = isSwapsDefaultTokenAddress(
destinationToken === ETH_SWAPS_TOKEN_OBJECT.address destinationToken,
? 1 chainId,
: tokenConversionRate; )
? 1
: tokenConversionRate;
const overallValueOfQuoteForSorting = const overallValueOfQuoteForSorting =
conversionRateForCalculations === undefined conversionRateForCalculations === undefined
@ -618,8 +627,10 @@ export default class SwapsController {
}); });
const isBest = const isBest =
newQuotes[topAggId].destinationToken === ETH_SWAPS_TOKEN_OBJECT.address || isSwapsDefaultTokenAddress(
Boolean(tokenConversionRates[newQuotes[topAggId]?.destinationToken]); newQuotes[topAggId].destinationToken,
chainId,
) || Boolean(tokenConversionRates[newQuotes[topAggId]?.destinationToken]);
let savings = null; let savings = null;
@ -726,13 +737,17 @@ export default class SwapsController {
async _fetchAndSetSwapsLiveness() { async _fetchAndSetSwapsLiveness() {
const { swapsState } = this.store.getState(); const { swapsState } = this.store.getState();
const { swapsFeatureIsLive: oldSwapsFeatureIsLive } = swapsState; const { swapsFeatureIsLive: oldSwapsFeatureIsLive } = swapsState;
const chainId = this._getCurrentChainId();
let swapsFeatureIsLive = false; let swapsFeatureIsLive = false;
let successfullyFetched = false; let successfullyFetched = false;
let numAttempts = 0; let numAttempts = 0;
const fetchAndIncrementNumAttempts = async () => { const fetchAndIncrementNumAttempts = async () => {
try { try {
swapsFeatureIsLive = Boolean(await this._fetchSwapsFeatureLiveness()); swapsFeatureIsLive = Boolean(
await this._fetchSwapsFeatureLiveness(chainId),
);
successfullyFetched = true; successfullyFetched = true;
} catch (err) { } catch (err) {
log.error(err); log.error(err);

@ -8,13 +8,12 @@ import { ObservableStore } from '@metamask/obs-store';
import { import {
ROPSTEN_NETWORK_ID, ROPSTEN_NETWORK_ID,
MAINNET_NETWORK_ID, MAINNET_NETWORK_ID,
} from '../../../../shared/constants/network'; MAINNET_CHAIN_ID,
import { ETH_SWAPS_TOKEN_OBJECT } from '../../../../ui/app/helpers/constants/swaps'; } from '../../../shared/constants/network';
import { createTestProviderTools } from '../../../stub/provider'; import { ETH_SWAPS_TOKEN_OBJECT } from '../../../shared/constants/swaps';
import SwapsController, { import { createTestProviderTools } from '../../../test/stub/provider';
utils, import SwapsController, { utils } from './swaps';
} from '../../../../app/scripts/controllers/swaps'; import { NETWORK_EVENTS } from './network';
import { NETWORK_EVENTS } from '../../../../app/scripts/controllers/network';
const MOCK_FETCH_PARAMS = { const MOCK_FETCH_PARAMS = {
slippage: 3, slippage: 3,
@ -77,6 +76,7 @@ const MOCK_FETCH_METADATA = {
symbol: 'FOO', symbol: 'FOO',
decimals: 18, decimals: 18,
}, },
chainId: MAINNET_CHAIN_ID,
}; };
const MOCK_TOKEN_RATES_STORE = new ObservableStore({ const MOCK_TOKEN_RATES_STORE = new ObservableStore({
@ -133,6 +133,8 @@ const sandbox = sinon.createSandbox();
const fetchTradesInfoStub = sandbox.stub(); const fetchTradesInfoStub = sandbox.stub();
const fetchSwapsFeatureLivenessStub = sandbox.stub(); const fetchSwapsFeatureLivenessStub = sandbox.stub();
const fetchSwapsQuoteRefreshTimeStub = sandbox.stub(); const fetchSwapsQuoteRefreshTimeStub = sandbox.stub();
const getCurrentChainIdStub = sandbox.stub();
getCurrentChainIdStub.returns(MAINNET_CHAIN_ID);
describe('SwapsController', function () { describe('SwapsController', function () {
let provider; let provider;
@ -147,6 +149,7 @@ describe('SwapsController', function () {
fetchTradesInfo: fetchTradesInfoStub, fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub, fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
fetchSwapsQuoteRefreshTime: fetchSwapsQuoteRefreshTimeStub, fetchSwapsQuoteRefreshTime: fetchSwapsQuoteRefreshTimeStub,
getCurrentChainId: getCurrentChainIdStub,
}); });
}; };
@ -196,6 +199,7 @@ describe('SwapsController', function () {
tokenRatesStore: MOCK_TOKEN_RATES_STORE, tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub, fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub, fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
getCurrentChainId: getCurrentChainIdStub,
}); });
const currentEthersInstance = swapsController.ethersProvider; const currentEthersInstance = swapsController.ethersProvider;
const onNetworkDidChange = networkController.on.getCall(0).args[1]; const onNetworkDidChange = networkController.on.getCall(0).args[1];
@ -220,6 +224,7 @@ describe('SwapsController', function () {
tokenRatesStore: MOCK_TOKEN_RATES_STORE, tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub, fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub, fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
getCurrentChainId: getCurrentChainIdStub,
}); });
const currentEthersInstance = swapsController.ethersProvider; const currentEthersInstance = swapsController.ethersProvider;
const onNetworkDidChange = networkController.on.getCall(0).args[1]; const onNetworkDidChange = networkController.on.getCall(0).args[1];
@ -244,6 +249,7 @@ describe('SwapsController', function () {
tokenRatesStore: MOCK_TOKEN_RATES_STORE, tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub, fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub, fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
getCurrentChainId: getCurrentChainIdStub,
}); });
const currentEthersInstance = swapsController.ethersProvider; const currentEthersInstance = swapsController.ethersProvider;
const onNetworkDidChange = networkController.on.getCall(0).args[1]; const onNetworkDidChange = networkController.on.getCall(0).args[1];
@ -688,7 +694,10 @@ describe('SwapsController', function () {
}); });
assert.strictEqual( assert.strictEqual(
fetchTradesInfoStub.calledOnceWithExactly(MOCK_FETCH_PARAMS), fetchTradesInfoStub.calledOnceWithExactly(
MOCK_FETCH_PARAMS,
MOCK_FETCH_METADATA,
),
true, true,
); );
}); });

@ -1,7 +1,7 @@
import assert from 'assert'; import assert from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import { ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import TokenRatesController from '../../../../app/scripts/controllers/token-rates'; import TokenRatesController from './token-rates';
describe('TokenRatesController', function () { describe('TokenRatesController', function () {
let nativeCurrency; let nativeCurrency;

@ -19,7 +19,6 @@ import {
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys'; import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys';
import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/app/pages/swaps/swaps.util'; import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/app/pages/swaps/swaps.util';
import { import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES, TRANSACTION_STATUSES,
TRANSACTION_TYPES, TRANSACTION_TYPES,
} from '../../../../shared/constants/transaction'; } from '../../../../shared/constants/transaction';
@ -235,11 +234,10 @@ export default class TransactionController extends EventEmitter {
`generateTxMeta` adds the default txMeta properties to the passed object. `generateTxMeta` adds the default txMeta properties to the passed object.
These include the tx's `id`. As we use the id for determining order of These include the tx's `id`. As we use the id for determining order of
txes in the tx-state-manager, it is necessary to call the asynchronous txes in the tx-state-manager, it is necessary to call the asynchronous
method `this._determineTransactionCategory` after `generateTxMeta`. method `this._determineTransactionType` after `generateTxMeta`.
*/ */
let txMeta = this.txStateManager.generateTxMeta({ let txMeta = this.txStateManager.generateTxMeta({
txParams: normalizedTxParams, txParams: normalizedTxParams,
type: TRANSACTION_TYPES.STANDARD,
}); });
if (origin === 'metamask') { if (origin === 'metamask') {
@ -265,11 +263,10 @@ export default class TransactionController extends EventEmitter {
txMeta.origin = origin; txMeta.origin = origin;
const { const { type, getCodeResponse } = await this._determineTransactionType(
transactionCategory, txParams,
getCodeResponse, );
} = await this._determineTransactionCategory(txParams); txMeta.type = type;
txMeta.transactionCategory = transactionCategory;
// ensure value // ensure value
txMeta.txParams.value = txMeta.txParams.value txMeta.txParams.value = txMeta.txParams.value
@ -347,7 +344,7 @@ export default class TransactionController extends EventEmitter {
return {}; return {};
} else if ( } else if (
txMeta.txParams.to && txMeta.txParams.to &&
txMeta.transactionCategory === TRANSACTION_CATEGORIES.SENT_ETHER txMeta.type === TRANSACTION_TYPES.SENT_ETHER
) { ) {
// if there's data in the params, but there's no contract code, it's not a valid transaction // if there's data in the params, but there's no contract code, it's not a valid transaction
if (txMeta.txParams.data) { if (txMeta.txParams.data) {
@ -388,7 +385,7 @@ export default class TransactionController extends EventEmitter {
* @param {string} [customGasPrice] - the hex value to use for the cancel transaction * @param {string} [customGasPrice] - the hex value to use for the cancel transaction
* @returns {txMeta} * @returns {txMeta}
*/ */
async createCancelTransaction(originalTxId, customGasPrice) { async createCancelTransaction(originalTxId, customGasPrice, customGasLimit) {
const originalTxMeta = this.txStateManager.getTx(originalTxId); const originalTxMeta = this.txStateManager.getTx(originalTxId);
const { txParams } = originalTxMeta; const { txParams } = originalTxMeta;
const { gasPrice: lastGasPrice, from, nonce } = txParams; const { gasPrice: lastGasPrice, from, nonce } = txParams;
@ -401,7 +398,7 @@ export default class TransactionController extends EventEmitter {
from, from,
to: from, to: from,
nonce, nonce,
gas: '0x5208', gas: customGasLimit || '0x5208',
value: '0x0', value: '0x0',
gasPrice: newGasPrice, gasPrice: newGasPrice,
}, },
@ -581,7 +578,7 @@ export default class TransactionController extends EventEmitter {
async publishTransaction(txId, rawTx) { async publishTransaction(txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId); const txMeta = this.txStateManager.getTx(txId);
txMeta.rawTx = rawTx; txMeta.rawTx = rawTx;
if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) { if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const preTxBalance = await this.query.getBalance(txMeta.txParams.from); const preTxBalance = await this.query.getBalance(txMeta.txParams.from);
txMeta.preTxBalance = preTxBalance.toString(16); txMeta.preTxBalance = preTxBalance.toString(16);
} }
@ -637,7 +634,7 @@ export default class TransactionController extends EventEmitter {
'transactions#confirmTransaction - add txReceipt', 'transactions#confirmTransaction - add txReceipt',
); );
if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) { if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const postTxBalance = await this.query.getBalance(txMeta.txParams.from); const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
const latestTxMeta = this.txStateManager.getTx(txId); const latestTxMeta = this.txStateManager.getTx(txId);
@ -812,10 +809,27 @@ export default class TransactionController extends EventEmitter {
} }
/** /**
Returns a "type" for a transaction out of the following list: simpleSend, tokenTransfer, tokenApprove, * @typedef { 'transfer' | 'approve' | 'transferfrom' | 'contractInteraction'| 'sentEther' } InferrableTransactionTypes
contractDeployment, contractMethodCall */
*/
async _determineTransactionCategory(txParams) { /**
* @typedef {Object} InferTransactionTypeResult
* @property {InferrableTransactionTypes} type - The type of transaction
* @property {string} getCodeResponse - The contract code, in hex format if
* it exists. '0x0' or '0x' are also indicators of non-existent contract
* code
*/
/**
* Determines the type of the transaction by analyzing the txParams.
* This method will return one of the types defined in shared/constants/transactions
* It will never return TRANSACTION_TYPE_CANCEL or TRANSACTION_TYPE_RETRY as these
* represent specific events that we control from the extension and are added manually
* at transaction creation.
* @param {Object} txParams - Parameters for the transaction
* @returns {InferTransactionTypeResult}
*/
async _determineTransactionType(txParams) {
const { data, to } = txParams; const { data, to } = txParams;
let name; let name;
try { try {
@ -825,16 +839,16 @@ export default class TransactionController extends EventEmitter {
} }
const tokenMethodName = [ const tokenMethodName = [
TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE, TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER, TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER_FROM, TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
].find((methodName) => methodName === name && name.toLowerCase()); ].find((methodName) => methodName === name && name.toLowerCase());
let result; let result;
if (data && tokenMethodName) { if (data && tokenMethodName) {
result = tokenMethodName; result = tokenMethodName;
} else if (data && !to) { } else if (data && !to) {
result = TRANSACTION_CATEGORIES.DEPLOY_CONTRACT; result = TRANSACTION_TYPES.DEPLOY_CONTRACT;
} }
let code; let code;
@ -849,11 +863,11 @@ export default class TransactionController extends EventEmitter {
const codeIsEmpty = !code || code === '0x' || code === '0x0'; const codeIsEmpty = !code || code === '0x' || code === '0x0';
result = codeIsEmpty result = codeIsEmpty
? TRANSACTION_CATEGORIES.SENT_ETHER ? TRANSACTION_TYPES.SENT_ETHER
: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION; : TRANSACTION_TYPES.CONTRACT_INTERACTION;
} }
return { transactionCategory: result, getCodeResponse: code }; return { type: result, getCodeResponse: code };
} }
/** /**
@ -944,6 +958,7 @@ export default class TransactionController extends EventEmitter {
txMeta.txParams.from, txMeta.txParams.from,
txMeta.destinationTokenDecimals, txMeta.destinationTokenDecimals,
approvalTxMeta, approvalTxMeta,
txMeta.chainId,
); );
const quoteVsExecutionRatio = `${new BigNumber(tokensReceived, 10) const quoteVsExecutionRatio = `${new BigNumber(tokensReceived, 10)

@ -4,18 +4,17 @@ import ethUtil from 'ethereumjs-util';
import EthTx from 'ethereumjs-tx'; import EthTx from 'ethereumjs-tx';
import { ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import sinon from 'sinon'; import sinon from 'sinon';
import TransactionController from '../../../../../app/scripts/controllers/transactions';
import { import {
createTestProviderTools, createTestProviderTools,
getTestAccounts, getTestAccounts,
} from '../../../../stub/provider'; } from '../../../../test/stub/provider';
import { import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES, TRANSACTION_STATUSES,
TRANSACTION_TYPES, TRANSACTION_TYPES,
} from '../../../../../shared/constants/transaction'; } from '../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../../../../app/scripts/metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import TransactionController from '.';
const noop = () => true; const noop = () => true;
const currentNetworkId = '42'; const currentNetworkId = '42';
@ -776,76 +775,76 @@ describe('Transaction Controller', function () {
}); });
}); });
describe('#_determineTransactionCategory', function () { describe('#_determineTransactionType', function () {
it('should return a simple send transactionCategory when to is truthy but data is falsy', async function () { it('should return a simple send type when to is truthy but data is falsy', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '0xabc', to: '0xabc',
data: '', data: '',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: null, getCodeResponse: null,
}); });
}); });
it('should return a token transfer transactionCategory when data is for the respective method call', async function () { it('should return a token transfer type when data is for the respective method call', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '0xabc', to: '0xabc',
data: data:
'0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER, type: TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
getCodeResponse: undefined, getCodeResponse: undefined,
}); });
}); });
it('should return a token approve transactionCategory when data is for the respective method call', async function () { it('should return a token approve type when data is for the respective method call', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '0xabc', to: '0xabc',
data: data:
'0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE, type: TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
getCodeResponse: undefined, getCodeResponse: undefined,
}); });
}); });
it('should return a contract deployment transactionCategory when to is falsy and there is data', async function () { it('should return a contract deployment type when to is falsy and there is data', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '', to: '',
data: '0xabd', data: '0xabd',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.DEPLOY_CONTRACT, type: TRANSACTION_TYPES.DEPLOY_CONTRACT,
getCodeResponse: undefined, getCodeResponse: undefined,
}); });
}); });
it('should return a simple send transactionCategory with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () { it('should return a simple send type with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: '0xabd', data: '0xabd',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: '0x', getCodeResponse: '0x',
}); });
}); });
it('should return a simple send transactionCategory with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () { it('should return a simple send type with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () {
const result = await txController._determineTransactionCategory({ const result = await txController._determineTransactionType({
to: '0xabc', to: '0xabc',
data: '0xabd', data: '0xabd',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: null, getCodeResponse: null,
}); });
}); });
it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () { it('should return a contract interaction type with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () {
const _providerResultStub = { const _providerResultStub = {
// 1 gwei // 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000', eth_gasPrice: '0x0de0b6b3a7640000',
@ -875,17 +874,17 @@ describe('Transaction Controller', function () {
}), }),
getParticipateInMetrics: () => false, getParticipateInMetrics: () => false,
}); });
const result = await _txController._determineTransactionCategory({ const result = await _txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: 'abd', data: 'abd',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION, type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
getCodeResponse: '0x0a', getCodeResponse: '0x0a',
}); });
}); });
it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is a contract address and data is falsy', async function () { it('should return a contract interaction type with the correct getCodeResponse when to is a contract address and data is falsy', async function () {
const _providerResultStub = { const _providerResultStub = {
// 1 gwei // 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000', eth_gasPrice: '0x0de0b6b3a7640000',
@ -915,12 +914,12 @@ describe('Transaction Controller', function () {
}), }),
getParticipateInMetrics: () => false, getParticipateInMetrics: () => false,
}); });
const result = await _txController._determineTransactionCategory({ const result = await _txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: '', data: '',
}); });
assert.deepEqual(result, { assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION, type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
getCodeResponse: '0x0a', getCodeResponse: '0x0a',
}); });
}); });

@ -1,11 +1,11 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import testData from '../../../../../test/data/mock-tx-history.json';
import { import {
snapshotFromTxMeta, snapshotFromTxMeta,
migrateFromSnapshotsToDiffs, migrateFromSnapshotsToDiffs,
replayHistory, replayHistory,
generateHistoryEntry, generateHistoryEntry,
} from '../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helpers'; } from './tx-state-history-helpers';
import testData from '../../../../data/mock-tx-history.json';
describe('Transaction state history helper', function () { describe('Transaction state history helper', function () {
describe('#snapshotFromTxMeta', function () { describe('#snapshotFromTxMeta', function () {

@ -1,5 +1,5 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import * as txUtils from '../../../../../app/scripts/controllers/transactions/lib/util'; import * as txUtils from './util';
describe('txUtils', function () { describe('txUtils', function () {
describe('#validateTxParams', function () { describe('#validateTxParams', function () {

@ -1,8 +1,8 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import BN from 'bn.js'; import BN from 'bn.js';
import PendingTransactionTracker from '../../../../../app/scripts/controllers/transactions/pending-tx-tracker'; import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction'; import PendingTransactionTracker from './pending-tx-tracker';
describe('PendingTransactionTracker', function () { describe('PendingTransactionTracker', function () {
describe('#resubmitPendingTxs', function () { describe('#resubmitPendingTxs', function () {

@ -1,7 +1,7 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import Transaction from 'ethereumjs-tx'; import Transaction from 'ethereumjs-tx';
import { hexToBn, bnToHex } from '../../../../../app/scripts/lib/util'; import { hexToBn, bnToHex } from '../../lib/util';
import TxUtils from '../../../../../app/scripts/controllers/transactions/tx-gas-utils'; import TxUtils from './tx-gas-utils';
describe('txUtils', function () { describe('txUtils', function () {
let txUtils; let txUtils;

@ -1,7 +1,7 @@
import EventEmitter from 'safe-event-emitter'; import EventEmitter from 'safe-event-emitter';
import { ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel'; import log from 'loglevel';
import createId from '../../lib/random-id'; import createId from '../../../../shared/modules/random-id';
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction'; import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import { transactionMatchesNetwork } from '../../../../shared/modules/transaction.utils'; import { transactionMatchesNetwork } from '../../../../shared/modules/transaction.utils';

@ -1,12 +1,12 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import sinon from 'sinon'; import sinon from 'sinon';
import TxStateManager from '../../../../../app/scripts/controllers/transactions/tx-state-manager'; import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
import { snapshotFromTxMeta } from '../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helpers';
import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction';
import { import {
KOVAN_CHAIN_ID, KOVAN_CHAIN_ID,
KOVAN_NETWORK_ID, KOVAN_NETWORK_ID,
} from '../../../../../shared/constants/network'; } from '../../../../shared/constants/network';
import TxStateManager from './tx-state-manager';
import { snapshotFromTxMeta } from './lib/tx-state-history-helpers';
const noop = () => true; const noop = () => true;

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import { ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import ComposableObservableStore from '../../../app/scripts/lib/ComposableObservableStore'; import ComposableObservableStore from './ComposableObservableStore';
describe('ComposableObservableStore', function () { describe('ComposableObservableStore', function () {
it('should register initial state', function () { it('should register initial state', function () {

@ -1,18 +1,26 @@
import {
GOERLI_CHAIN_ID,
KOVAN_CHAIN_ID,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
/** /**
* Gives the caller a url at which the user can acquire eth, depending on the network they are in * Gives the caller a url at which the user can acquire eth, depending on the network they are in
* *
* @param {Object} opts - Options required to determine the correct url * @param {Object} opts - Options required to determine the correct url
* @param {string} opts.network - The network for which to return a url * @param {string} opts.chainId - The chainId for which to return a url
* @param {string} opts.address - The address the bought ETH should be sent to. Only relevant if network === '1'. * @param {string} opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'.
* @returns {string|undefined} The url at which the user can access ETH, while in the given network. If the passed * @returns {string|undefined} The url at which the user can access ETH, while in the given chain. If the passed
* network does not match any of the specified cases, or if no network is given, returns undefined. * chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
* *
*/ */
export default function getBuyEthUrl({ network, address, service }) { export default function getBuyEthUrl({ chainId, address, service }) {
// default service by network if not specified // default service by network if not specified
if (!service) { if (!service) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
service = getDefaultServiceForNetwork(network); service = getDefaultServiceForChain(chainId);
} }
switch (service) { switch (service) {
@ -33,21 +41,21 @@ export default function getBuyEthUrl({ network, address, service }) {
} }
} }
function getDefaultServiceForNetwork(network) { function getDefaultServiceForChain(chainId) {
switch (network) { switch (chainId) {
case '1': case MAINNET_CHAIN_ID:
return 'wyre'; return 'wyre';
case '3': case ROPSTEN_CHAIN_ID:
return 'metamask-faucet'; return 'metamask-faucet';
case '4': case RINKEBY_CHAIN_ID:
return 'rinkeby-faucet'; return 'rinkeby-faucet';
case '42': case KOVAN_CHAIN_ID:
return 'kovan-faucet'; return 'kovan-faucet';
case '5': case GOERLI_CHAIN_ID:
return 'goerli-faucet'; return 'goerli-faucet';
default: default:
throw new Error( throw new Error(
`No default cryptocurrency exchange or faucet for networkId: "${network}"`, `No default cryptocurrency exchange or faucet for chainId: "${chainId}"`,
); );
} }
} }

@ -1,20 +1,26 @@
import assert from 'assert'; import assert from 'assert';
import getBuyEthUrl from '../../../app/scripts/lib/buy-eth-url'; import {
KOVAN_CHAIN_ID,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import getBuyEthUrl from './buy-eth-url';
describe('buy-eth-url', function () { describe('buy-eth-url', function () {
const mainnet = { const mainnet = {
network: '1', chainId: MAINNET_CHAIN_ID,
amount: 5, amount: 5,
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
}; };
const ropsten = { const ropsten = {
network: '3', chainId: ROPSTEN_CHAIN_ID,
}; };
const rinkeby = { const rinkeby = {
network: '4', chainId: RINKEBY_CHAIN_ID,
}; };
const kovan = { const kovan = {
network: '42', chainId: KOVAN_CHAIN_ID,
}; };
it('returns wyre url with address for network 1', function () { it('returns wyre url with address for network 1', function () {

@ -1,5 +1,5 @@
import assert from 'assert'; import assert from 'assert';
import cleanErrorStack from '../../../app/scripts/lib/cleanErrorStack'; import cleanErrorStack from './cleanErrorStack';
describe('Clean Error Stack', function () { describe('Clean Error Stack', function () {
const testMessage = 'Test Message'; const testMessage = 'Test Message';

@ -0,0 +1,33 @@
import { ethErrors, serializeError } from 'eth-rpc-errors';
const createMetaRPCHandler = (api, outStream) => {
return (data) => {
if (!api[data.method]) {
outStream.write({
jsonrpc: '2.0',
error: ethErrors.rpc.methodNotFound({
message: `${data.method} not found`,
}),
id: data.id,
});
return;
}
api[data.method](...data.params, (err, result) => {
if (err) {
outStream.write({
jsonrpc: '2.0',
error: serializeError(err, { shouldIncludeStack: true }),
id: data.id,
});
} else {
outStream.write({
jsonrpc: '2.0',
result,
id: data.id,
});
}
});
};
};
export default createMetaRPCHandler;

@ -0,0 +1,61 @@
import assert from 'assert';
import { obj as createThoughStream } from 'through2';
import createMetaRPCHandler from './createMetaRPCHandler';
describe('createMetaRPCHandler', function () {
it('can call the api when handler receives a JSON-RPC request', function (done) {
const api = {
foo: (param1) => {
assert.strictEqual(param1, 'bar');
done();
},
};
const streamTest = createThoughStream();
const handler = createMetaRPCHandler(api, streamTest);
handler({
id: 1,
method: 'foo',
params: ['bar'],
});
});
it('can write the response to the outstream when api callback is called', function (done) {
const api = {
foo: (param1, cb) => {
assert.strictEqual(param1, 'bar');
cb(null, 'foobarbaz');
},
};
const streamTest = createThoughStream();
const handler = createMetaRPCHandler(api, streamTest);
handler({
id: 1,
method: 'foo',
params: ['bar'],
});
streamTest.on('data', (data) => {
assert.strictEqual(data.result, 'foobarbaz');
streamTest.end();
done();
});
});
it('can write the error to the outstream when api callback is called with an error', function (done) {
const api = {
foo: (param1, cb) => {
assert.strictEqual(param1, 'bar');
cb(new Error('foo-error'));
},
};
const streamTest = createThoughStream();
const handler = createMetaRPCHandler(api, streamTest);
handler({
id: 1,
method: 'foo',
params: ['bar'],
});
streamTest.on('data', (data) => {
assert.strictEqual(data.error.message, 'foo-error');
streamTest.end();
done();
});
});
});

@ -5,8 +5,8 @@ import { ethErrors } from 'eth-rpc-errors';
import log from 'loglevel'; import log from 'loglevel';
import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
import createId from '../../../shared/modules/random-id';
import { addHexPrefix } from './util'; import { addHexPrefix } from './util';
import createId from './random-id';
const hexRe = /^[0-9A-Fa-f]+$/gu; const hexRe = /^[0-9A-Fa-f]+$/gu;

@ -4,7 +4,7 @@ import { ethErrors } from 'eth-rpc-errors';
import log from 'loglevel'; import log from 'loglevel';
import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
import createId from './random-id'; import createId from '../../../shared/modules/random-id';
/** /**
* Represents, and contains data about, an 'eth_getEncryptionPublicKey' type request. These are created when * Represents, and contains data about, an 'eth_getEncryptionPublicKey' type request. These are created when

@ -4,7 +4,7 @@ import ethUtil from 'ethereumjs-util';
import { ethErrors } from 'eth-rpc-errors'; import { ethErrors } from 'eth-rpc-errors';
import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
import createId from './random-id'; import createId from '../../../shared/modules/random-id';
/** /**
* Represents, and contains data about, an 'eth_sign' type signature request. These are created when a signature for * Represents, and contains data about, an 'eth_sign' type signature request. These are created when a signature for

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import MessageManager from '../../../app/scripts/lib/message-manager';
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction'; import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
import MessageManager from './message-manager';
describe('Message Manager', function () { describe('Message Manager', function () {
let messageManager; let messageManager;

@ -0,0 +1,81 @@
import { EthereumRpcError } from 'eth-rpc-errors';
import SafeEventEmitter from 'safe-event-emitter';
import createRandomId from '../../../shared/modules/random-id';
class MetaRPCClient {
constructor(connectionStream) {
this.connectionStream = connectionStream;
this.notificationChannel = new SafeEventEmitter();
this.requests = new Map();
this.connectionStream.on('data', this.handleResponse.bind(this));
this.connectionStream.on('end', this.close.bind(this));
}
onNotification(handler) {
this.notificationChannel.addListener('notification', (data) => {
handler(data);
});
}
close() {
this.notificationChannel.removeAllListeners();
}
handleResponse(data) {
const { id, result, error, method, params } = data;
const cb = this.requests.get(id);
if (method && params && id) {
// dont handle server-side to client-side requests
return;
}
if (method && params && !id) {
// handle servier-side to client-side notification
this.notificationChannel.emit('notification', data);
return;
}
if (!cb) {
// not found in request list
return;
}
if (error) {
const e = new EthereumRpcError(error.code, error.message, error.data);
// preserve the stack from serializeError
e.stack = error.stack;
this.requests.delete(id);
cb(e);
return;
}
this.requests.delete(id);
cb(null, result);
}
}
const metaRPCClientFactory = (connectionStream) => {
const metaRPCClient = new MetaRPCClient(connectionStream);
return new Proxy(metaRPCClient, {
get: (object, property) => {
if (object[property]) {
return object[property];
}
return (...p) => {
const cb = p[p.length - 1];
const params = p.slice(0, -1);
const id = createRandomId();
object.requests.set(id, cb);
object.connectionStream.write({
jsonrpc: '2.0',
method: property,
params,
id,
});
};
},
});
};
export default metaRPCClientFactory;

@ -0,0 +1,88 @@
import assert from 'assert';
import { obj as createThoughStream } from 'through2';
import metaRPCClientFactory from './metaRPCClientFactory';
describe('metaRPCClientFactory', function () {
it('should be able to make an rpc request with the method', function (done) {
const streamTest = createThoughStream((chunk) => {
assert.strictEqual(chunk.method, 'foo');
done();
});
const metaRPCClient = metaRPCClientFactory(streamTest);
metaRPCClient.foo();
});
it('should be able to make an rpc request/response with the method and params and node-style callback', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
// make a "foo" method call
metaRPCClient.foo('bar', (_, result) => {
assert.strictEqual(result, 'foobarbaz');
done();
});
// fake a response
metaRPCClient.requests.forEach((_, key) => {
streamTest.write({
jsonrpc: '2.0',
id: key,
result: 'foobarbaz',
});
});
});
it('should be able to make an rpc request/error with the method and params and node-style callback', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
// make a "foo" method call
metaRPCClient.foo('bar', (err) => {
assert.strictEqual(err.message, 'foo-message');
assert.strictEqual(err.code, 1);
done();
});
metaRPCClient.requests.forEach((_, key) => {
streamTest.write({
jsonrpc: '2.0',
id: key,
error: {
code: 1,
message: 'foo-message',
},
});
});
});
it('should be able to make an rpc request/response with the method and params and node-style callback with multiple instances of metaRPCClientFactory and the same connectionStream', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
const metaRPCClient2 = metaRPCClientFactory(streamTest);
// make a "foo" method call, followed by "baz" call on metaRPCClient2
metaRPCClient.foo('bar', (_, result) => {
assert.strictEqual(result, 'foobarbaz');
metaRPCClient2.baz('bar', (err) => {
assert.strictEqual(err, null);
done();
});
});
// fake a response
metaRPCClient.requests.forEach((_, key) => {
streamTest.write({
jsonrpc: '2.0',
id: key,
result: 'foobarbaz',
});
});
// fake client2's response
metaRPCClient2.requests.forEach((_, key) => {
streamTest.write({
jsonrpc: '2.0',
id: key,
result: 'foobarbaz',
});
});
});
});

@ -1,9 +1,9 @@
import fs from 'fs'; import fs from 'fs';
import assert from 'assert'; import assert from 'assert';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import Migrator from '../../../app/scripts/lib/migrator'; import liveMigrations from '../../migrations';
import liveMigrations from '../../../app/scripts/migrations'; import data from '../../first-time-state';
import data from '../../../app/scripts/first-time-state'; import Migrator from '.';
const stubMigrations = [ const stubMigrations = [
{ {
@ -67,7 +67,7 @@ describe('migrations', function () {
}); });
it('should have tests for all migrations', function () { it('should have tests for all migrations', function () {
const fileNames = fs.readdirSync('./test/unit/migrations/'); const fileNames = fs.readdirSync('./app/scripts/migrations/');
const testNumbers = fileNames const testNumbers = fileNames
.reduce((acc, filename) => { .reduce((acc, filename) => {
const name = filename.split('.test.')[0]; const name = filename.split('.test.')[0];

@ -1,5 +1,5 @@
import assert from 'assert'; import assert from 'assert';
import nodeify from '../../../app/scripts/lib/nodeify'; import nodeify from './nodeify';
describe('nodeify', function () { describe('nodeify', function () {
const obj = { const obj = {

@ -5,8 +5,8 @@ import { ethErrors } from 'eth-rpc-errors';
import log from 'loglevel'; import log from 'loglevel';
import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
import createId from '../../../shared/modules/random-id';
import { addHexPrefix } from './util'; import { addHexPrefix } from './util';
import createId from './random-id';
const hexRe = /^[0-9A-Fa-f]+$/gu; const hexRe = /^[0-9A-Fa-f]+$/gu;

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import PersonalMessageManager from '../../../app/scripts/lib/personal-message-manager';
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction'; import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
import PersonalMessageManager from './personal-message-manager';
describe('Personal Message Manager', function () { describe('Personal Message Manager', function () {
let messageManager; let messageManager;

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

Loading…
Cancel
Save