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

feature/default_network_editable
ryanml 3 years ago
commit b4f27d8916
  1. 10
      .circleci/config.yml
  2. 3
      .circleci/scripts/chrome-install.sh
  3. 8
      .eslintrc.js
  4. 5
      .storybook/test-data.js
  5. 2
      README.md
  6. 6
      app/_locales/am/messages.json
  7. 6
      app/_locales/ar/messages.json
  8. 6
      app/_locales/bg/messages.json
  9. 6
      app/_locales/bn/messages.json
  10. 6
      app/_locales/ca/messages.json
  11. 6
      app/_locales/cs/messages.json
  12. 6
      app/_locales/da/messages.json
  13. 6
      app/_locales/de/messages.json
  14. 6
      app/_locales/el/messages.json
  15. 66
      app/_locales/en/messages.json
  16. 176
      app/_locales/es/messages.json
  17. 130
      app/_locales/es_419/messages.json
  18. 6
      app/_locales/et/messages.json
  19. 6
      app/_locales/fa/messages.json
  20. 6
      app/_locales/fi/messages.json
  21. 6
      app/_locales/fil/messages.json
  22. 6
      app/_locales/fr/messages.json
  23. 6
      app/_locales/he/messages.json
  24. 123
      app/_locales/hi/messages.json
  25. 6
      app/_locales/hn/messages.json
  26. 6
      app/_locales/hr/messages.json
  27. 6
      app/_locales/ht/messages.json
  28. 6
      app/_locales/hu/messages.json
  29. 123
      app/_locales/id/messages.json
  30. 6
      app/_locales/it/messages.json
  31. 130
      app/_locales/ja/messages.json
  32. 6
      app/_locales/kn/messages.json
  33. 399
      app/_locales/ko/messages.json
  34. 6
      app/_locales/lt/messages.json
  35. 6
      app/_locales/lv/messages.json
  36. 6
      app/_locales/ms/messages.json
  37. 6
      app/_locales/nl/messages.json
  38. 6
      app/_locales/no/messages.json
  39. 93
      app/_locales/ph/messages.json
  40. 6
      app/_locales/pl/messages.json
  41. 6
      app/_locales/pt/messages.json
  42. 141
      app/_locales/pt_BR/messages.json
  43. 6
      app/_locales/ro/messages.json
  44. 125
      app/_locales/ru/messages.json
  45. 6
      app/_locales/sk/messages.json
  46. 6
      app/_locales/sl/messages.json
  47. 6
      app/_locales/sr/messages.json
  48. 6
      app/_locales/sv/messages.json
  49. 6
      app/_locales/sw/messages.json
  50. 6
      app/_locales/ta/messages.json
  51. 6
      app/_locales/th/messages.json
  52. 6
      app/_locales/tl/messages.json
  53. 6
      app/_locales/tr/messages.json
  54. 6
      app/_locales/uk/messages.json
  55. 131
      app/_locales/vi/messages.json
  56. 6
      app/_locales/zh_CN/messages.json
  57. 6
      app/_locales/zh_TW/messages.json
  58. BIN
      app/images/logo.png
  59. 112
      app/images/transak.svg
  60. 1
      app/scripts/constants/on-ramp.js
  61. 18
      app/scripts/controllers/detect-tokens.test.js
  62. 34
      app/scripts/controllers/incoming-transactions.js
  63. 120
      app/scripts/controllers/incoming-transactions.test.js
  64. 38
      app/scripts/controllers/metametrics.js
  65. 65
      app/scripts/controllers/metametrics.test.js
  66. 71
      app/scripts/controllers/network/network-controller.test.js
  67. 83
      app/scripts/controllers/network/network.js
  68. 93
      app/scripts/controllers/preferences.js
  69. 146
      app/scripts/controllers/preferences.test.js
  70. 203
      app/scripts/controllers/transactions/index.js
  71. 242
      app/scripts/controllers/transactions/index.test.js
  72. 13
      app/scripts/controllers/transactions/tx-gas-utils.test.js
  73. 57
      app/scripts/lib/buy-eth-url.js
  74. 75
      app/scripts/lib/buy-eth-url.test.js
  75. 1
      app/scripts/lib/setupSentry.js
  76. 11
      app/scripts/lib/typed-message-manager.js
  77. 35
      app/scripts/lib/util.js
  78. 40
      app/scripts/lib/util.test.js
  79. 31
      app/scripts/metamask-controller.js
  80. 5
      app/scripts/metamask-controller.test.js
  81. 28
      app/scripts/migrations/062.js
  82. 80
      app/scripts/migrations/062.test.js
  83. 1
      app/scripts/migrations/index.js
  84. 3
      development/build/scripts.js
  85. 2
      development/build/static.js
  86. 16
      development/lib/exit-with-error.js
  87. 23
      development/lib/retry.js
  88. 8
      jest.config.js
  89. 28
      package.json
  90. 19
      patches/selenium-webdriver+4.0.0-alpha.7.patch
  91. 108
      test/e2e/benchmark.js
  92. 1
      test/e2e/fixtures/address-entry/state.json
  93. 1
      test/e2e/fixtures/connected-state/state.json
  94. 1
      test/e2e/fixtures/custom-rpc/state.json
  95. 1
      test/e2e/fixtures/custom-token/state.json
  96. 3
      test/e2e/fixtures/import-ui/state.json
  97. 1
      test/e2e/fixtures/imported-account/state.json
  98. 1
      test/e2e/fixtures/localization/state.json
  99. 1
      test/e2e/fixtures/metrics-enabled/state.json
  100. 1
      test/e2e/fixtures/send-edit/state.json
  101. Some files were not shown because too many files have changed in this diff Show More

@ -343,7 +343,7 @@ jobs:
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:chrome
yarn test:e2e:chrome --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
@ -370,7 +370,7 @@ jobs:
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:chrome:metrics
yarn test:e2e:chrome:metrics --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
@ -397,7 +397,7 @@ jobs:
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:firefox
yarn test:e2e:firefox --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
@ -424,7 +424,7 @@ jobs:
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:firefox:metrics
yarn test:e2e:firefox:metrics --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
@ -448,7 +448,7 @@ jobs:
command: mv ./builds-test ./builds
- run:
name: Run page load benchmark
command: yarn benchmark:chrome --out test-artifacts/chrome/benchmark/pageload.json
command: yarn benchmark:chrome --out test-artifacts/chrome/benchmark/pageload.json --retries 2
- store_artifacts:
path: test-artifacts
destination: test-artifacts

@ -14,7 +14,10 @@ wget -O "${CHROME_BINARY}" -t 5 "${CHROME_BINARY_URL}"
if [[ $(shasum -a 512 "${CHROME_BINARY}" | cut '--delimiter= ' -f1) != "${CHROME_BINARY_SHA512SUM}" ]]
then
echo "Google Chrome binary checksum did not match."
exit 1
else
echo "Google Chrome binary checksum verified."
fi
(sudo dpkg -i "${CHROME_BINARY}" || sudo apt-get -fy install)

@ -108,7 +108,11 @@ module.exports = {
},
{
files: ['**/*.test.js'],
excludedFiles: ['ui/**/*.test.js', 'ui/__mocks__/*.js'],
excludedFiles: [
'ui/**/*.test.js',
'ui/__mocks__/*.js',
'shared/**/*.test.js',
],
extends: ['@metamask/eslint-config-mocha'],
rules: {
'mocha/no-setup-in-describe': 'off',
@ -125,7 +129,7 @@ module.exports = {
},
},
{
files: ['ui/**/*.test.js', 'ui/__mocks__/*.js'],
files: ['ui/**/*.test.js', 'ui/__mocks__/*.js', 'shared/**/*.test.js'],
extends: ['@metamask/eslint-config-jest'],
rules: {
'jest/no-restricted-matchers': 'off',

@ -140,7 +140,6 @@ const state = {
}
},
"participateInMetaMetrics": true,
"metaMetricsSendCount": 2,
"nextNonce": 71,
"connectedStatusPopoverHasBeenShown": true,
"swapsWelcomeMessageHasBeenShown": true,
@ -261,7 +260,7 @@ const state = {
}
},
"assetImages": {
"0xad6d458402f60fd3bd25163575031acdce07538d": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xaD6D458402F60fD3Bd25163575031ACDce07538D/logo.png"
"0xad6d458402f60fd3bd25163575031acdce07538d": "./images/logo.png"
},
"hiddenTokens": [],
"suggestedTokens": {},
@ -272,7 +271,7 @@ const state = {
"ipfsGateway": "dweb.link",
"infuraBlocked": false,
"migratedPrivacyMode": false,
"selectedAddress": "0x64a845a5b02460acf8a3d84503b0d68d028b4bb4",
"selectedAddress": "0x9d0ba4ddac06032527b140912ec808ab9451b788",
"metaMetricsId": "0xc2377d11fec1c3b7dd88c4854240ee5e3ed0d9f63b00456d98d80320337b827f",
"conversionDate": 1620710825.03,
"conversionRate": 3910.28,

@ -5,7 +5,7 @@ Hey! We are hiring JavaScript Engineers! [Apply here](https://boards.greenhouse.
You can find the latest version of MetaMask on [our official website](https://metamask.io/). For help using MetaMask, visit our [User Support Site](https://metamask.zendesk.com/hc/en-us).
For [general questions](https://metamask.zendesk.com/hc/en-us/community/topics/360000682532-General), [feature requests](https://metamask.zendesk.com/hc/en-us/community/topics/360000682552-Feature-Requests-Ideas), or [developer questions](https://metamask.zendesk.com/hc/en-us/community/topics/360001751291-Developer-Questions), visit our [Community Forum](https://metamask.zendesk.com/hc/en-us/community/topics).
For [general questions](https://community.metamask.io/c/learn/26), [feature requests](https://community.metamask.io/c/feature-requests-ideas/13), or [developer questions](https://community.metamask.io/c/developer-questions/11), visit our [Community Forum](https://community.metamask.io/).
MetaMask supports Firefox, Google Chrome, and Chromium-based browsers. We recommend using the latest available browser version.

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "ማሰሺያዎት አልተደገፈም..."
},
"builtInCalifornia": {
"message": "MetaMask ካሊፎርኒያ ውስጥ ተዘጋጅቶ የተገነባ ነው።"
},
"buyWithWyre": {
"message": "ETH በ Wyre ይግዙ"
},
@ -751,9 +748,6 @@
"recents": {
"message": "የቅርብ ጊዜያት"
},
"recipientAddress": {
"message": "የተቀባይ አድራሻ"
},
"recipientAddressPlaceholder": {
"message": "ፍለጋ፣ ለሕዝብ ክፍት የሆነ አድራሻ (0x), ወይም ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "متصفحك غير مدعوم..."
},
"builtInCalifornia": {
"message": "تم تصميم وإنشاء MetaMask في ولاية كاليفورنيا."
},
"buyWithWyre": {
"message": "قم بشراء عملة إيثير بواسطة Wyre"
},
@ -747,9 +744,6 @@
"recents": {
"message": "الحديث"
},
"recipientAddress": {
"message": "عنوان المستلم"
},
"recipientAddressPlaceholder": {
"message": "البحث، العنوان العام (0x)، أو ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Браузърът ви не се поддържа ..."
},
"builtInCalifornia": {
"message": "MetaMask е проектиран и създаден в Калифорния."
},
"buyWithWyre": {
"message": "Купете ETH с Wyre"
},
@ -750,9 +747,6 @@
"recents": {
"message": "Скорошни"
},
"recipientAddress": {
"message": "Адрес на получателя"
},
"recipientAddressPlaceholder": {
"message": "Търсене, публичен адрес (0x) или ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "আপনর বউজর সমরিত নয়..."
},
"builtInCalifornia": {
"message": "MetaMask কিিিইন কর এবিিত।"
},
"buyWithWyre": {
"message": "Wyre দি ETH করয় করন"
},
@ -754,9 +751,6 @@
"recents": {
"message": "সরতিকগি"
},
"recipientAddress": {
"message": "পপকর ঠি"
},
"recipientAddressPlaceholder": {
"message": "অনসনন, সবজনন ঠি (0x), ব ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "El teu navegador no és suportat..."
},
"builtInCalifornia": {
"message": "MetaMask ha estat dissenyat i desenvolupat a Califòrnia."
},
"buyWithWyre": {
"message": "Compra ETH amb Wyre"
},
@ -732,9 +729,6 @@
"readdToken": {
"message": "Pots tornar a afegir aquesta fitxa en el futur anant a \"Afegir fitxa\" al menu d'opcions dels teus comptes."
},
"recipientAddress": {
"message": "Adreça del destinatari"
},
"recipientAddressPlaceholder": {
"message": "Cerca, adreça pública (0x), o ENS"
},

@ -46,9 +46,6 @@
"blockiesIdenticon": {
"message": "Použít Blockies Identicon"
},
"builtInCalifornia": {
"message": "MetaMask je navržen a vytvořen v Kalifornii."
},
"cancel": {
"message": "Zrušit"
},
@ -308,9 +305,6 @@
"readdToken": {
"message": "Tento token můžete v budoucnu přidat zpět s „Přidat token“ v nastavení účtu."
},
"recipientAddress": {
"message": "Adresa příjemce"
},
"reject": {
"message": "Odmítnout"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Din browser er ikke understøttet..."
},
"builtInCalifornia": {
"message": "MetaMask er designet og bygget i Californien."
},
"buyWithWyre": {
"message": "Køb ETH med Wyre"
},
@ -735,9 +732,6 @@
"recents": {
"message": "Seneste"
},
"recipientAddress": {
"message": "Modtagerens adresse"
},
"recipientAddressPlaceholder": {
"message": "Søg, offentlig adresse (0x) eller ENS"
},

@ -140,9 +140,6 @@
"browserNotSupported": {
"message": "Ihr Browser wird nicht unterstützt …"
},
"builtInCalifornia": {
"message": "MetaMask wurde in Kalifornien entwickelt und gebaut."
},
"buyWithWyre": {
"message": "ETH mit Wyre kaufen"
},
@ -723,9 +720,6 @@
"recents": {
"message": "Letzte"
},
"recipientAddress": {
"message": "Empfängeradresse"
},
"recipientAddressPlaceholder": {
"message": "Suchen, öffentliche Adresse (0x) oder ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Το Πρόγραμμα Περιήγησής σας δεν υποστηρίζεται..."
},
"builtInCalifornia": {
"message": "Το MetaMask έχει σχεδιαστεί και αναπτυχθεί στην Καλιφόρνια."
},
"buyWithWyre": {
"message": "Αγοράστε ETH με το Wyre"
},
@ -751,9 +748,6 @@
"recents": {
"message": "Πρόσφατα"
},
"recipientAddress": {
"message": "Διεύθυνση Παραλήπτη"
},
"recipientAddressPlaceholder": {
"message": "Αναζήτηση, δημόσια διεύθυνση (0x) ή ENS"
},

@ -97,6 +97,9 @@
"addTokens": {
"message": "Add Tokens"
},
"addressBookIcon": {
"message": "Address book icon"
},
"advanced": {
"message": "Advanced"
},
@ -150,6 +153,9 @@
"amount": {
"message": "Amount"
},
"amountGasFee": {
"message": "Amount + Gas Fee"
},
"amountWithColon": {
"message": "Amount:"
},
@ -223,7 +229,7 @@
"message": "This secret code is required to recover your wallet in case you lose your device, forget your password, have to re-install MetaMask, or want to access your wallet on another device."
},
"backupApprovalNotice": {
"message": "Backup your Secret Recovery code to keep your wallet and funds secure."
"message": "Backup your Secret Recovery Phrase to keep your wallet and funds secure."
},
"backupNow": {
"message": "Backup now"
@ -253,15 +259,21 @@
"browserNotSupported": {
"message": "Your Browser is not supported..."
},
"builContactList": {
"buildContactList": {
"message": "Build your contact list"
},
"builtInCalifornia": {
"message": "MetaMask is designed and built in California."
"builtAroundTheWorld": {
"message": "MetaMask is designed and built around the world."
},
"buy": {
"message": "Buy"
},
"buyWithTransak": {
"message": "Buy ETH with Transak"
},
"buyWithTransakDescription": {
"message": "Transak supports debit card and bank transfers (depending on location) in 59+ countries. ETH deposits into your MetaMask account."
},
"buyWithWyre": {
"message": "Buy ETH with Wyre"
},
@ -414,6 +426,9 @@
"continue": {
"message": "Continue"
},
"continueToTransak": {
"message": "Continue to Transak"
},
"continueToWyre": {
"message": "Continue to Wyre"
},
@ -492,6 +507,9 @@
"customToken": {
"message": "Custom Token"
},
"data": {
"message": "Data"
},
"dataBackupFoundInfo": {
"message": "Some of your account data was backed up during a previous installation of MetaMask. This could include your settings, contacts, and tokens. Would you like to restore this data now?"
},
@ -650,12 +668,21 @@
"message": "The endpoint returned a different chain ID: $1",
"description": "$1 is the return value of eth_chainId from an RPC endpoint"
},
"ensIllegalCharacter": {
"message": "Illegal Character for ENS."
},
"ensNotFoundOnCurrentNetwork": {
"message": "ENS name not found on the current network. Try switching to Ethereum Mainnet."
},
"ensNotSupportedOnNetwork": {
"message": "Network does not support ENS"
},
"ensRegistrationError": {
"message": "Error in ENS name registration"
},
"ensUnknownError": {
"message": "ENS Lookup failed."
},
"enterAnAlias": {
"message": "Enter an alias"
},
@ -777,6 +804,12 @@
"functionType": {
"message": "Function Type"
},
"gasFee": {
"message": "Gas Fee"
},
"gasFeeEstimate": {
"message": "Estimate"
},
"gasLimit": {
"message": "Gas Limit"
},
@ -1064,6 +1097,12 @@
"max": {
"message": "Max"
},
"maxFee": {
"message": "Max fee"
},
"maxPriorityFee": {
"message": "Max priority fee"
},
"memo": {
"message": "memo"
},
@ -1355,6 +1394,9 @@
"onlyConnectTrust": {
"message": "Only connect with sites you trust."
},
"optional": {
"message": "Optional"
},
"optionalBlockExplorerUrl": {
"message": "Block Explorer URL (optional)"
},
@ -1451,12 +1493,12 @@
"recents": {
"message": "Recents"
},
"recipientAddress": {
"message": "Recipient Address"
},
"recipientAddressPlaceholder": {
"message": "Search, public address (0x), or ENS"
},
"recommendedGasLabel": {
"message": "Recommended"
},
"recoveryPhraseReminderBackupStart": {
"message": "Start here"
},
@ -2189,6 +2231,9 @@
"symbolBetweenZeroTwelve": {
"message": "Symbol must be 11 characters or fewer."
},
"syncInProgress": {
"message": "Sync in progress"
},
"syncWithMobile": {
"message": "Sync with mobile"
},
@ -2369,6 +2414,10 @@
"message": "verify the network details",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Sending collectible (ERC-721) tokens is not currently supported",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
},
"updatedWithDate": {
"message": "Updated $1"
},
@ -2411,6 +2460,9 @@
"viewContact": {
"message": "View Contact"
},
"viewFullTransactionDetails": {
"message": "View full transaction details"
},
"viewMore": {
"message": "View More"
},

@ -6,7 +6,7 @@
"message": "Versión, centro de soporte técnico e información de contacto"
},
"acceleratingATransaction": {
"message": "* Usar un precio de gas más alto para acelerar una transacción aumenta las posibilidades de un procesamiento más rápido en la red, pero esto no siempre se garantiza."
"message": "* Usar un precio de gas más alto para acelerar una transacción aumenta las posibilidades de un procesamiento más rápido en la red, pero esto no siempre se garantiza."
},
"acceptTermsOfUse": {
"message": "Leí y estoy de acuerdo con $1",
@ -52,6 +52,10 @@
"addContact": {
"message": "Agregar contacto"
},
"addCustomTokenByContractAddress": {
"message": "¿No encuentra un token? Puede agregar cualquier token si copia su dirección. Puede encontrar la dirección de contrato del token en $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Esto permitirá que la red se utilice en MetaMask."
},
@ -85,7 +89,7 @@
"message": "Agregar a la libreta de direcciones"
},
"addToAddressBookModalPlaceholder": {
"message": "p. ej., John D."
"message": "p. ej., John D."
},
"addToken": {
"message": "Agregar token"
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "El explorador no es compatible…"
},
"builContactList": {
"buildContactList": {
"message": "Cree su lista de contactos"
},
"builtInCalifornia": {
"message": "MetaMask se diseñó y compiló en California."
},
"buy": {
"message": "Comprar"
},
@ -268,7 +269,7 @@
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Puede volver a activar esta notificación desde Configuración > Alertas."
"message": "Puede volver a activar esta notificación desde Configuración -> Alertas."
},
"cancel": {
"message": "Cancelar"
@ -285,8 +286,11 @@
"chainIdDefinition": {
"message": "El identificador de cadena que se utiliza para firmar transacciones en esta red."
},
"chainIdExistsErrorMsg": {
"message": "En este momento, la red $1 está utilizando este identificador de cadena."
},
"chromeRequiredForHardwareWallets": {
"message": "Debe usar MetaMask en Google Chrome para poder conectarse a su cartera de hardware."
"message": "Debe usar MetaMask en Google Chrome para poder conectarse a su cartera de hardware."
},
"clickToRevealSeed": {
"message": "Haga clic aquí para revelar las palabras secretas"
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Continuar a Wyre"
},
"contract": {
"message": "Contrato"
},
"contractAddressError": {
"message": "Está enviando tokens a la dirección de contrato del token. Esto puede provocar la pérdida de los tokens."
},
@ -572,7 +579,7 @@
"message": "No volver a mostrar"
},
"downloadGoogleChrome": {
"message": "Descargar Google Chrome"
"message": "Descargar Google Chrome"
},
"downloadSecretBackup": {
"message": "Descargue esta frase secreta de respaldo y guárdela en un medio de almacenamiento o disco duro externo cifrado."
@ -626,6 +633,10 @@
"endOfFlowMessage6": {
"message": "Si necesita volver a crear una copia de seguridad de la frase secreta de recuperación, puede encontrarla en Configuración -> Seguridad."
},
"endOfFlowMessage7": {
"message": "Si tiene preguntas o nota movimientos sospechosos, comuníquese con soporte técnico $1.",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "MetaMask no puede recuperar la frase secreta de recuperación."
},
@ -770,7 +781,7 @@
"message": "El límite de gas es la cantidad máxima de unidades de gas que está dispuesto a gastar."
},
"gasLimitTooLow": {
"message": "El límite de gas debe ser al menos 21 000"
"message": "El límite de gas debe ser al menos 21 000"
},
"gasLimitTooLowWithDynamicFee": {
"message": "El límite de gas debe ser al menos $1",
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "Importar una cuenta con la frase secreta de recuperación"
},
"importAccountText": {
"message": "o $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "¿Desea importar el token?"
},
"importTokenWarning": {
"message": "Toda persona puede crear un token con cualquier nombre, incluso versiones falsas de tokens existentes. ¡Agréguelo y realice transacciones bajo su propio riesgo!"
},
"importWallet": {
"message": "Importar cartera"
},
@ -956,7 +977,7 @@
"message": "Número no válido. Quite todos los ceros iniciales."
},
"invalidRPC": {
"message": "Dirección URL de RPC no válida"
"message": "Dirección URL de RPC no válida"
},
"invalidSeedPhrase": {
"message": "Frase secreta de recuperación no válida"
@ -1023,7 +1044,7 @@
"message": "Cargando tokens…"
},
"localhost": {
"message": "Host local 8545"
"message": "Host local 8545"
},
"lock": {
"message": "Bloquear"
@ -1110,7 +1131,7 @@
"message": "Escriba su contraseña para confirmar que es usted."
},
"mustSelectOne": {
"message": "Debe seleccionar al menos 1 token."
"message": "Debe seleccionar al menos 1 token."
},
"myAccounts": {
"message": "Mis cuentas"
@ -1160,10 +1181,10 @@
"message": "Agregar y editar redes RPC personalizadas"
},
"networkURL": {
"message": "Dirección URL de la red"
"message": "Dirección URL de la red"
},
"networkURLDefinition": {
"message": "La dirección URL que se utilizó para acceder a esta red."
"message": "La dirección URL que se utilizó para acceder a esta red."
},
"networks": {
"message": "Redes"
@ -1191,7 +1212,7 @@
"message": "Red nueva"
},
"newPassword": {
"message": "Contraseña nueva (mín. de 8 caracteres)"
"message": "Contraseña nueva (mín. de 8 caracteres)"
},
"newToMetaMask": {
"message": "¿Es nuevo en MetaMask?"
@ -1287,6 +1308,22 @@
"message": "Su \"frase de recuperación\" ahora se llama \"frase secreta de recuperación.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "A partir de la versión 91 de Chrome, la API que habilitaba nuestro soporte para Ledger (U2F) ya no es compatible con carteras de hardware. MetaMask ha implementado un nuevo soporte para Ledger Live mediante el cual usted puede seguir conectándose a su dispositivo Ledger a través de la aplicación de escritorio Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Cuando interactúe con su cuenta de Ledger a través de MetaMask, se abrirá una nueva pestaña y se le pedirá que abra la aplicación Ledger Live. Una vez que se abra la aplicación, se le pedirá que otorgue permiso para establecer una conexión WebSocket con su cuenta de MetaMask. ¡Eso es todo!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "A fin de habilitar el soporte para Live Ledger, haga clic en Configuración > Avanzada > Utilizar Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Actualización del soporte para Ledger destinada a usuarios de Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "de"
},
@ -1372,7 +1409,7 @@
"message": "Moneda principal"
},
"primaryCurrencySettingDescription": {
"message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada."
"message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada."
},
"privacyMsg": {
"message": "Política de privacidad"
@ -1411,12 +1448,33 @@
"recents": {
"message": "Recientes"
},
"recipientAddress": {
"message": "Dirección del destinatario"
},
"recipientAddressPlaceholder": {
"message": "Búsqueda, dirección pública (0x) o ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Iniciar aquí"
},
"recoveryPhraseReminderConfirm": {
"message": "Entendido"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Guarde siempre su frase secreta de recuperación en un lugar seguro y secreto."
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "¿Necesita volver a crear una copia de seguridad de su frase secreta de recuperación?"
},
"recoveryPhraseReminderItemOne": {
"message": "No comparta nunca su frase secreta de recuperación con nadie."
},
"recoveryPhraseReminderItemTwo": {
"message": "El equipo de MetaMask nunca le pedirá su frase secreta de recuperación."
},
"recoveryPhraseReminderSubText": {
"message": "Mediante su frase secreta de recuperación, se controlan todas sus cuentas."
},
"recoveryPhraseReminderTitle": {
"message": "Proteja sus fondos."
},
"reject": {
"message": "Rechazar"
},
@ -1424,7 +1482,7 @@
"message": "Rechazar todo"
},
"rejectTxsDescription": {
"message": "Está a punto de rechazar $1 transacciones en lote."
"message": "Está a punto de rechazar $1 transacciones en lote."
},
"rejectTxsN": {
"message": "Rechazar $1 transacciones"
@ -1442,7 +1500,7 @@
"message": "Quitar cuenta"
},
"removeAccountDescription": {
"message": "Esta cuenta se quitará de la cartera. Antes de continuar, asegúrese de tener la frase secreta de recuperación original o la clave privada de esta cuenta importada. Puede importar o crear cuentas nuevamente desde el menú desplegable de la cuenta."
"message": "Esta cuenta se quitará de la cartera. Antes de continuar, asegúrese de tener la frase secreta de recuperación original o la clave privada de esta cuenta importada. Puede importar o crear cuentas nuevamente en la lista desplegable de la cuenta. "
},
"requestsAwaitingAcknowledgement": {
"message": "solicitudes en espera de confirmación"
@ -1539,11 +1597,47 @@
"message": "Ingrese su frase secreta aquí para restaurar su bóveda."
},
"securityAndPrivacy": {
"message": "Seguridad y privacidad"
"message": "Seguridad y privacidad"
},
"securitySettingsDescription": {
"message": "Configuración de privacidad y frase secreta de recuperación de la cartera"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "Escríbala y guárdela en varios lugares secretos."
},
"seedPhraseIntroSidebarBulletOne": {
"message": "Guárdela en un administrador de contraseñas"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "Guárdela en una caja fuerte."
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "Guárdela en una bóveda bancaria."
},
"seedPhraseIntroSidebarCopyOne": {
"message": "Su frase secreta de recuperación es la “llave maestra” de su cartera y sus fondos."
},
"seedPhraseIntroSidebarCopyThree": {
"message": "Si alguien le pide su frase de recuperación, es posible que tenga intenciones de estafarlo."
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "Nunca comparta su frase secreta de recuperación, ni siquiera con MetaMask."
},
"seedPhraseIntroSidebarTitleOne": {
"message": "¿Qué es una frase de recuperación?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "¿Debería compartir mi frase de recuperación?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "¿Cómo guardo mi frase de recuperación?"
},
"seedPhraseIntroTitle": {
"message": "Proteger su cartera"
},
"seedPhraseIntroTitleCopy": {
"message": "Antes de comenzar, mire este breve video para aprender sobre su frase de recuperación y sobre cómo mantener segura su cartera."
},
"seedPhrasePlaceholder": {
"message": "Separar cada palabra con un solo espacio"
},
@ -1551,7 +1645,7 @@
"message": "Pegar la frase secreta de recuperación desde el Portapapeles"
},
"seedPhraseReq": {
"message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras"
"message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras"
},
"selectAHigherGasFee": {
"message": "Seleccione una cuota de gas más alta para acelerar el procesamiento de la transacción.*"
@ -1870,7 +1964,7 @@
"message": "Cuota de MetaMask"
},
"swapMetaMaskFeeDescription": {
"message": "Buscamos el mejor precio en las fuentes de liquidez más importantes, todo el tiempo. Se incorpora de manera automática a esta cotización una cuota del $1 %.",
"message": "Buscamos el mejor precio en las fuentes de liquidez más importantes, todo el tiempo. Se incorpora de manera automática a esta cotización una cuota del $1 %.",
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNQuotes": {
@ -1893,9 +1987,18 @@
"description": "This message represents the price slippage for the swap. $1 and $4 are a number (ex: 2.89), $2 and $5 are symbols (ex: ETH), and $3 and $6 are fiat currency amounts."
},
"swapPriceDifferenceTitle": {
"message": "Diferencia de precio de ~$1 %",
"message": "Diferencia de precio de ~$1 %",
"description": "$1 is a number (ex: 1.23) that represents the price difference."
},
"swapPriceImpactTooltip": {
"message": "El impacto sobre el precio es la diferencia entre el precio actual del mercado y el monto recibido durante la ejecución de la transacción. El impacto sobre el precio es una función del tamaño de su transacción respecto de la dimensión del fondo de liquidez."
},
"swapPriceUnavailableDescription": {
"message": "No se pudo determinar el impacto sobre el precio debido a la falta de datos de los precios del mercado. Antes de realizar el canje, confirme que está de acuerdo con la cantidad de tokens que está a punto de recibir."
},
"swapPriceUnavailableTitle": {
"message": "Antes de continuar, verifique su tasa"
},
"swapProcessing": {
"message": "Procesamiento"
},
@ -1906,7 +2009,7 @@
"message": "Si el precio cambia entre el momento en que hace el pedido y cuando se confirma, se denomina \"desfase\". El canje se cancelará automáticamente si el desfase supera lo establecido en la configuración \"tolerancia de desfase\"."
},
"swapQuoteIncludesRate": {
"message": "La cotización incluye una cuota de MetaMask de $1 %",
"message": "La cotización incluye una cuota de MetaMask de $1 %",
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapQuoteNofN": {
@ -1997,6 +2100,9 @@
"message": "Canjear $1 por $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Este token se añadió de forma manual."
},
"swapTokenVerificationMessage": {
"message": "Siempre confirme la dirección del token en $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2012,7 +2118,7 @@
"message": "Transacción completa"
},
"swapTwoTransactions": {
"message": "2 transacciones"
"message": "2 transacciones"
},
"swapUnknown": {
"message": "Desconocido"
@ -2029,13 +2135,13 @@
"description": "Tells the user how much of a token they have in their balance. $1 is a decimal number amount of tokens, and $2 is a token symbol"
},
"swapZeroSlippage": {
"message": "0 % de desfase"
"message": "0 % de desfase"
},
"swapsAdvancedOptions": {
"message": "Opciones avanzadas"
},
"swapsExcessiveSlippageWarning": {
"message": "El monto del desfase es muy alto, por lo que recibirá una tasa de conversión desfavorable. Disminuya su tolerancia de desfase a un valor menor al 15 %."
"message": "El monto del desfase es muy alto, por lo que recibirá una tasa de conversión desfavorable. Disminuya su tolerancia de desfase a un valor menor al 15 %."
},
"swapsMaxSlippage": {
"message": "Tolerancia de desfase"
@ -2075,7 +2181,7 @@
"message": "Símbolo"
},
"symbolBetweenZeroTwelve": {
"message": "El símbolo debe tener 11 caracteres o menos."
"message": "El símbolo debe tener 11 caracteres o menos."
},
"syncWithMobile": {
"message": "Sincronizar con dispositivo móvil"
@ -2264,7 +2370,7 @@
"message": "Las direcciones URL requieren el prefijo HTTP/HTTPS adecuado."
},
"urlExistsErrorMsg": {
"message": "La dirección URL ya está en la lista de redes existentes"
"message": "En este momento, la red $1 está utilizando esta dirección URL."
},
"usePhishingDetection": {
"message": "Usar detección de phishing"
@ -2286,6 +2392,10 @@
"message": "Comprobar este token en $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Verifique este token en $1 y asegúrese de que sea el token con el que quiere realizar la transacción.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Ver cuenta"
},
@ -2320,7 +2430,7 @@
"message": "Frase secreta de recuperación de la cartera"
},
"web3ShimUsageNotification": {
"message": "Parece que el sitio web actual intentó utilizar la API de window.web3 que se eliminó. Si el sitio no funciona, haga clic en $1 para obtener más información.",
"message": "Parece que el sitio web actual intentó utilizar la API de window.web3 que se eliminó. Si el sitio no funciona, haga clic en $1 para obtener más información.",
"description": "$1 is a clickable link."
},
"welcome": {

@ -6,7 +6,7 @@
"message": "Versión, centro de soporte técnico e información de contacto"
},
"acceleratingATransaction": {
"message": "* Usar un precio de gas más alto para acelerar una transacción aumenta las posibilidades de un procesamiento más rápido en la red, pero esto no siempre se garantiza."
"message": "* Usar un precio de gas más alto para acelerar una transacción aumenta las posibilidades de un procesamiento más rápido en la red, pero esto no siempre se garantiza."
},
"acceptTermsOfUse": {
"message": "Leí y estoy de acuerdo con $1",
@ -52,6 +52,10 @@
"addContact": {
"message": "Agregar contacto"
},
"addCustomTokenByContractAddress": {
"message": "¿No encuentra un token? Puede agregar cualquier token si copia su dirección. Puede encontrar la dirección de contrato del token en $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Esto permitirá que la red se utilice en MetaMask."
},
@ -85,7 +89,7 @@
"message": "Agregar a la libreta de direcciones"
},
"addToAddressBookModalPlaceholder": {
"message": "p. ej., John D."
"message": "p. ej., John D."
},
"addToken": {
"message": "Agregar token"
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "El explorador no es compatible…"
},
"builContactList": {
"buildContactList": {
"message": "Cree su lista de contactos"
},
"builtInCalifornia": {
"message": "MetaMask se diseñó y compiló en California."
},
"buy": {
"message": "Comprar"
},
@ -268,7 +269,7 @@
"message": "Bytes"
},
"canToggleInSettings": {
"message": "Puede volver a activar esta notificación desde Configuración > Alertas."
"message": "Puede volver a activar esta notificación desde Configuración -> Alertas."
},
"cancel": {
"message": "Cancelar"
@ -285,8 +286,11 @@
"chainIdDefinition": {
"message": "El identificador de cadena que se utiliza para firmar transacciones en esta red."
},
"chainIdExistsErrorMsg": {
"message": "En este momento, la red $1 está utilizando este identificador de cadena."
},
"chromeRequiredForHardwareWallets": {
"message": "Debe usar MetaMask en Google Chrome para poder conectarse a su cartera de hardware."
"message": "Debe usar MetaMask en Google Chrome para poder conectarse a su cartera de hardware."
},
"clickToRevealSeed": {
"message": "Haga clic aquí para revelar las palabras secretas"
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Continuar a Wyre"
},
"contract": {
"message": "Contrato"
},
"contractAddressError": {
"message": "Está enviando tokens a la dirección de contrato del token. Esto puede provocar la pérdida de los tokens."
},
@ -572,7 +579,7 @@
"message": "No volver a mostrar"
},
"downloadGoogleChrome": {
"message": "Descargar Google Chrome"
"message": "Descargar Google Chrome"
},
"downloadSecretBackup": {
"message": "Descargue esta frase secreta de respaldo y guárdela en un medio de almacenamiento o disco duro externo cifrado."
@ -774,7 +781,7 @@
"message": "El límite de gas es la cantidad máxima de unidades de gas que está dispuesto a gastar."
},
"gasLimitTooLow": {
"message": "El límite de gas debe ser al menos 21 000"
"message": "El límite de gas debe ser al menos 21 000"
},
"gasLimitTooLowWithDynamicFee": {
"message": "El límite de gas debe ser al menos $1",
@ -893,6 +900,12 @@
"message": "o $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "¿Desea importar el token?"
},
"importTokenWarning": {
"message": "Toda persona puede crear un token con cualquier nombre, incluso versiones falsas de tokens existentes. ¡Agréguelo y realice transacciones bajo su propio riesgo!"
},
"importWallet": {
"message": "Importar cartera"
},
@ -964,7 +977,7 @@
"message": "Número no válido. Quite todos los ceros iniciales."
},
"invalidRPC": {
"message": "Dirección URL de RPC no válida"
"message": "Dirección URL de RPC no válida"
},
"invalidSeedPhrase": {
"message": "Frase secreta de recuperación no válida"
@ -1031,7 +1044,7 @@
"message": "Cargando tokens…"
},
"localhost": {
"message": "Host local 8545"
"message": "Host local 8545"
},
"lock": {
"message": "Bloquear"
@ -1118,7 +1131,7 @@
"message": "Escriba su contraseña para confirmar que es usted."
},
"mustSelectOne": {
"message": "Debe seleccionar al menos 1 token."
"message": "Debe seleccionar al menos 1 token."
},
"myAccounts": {
"message": "Mis cuentas"
@ -1168,10 +1181,10 @@
"message": "Agregar y editar redes RPC personalizadas"
},
"networkURL": {
"message": "Dirección URL de la red"
"message": "Dirección URL de la red"
},
"networkURLDefinition": {
"message": "La dirección URL que se utilizó para acceder a esta red."
"message": "La dirección URL que se utilizó para acceder a esta red."
},
"networks": {
"message": "Redes"
@ -1199,7 +1212,7 @@
"message": "Red nueva"
},
"newPassword": {
"message": "Contraseña nueva (mín. de 8 caracteres)"
"message": "Contraseña nueva (mín. de 8 caracteres)"
},
"newToMetaMask": {
"message": "¿Es nuevo en MetaMask?"
@ -1295,6 +1308,22 @@
"message": "Su \"frase de recuperación\" ahora se llama \"frase secreta de recuperación.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "A partir de la versión 91 de Chrome, la API que habilitaba nuestro soporte para Ledger (U2F) ya no es compatible con carteras de hardware. MetaMask ha implementado un nuevo soporte para Ledger Live mediante el cual usted puede seguir conectándose a su dispositivo Ledger a través de la aplicación de escritorio Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Cuando interactúe con su cuenta de Ledger a través de MetaMask, se abrirá una nueva pestaña y se le pedirá que abra la aplicación Ledger Live. Una vez que se abra la aplicación, se le pedirá que otorgue permiso para establecer una conexión WebSocket con su cuenta de MetaMask. ¡Eso es todo!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "A fin de habilitar el soporte para Live Ledger, haga clic en Configuración > Avanzada > Utilizar Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Actualización del soporte para Ledger destinada a usuarios de Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "de"
},
@ -1380,7 +1409,7 @@
"message": "Moneda principal"
},
"primaryCurrencySettingDescription": {
"message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada."
"message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada."
},
"privacyMsg": {
"message": "Política de privacidad"
@ -1419,12 +1448,33 @@
"recents": {
"message": "Recientes"
},
"recipientAddress": {
"message": "Dirección del destinatario"
},
"recipientAddressPlaceholder": {
"message": "Búsqueda, dirección pública (0x) o ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Iniciar aquí"
},
"recoveryPhraseReminderConfirm": {
"message": "Entendido"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Guarde siempre su frase secreta de recuperación en un lugar seguro y secreto."
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "¿Necesita volver a crear una copia de seguridad de su frase secreta de recuperación?"
},
"recoveryPhraseReminderItemOne": {
"message": "No comparta nunca su frase secreta de recuperación con nadie."
},
"recoveryPhraseReminderItemTwo": {
"message": "El equipo de MetaMask nunca le pedirá su frase secreta de recuperación."
},
"recoveryPhraseReminderSubText": {
"message": "Mediante su frase secreta de recuperación, se controlan todas sus cuentas."
},
"recoveryPhraseReminderTitle": {
"message": "Proteja sus fondos."
},
"reject": {
"message": "Rechazar"
},
@ -1432,7 +1482,7 @@
"message": "Rechazar todo"
},
"rejectTxsDescription": {
"message": "Está a punto de rechazar $1 transacciones en lote."
"message": "Está a punto de rechazar $1 transacciones en lote."
},
"rejectTxsN": {
"message": "Rechazar $1 transacciones"
@ -1547,7 +1597,7 @@
"message": "Ingrese su frase secreta aquí para restaurar su bóveda."
},
"securityAndPrivacy": {
"message": "Seguridad y privacidad"
"message": "Seguridad y privacidad"
},
"securitySettingsDescription": {
"message": "Configuración de privacidad y frase secreta de recuperación de la cartera"
@ -1595,7 +1645,7 @@
"message": "Pegar la frase secreta de recuperación desde el Portapapeles"
},
"seedPhraseReq": {
"message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras"
"message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras"
},
"selectAHigherGasFee": {
"message": "Seleccione una cuota de gas más alta para acelerar el procesamiento de la transacción.*"
@ -1914,7 +1964,7 @@
"message": "Cuota de MetaMask"
},
"swapMetaMaskFeeDescription": {
"message": "Buscamos el mejor precio en las fuentes de liquidez más importantes, todo el tiempo. Se incorpora de manera automática a esta cotización una cuota del $1 %.",
"message": "Buscamos el mejor precio en las fuentes de liquidez más importantes, todo el tiempo. Se incorpora de manera automática a esta cotización una cuota del $1 %.",
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNQuotes": {
@ -1937,9 +1987,18 @@
"description": "This message represents the price slippage for the swap. $1 and $4 are a number (ex: 2.89), $2 and $5 are symbols (ex: ETH), and $3 and $6 are fiat currency amounts."
},
"swapPriceDifferenceTitle": {
"message": "Diferencia de precio de ~$1 %",
"message": "Diferencia de precio de ~$1 %",
"description": "$1 is a number (ex: 1.23) that represents the price difference."
},
"swapPriceImpactTooltip": {
"message": "El impacto sobre el precio es la diferencia entre el precio actual del mercado y el monto recibido durante la ejecución de la transacción. El impacto sobre el precio es una función del tamaño de su transacción respecto de la dimensión del fondo de liquidez."
},
"swapPriceUnavailableDescription": {
"message": "No se pudo determinar el impacto sobre el precio debido a la falta de datos de los precios del mercado. Antes de realizar el canje, confirme que está de acuerdo con la cantidad de tokens que está a punto de recibir."
},
"swapPriceUnavailableTitle": {
"message": "Antes de continuar, verifique su tasa"
},
"swapProcessing": {
"message": "Procesamiento"
},
@ -1950,7 +2009,7 @@
"message": "Si el precio cambia entre el momento en que hace el pedido y cuando se confirma, se denomina \"desfase\". El canje se cancelará automáticamente si el desfase supera lo establecido en la configuración \"tolerancia de desfase\"."
},
"swapQuoteIncludesRate": {
"message": "La cotización incluye una cuota de MetaMask de $1 %",
"message": "La cotización incluye una cuota de MetaMask de $1 %",
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapQuoteNofN": {
@ -2041,6 +2100,9 @@
"message": "Canjear $1 por $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Este token se añadió de forma manual."
},
"swapTokenVerificationMessage": {
"message": "Siempre confirme la dirección del token en $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2056,7 +2118,7 @@
"message": "Transacción completa"
},
"swapTwoTransactions": {
"message": "2 transacciones"
"message": "2 transacciones"
},
"swapUnknown": {
"message": "Desconocido"
@ -2073,13 +2135,13 @@
"description": "Tells the user how much of a token they have in their balance. $1 is a decimal number amount of tokens, and $2 is a token symbol"
},
"swapZeroSlippage": {
"message": "0 % de desfase"
"message": "0 % de desfase"
},
"swapsAdvancedOptions": {
"message": "Opciones avanzadas"
},
"swapsExcessiveSlippageWarning": {
"message": "El monto del desfase es muy alto, por lo que recibirá una tasa de conversión desfavorable. Disminuya su tolerancia de desfase a un valor menor al 15 %."
"message": "El monto del desfase es muy alto, por lo que recibirá una tasa de conversión desfavorable. Disminuya su tolerancia de desfase a un valor menor al 15 %."
},
"swapsMaxSlippage": {
"message": "Tolerancia de desfase"
@ -2119,7 +2181,7 @@
"message": "Símbolo"
},
"symbolBetweenZeroTwelve": {
"message": "El símbolo debe tener 11 caracteres o menos."
"message": "El símbolo debe tener 11 caracteres o menos."
},
"syncWithMobile": {
"message": "Sincronizar con dispositivo móvil"
@ -2308,7 +2370,7 @@
"message": "Las direcciones URL requieren el prefijo HTTP/HTTPS adecuado."
},
"urlExistsErrorMsg": {
"message": "La dirección URL ya está en la lista de redes existentes"
"message": "En este momento, la red $1 está utilizando esta dirección URL."
},
"usePhishingDetection": {
"message": "Usar detección de phishing"
@ -2330,6 +2392,10 @@
"message": "Comprobar este token en $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Verifique este token en $1 y asegúrese de que sea el token con el que quiere realizar la transacción.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Ver cuenta"
},
@ -2364,7 +2430,7 @@
"message": "Frase secreta de recuperación de la cartera"
},
"web3ShimUsageNotification": {
"message": "Parece que el sitio web actual intentó utilizar la API de window.web3 que se eliminó. Si el sitio no funciona, haga clic en $1 para obtener más información.",
"message": "Parece que el sitio web actual intentó utilizar la API de window.web3 que se eliminó. Si el sitio no funciona, haga clic en $1 para obtener más información.",
"description": "$1 is a clickable link."
},
"welcome": {

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Teie lehitsejat ei toetata..."
},
"builtInCalifornia": {
"message": "MetaMask on projekteeritud ja loodud Californias."
},
"buyWithWyre": {
"message": "Ostke ETH-d Wyre'iga"
},
@ -744,9 +741,6 @@
"recents": {
"message": "Hiljutised"
},
"recipientAddress": {
"message": "Saaja aadress"
},
"recipientAddressPlaceholder": {
"message": "Otsing, avalik aadress (0x) või ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "مرورگر شما پشتیبانی نمیشود"
},
"builtInCalifornia": {
"message": "MetaMask در کالیفورنیا طراحی و ساخته شده است."
},
"buyWithWyre": {
"message": "ETH را توسط Wyre خریداری نمایید"
},
@ -754,9 +751,6 @@
"recents": {
"message": "واپسین"
},
"recipientAddress": {
"message": "آدرس دریافت کننده"
},
"recipientAddressPlaceholder": {
"message": "جستجو، آدرس عمومی (0x)، یا ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Selaintasi ei tueta..."
},
"builtInCalifornia": {
"message": "MetaMask on suunniteltu ja koottu Kaliforniassa."
},
"buyWithWyre": {
"message": "Osta ETH:ta Wyrella"
},
@ -751,9 +748,6 @@
"recents": {
"message": "Viimeaikaiset"
},
"recipientAddress": {
"message": "Vastaanottajan osoite"
},
"recipientAddressPlaceholder": {
"message": "Haku, julkinen osoite (0x) tai ENS"
},

@ -128,9 +128,6 @@
"browserNotSupported": {
"message": "Hindi sinusuportahan ang iyong Browser..."
},
"builtInCalifornia": {
"message": "Ang MetaMask ay dinisenyo at binuo sa California."
},
"buyWithWyre": {
"message": "Bumili ng ETH gamit ang Wyre"
},
@ -678,9 +675,6 @@
"recents": {
"message": "Kamakailan"
},
"recipientAddress": {
"message": "Address ng Recipient"
},
"recipientAddressPlaceholder": {
"message": "Maghanap, pampublikong address (0x), o ENS"
},

@ -137,9 +137,6 @@
"browserNotSupported": {
"message": "Votre navigateur internet n'est pas supporté..."
},
"builtInCalifornia": {
"message": "MetaMask est designé et developpé en Californie."
},
"buyWithWyre": {
"message": "Acheter ETH avec Wyre"
},
@ -736,9 +733,6 @@
"recents": {
"message": "Récents"
},
"recipientAddress": {
"message": "Adresse du destinataire"
},
"recipientAddressPlaceholder": {
"message": "Recherche, adresse publique (0x) ou ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "הדפדפן שלך אינו נתמך..."
},
"builtInCalifornia": {
"message": "MetaMask תוכנן ונבנה בקליפורניה."
},
"buyWithWyre": {
"message": "רכישת את'ר עם Wyre"
},
@ -751,9 +748,6 @@
"recents": {
"message": "אחרונים"
},
"recipientAddress": {
"message": "כתובת הנמען"
},
"recipientAddressPlaceholder": {
"message": "חיפוש, כתובת ציבורית (0x), או ENS"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "सपरक ज"
},
"addCustomTokenByContractAddress": {
"message": "टकन नहिल रह? आप अपन पतिपककर मअल रप सिकन क सकत। टकन अनध पत $1 पर मिल सकत।",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "इसस इस नटवरक क MetaMask कदर उपयग करन अनमतिि।"
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "आपकउजर समरित नह..."
},
"builContactList": {
"buildContactList": {
"message": "अपनपरक स बन"
},
"builtInCalifornia": {
"message": "MetaMask किििइन और निित कि गय।"
},
"buy": {
"message": "खर"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "इस नटवरक किए लन-दन पर हसषर करनिए उपयग कन ID।"
},
"chainIdExistsErrorMsg": {
"message": "यह चन ID वरतमन म $1 नटवरक द उपयग कि।"
},
"chromeRequiredForHardwareWallets": {
"message": "अपनडवयर वट स कनट करनिए आपक Google Chrome पर MetaMask क उपयग करन आवशयकत।"
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Wyre पर ज रख"
},
"contract": {
"message": "अनध"
},
"contractAddressError": {
"message": "आप टकन क अनध पत पर टकन भज रह। इसक परिमसवरप इन टकनकसन ह सकत।"
},
@ -624,7 +631,11 @@
"message": "फििग सवधन रह! MetaMask कभ अनस ह आपकत रिकवर नह।"
},
"endOfFlowMessage6": {
"message": "यदि आपक अपनत रिकवरिर सकअप ल आवशयकत, त आप इसिस -> सरक सकत।"
"message": "यदि आपक अपनत रिकवरिर सकअप ल आवशयकत, त आप इसिग -> सरक सकत।"
},
"endOfFlowMessage7": {
"message": "यदि आपक कभछ पछनछ गडबड लग, त हम सहयत $1 सपरक कर।",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "MetaMask आपकत रिकवरनरत नह कर सकत।"
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "गत रिकवरथ एक ख आयत कर"
},
"importAccountText": {
"message": "य $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "टकन क आयत कर?"
},
"importTokenWarning": {
"message": "कई भिम कथ एक टकन बन सकत, जिसमकन क नकलकरण शिल ह। अपनिम पर ज और वर कर!"
},
"importWallet": {
"message": "वट आयत कर"
},
@ -1287,6 +1308,22 @@
"message": "आपक \"सड फ\" क अब आपक \"गत रिकवर\" कह।",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Chrome ककरण 91 स, वह API ज हम Ledger सपट (U2F) क सकषम करत वह अब हडवयर वट क समरथन नह करत। MetaMask न एक नय Ledger Live सपट लि, जिसक मदद स आप Ledger Live डकटप ऐप कयम स अपन Ledger डिइस स कनट करन रख सकत।",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "MetaMask म अपन Ledger ख पर कम करत समय, एक नयब खल जएग और आपक Ledger Live ऐप खलनिए कहएग। ऐप खलनद, आपक अपन MetaMask खिए एक WebSocket कनशन क अनमतििए कहएग। बस इतन!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "आप सिग > उननत > Ledger Live क उपयग कर पर किक करक Ledger Live सहयत सकषम कर सकत।",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Chrome उपयगकरिए Ledger सहयत अदयतन",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "/"
},
@ -1411,12 +1448,33 @@
"recents": {
"message": "हल ह"
},
"recipientAddress": {
"message": "पतकर पत"
},
"recipientAddressPlaceholder": {
"message": "खज, सवजनिक पत (0x) य ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "यहभ कर"
},
"recoveryPhraseReminderConfirm": {
"message": "समझ गय"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "अपनत रिकवर हमरकित और गत सन पर रख।"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "अपनत रिकवरिर सकअप करन आवशयकत?"
},
"recoveryPhraseReminderItemOne": {
"message": "कभ अपनत रिकवरिथ स न कर"
},
"recoveryPhraseReminderItemTwo": {
"message": "MetaMask टम कभ आपकत रिकवर नह"
},
"recoveryPhraseReminderSubText": {
"message": "आपकत रिकवर आपक सभिित करत।"
},
"recoveryPhraseReminderTitle": {
"message": "अपन धन करकित रख"
},
"reject": {
"message": "असर कर"
},
@ -1544,6 +1602,42 @@
"securitySettingsDescription": {
"message": "गपनयतिस और वट कत रिकवर"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "लिख ल और कई गत सर कर।"
},
"seedPhraseIntroSidebarBulletOne": {
"message": "पसवरड मजर म सह"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "सििट बस मर कर।"
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "बक कि रख।"
},
"seedPhraseIntroSidebarCopyOne": {
"message": "आपकिकवर आपकट और धन किए “मटर क” ह।"
},
"seedPhraseIntroSidebarCopyThree": {
"message": "यदिई वयकि आपकिकवरगत, त सबस अधिक सवनि आपकरयस कर रह।"
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "कभ अपनिकवर न कर, MetaMask कथ भ नह!"
},
"seedPhraseIntroSidebarTitleOne": {
"message": "रिकवर?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "क अपनिकवर करनिए?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "म अपनिकवर सह?"
},
"seedPhraseIntroTitle": {
"message": "अपनट करकित कर"
},
"seedPhraseIntroTitleCopy": {
"message": "शआत करन पहल, अपनिकवर और अपनट करकित रखन तरननिए यह छ-सि।"
},
"seedPhrasePlaceholder": {
"message": "परतक शबद क एक रिि अलग कर"
},
@ -2006,6 +2100,9 @@
"message": "$1 स $2 मप कर",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "इस टकन कअल रप स गय।"
},
"swapTokenVerificationMessage": {
"message": "हम $1 पर टकन पति कर।",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2273,7 +2370,7 @@
"message": "URL क उपयत HTTP/HTTPS उपसरग क आवशयकत।"
},
"urlExistsErrorMsg": {
"message": "URL नटवरक क पहलद ह"
"message": "यह URL वरतमन म $1 नटवरक द उपयग कि"
},
"usePhishingDetection": {
"message": "फििग डिशन क उपयग कर"
@ -2295,6 +2392,10 @@
"message": "इस टकन क $1 पर सतित कर",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "इस टकन क $1 पर सतित कर और सिित करि यह वहकन हिसस आप वर करनहत।",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "ख"
},
@ -2328,6 +2429,10 @@
"walletSeedRestore": {
"message": "वट कत रिकवर"
},
"web3ShimUsageNotification": {
"message": "हमनि वरतमन वबसइट न हटए गए window.web3 API क उपयग करनिश क। यदिइट म गडबड लगत, तपय अधिक जनकिए $1 पर किक कर।",
"description": "$1 is a clickable link."
},
"welcome": {
"message": "MetaMask म आपकगत ह"
},

@ -43,9 +43,6 @@
"blockiesIdenticon": {
"message": "बज पहचन क उपयग कर"
},
"builtInCalifornia": {
"message": "मक किििइन और बन गय।"
},
"cancel": {
"message": "रदद कर"
},
@ -285,9 +282,6 @@
"readdToken": {
"message": "आप अपनिकलप म .टकन ज. पर जकर भविय म इस टकन कपस ज सकत।"
},
"recipientAddress": {
"message": "पतकर पत"
},
"reject": {
"message": "असर"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Vaš se preglednik ne podržava..."
},
"builtInCalifornia": {
"message": "MetaMask je osmišljen i izrađen u Kaliforniji."
},
"buyWithWyre": {
"message": "Kupi ETH Wyerom"
},
@ -747,9 +744,6 @@
"recents": {
"message": "Nedavno"
},
"recipientAddress": {
"message": "Adresa primatelja"
},
"recipientAddressPlaceholder": {
"message": "Pretraži, javne adrese (0x) ili ENS"
},

@ -73,9 +73,6 @@
"browserNotSupported": {
"message": "Navigatè ou a pa sipòte..."
},
"builtInCalifornia": {
"message": "MetaMask fèt e bati nan California."
},
"cancel": {
"message": "Anile"
},
@ -450,9 +447,6 @@
"readdToken": {
"message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an."
},
"recipientAddress": {
"message": "Adrès pou resevwa"
},
"reject": {
"message": "Rejte"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Az ön böngészője nem támogatott..."
},
"builtInCalifornia": {
"message": "A MetaMaskot Kaliforniában tervezték és hozták létre."
},
"buyWithWyre": {
"message": "Vásároljon ETH-t a Wyre-rel"
},
@ -747,9 +744,6 @@
"recents": {
"message": "Legutóbbiak"
},
"recipientAddress": {
"message": "Címzett címe"
},
"recipientAddressPlaceholder": {
"message": "Keresés, nyilvános cím (0x) vagy ENS"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "Tambah kontak"
},
"addCustomTokenByContractAddress": {
"message": "Tidak dapat menemukan token? Anda dapat menambahkan token secara manual dengan menempelkan alamatnya. Alamat kontrak token dapat ditemukan di $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Ini akan memungkinkan jaringan ini digunakan dengan MetaMask."
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "Browser Anda tidak didukung..."
},
"builContactList": {
"buildContactList": {
"message": "Buat daftar kontak Anda"
},
"builtInCalifornia": {
"message": "MetaMask didesain dan didirikan di California."
},
"buy": {
"message": "Beli"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "ID rantai digunakan untuk menandatangani transaksi untuk jaringan ini."
},
"chainIdExistsErrorMsg": {
"message": "ID Rantai ini saat ini digunakan oleh jaringan $1."
},
"chromeRequiredForHardwareWallets": {
"message": "Anda perlu menggunakan MetaMask di Google Chrome untuk terhubung ke Dompet Perangkat Keras Anda."
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Lanjutkan ke Wyre"
},
"contract": {
"message": "Kontrak"
},
"contractAddressError": {
"message": "Anda mengirim token ke alamat kontrak token. Ini dapat mengakibatkan token ini hilang."
},
@ -626,6 +633,10 @@
"endOfFlowMessage6": {
"message": "Jika Anda perlu mencadangkan Frasa Pemulihan Rahasia lagi, Anda dapat menemukannya di Pengaturan -> Keamanan."
},
"endOfFlowMessage7": {
"message": "Jika Anda memiliki pertanyaan atau melihat sesuatu yang mencurigakan, hubungi dukungan $1 kami.",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "MetaMask tidak dapat memulihkan Frasa Pemulihan Rahasia Anda."
},
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "Impor akun dengan Frasa Pemulihan Rahasia"
},
"importAccountText": {
"message": "atau $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "Impor token?"
},
"importTokenWarning": {
"message": "Siapa pun dapat membuat token dengan nama apa pun, termasuk versi palsu dari token yang ada. Tambahkan dan perdagangkan dengan risiko Anda sendiri!"
},
"importWallet": {
"message": "Impor dompet"
},
@ -1287,6 +1308,22 @@
"message": "\"Frasa Pemulihan\" Anda kini disebut \"Frasa Pemulihan Rahasia.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Pada Chrome versi 91, API yang memungkinkan dukungan Ledger (U2F) kami tidak lagi mendukung dompet perangkat keras. MetaMask telah menerapkan dukungan Ledger Live baru yang memungkinkan Anda terus terhubung ke perangkat Ledger Anda melalui aplikasi desktop Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Saat berinteraksi dengan akun Ledger Anda di MetaMask, tab baru akan terbuka dan Anda akan diminta untuk membuka aplikasi Ledger Live. Setelah aplikasi tersebut terbuka, Anda akan diminta untuk mengizinkan koneksi WebSocket ke akun MetaMask Anda. Tidak diperlukan tindakan lebih lanjut.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "Anda dapat mengaktifkan dukungan Ledger Live dengan mengklik Pengaturan > Lanjutan > Gunakan Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Pembaruan Dukungan Ledger untuk Pengguna Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "dari"
},
@ -1411,12 +1448,33 @@
"recents": {
"message": "Terkini"
},
"recipientAddress": {
"message": "Alamat Penerima"
},
"recipientAddressPlaceholder": {
"message": "Cari, alamat publik (0x), atau ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Mulai di sini"
},
"recoveryPhraseReminderConfirm": {
"message": "Mengerti"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Jaga selalu Frasa Pemulihan Rahasia Anda di tempat yang aman dan rahasia"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "Perlu mencadangkan Frasa Pemulihan Rahasia Anda lagi?"
},
"recoveryPhraseReminderItemOne": {
"message": "Jangan membagikan Frasa Pemulihan Rahasia Anda kepada siapa pun"
},
"recoveryPhraseReminderItemTwo": {
"message": "Tim MetaMask tidak akan pernah meminta Frasa Pemulihan Rahasia Anda"
},
"recoveryPhraseReminderSubText": {
"message": "Frasa Pemulihan Rahasia Anda mengendalikan semua akun Anda."
},
"recoveryPhraseReminderTitle": {
"message": "Lindungi dana Anda"
},
"reject": {
"message": "Tolak"
},
@ -1442,7 +1500,7 @@
"message": "Hapus akun"
},
"removeAccountDescription": {
"message": "Akun ini akan dihapus dari dompet Anda. Pastikan Anda memiliki Frasa Pemulihan Rahasia asli atau kunci privat untuk akun impor ini sebelum melanjutkan. Anda dapat mengimpor atau membuat akun lagi dari drop down akun. "
"message": "Akun ini akan dihapus dari dompet Anda. Pastikan Anda memiliki Frasa Pemulihan Rahasia asli atau kunci privat untuk akun impor ini sebelum melanjutkan. Anda dapat mengimpor atau membuat akun lagi dari akun drop down. "
},
"requestsAwaitingAcknowledgement": {
"message": "permintaan menunggu untuk diakui"
@ -1544,6 +1602,42 @@
"securitySettingsDescription": {
"message": "Pengaturan privasi dan Frasa Pemulihan Rahasia dompet"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "Tuliskan dan simpan di beberapa tempat rahasia."
},
"seedPhraseIntroSidebarBulletOne": {
"message": "Simpan dalam pengelola kata sandi"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "Simpan di kotak deposit yang aman."
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "Simpan di vault bank."
},
"seedPhraseIntroSidebarCopyOne": {
"message": "Frasa pemulihan Anda adalah “kunci induk” ke dompet dan dana Anda."
},
"seedPhraseIntroSidebarCopyThree": {
"message": "Jika seseorang menanyakan frasa pemulihan Anda, kemungkinan mereka akan mencoba menipu Anda."
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "Jangan pernah membagikan frasa pemulihan Anda bahkan kepada MetaMask!"
},
"seedPhraseIntroSidebarTitleOne": {
"message": "Apa itu frasa pemulihan?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "Haruskah saya membagikan frasa pemulihan saya?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "Bagaimana cara menyimpan frasa pemulihan saya?"
},
"seedPhraseIntroTitle": {
"message": "Amankan dompet Anda"
},
"seedPhraseIntroTitleCopy": {
"message": "Sebelum memulai, lihat video singkat ini untuk mempelajari tentang frasa pemulihan Anda dan cara menjaga keamanan dompet Anda."
},
"seedPhrasePlaceholder": {
"message": "Pisahkan setiap kata dengan satu spasi"
},
@ -2006,6 +2100,9 @@
"message": "Tukar $1 untuk $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Token ini telah ditambahkan secara manual."
},
"swapTokenVerificationMessage": {
"message": "Selalu konfirmasikan alamat token di $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2273,7 +2370,7 @@
"message": "URL memerlukan awalan HTTP/HTTPS yang sesuai."
},
"urlExistsErrorMsg": {
"message": "URL sudah ada dalam daftar jaringan yang ada"
"message": "URL ini saat ini digunakan oleh jaringan $1."
},
"usePhishingDetection": {
"message": "Menggunakan Deteksi Phishing"
@ -2295,6 +2392,10 @@
"message": "Verifikasikan token ini di $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Verifikasi token ini di $1 dan pastikan ini adalah token yang ingin Anda perdagangkan.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Lihat Akun"
},
@ -2328,6 +2429,10 @@
"walletSeedRestore": {
"message": "Frasa Pemulihan Rahasia Dompet"
},
"web3ShimUsageNotification": {
"message": "Kami melihat situs web saat ini mencoba menggunakan API window.web3 yang dihapus. Jika situs tersebut tampak bermasalah, silakan klik $1 untuk informasi selengkapnya.",
"description": "$1 is a clickable link."
},
"welcome": {
"message": "Selamat datang di MetaMask"
},

@ -217,9 +217,6 @@
"browserNotSupported": {
"message": "Il tuo Browser non è supportato..."
},
"builtInCalifornia": {
"message": "MetaMask è progettato e realizzato in California."
},
"buy": {
"message": "Compra"
},
@ -1201,9 +1198,6 @@
"recents": {
"message": "Recenti"
},
"recipientAddress": {
"message": "Indirizzo Destinatario"
},
"recipientAddressPlaceholder": {
"message": "Ricerca, indirizzo pubblico (0x) o ENS"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "連絡先の追加"
},
"addCustomTokenByContractAddress": {
"message": "トークンを発見できませんか?アドレスをペーストすることで手動でトークンを追加することができます。トークン コントラクト アドレスは $1 にあります。",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "これにより、このネットワークは MetaMask 内で使用できるようになります。"
},
@ -109,7 +113,7 @@
"message": "アグリゲーター ネットワーク料金"
},
"alertDisableTooltip": {
"message": "\"設定 > 警告\" の設定で変更できます"
"message": "これは、[\"設定 > 警告\"] で変更できます"
},
"alertSettingsUnconnectedAccount": {
"message": "選択した未接続のアカウントを使用して Web サイトをブラウズしています"
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "ご使用のブラウザーはサポートされていません..."
},
"builContactList": {
"buildContactList": {
"message": "連絡先リストを作成する"
},
"builtInCalifornia": {
"message": "MetaMask はカリフォルニアで設計および作成されました。"
},
"buy": {
"message": "購入"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "このネットワークのトランザクションの署名に使用されるチェーン ID。"
},
"chainIdExistsErrorMsg": {
"message": "このチェーン ID は現在 $1 ネットワークで使用しています。"
},
"chromeRequiredForHardwareWallets": {
"message": "ハードウェア ウォレットに接続するには、MetaMask on Google Chrome を使用する必要があります。"
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Wyre に進む"
},
"contract": {
"message": "コントラクト"
},
"contractAddressError": {
"message": "トークンのコントラクト アドレスにトークンを送信しています。これにより、これらのトークンが失われる可能性があります。"
},
@ -624,7 +631,11 @@
"message": "フィッシングにご注意ください!MetaMask の動作として、シークレット リカバリー フレーズを要求することは絶対にありません。"
},
"endOfFlowMessage6": {
"message": "シークレット リカバリー フレーズを再度バックアップする場合は、[設定] -> [セキュリティとプライバシー] にアクセスしてください。"
"message": "シークレット リカバリー フレーズを再度バックアップする場合は、[設定] -> [セキュリティ] でそれを見つけることができます。"
},
"endOfFlowMessage7": {
"message": "ご質問、または不審な点がある場合は、当社のサポート $1 までお問い合わせください。",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "MetaMask はシークレット リカバリー フレーズを復元できません。"
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "シークレット リカバリー フレーズを使用してアカウントをインポートする:"
},
"importAccountText": {
"message": "または $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "トークンをインポートしますか?"
},
"importTokenWarning": {
"message": "誰でも既存のトークンの偽バージョンを含めて、任意の名前でトークンを作成することができます。自己責任で追加およびトレードしてください。"
},
"importWallet": {
"message": "ウォレットのインポート"
},
@ -1287,6 +1308,22 @@
"message": "これで、\"シード フレーズ\" は \"シークレット リカバリー フレーズ\" と呼ばれます。",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Chrome バージョン 91 以降は、レジャーのサポート (U2F) を可能にした API がハードウェア ウォレットをサポートしなくなります。MetaMask では、ユーザーがレジャー ライブのデスクトップ アプリを介して、レジャー デバイスに継続的に接続することができる新しいレジャー ライブのサポートを導入しました。",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "MetaMask のレジャーのアカウントを使用する際は、新しいタブが開き、レジャー ライブのアプリを開くよう指示されます。アプリが開いたら、WebSocket 接続を MetaMask のアカウントに許可するよう指示されます。以上です。",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "[設定] > [詳細] > [レジャー ライブを使用] の順にクリックすることで、レジャー ライブのサポートを有効にすることができます。",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Chrome ユーザー向けのレジャーのサポートの更新",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "中の"
},
@ -1411,12 +1448,33 @@
"recents": {
"message": "最近"
},
"recipientAddress": {
"message": "受信者のアドレス"
},
"recipientAddressPlaceholder": {
"message": "検索、パブリック アドレス (0x)、または ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "ここから開始"
},
"recoveryPhraseReminderConfirm": {
"message": "OK"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "シークレット リカバリー フレーズは常に安全かつ秘密の場所に保管してください"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "シークレット リカバリー フレーズのバックアップが必要ですか?"
},
"recoveryPhraseReminderItemOne": {
"message": "シークレット リカバリー フレーズは誰とも決して共有しないでください"
},
"recoveryPhraseReminderItemTwo": {
"message": "MetaMask チームが、ユーザーのシークレット リカバリー フレーズを確認することは絶対にありません"
},
"recoveryPhraseReminderSubText": {
"message": "シークレット リカバリー フレーズは、ご利用のすべてのアカウントを制御します。"
},
"recoveryPhraseReminderTitle": {
"message": "資産を保護してください"
},
"reject": {
"message": "拒否"
},
@ -1544,6 +1602,42 @@
"securitySettingsDescription": {
"message": "プライバシーの設定とシークレット リカバリー フレーズ"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "書き留めて、複数の秘密の場所に保存します。"
},
"seedPhraseIntroSidebarBulletOne": {
"message": "パスワード マネージャーに保存する"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "セーフティ ボックスに保管する。"
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "銀行の金庫に保管する。"
},
"seedPhraseIntroSidebarCopyOne": {
"message": "あなたのリカバリー フレーズは、ウォレットと資金への「マスターキー」です。"
},
"seedPhraseIntroSidebarCopyThree": {
"message": "誰かがあなたのリカバリー フレーズを尋ねてきたら、おそらくあなたを騙そうとしているのです。"
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "MetaMask を共有しても、リカバリ フレーズは決して共有しないでください。"
},
"seedPhraseIntroSidebarTitleOne": {
"message": "リカバリー フレーズとは何ですか?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "リカバリーフレーズは共有すべきですか?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "リカバリー フレーズはどのように保存すべきですか?"
},
"seedPhraseIntroTitle": {
"message": "ウォレットの保護"
},
"seedPhraseIntroTitleCopy": {
"message": "始める前に、この短いビデオを見て、リカバリー フレーズとウォレットを安全に保つ方法について確認してください。"
},
"seedPhrasePlaceholder": {
"message": "単語ごとにスペースを 1 つ置いて分離します"
},
@ -1896,6 +1990,15 @@
"message": "約 $1% の価格差",
"description": "$1 is a number (ex: 1.23) that represents the price difference."
},
"swapPriceImpactTooltip": {
"message": "プライスインパクトとは、現在の市場価格と取引の約定時に受け取った金額の差のことです。プライスインパクトとは、流動性プールの大きさに対するあなたのトレードの大きさを表わす関数です。"
},
"swapPriceUnavailableDescription": {
"message": "市場価格のデータが不足しているため、プライスインパクトを測定できませんでした。スワップする前に、これから受領するトークンの額に問題がないか確認してください。"
},
"swapPriceUnavailableTitle": {
"message": "続行する前にレートを確認してください"
},
"swapProcessing": {
"message": "処理中"
},
@ -1997,6 +2100,9 @@
"message": "$1 を $2 にスワップ",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "このトークンは手動で追加されました。"
},
"swapTokenVerificationMessage": {
"message": "常に $1 のトークン アドレスを確認してください。",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2264,7 +2370,7 @@
"message": "URL には適切な HTTP/HTTPS プレフィックスが必要です。"
},
"urlExistsErrorMsg": {
"message": "URL はネットワークの既存のリストに既に存在します"
"message": "この URL は現在 $1 ネットワークで使用しています。"
},
"usePhishingDetection": {
"message": "フィッシング検出を使用"
@ -2286,6 +2392,10 @@
"message": "このトークンを $1 で検証",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "このトークンを $1 で検証して、それがトレードしたいトークンであることを確認してください。",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "アカウントを表示"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "ನಿಮ ಬಸರಬಲಿಿಲ..."
},
"builtInCalifornia": {
"message": "MetaMask ಅನಿಸಗಿಸಲಿ ಮತಿಿದಲಿಿಿಸಲಿ."
},
"buyWithWyre": {
"message": "Wyre ನಿ ETH ಖರಿಿ"
},
@ -754,9 +751,6 @@
"recents": {
"message": "ಇತಿನವಗಳ"
},
"recipientAddress": {
"message": "ಸಕರಿವವರ ವಿಸ"
},
"recipientAddressPlaceholder": {
"message": "ಸವಜನಿಕ ವಿಸ (0x) ಅಥವ ENS ಹಿ"
},

File diff suppressed because it is too large Load Diff

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Jūsų naršyklė neatpažįstama..."
},
"builtInCalifornia": {
"message": "„MetaMask“ suprojektuota ir įdiegta Kalifornijoje."
},
"buyWithWyre": {
"message": "Pirkti ETH su „Wyre“"
},
@ -754,9 +751,6 @@
"recents": {
"message": "Naujausi"
},
"recipientAddress": {
"message": "Gavėjo adresas"
},
"recipientAddressPlaceholder": {
"message": "Ieška, viešieji adresai (0x) arba ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Jūsu pārlūkprogramma netiek atbalstīta..."
},
"builtInCalifornia": {
"message": "MetaMask ir izstrādāta un izveidota Kalifornijā."
},
"buyWithWyre": {
"message": "Pirkt ETH ar Wyre"
},
@ -750,9 +747,6 @@
"recents": {
"message": "Nesenie"
},
"recipientAddress": {
"message": "Saņēmēja adrese"
},
"recipientAddressPlaceholder": {
"message": "Meklēšana, publiskā adrese (0x) vai ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Pelayar anda tidak disokong..."
},
"builtInCalifornia": {
"message": "MetaMask direka dan dibina di California."
},
"buyWithWyre": {
"message": "Beli ETH dengan Wyre"
},
@ -731,9 +728,6 @@
"recents": {
"message": "Baru-baru ini"
},
"recipientAddress": {
"message": "Alamat Penerima"
},
"recipientAddressPlaceholder": {
"message": "Cari, alamat awam (0x), atau ENS"
},

@ -40,9 +40,6 @@
"blockiesIdenticon": {
"message": "Gebruik Blockies Identicon"
},
"builtInCalifornia": {
"message": "MetaMask is ontworpen en gebouwd in Californië."
},
"cancel": {
"message": "Annuleer"
},
@ -272,9 +269,6 @@
"readdToken": {
"message": "U kunt dit token in de toekomst weer toevoegen door naar \"Token toevoegen\" te gaan in het menu met accountopties."
},
"recipientAddress": {
"message": "Geadresseerde adres"
},
"reject": {
"message": "Afwijzen"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Nettleseren din støttes ikke ..."
},
"builtInCalifornia": {
"message": "MetaMask ble bygget og designet i California."
},
"buyWithWyre": {
"message": "Kjøp ETH med Wyre"
},
@ -741,9 +738,6 @@
"recents": {
"message": "Nylige"
},
"recipientAddress": {
"message": "Mottakeradresse"
},
"recipientAddressPlaceholder": {
"message": "Søk, offentlig adresse (0x) eller ENS"
},

@ -6,7 +6,7 @@
"message": "Bersyon, support center, at impormasyon sa pakikipag-ugnayan"
},
"acceleratingATransaction": {
"message": "* Kapag in-accelerate ang transaksyon sa pamamagitan ng paggamit ng mas mataas na presyo ng gas, mas magiging malaki ang tsansang mas mabilis na maproseso ng network, pero hindi ito palaging ginagarantiya."
"message": "* Kapag in-accelerate ang transaksyon sa pamamagitan ng paggamit ng mas mataas na presyo ng gas, mas magiging malaki ang tsansang mas mabilis na maiproseso ng network, pero hindi ito palaging ginagarantiya."
},
"acceptTermsOfUse": {
"message": "Nabasa ko at sumasang-ayon ako sa $1",
@ -52,6 +52,10 @@
"addContact": {
"message": "Magdagdag ng contact"
},
"addCustomTokenByContractAddress": {
"message": "Walang makitang token? Puwede kang manual na magdagdag ng anumang token sa pamamagitan ng pag-paste ng address nito. Makikita ang mga address ng kontrata ng token sa $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Bibigyang-daan nito na magamit ang network na ito sa MetaMask."
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "Hindi sinusuportahan ang iyong Browser..."
},
"builContactList": {
"buildContactList": {
"message": "Buuin ang iyong listahan ng contact"
},
"builtInCalifornia": {
"message": "Ang MetaMask ay idinisenyo at binuo sa California."
},
"buy": {
"message": "Bumili"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "Ginagamit ang chain ID para maglagda ng mga transaksyon para sa network na ito."
},
"chainIdExistsErrorMsg": {
"message": "Kasalukuyang ginagamit ng $1 network ang Chain ID na ito."
},
"chromeRequiredForHardwareWallets": {
"message": "Kailangan mong gamitin ang MetaMask sa Google Chrome para maikonekta sa iyong Hardware Wallet."
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Magpatuloy sa Wyre"
},
"contract": {
"message": "Kontrata"
},
"contractAddressError": {
"message": "Magpapadala ka ng mga token sa address ng kontrata ng token. Posible itong magresulta sa pagkawala ng mga token na ito."
},
@ -641,7 +648,7 @@
"description": "$1 is the return value of eth_chainId from an RPC endpoint"
},
"ensNotFoundOnCurrentNetwork": {
"message": "Hindi nahanapa ang ENS name sa kasalukuyang network. Subukang lumipat sa Ethereum Mainnet."
"message": "Hindi nahanap ang ENS name sa kasalukuyang network. Subukang lumipat sa Ethereum Mainnet."
},
"ensRegistrationError": {
"message": "Nagka-error sa pag-register ng ENS name"
@ -694,7 +701,7 @@
"message": "Mga Tinatantyang Tagal ng Pagproseso"
},
"ethGasPriceFetchWarning": {
"message": "Ibinibigay ang backup na presyo ng gas dahil hindi available ang pangunahing serbisyo sa pagtatantiya ng gas sa ngayon."
"message": "Ibinibigay ang backup na presyo ng gas dahil hindi available ang pangunahing serbisyo sa pagtatantya ng gas sa ngayon."
},
"eth_accounts": {
"message": "Tingnan ang mga address ng iyong mga pinapayagang account (kinakailangan)",
@ -793,7 +800,7 @@
"message": "Sobrang Baba ng Presyo ng Gas"
},
"gasPriceFetchFailed": {
"message": "Hindi nagtagumpay ang pagtatantiya ng presyo ng gas dahil sa error sa network."
"message": "Hindi nagtagumpay ang pagtatantya ng presyo ng gas dahil sa error sa network."
},
"gasPriceInfoTooltipContent": {
"message": "Tinutukoy ng presyo ng gas ang halaga ng Ether na handa mong bayaran para sa bawat unit ng gas."
@ -893,6 +900,12 @@
"message": "o $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "Mag-import ng token?"
},
"importTokenWarning": {
"message": "Sinuman ay makakagawa ng token na may anumang pangalan, kasama ang mga pekeng bersyon ng mga token na mayroon na. Magdagdag at mag-trade sa sarili mong pananagutan!"
},
"importWallet": {
"message": "Mag-import ng wallet"
},
@ -1022,7 +1035,7 @@
"message": "Mga Link"
},
"loadMore": {
"message": "Matuto Pa"
"message": "Mag-load Pa"
},
"loading": {
"message": "Nilo-load..."
@ -1127,7 +1140,7 @@
"message": "Pangalan"
},
"needEtherInWallet": {
"message": "Para makaugnayan ang mga decentralized ma application gamit ang MetaMask, kakailanganin mo ang Ether sa iyong wallet."
"message": "Para makaugnayan ang mga decentralized na application gamit ang MetaMask, kakailanganin mo ang Ether sa iyong wallet."
},
"needHelp": {
"message": "Kailangan ng tulong? Makipag-ugnayan sa $1",
@ -1162,7 +1175,7 @@
"message": "Testnet"
},
"networkSettingsChainIdDescription": {
"message": "Ginagaamit ang chain ID sa paglagda ng mga transaksyon. Dapat itong tumugma sa chain ID na ibinalik ng network. Puwede kang maglagay ng decimal o '0x'-prefixed hexadecimal number, pero ipapakita namin ang numero sa decimal."
"message": "Ginagamit ang chain ID sa paglagda ng mga transaksyon. Dapat itong tumugma sa chain ID na ibinalik ng network. Puwede kang maglagay ng decimal o '0x'-prefixed hexadecimal number, pero ipapakita namin ang numero sa decimal."
},
"networkSettingsDescription": {
"message": "Magdagdag at mag-edit ng mga custom na RPC network"
@ -1214,7 +1227,7 @@
"message": "Susunod"
},
"nextNonceWarning": {
"message": "Mas mataas ang noncesa iminumungkahing nonce na $1",
"message": "Mas mataas ang nonce sa iminumungkahing nonce na $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"noAccountsFound": {
@ -1295,6 +1308,22 @@
"message": "Tinatawag na ngayong \"Secret Recovery Phrase\" mo ang iyong \"Seed Phrase.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Simula sa Chrome version 91, hindi na susuportahan ng API na nag-enable sa aming Ledger support (U2F) ang mga hardware wallet. Nagpatupad ang MetaMask ng bagong Ledger Live support na nagbibigay-daan sa iyong patuloy na ikonekta ang Ledger device mo sa pamamagitan ng Ledger Live desktop app.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Kapag ginagamit ang iyong Ledger account sa MetaMask, may bagong tab na magbubukas at hihilingin sa iyong buksan ang Ledger Live app. Kapag nagbukas ang app, hihilingin sa iyong payagan ang isang koneksyon ng WebSocket sa MetaMask account mo. Iyon lang!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "Puwede mong i-enable ang Ledger Live support sa pamamagitan ng pag-click sa Mga Setting > Advanced > Gamitin ang Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Update sa Ledger Support para sa Mga Chrome User",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "ng"
},
@ -1419,12 +1448,33 @@
"recents": {
"message": "Mga Kamakailan"
},
"recipientAddress": {
"message": "Address ng Tatanggap"
},
"recipientAddressPlaceholder": {
"message": "Maghanap, pampublikong address (0x), o ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Magsimula rito"
},
"recoveryPhraseReminderConfirm": {
"message": "OK"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Palaging panatilihin ang iyong Secret Recovery Phrase sa isang ligtas at lihim na lugar"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "Kailangan ulit i-back up ang Secret Recovery Phrase mo?"
},
"recoveryPhraseReminderItemOne": {
"message": "Huwag kailanman ipaalam sa iba ang iyong Secret Recovery Phrase"
},
"recoveryPhraseReminderItemTwo": {
"message": "Hindi kailanman hihingin ng MetaMask team ang iyong Secret Recovery Phrase"
},
"recoveryPhraseReminderSubText": {
"message": "Kinokontrol ng iyong Secret Recovery Phrase ang lahat ng iyong account."
},
"recoveryPhraseReminderTitle": {
"message": "Protektahan ang iyong pondo!"
},
"reject": {
"message": "Tanggihan"
},
@ -1869,7 +1919,7 @@
"message": "Ito ay pagtatantya ng bayarin sa network na gagamitin para kumpletuhin ang iyong pag-swap. Posibleng magbago ang aktuwal na halaga ayon sa mga kundisyon ng network."
},
"swapFailedErrorDescriptionWithSupportLink": {
"message": "May mga hindi pagtatagumpay sa transkasyon na nangyayari at narito kami para tumulong. Kung magpapatuloy ang isyung ito, puwede kang makipag-ugnayan sa aming suporta sa customer sa $1 para sa karagdagang tulong.",
"message": "May mga hindi pagtatagumpay sa transaksyon na nangyayari at narito kami para tumulong. Kung magpapatuloy ang isyung ito, puwede kang makipag-ugnayan sa aming suporta sa customer sa $1 para sa karagdagang tulong.",
"description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io"
},
"swapFailedErrorTitle": {
@ -1901,7 +1951,7 @@
"message": "Posibleng hindi magtagumpay ang transaksyon, masyadong mababa ang max na slippage."
},
"swapMaxNetworkFeeInfo": {
"message": "Aang “$1” ay ang pinakamalaking gagastusin mo. Kapag volatile ang network, maaaring malaking halaga ito.",
"message": "“$1” ang pinakamalaking gagastusin mo. Kapag volatile ang network, maaaring malaking halaga ito.",
"description": "$1 will be the translation of swapMaxNetworkFees, with the font bolded"
},
"swapMaxNetworkFees": {
@ -2050,6 +2100,9 @@
"message": "I-swap ang $1 sa $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Manual na idinagdag ang token na ito."
},
"swapTokenVerificationMessage": {
"message": "Palaging kumpirmahin ang address ng token sa $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2317,7 +2370,7 @@
"message": "Kinakailangan ng mga URL ang naaangkop na HTTP/HTTPS prefix."
},
"urlExistsErrorMsg": {
"message": "Nasa kasalukuyang listahan ng mga network na ang URL"
"message": "Kasalukuyang ginagamit ng $1 network ang URL na ito."
},
"usePhishingDetection": {
"message": "Gumamit ng Pag-detect ng Phishing"
@ -2339,6 +2392,10 @@
"message": "I-verify ang token na ito sa $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "I-verify ang token na ito sa $1 at tiyaking ito ang token na gusto mong i-trade.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Tingnan ang Account"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Twoja przeglądarka nie jest obsługiwana..."
},
"builtInCalifornia": {
"message": "MetaMask został zaprojektowany i stworzony w Kaliforni."
},
"buyWithWyre": {
"message": "Kup ETH poprzez Wyre"
},
@ -748,9 +745,6 @@
"recents": {
"message": "Ostatnie"
},
"recipientAddress": {
"message": "Adres odbiorcy"
},
"recipientAddressPlaceholder": {
"message": "Szukaj, adres publiczny (0x) lub ENS"
},

@ -43,9 +43,6 @@
"blockiesIdenticon": {
"message": "Usar Blockies Identicon"
},
"builtInCalifornia": {
"message": "MetaMask é desenhada e construída na California."
},
"cancel": {
"message": "Cancelar"
},
@ -282,9 +279,6 @@
"readdToken": {
"message": "Pode adicionar este token de novo clicando na opção “Adicionar token” no menu de opções da sua conta."
},
"recipientAddress": {
"message": "Endereço do Destinatário"
},
"reject": {
"message": "Rejeitar"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "Adicionar contato"
},
"addCustomTokenByContractAddress": {
"message": "Não conseguiu encontrar um token? Cole o endereço para adicionar manualmente qualquer token. Os endereços de contato do token podem ser encontrados em $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Isso permitirá esta rede ser usada dentro do MetaMask."
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "Seu navegador não é compatível..."
},
"builContactList": {
"buildContactList": {
"message": "Crie sua lista de contatos"
},
"builtInCalifornia": {
"message": "O MetaMask é projetado e construído na Califórnia."
},
"buy": {
"message": "Comprar"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "O ID da chain usado para assinar transações para essa rede."
},
"chainIdExistsErrorMsg": {
"message": "O ID da chain é usado no momento pela rede $1."
},
"chromeRequiredForHardwareWallets": {
"message": "Você precisa usar MetaMask no Google Chrome para se conectar com sua carteira de hardware."
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Continuar para o Wyre"
},
"contract": {
"message": "Contrato"
},
"contractAddressError": {
"message": "Você está enviando tokens ao endereço de contrato do token. Isso pode resultar na perda destes tokens."
},
@ -626,6 +633,10 @@
"endOfFlowMessage6": {
"message": "Se você precisar fazer backup da sua Frase de recuperação secreta novamente, encontre-a em Configurações -> Segurança."
},
"endOfFlowMessage7": {
"message": "Se você tiver alguma pergunta ou vir algo suspeito, entre em contato com o atendimento ao cliente em $1.",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "O MetaMask não pode recuperar sua Frase de recuperação secreta."
},
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "Importe uma conta com a Frase de recuperação secreta"
},
"importAccountText": {
"message": "ou $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "Importar token?"
},
"importTokenWarning": {
"message": "Qualquer pessoa pode criar um token com um nome, incluindo versões falsas de tokens existentes. Adicione e negocie, assumindo o risco sozinho!"
},
"importWallet": {
"message": "Importar carteira"
},
@ -961,6 +982,12 @@
"invalidSeedPhrase": {
"message": "Frase de recuperação secreta inválida"
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
"ipfsGatewayDescription": {
"message": "Informe o URL do gateway de CID do IPFS para usar com resolução de conteúdo de ENS."
},
"jsonFile": {
"message": "Arquivo JSON",
"description": "format for importing an account"
@ -1104,7 +1131,7 @@
"message": "Informe sua senha para confirmar que é você mesmo!"
},
"mustSelectOne": {
"message": "Selecione pelo menos 1 token."
"message": "Selecione pelo menos 1 token."
},
"myAccounts": {
"message": "Minhas contas"
@ -1281,8 +1308,24 @@
"message": "A sua \"Frase Semente\" agora é chamada de sua \"Frase Secreta de Recuperação.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "A partir do Chrome versão 91, a API que permitia nosso suporte ao Ledger (U2F) não é mais compatível com carteiras de hardware. O MetaMask implementou um novo suporte ao Ledger Live que permite continuar conectando o seu dispositivo Ledger device por meio do aplicativo de desktop Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Ao interagir com sua conta do Ledger no MetaMask, uma nova aba será aberta e você deverá abrir o aplicativo Ledger Live. Quando o aplicativo for aberto, você precisará permitir uma conexão do WebSocket com sua conta do MetaMask. É isso!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "Você pode habilitar o suporte do Ledger Live clicando em Configurações > Avançadas > Usar Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Atualização de suporte do Ledger para usuários do Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": " de "
"message": "de"
},
"off": {
"message": "Desativado"
@ -1405,12 +1448,33 @@
"recents": {
"message": "Recentes"
},
"recipientAddress": {
"message": "Endereço do destinatário"
},
"recipientAddressPlaceholder": {
"message": "Busca, endereço público (0x) ou ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Iniciar aqui"
},
"recoveryPhraseReminderConfirm": {
"message": "Entendi"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Mantenha sempre o sigilo e proteja a sua Frase de Recuperação Secreta."
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "Precisa fazer backup da sua Frase de recuperação Secreta novamente?"
},
"recoveryPhraseReminderItemOne": {
"message": "Nunca compartilhe a sua Frase de recuperação secreta com ninguém"
},
"recoveryPhraseReminderItemTwo": {
"message": "A equipe do MetaMask jamais pedirá sua Frase de recuperação secreta."
},
"recoveryPhraseReminderSubText": {
"message": "Sua Frase de recuperação secreta controla todas as suas contas."
},
"recoveryPhraseReminderTitle": {
"message": "Proteja seu dinheiro"
},
"reject": {
"message": "Rejeitar"
},
@ -1459,6 +1523,16 @@
"restoreAccountWithSeed": {
"message": "Restaure sua conta com a Frase de recuperação secreta"
},
"restoreWalletPreferences": {
"message": "Encontramos um backup dos seus dados de $1. Gostaria de restaurar as preferências da sua carteira?",
"description": "$1 is the date at which the data was backed up"
},
"retryTransaction": {
"message": "Refazer transação"
},
"reusedTokenNameWarning": {
"message": "O token aqui reutiliza um símbolo de outro token que você observa; isso pode causar confusões ou induzir ao erro."
},
"revealSeedWords": {
"message": "Revelar Frase de recuperação secreta"
},
@ -1528,6 +1602,42 @@
"securitySettingsDescription": {
"message": "Configurações de privacidade e Frase de recuperação secreta"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "Anote e guarde em vários locais secretos."
},
"seedPhraseIntroSidebarBulletOne": {
"message": "Salve em um gerenciador de senhas"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "Guarde dentro de um cofre."
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "Guarde em um cofre-forte bancário."
},
"seedPhraseIntroSidebarCopyOne": {
"message": "A sua frase de recuperação é a “chave-mestra” para sua carteira e seus fundos."
},
"seedPhraseIntroSidebarCopyThree": {
"message": "Caso alguém lhe peça a sua frase de recuperação, essa pessoa provavelmente está tentando dar um golpe em você."
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "Jamais compartilhe a sua frase de recuperação, mesmo com o MetaMask!"
},
"seedPhraseIntroSidebarTitleOne": {
"message": "O que é uma frase de recuperação?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "Devo compartilhar minha frase de recuperação?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "Como salvo minha frase de recuperação?"
},
"seedPhraseIntroTitle": {
"message": "Proteger sua carteira"
},
"seedPhraseIntroTitleCopy": {
"message": "Antes de iniciar, assista esse vídeo curto para aprender sobre sua frase de recuperação e sobre como manter sua carteira segura."
},
"seedPhrasePlaceholder": {
"message": "Separe cada palavra com um único espaço"
},
@ -1990,6 +2100,9 @@
"message": "Swap $1 para $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Este token foi adicionado manualmente."
},
"swapTokenVerificationMessage": {
"message": "Sempre confirme o endereço do token em $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2257,7 +2370,7 @@
"message": "Os URLs precisam do prefixo HTTP/HTTPS adequado."
},
"urlExistsErrorMsg": {
"message": "O URL já está presente na lista de redes existente"
"message": "O ID da chain é usado no momento pela rede $1."
},
"usePhishingDetection": {
"message": "Usar detecção de phishing"
@ -2279,6 +2392,10 @@
"message": "Verificar este token em $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Verifique este token em $1 garanta que seja o token que você deseja negociar.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Exibir conta"
},
@ -2312,6 +2429,10 @@
"walletSeedRestore": {
"message": "Frase de recuperação secreta da carteira"
},
"web3ShimUsageNotification": {
"message": "Percebemos que o site atual tentou usar a API window.web3 removida. Se o site parecer estar corrompido, clique em $1 para obter mais informações.",
"description": "$1 is a clickable link."
},
"welcome": {
"message": "Bem-vindo(a) ao MetaMask"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Browserul dvs. nu este compatibil..."
},
"builtInCalifornia": {
"message": "MetaMask este concepută și creată în California."
},
"buyWithWyre": {
"message": "Cumpărați ETH cu Wyre"
},
@ -741,9 +738,6 @@
"recents": {
"message": "Recente"
},
"recipientAddress": {
"message": "Adresă destinatar"
},
"recipientAddressPlaceholder": {
"message": "Căutare, adresa publică (0x) sau ENS"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "Добавить контакт"
},
"addCustomTokenByContractAddress": {
"message": "Невозможно найти токен? Вы можете вручную добавить любой токен, вставив его адрес. Контактные адреса токена можно найти на $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Это позволит использовать ее в MetaMask."
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "Ваш браузер не поддерживается..."
},
"builContactList": {
"buildContactList": {
"message": "Создайте список контактов"
},
"builtInCalifornia": {
"message": "MetaMask разработан и построен в Калифорнии."
},
"buy": {
"message": "Купить"
},
@ -280,11 +281,14 @@
"message": "Отменено"
},
"chainId": {
"message": "Идентификатор цепи"
"message": "Идентификатор цепочки"
},
"chainIdDefinition": {
"message": "Идентификатор цепочки, используемый для подписания транзакций для этой сети."
},
"chainIdExistsErrorMsg": {
"message": "Этот идентификатор цепочки в настоящее время используется сетью $1."
},
"chromeRequiredForHardwareWallets": {
"message": "Вам необходимо использовать MetaMask в Google Chrome, чтобы подключиться к аппаратному кошельку."
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Продолжить к Wyre"
},
"contract": {
"message": "Контракт"
},
"contractAddressError": {
"message": "Вы отправляете токены на адрес контракта токена. Это может привести к потере токенов."
},
@ -626,6 +633,10 @@
"endOfFlowMessage6": {
"message": "Если вам нужно снова создать резервную копию секретной фразы восстановления, вы можете найти ее в Настройки -> Безопасность."
},
"endOfFlowMessage7": {
"message": "Если у вас возникнут вопросы или вы увидите что-то подозрительное, обратитесь в службу поддержки $1.",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "Просто помните, что MetaMask не может восстановить секретную фразу восстановления."
},
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "Импортировать счет с секретной фразой восстановления"
},
"importAccountText": {
"message": "или $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "Импортировать токен?"
},
"importTokenWarning": {
"message": "Кто угодно может создать токен с любым именем, включая поддельные версии существующих токенов. Добавляйте и торгуйте на свой страх и риск!"
},
"importWallet": {
"message": "Импортировать кошелек"
},
@ -1287,6 +1308,22 @@
"message": "Исходная фраза теперь называется секретной фразой восстановления.",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Начиная с Chrome версии 91, API, обеспечивающий поддержку нашего Ledger (U2F), аппаратные кошельки больше не поддерживаются. MetaMask реализовала новую поддержку Ledger Live, которая позволяет продолжать подключаться к устройству Ledger через настольное приложение Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "При взаимодействии с вашим счетом Ledger в MetaMask откроется новая вкладка, и вам будет предложено открыть приложение Ledger Live. Когда приложение откроется, вам будет предложено разрешить WebSocket-соединение с вашим счетом MetaMask. Вот и все!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "Вы можете включить поддержку Ledger Live, нажав «Настройки» > «Дополнительно» > «Использовать Ledger Live».",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Обновление поддержки Ledger для пользователей Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "из"
},
@ -1411,12 +1448,33 @@
"recents": {
"message": "Недавние"
},
"recipientAddress": {
"message": "Адрес получателя"
},
"recipientAddressPlaceholder": {
"message": "Поиск, публичный адрес (0x) или ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Начать здесь"
},
"recoveryPhraseReminderConfirm": {
"message": "Понятно"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Всегда храните свою секретную фразу восстановления в надежном и секретном месте"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "Нужно снова сделать резервную копию секретной фразы восстановления?"
},
"recoveryPhraseReminderItemOne": {
"message": "Никогда никому не сообщайте свою секретную фразу восстановления"
},
"recoveryPhraseReminderItemTwo": {
"message": "Команда MetaMask никогда неожиданно не запросит вашу секретную фразу восстановления"
},
"recoveryPhraseReminderSubText": {
"message": "Ваша секретная фраза восстановления контролирует все ваши счета."
},
"recoveryPhraseReminderTitle": {
"message": "Защитите свои активы"
},
"reject": {
"message": "Отклонить"
},
@ -1476,7 +1534,7 @@
"message": "Токен здесь повторно использует символ из другого токена, который вы смотрите, это может запутать или ввести в заблуждение."
},
"revealSeedWords": {
"message": "Показать секретную фразу восстановления"
"message": "Раскрыть секретную фразу восстановления"
},
"revealSeedWordsDescription": {
"message": "Если вы меняете браузер или переходите на другой компьютер, вам понадобится эта секретная фраза восстановления для доступа к своим счетам. Сохраните ее в безопасном секретном месте."
@ -1544,6 +1602,42 @@
"securitySettingsDescription": {
"message": "Настройки конфиденциальности и секретная фраза восстановления кошелька"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "Запишите и храните в нескольких секретных местах."
},
"seedPhraseIntroSidebarBulletOne": {
"message": "В диспетчере паролей."
},
"seedPhraseIntroSidebarBulletThree": {
"message": "В банковской ячейке."
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "В банковском сейфе."
},
"seedPhraseIntroSidebarCopyOne": {
"message": "Фраза восстановления — это главный ключ к кошельку и средствам в нем."
},
"seedPhraseIntroSidebarCopyThree": {
"message": "Если кто-нибудь интересуется вашей фразой восстановления, этот человек, скорее всего, пытается вас обмануть."
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "Не сообщайте свою фразу восстановления никому, даже сотрудникам MetaMask."
},
"seedPhraseIntroSidebarTitleOne": {
"message": "Что такое фраза восстановления?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "Можно ли сообщать кому-либо свою фразу восстановления?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "Как хранить фразу восстановления?"
},
"seedPhraseIntroTitle": {
"message": "Защитите свой кошелек"
},
"seedPhraseIntroTitleCopy": {
"message": "Прежде чем приступить к работе, посмотрите это короткое видео о том, что такое фраза восстановления и как обезопасить кошелек."
},
"seedPhrasePlaceholder": {
"message": "Отделяйте каждое слово одним пробелом"
},
@ -2006,6 +2100,9 @@
"message": "Своп $1 на $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Этот токен был добавлен вручную."
},
"swapTokenVerificationMessage": {
"message": "Всегда проверяйте адрес токена на $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2273,7 +2370,7 @@
"message": "Для URL требуется соответствующий префикс HTTP/HTTPS."
},
"urlExistsErrorMsg": {
"message": "URL уже присутствует в имеющемся списке сетей"
"message": "Это URL в настоящее время используется сетью $1."
},
"usePhishingDetection": {
"message": "Использовать обнаружение фишинга"
@ -2295,6 +2392,10 @@
"message": "Проверить этот токен на $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Проверьте этот токен на $1 и убедитесь, что это тот токен, которым вы хотите торговать.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Посмотреть счет"
},
@ -2328,6 +2429,10 @@
"walletSeedRestore": {
"message": "Секретная фраза восстановления кошелька"
},
"web3ShimUsageNotification": {
"message": "Мы заметили, что текущий веб-сайт пытался использовать удаленный API window.web3. Если сайт не работает, нажмите $1 для получения дополнительной информации.",
"description": "$1 is a clickable link."
},
"welcome": {
"message": "Добро пожаловать в MetaMask"
},

@ -137,9 +137,6 @@
"browserNotSupported": {
"message": "Váš prehliadač nie je podporovaný..."
},
"builtInCalifornia": {
"message": "MetaMask je navržen a vytvořen v Kalifornii."
},
"buyWithWyre": {
"message": "Kúpte ETH s Wyre"
},
@ -723,9 +720,6 @@
"recents": {
"message": "Posledné"
},
"recipientAddress": {
"message": "Adresa příjemce"
},
"recipientAddressPlaceholder": {
"message": "Vyhľadávať verejnú adresu (0x) alebo ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Vaš brskalnik ni podptrt ..."
},
"builtInCalifornia": {
"message": "MetaMask je zasnovan in ustvarjen v Kaliforniji."
},
"buyWithWyre": {
"message": "Kupi ETH z Wyre"
},
@ -742,9 +739,6 @@
"recents": {
"message": "Nedavno"
},
"recipientAddress": {
"message": "Prejemnikov naslov"
},
"recipientAddressPlaceholder": {
"message": "Iskanje, javni naslov (0x) ali ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Vaš pregledač nije podržan..."
},
"builtInCalifornia": {
"message": "MetaMask je dizajniran i izgrađen u Kaliforniji."
},
"buyWithWyre": {
"message": "Kupite ETH preko servisa Wyre"
},
@ -745,9 +742,6 @@
"recents": {
"message": "Skorašnje"
},
"recipientAddress": {
"message": "Adresa primaoca"
},
"recipientAddressPlaceholder": {
"message": "Pretraga, javna adresa (0x) ili ENS"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Din webbläsare stöds inte..."
},
"builtInCalifornia": {
"message": "MetaMask är skapat och utformat i Kalifornien."
},
"buyWithWyre": {
"message": "Köp ETH med Wyre"
},
@ -738,9 +735,6 @@
"recents": {
"message": "Senaste"
},
"recipientAddress": {
"message": "Mottagaradress"
},
"recipientAddressPlaceholder": {
"message": "Sök, allmän adress (0x) eller ENS"
},

@ -140,9 +140,6 @@
"browserNotSupported": {
"message": "Kivinjari chaku hakiwezeshwi..."
},
"builtInCalifornia": {
"message": "MetaMask imeundwa na kutengenezwa California."
},
"buyWithWyre": {
"message": "Nunua ETH kwa kutumia Wyre"
},
@ -732,9 +729,6 @@
"recents": {
"message": "Za hivi karibuni"
},
"recipientAddress": {
"message": "Anwani ya Mpokeaji"
},
"recipientAddressPlaceholder": {
"message": "Tafuta, anwani za umma (0x), au ENS"
},

@ -55,9 +55,6 @@
"blockiesIdenticon": {
"message": "பி ஐடி பயன"
},
"builtInCalifornia": {
"message": "மடமஸ வடிவமகபபட கலிிி கடடபபடளத."
},
"cancel": {
"message": "ரத"
},
@ -372,9 +369,6 @@
"readdToken": {
"message": "உஙகள கணகிபஙகளி \"டகன\" எனபதனலமகள எதிலதி இநத டகனகல."
},
"recipientAddress": {
"message": "பநரகவரி"
},
"reject": {
"message": "நிகரி"
},

@ -49,9 +49,6 @@
"blockiesIdenticon": {
"message": "ใชงาน Blockies Identicon"
},
"builtInCalifornia": {
"message": "MetaMask ออกแบบและพฒนาทแคลฟอรเนย"
},
"cancel": {
"message": "ยกเลก"
},
@ -375,9 +372,6 @@
"readdToken": {
"message": "คณสามารถเพมโทเคนนในอนาคตไดโดยไปท “เพมโทเคน” ในเมนวเลอกบญชของคณ"
},
"recipientAddress": {
"message": "แอดแดรสผบ"
},
"reject": {
"message": "ปฏเสธ"
},

@ -211,9 +211,6 @@
"browserNotSupported": {
"message": "Hindi sinusuportahan ang iyong Browser..."
},
"builtInCalifornia": {
"message": "Ang MetaMask ay idinisenyo at binuo sa California."
},
"buy": {
"message": "Bilhin"
},
@ -1192,9 +1189,6 @@
"recents": {
"message": "Mga Kamakailan"
},
"recipientAddress": {
"message": "Address ng Tatanggap"
},
"recipientAddressPlaceholder": {
"message": "Maghanap, pampublikong address (0x), o ENS"
},

@ -46,9 +46,6 @@
"blockiesIdenticon": {
"message": "Blockies Identicon kullan"
},
"builtInCalifornia": {
"message": "MetaMask California'da tasarlandı ve yaratıldı"
},
"cancel": {
"message": "Vazgeç"
},
@ -324,9 +321,6 @@
"readdToken": {
"message": "Gelecekte Bu jetonu hesap seçenekleri menüsünde “Jeton ekle”'ye giderek geri ekleyebilirsiniz."
},
"recipientAddress": {
"message": "Alıcı adresi"
},
"reject": {
"message": "Reddetmek"
},

@ -143,9 +143,6 @@
"browserNotSupported": {
"message": "Ваш браузер не підтримується..."
},
"builtInCalifornia": {
"message": "MetaMask розроблено й створено в Каліфорнії."
},
"buyWithWyre": {
"message": "Купити ETH через Wyre"
},
@ -754,9 +751,6 @@
"recents": {
"message": "Останні"
},
"recipientAddress": {
"message": "Адреса отримувача"
},
"recipientAddressPlaceholder": {
"message": "Пошук, публічна адреса (0x), або ENS"
},

@ -52,6 +52,10 @@
"addContact": {
"message": "Thêm người liên hệ"
},
"addCustomTokenByContractAddress": {
"message": "Bạn không tìm thấy token? Bạn có thể dán địa chỉ của bất kỳ token nào để thêm token đó theo cách thủ công. Bạn có thể tìm thấy địa chỉ hợp đồng token trên $1.",
"description": "$1 is a blockchain explorer for a specific network, e.g. Etherscan for Ethereum"
},
"addEthereumChainConfirmationDescription": {
"message": "Thao tác này sẽ cho phép sử dụng mạng này trong MetaMask."
},
@ -249,12 +253,9 @@
"browserNotSupported": {
"message": "Trình duyệt của bạn không được hỗ trợ..."
},
"builContactList": {
"buildContactList": {
"message": "Xây dựng danh sách liên hệ của bạn"
},
"builtInCalifornia": {
"message": "MetaMask được thiết kế và phát triển tại California."
},
"buy": {
"message": "Mua"
},
@ -285,6 +286,9 @@
"chainIdDefinition": {
"message": "Mã chuỗi được dùng để ký các giao dịch cho mạng này."
},
"chainIdExistsErrorMsg": {
"message": "Mạng $1 hiện đang sử dụng mã chuỗi này."
},
"chromeRequiredForHardwareWallets": {
"message": "Bạn cần sử dụng MetaMask trên Google Chrome để kết nối với Ví cứng của bạn."
},
@ -410,6 +414,9 @@
"continueToWyre": {
"message": "Tiếp tục chuyển đến Wyre"
},
"contract": {
"message": "Hợp đồng"
},
"contractAddressError": {
"message": "Bạn đang gửi token đến địa chỉ hợp đồng của token. Điều này có thể khiến bạn bị mất những token này."
},
@ -624,7 +631,11 @@
"message": "Hãy cẩn thận với hoạt động lừa đảo! MetaMask sẽ không bao giờ tự ý hỏi Cụm mật khẩu khôi phục bí mật của bạn."
},
"endOfFlowMessage6": {
"message": "Nếu bạn cần sao lưu lại Cụm mật khẩu khôi phục bí mật, bạn có thể tìm thấy chức năng này trong Cài đặt -> Bảo mật."
"message": "Nếu bạn cần sao lưu lại Cụm mật khẩu khôi phục bí mật, bạn có thể tìm thấy chức năng này trong phần Cài đặt -> Bảo mật."
},
"endOfFlowMessage7": {
"message": "Nếu bạn có thắc mắc hoặc thấy điều gì đó đáng ngờ, hãy liên hệ với bộ phận hỗ trợ của chúng tôi $1.",
"description": "$1 is a clickable link with text defined by the 'here' key. The link will open to a form where users can file support tickets."
},
"endOfFlowMessage8": {
"message": "MetaMask không thể khôi phục Cụm mật khẩu khôi phục bí mật của bạn."
@ -885,6 +896,16 @@
"importAccountSeedPhrase": {
"message": "Nhập một tài khoản bằng Cụm mật khẩu khôi phục bí mật"
},
"importAccountText": {
"message": "hoặc $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importTokenQuestion": {
"message": "Bạn muốn nhập token?"
},
"importTokenWarning": {
"message": "Bất kỳ ai cũng tạo được token bằng bất kỳ tên nào, kể cả phiên bản giả của token hiện có. Bạn tự chịu rủi ro khi thêm và giao dịch!"
},
"importWallet": {
"message": "Nhập ví"
},
@ -1287,6 +1308,22 @@
"message": "Từ giờ, \"Cụm mật khẩu gốc\" sẽ được gọi là \"Cụm mật khẩu khôi phục bí mật.\"",
"description": "Description of a notification in the 'See What's New' popup. Describes the seed phrase wording update."
},
"notifications6DescriptionOne": {
"message": "Kể từ phiên bản Chrome 91, API từng cho phép hỗ trợ Ledger (U2F) của chúng tôi không còn hỗ trợ ví cứng nữa. MetaMask đã triển khai một tính năng hỗ trợ Ledger Live mới cho phép bạn tiếp tục kết nối với thiết bị Ledger của mình thông qua ứng dụng Ledger Live trên máy tính.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionThree": {
"message": "Khi tương tác với tài khoản Ledger của bạn trong MetaMask, một tab mới sẽ mở ra và bạn sẽ được yêu cầu mở ứng dụng Ledger Live. Khi ứng dụng này mở ra, bạn sẽ được yêu cầu cho phép kết nối WebSocket với tài khoản MetaMask của mình. Đơn giản vậy thôi!",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6DescriptionTwo": {
"message": "Bạn có thể kích hoạt tính năng hỗ trợ Ledger Live bằng cách nhấp vào phần Cài đặt > Nâng cao > Sử dụng Ledger Live.",
"description": "Description of a notification in the 'See What's New' popup. Describes the Ledger support update."
},
"notifications6Title": {
"message": "Thông tin cập nhật về việc hỗ trợ Ledger cho người dùng Chrome",
"description": "Title for a notification in the 'See What's New' popup. Lets users know about the Ledger support update"
},
"ofTextNofM": {
"message": "trên"
},
@ -1411,12 +1448,33 @@
"recents": {
"message": "Gần đây"
},
"recipientAddress": {
"message": "Địa chỉ người nhận"
},
"recipientAddressPlaceholder": {
"message": "Tìm kiếm, địa chỉ công khai (0x) hoặc ENS"
},
"recoveryPhraseReminderBackupStart": {
"message": "Bắt đầu tại đây"
},
"recoveryPhraseReminderConfirm": {
"message": "Đã hiểu"
},
"recoveryPhraseReminderHasBackedUp": {
"message": "Luôn lưu giữ Cụm mật khẩu khôi phục bí mật ở nơi an toàn và bí mật"
},
"recoveryPhraseReminderHasNotBackedUp": {
"message": "Bạn cần sao lưu lại Cụm mật khẩu khôi phục bí mật?"
},
"recoveryPhraseReminderItemOne": {
"message": "Tuyệt đối không cho ai biết Cụm mật khẩu khôi phục bí mật"
},
"recoveryPhraseReminderItemTwo": {
"message": "Nhóm MetaMask sẽ không bao giờ hỏi Cụm mật khẩu khôi phục bí mật của bạn"
},
"recoveryPhraseReminderSubText": {
"message": "Cụm mật khẩu khôi phục bí mật sẽ kiểm soát mọi thứ trong tài khoản của bạn."
},
"recoveryPhraseReminderTitle": {
"message": "Bảo vệ tiền của bạn"
},
"reject": {
"message": "Từ chối"
},
@ -1442,7 +1500,7 @@
"message": "Xóa tài khoản"
},
"removeAccountDescription": {
"message": "Tài khoản này sẽ được xóa khỏi ví của bạn. Xin đảm bảo rằng bạn có Cụm mật khẩu khôi phục bí mật ban đầu hoặc khóa riêng tư cho tài khoản được nhập trước khi tiếp tục. Bạn có thể nhập hoặc tạo lại tài khoản từ trình đơn tài khoản thả xuống. "
"message": "Tài khoản này sẽ được xóa khỏi ví của bạn. Hãy đảm bảo rằng bạn có Cụm mật khẩu khôi phục bí mật ban đầu hoặc khóa riêng tư cho tài khoản được nhập trước khi tiếp tục. Bạn có thể nhập hoặc tạo lại tài khoản từ trình đơn tài khoản thả xuống. "
},
"requestsAwaitingAcknowledgement": {
"message": "yêu cầu đang chờ xác nhận"
@ -1476,10 +1534,10 @@
"message": "Một token trong đây sử dụng lại ký hiệu của một token khác mà bạn thấy, điều này có thể gây nhầm lẫn hoặc mang tính lừa dối."
},
"revealSeedWords": {
"message": "Hiện cụm mật khẩu khôi phục bí mật"
"message": "Hiện Cụm mật khẩu khôi phục bí mật"
},
"revealSeedWordsDescription": {
"message": "Nếu thay đổi trình duyệt hoặc chuyển máy tính, bạn sẽ cần Cụm mật khẩu khôi phục bí mật này để truy cập tài khoản của mình. Hãy lưu cụm mật khẩu gốc này ở nơi an toàn và bí mật."
"message": "Nếu thay đổi trình duyệt hoặc chuyển máy tính, bạn sẽ cần Cụm mật khẩu khôi phục bí mật này để truy cập tài khoản của mình. Hãy lưu Cụm mật khẩu khôi phục bí mật này ở nơi an toàn và bí mật."
},
"revealSeedWordsTitle": {
"message": "Cụm mật khẩu khôi phục bí mật"
@ -1544,6 +1602,42 @@
"securitySettingsDescription": {
"message": "Các cài đặt quyền riêng tư và Cụm mật khẩu khôi phục bí mật của ví"
},
"seedPhraseIntroSidebarBulletFour": {
"message": "Viết ra và cất ở nhiều nơi bí mật."
},
"seedPhraseIntroSidebarBulletOne": {
"message": "Lưu trong một trình quản lý mật khẩu"
},
"seedPhraseIntroSidebarBulletThree": {
"message": "Lưu giữ trong hộp ký gửi an toàn."
},
"seedPhraseIntroSidebarBulletTwo": {
"message": "Lưu giữ trong két an toàn."
},
"seedPhraseIntroSidebarCopyOne": {
"message": "Cụm mật khẩu khôi phục bí mật là “chìa khóa chính” để truy cập ví và số tiền của bạn."
},
"seedPhraseIntroSidebarCopyThree": {
"message": "Nếu ai đó hỏi bạn cụm mật khẩu khôi phục bí mật, thì họ đang cố gắng lừa đảo bạn."
},
"seedPhraseIntroSidebarCopyTwo": {
"message": "Đừng bao giờ cho ai biết cụm mật khẩu khôi phục bí mật, kể cả MetaMask!"
},
"seedPhraseIntroSidebarTitleOne": {
"message": "Cụm mật khẩu khôi phục là gì?"
},
"seedPhraseIntroSidebarTitleThree": {
"message": "Tôi có nên cho ai biết cụm mật khẩu khôi phục bí mật của mình không?"
},
"seedPhraseIntroSidebarTitleTwo": {
"message": "Tôi lưu cụm mật khẩu khôi phục của mình bằng cách nào?"
},
"seedPhraseIntroTitle": {
"message": "Bảo mật cho ví của bạn"
},
"seedPhraseIntroTitleCopy": {
"message": "Trước khi bắt đầu, hãy xem video ngắn này để tìm hiểu thêm về cụm mật khẩu khôi phục bí mật của bạn và cách bảo vệ ví của bạn."
},
"seedPhrasePlaceholder": {
"message": "Phân tách mỗi từ bằng một dấu cách"
},
@ -1844,7 +1938,7 @@
"message": "Đang hoàn tất..."
},
"swapFromTo": {
"message": "Hoán đổi $1 sang $2",
"message": "Giao dịch hoán đổi $1 sang $2",
"description": "Tells a user that they need to confirm on their hardware wallet a swap of 2 tokens. $1 is a source token and $2 is a destination token"
},
"swapGasFeesSplit": {
@ -2006,6 +2100,9 @@
"message": "Hoán đổi $1 sang $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
},
"swapTokenVerificationAddedManually": {
"message": "Token này đã được thêm theo cách thủ công."
},
"swapTokenVerificationMessage": {
"message": "Luôn xác nhận địa chỉ token trên $1.",
"description": "Points the user to Etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"Etherscan\" followed by an info icon that shows more info on hover."
@ -2273,7 +2370,7 @@
"message": "URL phải có tiền tố HTTP/HTTPS phù hợp."
},
"urlExistsErrorMsg": {
"message": "URL đã có trong danh sách mạng hiện tại"
"message": "Mạng $1 hiện đang sử dụng URL này."
},
"usePhishingDetection": {
"message": "Sử dụng tính năng Phát hiện lừa đảo"
@ -2295,6 +2392,10 @@
"message": "Xác minh token này trên $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisUnconfirmedTokenOn": {
"message": "Hãy xác minh token này trên $1 và đảm bảo đây là token bạn muốn giao dịch.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"viewAccount": {
"message": "Xem tài khoản"
},
@ -2328,6 +2429,10 @@
"walletSeedRestore": {
"message": "Cụm mật khẩu khôi phục bí mật của ví"
},
"web3ShimUsageNotification": {
"message": "Chúng tôi nhận thấy rằng trang web hiện tại đã cố dùng API window.web3 đã bị xóa. Nếu trang web có vẻ như đã bị lỗi, vui lòng nhấp vào $1 để biết thêm thông tin.",
"description": "$1 is a clickable link."
},
"welcome": {
"message": "Chào mừng bạn đến với MetaMask"
},

@ -217,9 +217,6 @@
"browserNotSupported": {
"message": "您的浏览器不支持该功能……"
},
"builtInCalifornia": {
"message": "MetaMask在加利福尼亚设计和制造。"
},
"buy": {
"message": "购买"
},
@ -1195,9 +1192,6 @@
"recents": {
"message": "最近记录"
},
"recipientAddress": {
"message": "接收地址"
},
"recipientAddressPlaceholder": {
"message": "查找、公用地址 (0x) 或 ENS"
},

@ -149,9 +149,6 @@
"browserNotSupported": {
"message": "您的瀏覽器尚未支援..."
},
"builtInCalifornia": {
"message": "MetaMask 是在加州設計製造"
},
"buy": {
"message": "買"
},
@ -751,9 +748,6 @@
"recents": {
"message": "最近"
},
"recipientAddress": {
"message": "接收位址"
},
"recipientAddressPlaceholder": {
"message": "搜尋,公開地址 (0x),或 ENS"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2066.8 800" style="enable-background:new 0 0 2066.8 800;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#2970E2;}
.st2{fill:#D1D9E6;}
.st3{fill:#FFFFFF;}
.st4{fill:url(#SVGID_2_);}
</style>
<g id="transparent_1_">
<g id="logo_4_">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="119.932" y1="155.9459" x2="624.022" y2="547.843" gradientTransform="matrix(1 0 0 1 0 50)">
<stop offset="0.1304" style="stop-color:#3495F7"/>
<stop offset="0.3063" style="stop-color:#2B87F2"/>
<stop offset="0.6392" style="stop-color:#1461E5"/>
<stop offset="0.7232" style="stop-color:#0E57E1"/>
</linearGradient>
<path class="st0" d="M566.4,640.4H175.3c-22,0-39.8-17.8-39.8-39.8V201.5c0-22,17.8-39.8,39.8-39.8h391.2
c22,0,39.8,17.8,39.8,39.8v399.1C606.3,622.5,588.5,640.4,566.4,640.4z"/>
<path class="st1" d="M606.3,451.6v148.9c0,22-17.8,39.8-39.8,39.8H417.6L606.3,451.6z"/>
<g>
<g>
<g>
<path class="st2" d="M293.4,449.7l138.9-144.4c10.6-10.6,27.2-9.8,38.3,1.2l80.3,77.4c8.5,8.2,8.3,24.4,0.4,33.1
c-10.3,10.3-21.9,11-37.5,0.4l-58.2-63L309.3,493.5c-9.8,7.6-19.8,14-35.2,4.1c-5.3-7.1,5.2-21,1.1-25.1L293.4,449.7z"/>
</g>
<g>
<path class="st2" d="M287.1,498.2c-11.9-0.4-21.2-8.1-21.2-17.3l0.7-165.1c0-9.1,8.5-20.2,20.4-20.6
c15.8,0,22.7,12.8,22.7,22.3v163.8C309.8,490.8,299.5,498.5,287.1,498.2z"/>
</g>
<g>
<path class="st2" d="M449.1,502.7c-14.7,0-20.9-10.9-20.9-19.5V331.8c0-8.5,9.1-18.9,20.9-19.3c12.3-0.4,22.5,10,22.5,18.9
v149.7C471.6,491.7,464.3,502.7,449.1,502.7z"/>
</g>
</g>
<g>
<g>
<path class="st3" d="M282.1,500c-9.1-0.4-16.2-8.1-16.2-17.3V317.6c0-9.1,7.1-20.2,16.2-20.6c9.5-0.4,17.5,10.6,17.5,20.2v166
C299.6,492.7,291.7,500.4,282.1,500z"/>
</g>
<g>
<path class="st3" d="M444.5,501.7c-9.3,0-16.9-10.8-16.9-20.2V318.9c0-9.3,7.6-16.9,16.9-16.9c9.3,0,16.9,7.6,16.9,16.9v162.7
C461.3,490.8,453.8,501.7,444.5,501.7z"/>
</g>
<g>
<path class="st3" d="M282.8,498.4c-5.5,0-11-2.1-15.1-6.3l-76.5-76.7c-8.3-8.4-8.3-21.9,0.1-30.3c8.4-8.3,21.9-8.3,30.3,0.1
l61.6,62l147.4-140.3c8.3-7.9,21.3-7.9,29.6,0.1l80.2,77.4c8.5,8.2,8.7,21.7,0.6,30.3c-8.1,8.5-21.7,8.7-30.3,0.6l-65.5-63.1
L297.5,492.5C293.4,496.4,288.1,498.4,282.8,498.4z"/>
</g>
</g>
<path class="st3" d="M429.7,378.8l-9.3,8.8c0,0,2.6-14.7-4.9-7.6c-7.6,7.2,11.6-18.2,11.6-18.2l3.9,4.9L429.7,378.8z"/>
<path class="st3" d="M461.3,376.6c0,0,0.5-9,10.3,6.4v-12.1l-10.6-5.5L461.3,376.6z"/>
<path class="st3" d="M299.7,419.2c0,0,1.4,10,10.2-2.9v12.1l-10.6,5.5L299.7,419.2z"/>
</g>
</g>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="712.4824" y1="419.8029" x2="1947.4551" y2="419.8029">
<stop offset="0" style="stop-color:#3495F7"/>
<stop offset="0.4939" style="stop-color:#1461E5"/>
<stop offset="1" style="stop-color:#0E57E1"/>
</linearGradient>
<path class="st4" d="M809.3,337.3l2.1,0.7c0.3,5.7,0.5,16.4,0.5,32.1c0,1-1.5,1.4-4.5,1.4h-20.7c-1.9,0-2.9,1.5-2.9,4.5v122.8
c0,0.2-0.4,0.5-1.2,1.1c-0.8,0.6-1.3,0.8-1.7,0.8h-37.4l-1.7-1.4c-0.5-0.5-0.7-37.8-0.7-111.9v-14.8c-19.2,0-28.8-1.2-28.8-3.6
v-30.5c0-0.2,0.6-0.6,1.9-1.4h42.8c2.2,0.3,3.6,0.6,4,0.7c0.5,0,0.7-0.2,0.7-0.7H809.3z M868.1,336.9h65.9
c15.1,0,28.4,5.5,39.9,16.5c11.5,11,17.3,24.2,17.3,39.4c0,11.9-3.4,22.2-10.1,30.9c-6.7,8.7-15.8,15.5-27.3,20.2
c-0.5,0-0.7,0.4-0.7,1.2v0.2c0.2,0.2,0.2,0.3,0.2,0.5l40.7,49.7c0.5,0.8,1,1.7,1.4,2.6s0.8,1.6,1.1,2c0.2,0.4,0.4,0.7,0.4,0.8
c0,0.5-2.6,0.9-7.9,1.3c-5.2,0.4-8.7,0.6-10.5,0.6c-1.3,0-2.1-0.2-2.6-0.7h-25.5c-1.6-0.2-2.9-1-4-2.6l-33.1-39
c-0.2-0.2-0.5-0.6-1-1.2c-0.5-0.6-1-1.1-1.4-1.4c-0.5-0.3-1-0.5-1.4-0.5c-0.3,0-0.7,1-1.2,3.1v38.6c0,1.3-0.5,1.9-1.4,1.9h-32.4
c-2.9,0-4.8-0.6-5.7-1.9c-1-1.3-1.6-3.4-1.9-6.4c0-14.1,0.1-32,0.4-53.7c0.2-21.7,0.4-38,0.4-48.9c0-1.7-0.1-8.1-0.2-19l-0.5-16.4
C867.4,343.1,867.8,337.2,868.1,336.9z M948.3,392.3c0-4.4-1-8.3-3.1-11.7c-4-6.2-12.2-9.3-24.8-9.3c-2.2,0-5.6,0.2-10,0.5
l-2.1,2.4c0,2.1-0.1,5.3-0.2,9.6c-0.2,4.4-0.3,8.1-0.4,11.1c-0.1,3-0.1,5.2-0.1,6.4c0,10.6,1,16.6,2.9,17.9h2.6
c13.2-0.3,22.3-2.1,27.5-5.5C945.8,410.4,948.3,403.3,948.3,392.3z M1102.8,335h28.3c0.8,0,3.1,4.4,6.8,13.1
c3.7,8.7,5.6,13.6,5.6,14.5c3.3,8.7,21.3,53.1,54,133c0,2.2-1,3.6-2.9,4.2c-1.9,0.6-5.4,0.8-10.5,0.8l-12.1-0.2
c-8.1-0.2-14.2-0.2-18.3-0.2c-0.3-1-1-2.6-1.9-5c-1-2.4-1.7-4.2-2.3-5.5c-0.6-1.3-1.4-2.9-2.5-4.8c-1.1-1.9-2.3-3.6-3.6-5.2
c-1.1,0-3.3-0.2-6.7-0.6c-3.3-0.4-6.3-0.6-9-0.6l-29.8,0.5c-0.5,0-1.9-0.1-4.3-0.2c-2.4-0.2-3.7-0.2-3.8-0.2
c-2.9,0-5.3,3.7-7.4,11.2c-2.1,7.5-3.8,11.7-5.2,12.6c-4.3,0.2-9.6,0-15.8-0.4c-6.3-0.4-11.5-0.6-15.8-0.6c-6.7,0-10-1-10-2.9
c0-0.3,0-0.7,0.1-1.2c0.1-0.5,0.1-0.8,0.1-1l13.8-40c2.1-4.1,4.6-10.3,7.5-18.6c2.9-8.2,4.8-13.3,5.6-15.2
c3.2-8.2,8.6-22,16.3-41.2c7.7-19.2,13.5-34,17.5-44.5C1096.8,335.6,1098.8,335,1102.8,335z M1105.2,446.1h6.2
c11.4-0.3,17.1-1,17.1-1.9c0-2.9-2.5-10.1-7.4-21.7c-1.9-4.6-3-7.1-3.3-7.6l-3.1-7.4c-0.8,0-3.5,5.5-8,16.4
c-4.5,10.9-6.8,17.4-6.8,19.3C1099.9,445.1,1101.7,446.1,1105.2,446.1z M1388.2,426.3c0,0.3-0.1,1-0.2,2.1
c-0.2,1.1-0.3,2.2-0.5,3.3l-0.2,1.4c0,6.8,0.2,17.1,0.5,30.7c0.3,13.6,0.5,23.8,0.5,30.5c0,4.6-1,6.9-2.9,6.9h-30.9
c-2.5,0-4.4-0.9-5.5-2.6l-29.3-43.8c-0.2-0.6-0.9-1.7-2.1-3.1c-1.3-1.4-1.9-2.2-1.9-2.4l-24-34.7l-2.9-3.1l-0.5,1
c0,58.9-0.7,88.3-2.1,88.3h-37.6l-1.4-0.7c0-12.2,0.2-33.2,0.5-63c0.3-29.8,0.5-51.8,0.5-66.3c0-10.9-0.2-19.2-0.5-24.8l1-6.9
l4.8-1l30,1c0.8,0,1.7,0.8,2.9,2.4c1.1,1.6,1.8,2.9,2.1,3.8l22.4,32.4c0.3,0.6,0.9,1.5,1.8,2.7c0.9,1.2,1.5,2.1,1.8,2.7l30.7,42.1
c0.5,1.1,1.1,1.7,1.9,1.7c0.5,0,0.7-0.2,0.7-0.7v-85.9l1.4-1.2c0.2-0.2,3.6-0.2,10.2-0.2c18.7,0,28.1,0.3,28.1,1l1,1.4V426.3z
M1513.3,448.5c-2.4-2.4-5.4-4.8-9.2-7.3c-3.7-2.5-8-5.1-12.9-7.9c-4.8-2.8-7.8-4.6-8.9-5.4c-20.5-13-30.7-28.7-30.7-47.1
c0-15.4,5.4-26.9,16.2-34.5c10.8-7.6,24.8-11.4,41.9-11.4c9.4,0,18.8,1.9,28.3,5.7c1.7,0.6,4.6,1.9,8.4,3.8c3.9,1.9,5.8,3.3,5.8,4
l-0.2,1.2c0,0.2-0.2,0.4-0.5,0.8c-0.3,0.4-0.5,0.8-0.5,1.1c-4.9,10.2-9.7,18.4-14.3,24.8c-0.2,0.5-0.6,0.7-1.2,0.7
c-0.6,0-4.3-1.3-10.9-3.9c-6.7-2.6-11.8-3.9-15.5-3.9c-3.5,0-6.7,1-9.8,2.9c-3,1.9-4.5,4.5-4.5,7.9c0,4.3,2.4,8.3,7.1,12.1
c3.2,2.4,9.5,6.6,19,12.6c2.1,1.4,4.8,3.3,8.1,5.6c3.3,2.3,5.9,4.1,7.9,5.5c1.9,1.3,4,3,6.4,5c2.4,2,4.4,3.9,5.9,5.8
c3.8,4.9,6.4,9.4,7.7,13.3c1.3,4,2,8.8,2,14.5c0,14.9-5.6,27.2-16.9,36.8c-11.3,9.6-24.7,14.4-40.2,14.4c-17,0-32.9-4.1-47.8-12.4
c-6.7-4.1-10-6.6-10-7.4v-1c7-12.7,12.8-22.5,17.4-29.5c2.2,0,4.8,1.1,7.7,3.3c2.9,2.2,4.6,3.4,5.1,3.6c8.4,4.3,18,6.4,28.8,6.4
c9.4,0,14-3.5,14-10.5C1517.4,455.2,1516,452,1513.3,448.5z M1671.1,335h28.3c0.8,0,3.1,4.4,6.8,13.1c3.7,8.7,5.6,13.6,5.6,14.5
c3.3,8.7,21.3,53.1,54,133c0,2.2-1,3.6-2.9,4.2c-1.9,0.6-5.4,0.8-10.5,0.8l-12.1-0.2c-8.1-0.2-14.2-0.2-18.3-0.2
c-0.3-1-1-2.6-1.9-5c-1-2.4-1.7-4.2-2.3-5.5c-0.6-1.3-1.4-2.9-2.5-4.8c-1.1-1.9-2.3-3.6-3.6-5.2c-1.1,0-3.3-0.2-6.7-0.6
c-3.3-0.4-6.3-0.6-9-0.6l-29.8,0.5c-0.5,0-1.9-0.1-4.3-0.2c-2.4-0.2-3.7-0.2-3.8-0.2c-2.9,0-5.3,3.7-7.4,11.2
c-2.1,7.5-3.8,11.7-5.2,12.6c-4.3,0.2-9.6,0-15.8-0.4c-6.3-0.4-11.5-0.6-15.8-0.6c-6.7,0-10-1-10-2.9c0-0.3,0-0.7,0.1-1.2
c0.1-0.5,0.1-0.8,0.1-1l13.8-40c2.1-4.1,4.6-10.3,7.5-18.6c2.9-8.2,4.8-13.3,5.6-15.2c3.2-8.2,8.6-22,16.3-41.2
c7.7-19.2,13.5-34,17.5-44.5C1665.1,335.6,1667.2,335,1671.1,335z M1673.5,446.1h6.2c11.4-0.3,17.1-1,17.1-1.9
c0-2.9-2.5-10.1-7.4-21.7c-1.9-4.6-3-7.1-3.3-7.6l-3.1-7.4c-0.8,0-3.5,5.5-8,16.4s-6.8,17.4-6.8,19.3
C1668.3,445.1,1670,446.1,1673.5,446.1z M1851.1,334c4.9,0,7.4,0.9,7.4,2.6v48.6c0,1.6,0.2,2.4,0.5,2.4c1.1,0,2.5-1,4.2-3.1
c1.7-2.1,3.4-4.4,5.1-7c1.7-2.6,3.1-4.3,4-5.1l26.7-36.2c0.8-1,1.9-1.4,3.3-1.4h35.2l5.7,1c0.3,0,0.5,0.3,0.5,1
c0,1.1-0.2,1.8-0.5,2.1l-10.2,16.2l-1.4,1l-30.5,40.7c-0.5,0.5-0.7,1.1-0.7,1.9c0,1.1,0.2,2.1,0.7,2.9l46.2,95.4c0,0.2,0,0.4,0,0.7
l0.2,0.7c0,2.7-4.8,4-14.3,4c-5.6,0-12-0.2-19.4-0.7c-7.4-0.5-11.5-0.7-12.3-0.7l-1.7-1.2c-1-1-9.8-19.3-26.7-55
c-0.2-1.3-1.3-3.8-3.3-7.6c-0.5,0-2.3,2.2-5.6,6.7c-3.3,4.4-5,7.1-5.4,7.9c0,2.9,0,7.5,0.1,13.8c0.1,6.3,0.1,12.3,0.1,17.8
c0,11.3-1.3,17.1-3.8,17.6c-3.2,0-7.1,0.1-11.9,0.4c-4.8,0.2-8,0.4-9.8,0.4c-2.7,0-6.3-0.3-10.9-1c-4.6-0.6-6.9-1.2-6.9-1.7v-81.9
c1-7.6,1.4-12,1.4-13.1c0-7.1-0.3-17.8-1-32.1c-0.6-14.3-1-24.9-1-31.9c0-2.9,0.6-4.6,1.9-5.2C1825.4,334.2,1836.6,334,1851.1,334z
"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

@ -0,0 +1 @@
export const TRANSAK_API_KEY = '25ac1309-a49b-4411-b20e-5e56c61a5b1c'; // It's a public key, which will be included in a URL for Transak.

@ -11,7 +11,7 @@ import PreferencesController from './preferences';
describe('DetectTokensController', function () {
const sandbox = sinon.createSandbox();
let keyringMemStore, network, preferences;
let keyringMemStore, network, preferences, provider;
const noop = () => undefined;
@ -23,12 +23,19 @@ describe('DetectTokensController', function () {
keyringMemStore = new ObservableStore({ isUnlocked: false });
network = new NetworkController();
network.setInfuraProjectId('foo');
preferences = new PreferencesController({ network });
network.initializeProvider(networkControllerProviderConfig);
provider = network.getProviderAndBlockTracker().provider;
preferences = new PreferencesController({ network, provider });
preferences.setAddresses([
'0x7e57e2',
'0xbc86727e770de68b1060c91f6bb6945c73e10388',
]);
network.initializeProvider(networkControllerProviderConfig);
sandbox
.stub(network, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
sandbox
.stub(preferences, '_detectIsERC721')
.returns(Promise.resolve(false));
});
after(function () {
@ -125,6 +132,7 @@ describe('DetectTokensController', function () {
address: existingTokenAddress.toLowerCase(),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
isERC721: false,
},
]);
});
@ -177,11 +185,13 @@ describe('DetectTokensController', function () {
address: existingTokenAddress.toLowerCase(),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
isERC721: false,
},
{
address: tokenAddressToAdd.toLowerCase(),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
isERC721: false,
},
]);
});
@ -234,11 +244,13 @@ describe('DetectTokensController', function () {
address: existingTokenAddress.toLowerCase(),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
isERC721: false,
},
{
address: tokenAddressToAdd.toLowerCase(),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
isERC721: false,
},
]);
});

@ -34,8 +34,10 @@ const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
* @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} gas - The gas limit, in decimal GWEI
* @property {string} [gasPrice] - The gas price, in decimal WEI
* @property {string} [maxFeePerGas] - The maximum fee per gas, inclusive of tip, in decimal WEI
* @property {string} [maxPriorityFeePerGas] - The maximum tip per gas 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
@ -267,6 +269,25 @@ export default class IncomingTransactionsController {
etherscanTransaction.isError === '0'
? TRANSACTION_STATUSES.CONFIRMED
: TRANSACTION_STATUSES.FAILED;
const txParams = {
from: etherscanTransaction.from,
gas: bnToHex(new BN(etherscanTransaction.gas)),
nonce: bnToHex(new BN(etherscanTransaction.nonce)),
to: etherscanTransaction.to,
value: bnToHex(new BN(etherscanTransaction.value)),
};
if (etherscanTransaction.gasPrice) {
txParams.gasPrice = bnToHex(new BN(etherscanTransaction.gasPrice));
} else if (etherscanTransaction.maxFeePerGas) {
txParams.maxFeePerGas = bnToHex(
new BN(etherscanTransaction.maxFeePerGas),
);
txParams.maxPriorityFeePerGas = bnToHex(
new BN(etherscanTransaction.maxPriorityFeePerGas),
);
}
return {
blockNumber: etherscanTransaction.blockNumber,
id: createId(),
@ -274,14 +295,7 @@ export default class IncomingTransactionsController {
metamaskNetworkId: CHAIN_ID_TO_NETWORK_ID_MAP[chainId],
status,
time,
txParams: {
from: etherscanTransaction.from,
gas: bnToHex(new BN(etherscanTransaction.gas)),
gasPrice: bnToHex(new BN(etherscanTransaction.gasPrice)),
nonce: bnToHex(new BN(etherscanTransaction.nonce)),
to: etherscanTransaction.to,
value: bnToHex(new BN(etherscanTransaction.value)),
},
txParams,
hash: etherscanTransaction.hash,
type: TRANSACTION_TYPES.INCOMING,
};

@ -103,15 +103,34 @@ function getMockBlockTracker() {
/**
* Returns a transaction object matching the expected format returned
* by the Etherscan API
*
* @param {string} [toAddress] - The hex-prefixed address of the recipient
* @param {number} [blockNumber] - The block number for the transaction
* @param {Object} [params] - options bag
* @param {string} [params.toAddress] - The hex-prefixed address of the recipient
* @param {number} [params.blockNumber] - The block number for the transaction
* @param {boolean} [params.useEIP1559] - Use EIP-1559 gas fields
* @param
* @returns {EtherscanTransaction}
*/
const getFakeEtherscanTransaction = (
const getFakeEtherscanTransaction = ({
toAddress = MOCK_SELECTED_ADDRESS,
blockNumber = 10,
) => {
useEIP1559 = false,
hash = '0xfake',
} = {}) => {
if (useEIP1559) {
return {
blockNumber: blockNumber.toString(),
from: '0xfake',
gas: '0',
maxFeePerGas: '10',
maxPriorityFeePerGas: '1',
hash,
isError: '0',
nonce: '100',
timeStamp: '16000000000000',
to: toAddress,
value: '0',
};
}
return {
blockNumber: blockNumber.toString(),
from: '0xfake',
@ -243,7 +262,13 @@ describe('IncomingTransactionsController', function () {
200,
JSON.stringify({
status: '1',
result: [getFakeEtherscanTransaction()],
result: [
getFakeEtherscanTransaction(),
getFakeEtherscanTransaction({
hash: '0xfakeeip1559',
useEIP1559: true,
}),
],
}),
);
const updateStateStub = sinon.stub(
@ -263,6 +288,9 @@ describe('IncomingTransactionsController', function () {
const actualStateWithoutGenerated = cloneDeep(actualState);
delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id;
delete actualStateWithoutGenerated?.incomingTransactions?.[
'0xfakeeip1559'
]?.id;
assert.ok(
typeof generatedTxId === 'number' && generatedTxId > 0,
@ -290,6 +318,24 @@ describe('IncomingTransactionsController', function () {
value: '0x0',
},
},
'0xfakeeip1559': {
blockNumber: '10',
hash: '0xfakeeip1559',
metamaskNetworkId: ROPSTEN_NETWORK_ID,
chainId: ROPSTEN_CHAIN_ID,
status: TRANSACTION_STATUSES.CONFIRMED,
time: 16000000000000000,
type: TRANSACTION_TYPES.INCOMING,
txParams: {
from: '0xfake',
gas: '0x0',
maxFeePerGas: '0xa',
maxPriorityFeePerGas: '0x1',
nonce: '0x64',
to: '0x0101',
value: '0x0',
},
},
},
incomingTxLastFetchedBlockByChainId: {
...getNonEmptyInitState().incomingTxLastFetchedBlockByChainId,
@ -509,7 +555,11 @@ describe('IncomingTransactionsController', function () {
200,
JSON.stringify({
status: '1',
result: [getFakeEtherscanTransaction(NEW_MOCK_SELECTED_ADDRESS)],
result: [
getFakeEtherscanTransaction({
toAddress: NEW_MOCK_SELECTED_ADDRESS,
}),
],
}),
);
const updateStateStub = sinon.stub(
@ -586,7 +636,9 @@ describe('IncomingTransactionsController', function () {
// reply with a valid request for any supported network, so that this test has every opportunity to fail
nockEtherscanApiForAllChains({
status: '1',
result: [getFakeEtherscanTransaction(NEW_MOCK_SELECTED_ADDRESS)],
result: [
getFakeEtherscanTransaction({ toAddress: NEW_MOCK_SELECTED_ADDRESS }),
],
});
const updateStateStub = sinon.stub(
incomingTransactionsController.store,
@ -954,7 +1006,9 @@ describe('IncomingTransactionsController', function () {
describe('_getNewIncomingTransactions', function () {
const ADDRESS_TO_FETCH_FOR = '0xfakeaddress';
const FETCHED_TX = getFakeEtherscanTransaction(ADDRESS_TO_FETCH_FOR);
const FETCHED_TX = getFakeEtherscanTransaction({
toAddress: ADDRESS_TO_FETCH_FOR,
});
const mockFetch = sinon.stub().returns(
Promise.resolve({
json: () => Promise.resolve({ status: '1', result: [FETCHED_TX] }),
@ -1212,5 +1266,53 @@ describe('IncomingTransactionsController', function () {
type: TRANSACTION_TYPES.INCOMING,
});
});
it('should return the expected data when the tx uses EIP-1559 fields', function () {
const incomingTransactionsController = new IncomingTransactionsController(
{
blockTracker: getMockBlockTracker(),
...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID),
preferencesController: getMockPreferencesController(),
initState: getNonEmptyInitState(),
},
);
const result = incomingTransactionsController._normalizeTxFromEtherscan(
{
timeStamp: '4444',
isError: '0',
blockNumber: 333,
from: '0xa',
gas: '11',
maxFeePerGas: '12',
maxPriorityFeePerGas: '1',
nonce: '13',
to: '0xe',
value: '15',
hash: '0xg',
},
ROPSTEN_CHAIN_ID,
);
assert.deepStrictEqual(result, {
blockNumber: 333,
id: 54321,
metamaskNetworkId: ROPSTEN_NETWORK_ID,
chainId: ROPSTEN_CHAIN_ID,
status: TRANSACTION_STATUSES.CONFIRMED,
time: 4444000,
txParams: {
from: '0xa',
gas: '0xb',
maxFeePerGas: '0xc',
maxPriorityFeePerGas: '0x1',
nonce: '0xd',
to: '0xe',
value: '0xf',
},
hash: '0xg',
type: TRANSACTION_TYPES.INCOMING,
});
});
});
});

@ -7,30 +7,6 @@ import {
METAMETRICS_BACKGROUND_PAGE_OBJECT,
} from '../../../shared/constants/metametrics';
/**
* Used to determine whether or not to attach a user's metametrics id
* to events that include on-chain data. This helps to prevent identifying
* a user by being able to trace their activity on etherscan/block exploring
*/
const trackableSendCounts = {
1: true,
10: true,
30: true,
50: true,
100: true,
250: true,
500: true,
1000: true,
2500: true,
5000: true,
10000: true,
25000: true,
};
export function sendCountIsTrackable(sendCount) {
return Boolean(trackableSendCounts[sendCount]);
}
/**
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsContext} MetaMetricsContext
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsEventPayload} MetaMetricsEventPayload
@ -48,9 +24,6 @@ export function sendCountIsTrackable(sendCount) {
* @property {?boolean} participateInMetaMetrics - The user's preference for
* participating in the MetaMetrics analytics program. This setting controls
* whether or not events are tracked
* @property {number} metaMetricsSendCount - How many send transactions have
* been tracked through this controller. Used to prevent attaching sensitive
* data that can be traced through on chain data.
*/
export default class MetaMetricsController {
@ -89,7 +62,6 @@ export default class MetaMetricsController {
this.store = new ObservableStore({
participateInMetaMetrics: null,
metaMetricsId: null,
metaMetricsSendCount: 0,
...initState,
});
@ -138,10 +110,6 @@ export default class MetaMetricsController {
return this.store.getState();
}
setMetaMetricsSendCount(val) {
this.store.updateState({ metaMetricsSendCount: val });
}
/**
* Build the context object to attach to page and track events.
* @private
@ -231,11 +199,7 @@ export default class MetaMetricsController {
// to be updated to work with the new tracking plan. I think we should use
// a config setting for this instead of trying to match the event name
const isSendFlow = Boolean(payload.event.match(/^send|^confirm/iu));
if (
isSendFlow &&
this.state.metaMetricsSendCount &&
!sendCountIsTrackable(this.state.metaMetricsSendCount + 1)
) {
if (isSendFlow) {
excludeMetaMetricsId = true;
}
// If we are tracking sensitive data we will always use the anonymousId

@ -84,7 +84,6 @@ function getMockPreferencesStore({ currentLocale = LOCALE } = {}) {
function getMetaMetricsController({
participateInMetaMetrics = true,
metaMetricsId = TEST_META_METRICS_ID,
metaMetricsSendCount = 0,
preferencesStore = getMockPreferencesStore(),
networkController = getMockNetworkController(),
} = {}) {
@ -106,7 +105,6 @@ function getMetaMetricsController({
initState: {
participateInMetaMetrics,
metaMetricsId,
metaMetricsSendCount,
},
});
}
@ -198,14 +196,6 @@ describe('MetaMetricsController', function () {
});
});
describe('setMetaMetricsSendCount', function () {
it('should update the send count in state', function () {
const metaMetricsController = getMetaMetricsController();
metaMetricsController.setMetaMetricsSendCount(1);
assert.equal(metaMetricsController.state.metaMetricsSendCount, 1);
});
});
describe('trackEvent', function () {
it('should not track an event if user is not participating in metametrics', function () {
const mock = sinon.mock(segment);
@ -337,61 +327,6 @@ describe('MetaMetricsController', function () {
mock.verify();
});
it('should use anonymousId when metametrics send count is not trackable in send flow', function () {
const mock = sinon.mock(segment);
const metaMetricsController = getMetaMetricsController({
metaMetricsSendCount: 1,
});
mock
.expects('track')
.once()
.withArgs({
event: 'Send Fake Event',
anonymousId: METAMETRICS_ANONYMOUS_ID,
context: DEFAULT_TEST_CONTEXT,
properties: {
test: 1,
...DEFAULT_EVENT_PROPERTIES,
},
});
metaMetricsController.trackEvent({
event: 'Send Fake Event',
category: 'Unit Test',
properties: {
test: 1,
},
});
mock.verify();
});
it('should use user metametrics id when metametrics send count is trackable in send flow', function () {
const mock = sinon.mock(segment);
const metaMetricsController = getMetaMetricsController();
mock
.expects('track')
.once()
.withArgs({
event: 'Send Fake Event',
userId: TEST_META_METRICS_ID,
context: DEFAULT_TEST_CONTEXT,
properties: {
test: 1,
...DEFAULT_EVENT_PROPERTIES,
},
});
metaMetricsController.trackEvent(
{
event: 'Send Fake Event',
category: 'Unit Test',
properties: {
test: 1,
},
},
{ metaMetricsSendCount: 0 },
);
mock.verify();
});
it('should immediately flush queue if flushImmediately set to true', async function () {
const metaMetricsController = getMetaMetricsController();
const flushStub = sinon.stub(segment, 'flush');

@ -1,11 +1,13 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import { getNetworkDisplayName } from './util';
import NetworkController from './network';
import NetworkController, { NETWORK_EVENTS } from './network';
describe('NetworkController', function () {
describe('controller', function () {
let networkController;
let getLatestBlockStub;
let setProviderTypeAndWait;
const noop = () => undefined;
const networkControllerProviderConfig = {
getAccounts: noop,
@ -13,7 +15,21 @@ describe('NetworkController', function () {
beforeEach(function () {
networkController = new NetworkController();
getLatestBlockStub = sinon
.stub(networkController, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
networkController.setInfuraProjectId('foo');
setProviderTypeAndWait = () =>
new Promise((resolve) => {
networkController.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
resolve();
});
networkController.setProviderType('mainnet');
});
});
afterEach(function () {
getLatestBlockStub.reset();
});
describe('#provider', function () {
@ -67,6 +83,59 @@ describe('NetworkController', function () {
);
});
});
describe('#getEIP1559Compatibility', function () {
it('should return false when baseFeePerGas is not in the block header', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(supportsEIP1559, false);
});
it('should return true when baseFeePerGas is in block header', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(supportsEIP1559, true);
});
it('should store EIP1559 support in state to reduce calls to getLatestBlock', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
await networkController.getEIP1559Compatibility();
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(getLatestBlockStub.calledOnce, true);
assert.equal(supportsEIP1559, true);
});
it('should clear stored EIP1559 support when changing networks', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
networkController.consoleThis = true;
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
await networkController.getEIP1559Compatibility();
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
true,
);
getLatestBlockStub.callsFake(() => Promise.resolve({}));
await setProviderTypeAndWait('mainnet');
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
undefined,
);
await networkController.getEIP1559Compatibility();
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
false,
);
assert.equal(getLatestBlockStub.calledTwice, true);
});
});
});
describe('utils', function () {

@ -51,6 +51,10 @@ const defaultProviderConfig = {
...defaultProviderConfigOpts,
};
const defaultNetworkDetailsState = {
EIPS: { 1559: undefined },
};
export const NETWORK_EVENTS = {
// Fired after the actively selected network is changed
NETWORK_DID_CHANGE: 'networkDidChange',
@ -74,10 +78,21 @@ export default class NetworkController extends EventEmitter {
this.providerStore.getState(),
);
this.networkStore = new ObservableStore('loading');
// We need to keep track of a few details about the current network
// Ideally we'd merge this.networkStore with this new store, but doing so
// will require a decent sized refactor of how we're accessing network
// state. Currently this is only used for detecting EIP 1559 support but
// can be extended to track other network details.
this.networkDetails = new ObservableStore(
opts.networkDetails || {
...defaultNetworkDetailsState,
},
);
this.store = new ComposedStore({
provider: this.providerStore,
previousProviderStore: this.previousProviderStore,
network: this.networkStore,
networkDetails: this.networkDetails,
});
// provider and block tracker
@ -120,6 +135,42 @@ export default class NetworkController extends EventEmitter {
return { provider, blockTracker };
}
/**
* Method to return the latest block for the current network
* @returns {Object} Block header
*/
getLatestBlock() {
return new Promise((resolve, reject) => {
const { provider } = this.getProviderAndBlockTracker();
const ethQuery = new EthQuery(provider);
ethQuery.sendAsync(
{ method: 'eth_getBlockByNumber', params: ['latest', false] },
(err, block) => {
if (err) {
return reject(err);
}
return resolve(block);
},
);
});
}
/**
* Method to check if the block header contains fields that indicate EIP 1559
* support (baseFeePerGas).
* @returns {Promise<boolean>} true if current network supports EIP 1559
*/
async getEIP1559Compatibility() {
const { EIPS } = this.networkDetails.getState();
if (EIPS[1559] !== undefined) {
return EIPS[1559];
}
const latestBlock = await this.getLatestBlock();
const supportsEIP1559 = latestBlock.baseFeePerGas !== undefined;
this.setNetworkEIPSupport(1559, supportsEIP1559);
return supportsEIP1559;
}
verifyNetwork() {
// Check network when restoring connectivity:
if (this.isNetworkLoading()) {
@ -135,6 +186,26 @@ export default class NetworkController extends EventEmitter {
this.networkStore.putState(network);
}
/**
* Set EIP support indication in the networkDetails store
* @param {number} EIPNumber - The number of the EIP to mark support for
* @param {boolean} isSupported - True if the EIP is supported
*/
setNetworkEIPSupport(EIPNumber, isSupported) {
this.networkDetails.updateState({
EIPS: {
[EIPNumber]: isSupported,
},
});
}
/**
* Reset EIP support to default (no support)
*/
clearNetworkDetails() {
this.networkDetails.putState({ ...defaultNetworkDetailsState });
}
isNetworkLoading() {
return this.getNetworkState() === 'loading';
}
@ -154,6 +225,8 @@ export default class NetworkController extends EventEmitter {
'NetworkController - lookupNetwork aborted due to missing chainId',
);
this.setNetworkState('loading');
// keep network details in sync with network state
this.clearNetworkDetails();
return;
}
@ -174,10 +247,14 @@ export default class NetworkController extends EventEmitter {
if (initialNetwork === currentNetwork) {
if (err) {
this.setNetworkState('loading');
// keep network details in sync with network state
this.clearNetworkDetails();
return;
}
this.setNetworkState(networkVersion);
// look up EIP-1559 support
this.getEIP1559Compatibility();
}
});
}
@ -298,9 +375,15 @@ export default class NetworkController extends EventEmitter {
}
_switchNetwork(opts) {
// Indicate to subscribers that network is about to change
this.emit(NETWORK_EVENTS.NETWORK_WILL_CHANGE);
// Set loading state
this.setNetworkState('loading');
// Reset network details
this.clearNetworkDetails();
// Configure the provider appropriately
this._configureProvider(opts);
// Notify subscribers that network has changed
this.emit(NETWORK_EVENTS.NETWORK_DID_CHANGE, opts.type);
}

@ -2,14 +2,21 @@ import { strict as assert } from 'assert';
import { ObservableStore } from '@metamask/obs-store';
import { ethErrors } from 'eth-rpc-errors';
import { normalize as normalizeAddress } from 'eth-sig-util';
import ethers from 'ethers';
import { ethers } from 'ethers';
import log from 'loglevel';
import abiERC721 from 'human-standard-collectible-abi';
import contractsMap from '@metamask/contract-metadata';
import { LISTED_CONTRACT_ADDRESSES } from '../../../shared/constants/tokens';
import { NETWORK_TYPE_TO_ID_MAP } from '../../../shared/constants/network';
import { isPrefixedFormattedHexString } from '../../../shared/modules/network.utils';
import { isValidHexAddress } from '../../../shared/modules/hexstring-utils';
import {
isValidHexAddress,
toChecksumHexAddress,
} from '../../../shared/modules/hexstring-utils';
import { NETWORK_EVENTS } from './network';
const ERC721METADATA_INTERFACE_ID = '0x5b5e139f';
export default class PreferencesController {
/**
*
@ -73,11 +80,18 @@ export default class PreferencesController {
};
this.network = opts.network;
this.ethersProvider = new ethers.providers.Web3Provider(opts.provider);
this.store = new ObservableStore(initState);
this.store.setMaxListeners(12);
this.openPopup = opts.openPopup;
this.migrateAddressBookState = opts.migrateAddressBookState;
this._subscribeToNetworkDidChange();
this.network.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
const { tokens, hiddenTokens } = this._getTokenRelatedStates();
this.ethersProvider = new ethers.providers.Web3Provider(opts.provider);
this._updateAccountTokens(tokens, this.getAssetImages(), hiddenTokens);
});
this._subscribeToInfuraAvailability();
global.setPreference = (key, value) => {
@ -393,6 +407,8 @@ export default class PreferencesController {
});
const previousIndex = tokens.indexOf(previousEntry);
newEntry.isERC721 = await this._detectIsERC721(newEntry.address);
if (previousEntry) {
tokens[previousIndex] = newEntry;
} else {
@ -403,6 +419,24 @@ export default class PreferencesController {
return Promise.resolve(tokens);
}
/**
* Adds isERC721 field to token object
* (Called when a user attempts to add tokens that were previously added which do not yet had isERC721 field)
*
* @param {string} tokenAddress - The contract address of the token requiring the isERC721 field added.
* @returns {Promise<object>} The new token object with the added isERC721 field.
*
*/
async updateTokenType(tokenAddress) {
const { tokens } = this.store.getState();
const tokenIndex = tokens.findIndex((token) => {
return token.address === tokenAddress;
});
tokens[tokenIndex].isERC721 = await this._detectIsERC721(tokenAddress);
this.store.updateState({ tokens });
return Promise.resolve(tokens[tokenIndex]);
}
/**
* Removes a specified token from the tokens array and adds it to hiddenTokens array
*
@ -480,11 +514,8 @@ export default class PreferencesController {
let addressBookKey = rpcDetail.chainId;
if (!addressBookKey) {
// We need to find the networkId to determine what these addresses were keyed by
const provider = new ethers.providers.JsonRpcProvider(
rpcDetail.rpcUrl,
);
try {
addressBookKey = await provider.send('net_version');
addressBookKey = await this.ethersProvider.send('net_version');
assert(typeof addressBookKey === 'string');
} catch (error) {
log.debug(error);
@ -701,17 +732,6 @@ export default class PreferencesController {
// PRIVATE METHODS
//
/**
* Handle updating token list to reflect current network by listening for the
* NETWORK_DID_CHANGE event.
*/
_subscribeToNetworkDidChange() {
this.network.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
const { tokens, hiddenTokens } = this._getTokenRelatedStates();
this._updateAccountTokens(tokens, this.getAssetImages(), hiddenTokens);
});
}
_subscribeToInfuraAvailability() {
this.network.on(NETWORK_EVENTS.INFURA_IS_BLOCKED, () => {
this._setInfuraBlocked(true);
@ -763,6 +783,43 @@ export default class PreferencesController {
});
}
/**
* Detects whether or not a token is ERC-721 compatible.
*
* @param {string} tokensAddress - the token contract address.
*
*/
async _detectIsERC721(tokenAddress) {
const checksumAddress = toChecksumHexAddress(tokenAddress);
// if this token is already in our contract metadata map we don't need
// to check against the contract
if (contractsMap[checksumAddress]?.erc721 === true) {
return Promise.resolve(true);
}
const tokenContract = await this._createEthersContract(
tokenAddress,
abiERC721,
this.ethersProvider,
);
return await tokenContract
.supportsInterface(ERC721METADATA_INTERFACE_ID)
.catch((error) => {
console.log('error', error);
log.debug(error);
return false;
});
}
async _createEthersContract(tokenAddress, abi, ethersProvider) {
const tokenContract = await new ethers.Contract(
tokenAddress,
abi,
ethersProvider,
);
return tokenContract;
}
/**
* Updates `tokens` and `hiddenTokens` of current account and network.
*

@ -1,10 +1,13 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import contractMaps from '@metamask/contract-metadata';
import abiERC721 from 'human-standard-collectible-abi';
import {
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
} from '../../../shared/constants/network';
import PreferencesController from './preferences';
import NetworkController from './network';
describe('preferences controller', function () {
let preferencesController;
@ -13,19 +16,35 @@ describe('preferences controller', function () {
let triggerNetworkChange;
let switchToMainnet;
let switchToRinkeby;
let provider;
const migrateAddressBookState = sinon.stub();
beforeEach(function () {
const sandbox = sinon.createSandbox();
currentChainId = MAINNET_CHAIN_ID;
network = {
getCurrentChainId: () => currentChainId,
on: sinon.spy(),
const networkControllerProviderConfig = {
getAccounts: () => undefined,
};
network = new NetworkController();
network.setInfuraProjectId('foo');
network.initializeProvider(networkControllerProviderConfig);
provider = network.getProviderAndBlockTracker().provider;
sandbox
.stub(network, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
sandbox.stub(network, 'getCurrentChainId').callsFake(() => currentChainId);
sandbox
.stub(network, 'getProviderConfig')
.callsFake(() => ({ type: 'mainnet' }));
const spy = sandbox.spy(network, 'on');
preferencesController = new PreferencesController({
migrateAddressBookState,
network,
provider,
});
triggerNetworkChange = network.on.firstCall.args[1];
triggerNetworkChange = spy.firstCall.args[1];
switchToMainnet = () => {
currentChainId = MAINNET_CHAIN_ID;
triggerNetworkChange();
@ -86,6 +105,104 @@ describe('preferences controller', function () {
});
});
describe('updateTokenType', function () {
it('should add isERC721 = true to token object in state when token is collectible and in our contract-metadata repo', async function () {
const contractAddresses = Object.keys(contractMaps);
const erc721ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc721 === true,
);
const address = erc721ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];
preferencesController.store.updateState({
tokens: [{ address, symbol, decimals }],
});
const result = await preferencesController.updateTokenType(address);
assert.equal(result.isERC721, true);
});
it('should add isERC721 = true to token object in state when token is collectible and not in our contract-metadata repo', async function () {
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
preferencesController.store.updateState({
tokens: [
{
address: tokenAddress,
symbol: 'TESTNFT',
decimals: '0',
},
],
});
sinon
.stub(preferencesController, '_detectIsERC721')
.callsFake(() => true);
const result = await preferencesController.updateTokenType(tokenAddress);
assert.equal(
preferencesController._detectIsERC721.getCall(0).args[0],
tokenAddress,
);
assert.equal(result.isERC721, true);
});
});
describe('_detectIsERC721', function () {
it('should return true when token is in our contract-metadata repo', async function () {
const tokenAddress = '0x06012c8cf97BEaD5deAe237070F9587f8E7A266d';
const result = await preferencesController._detectIsERC721(tokenAddress);
assert.equal(result, true);
});
it('should return true when the token is not in our contract-metadata repo but tokenContract.supportsInterface returns true', async function () {
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
const supportsInterfaceStub = sinon.stub().returns(Promise.resolve(true));
sinon
.stub(preferencesController, '_createEthersContract')
.callsFake(() => ({ supportsInterface: supportsInterfaceStub }));
const result = await preferencesController._detectIsERC721(tokenAddress);
assert.equal(
preferencesController._createEthersContract.getCall(0).args[0],
tokenAddress,
);
assert.deepEqual(
preferencesController._createEthersContract.getCall(0).args[1],
abiERC721,
);
assert.equal(
preferencesController._createEthersContract.getCall(0).args[2],
preferencesController.ethersProvider,
);
assert.equal(result, true);
});
it('should return false when the token is not in our contract-metadata repo and tokenContract.supportsInterface returns false', async function () {
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(false));
sinon
.stub(preferencesController, '_createEthersContract')
.callsFake(() => ({ supportsInterface: supportsInterfaceStub }));
const result = await preferencesController._detectIsERC721(tokenAddress);
assert.equal(
preferencesController._createEthersContract.getCall(0).args[0],
tokenAddress,
);
assert.deepEqual(
preferencesController._createEthersContract.getCall(0).args[1],
abiERC721,
);
assert.equal(
preferencesController._createEthersContract.getCall(0).args[2],
preferencesController.ethersProvider,
);
assert.equal(result, false);
});
});
describe('removeAddress', function () {
it('should remove an address from state', function () {
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
@ -291,7 +408,12 @@ describe('preferences controller', function () {
assert.equal(tokens.length, 1, 'one token removed');
const [token1] = tokens;
assert.deepEqual(token1, { address: '0xb', symbol: 'B', decimals: 5 });
assert.deepEqual(token1, {
address: '0xb',
symbol: 'B',
decimals: 5,
isERC721: false,
});
});
it('should remove a token from its state on corresponding address', async function () {
@ -310,7 +432,12 @@ describe('preferences controller', function () {
assert.equal(tokensFirst.length, 1, 'one token removed in account');
const [token1] = tokensFirst;
assert.deepEqual(token1, { address: '0xb', symbol: 'B', decimals: 5 });
assert.deepEqual(token1, {
address: '0xb',
symbol: 'B',
decimals: 5,
isERC721: false,
});
await preferencesController.setSelectedAddress('0x7e57e3');
const tokensSecond = preferencesController.getTokens();
@ -335,7 +462,12 @@ describe('preferences controller', function () {
assert.equal(tokensFirst.length, 1, 'one token removed in network');
const [token1] = tokensFirst;
assert.deepEqual(token1, { address: '0xb', symbol: 'B', decimals: 5 });
assert.deepEqual(token1, {
address: '0xb',
symbol: 'B',
decimals: 5,
isERC721: false,
});
switchToRinkeby();
const tokensSecond = preferencesController.getTokens();

@ -1,10 +1,11 @@
import EventEmitter from 'safe-event-emitter';
import { ObservableStore } from '@metamask/obs-store';
import { bufferToHex, keccak, toBuffer } from 'ethereumjs-util';
import Transaction from 'ethereumjs-tx';
import EthQuery from 'ethjs-query';
import { ethErrors } from 'eth-rpc-errors';
import abi from 'human-standard-token-abi';
import Common from '@ethereumjs/common';
import { TransactionFactory } from '@ethereumjs/tx';
import { ethers } from 'ethers';
import NonceTracker from 'nonce-tracker';
import log from 'loglevel';
@ -24,15 +25,29 @@ import {
} from '../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import { GAS_LIMITS } from '../../../../shared/constants/gas';
import {
MAINNET,
NETWORK_TYPE_RPC,
} from '../../../../shared/constants/network';
import TransactionStateManager from './tx-state-manager';
import TxGasUtil from './tx-gas-utils';
import PendingTransactionTracker from './pending-tx-tracker';
import * as txUtils from './lib/util';
const HARDFORK = 'berlin';
const hstInterface = new ethers.utils.Interface(abi);
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
export const TRANSACTION_EVENTS = {
ADDED: 'Transaction Added',
APPROVED: 'Transaction Approved',
FINALIZED: 'Transaction Finalized',
REJECTED: 'Transaction Rejected',
SUBMITTED: 'Transaction Submitted',
};
/**
Transaction Controller is an aggregate of sub-controllers and trackers
composing them in a way to be exposed to the metamask controller
@ -53,7 +68,7 @@ const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonc
@param {Object} opts.networkStore - an observable store for network number
@param {Object} opts.blockTracker - An instance of eth-blocktracker
@param {Object} opts.provider - A network provider.
@param {Function} opts.signTransaction - function the signs an ethereumjs-tx
@param {Function} opts.signTransaction - function the signs an @ethereumjs/tx
@param {Object} opts.getPermittedAccounts - get accounts that an origin has permissions for
@param {Function} opts.signTransaction - ethTx signer that returns a rawTx
@param {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
@ -65,6 +80,7 @@ export default class TransactionController extends EventEmitter {
super();
this.networkStore = opts.networkStore || new ObservableStore({});
this._getCurrentChainId = opts.getCurrentChainId;
this.getProviderConfig = opts.getProviderConfig;
this.preferencesStore = opts.preferencesStore || new ObservableStore({});
this.provider = opts.provider;
this.getPermittedAccounts = opts.getPermittedAccounts;
@ -146,6 +162,49 @@ export default class TransactionController extends EventEmitter {
return integerChainId;
}
/**
* @ethereumjs/tx uses @ethereumjs/common as a configuration tool for
* specifying which chain, network, hardfork and EIPs to support for
* a transaction. By referencing this configuration, and analyzing the fields
* specified in txParams, @ethereumjs/tx is able to determine which EIP-2718
* transaction type to use.
* @returns {Common} common configuration object
*/
getCommonConfiguration() {
const { type, nickname: name } = this.getProviderConfig();
// type will be one of our default network names or 'rpc'. the default
// network names are sufficient configuration, simply pass the name as the
// chain argument in the constructor.
if (type !== NETWORK_TYPE_RPC) {
return new Common({ chain: type, hardfork: HARDFORK });
}
// For 'rpc' we need to use the same basic configuration as mainnet,
// since we only support EVM compatible chains, and then override the
// name, chainId and networkId properties. This is done using the
// `forCustomChain` static method on the Common class.
const chainId = parseInt(this._getCurrentChainId(), 16);
const networkId = this.networkStore.getState();
const customChainParams = {
name,
chainId,
// It is improbable for a transaction to be signed while the network
// is loading for two reasons.
// 1. Pending, unconfirmed transactions are wiped on network change
// 2. The UI is unusable (loading indicator) when network is loading.
// setting the networkId to 0 is for type safety and to explicity lead
// the transaction to failing if a user is able to get to this branch
// on a custom network that requires valid network id. I have not ran
// into this limitation on any network I have attempted, even when
// hardcoding networkId to 'loading'.
networkId: networkId === 'loading' ? 0 : parseInt(networkId, 10),
};
return Common.forCustomChain(MAINNET, customChainParams, HARDFORK);
}
/**
Adds a tx to the txlist
@emits ${txMeta.id}:unapproved
@ -153,6 +212,7 @@ export default class TransactionController extends EventEmitter {
addTransaction(txMeta) {
this.txStateManager.addTransaction(txMeta);
this.emit(`${txMeta.id}:unapproved`, txMeta);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.ADDED);
}
/**
@ -532,12 +592,13 @@ export default class TransactionController extends EventEmitter {
// sign transaction
const rawTx = await this.signTransaction(txId);
await this.publishTransaction(txId, rawTx);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.APPROVED);
// must set transaction to submitted/failed before releasing lock
nonceLock.releaseLock();
} catch (err) {
// this is try-catch wrapped so that we can guarantee that the nonceLock is released
try {
this.txStateManager.setTxStatusFailed(txId, err);
this._failTransaction(txId, err);
} catch (err2) {
log.error(err2);
}
@ -561,17 +622,22 @@ export default class TransactionController extends EventEmitter {
const txMeta = this.txStateManager.getTransaction(txId);
// add network/chain id
const chainId = this.getChainId();
const txParams = { ...txMeta.txParams, chainId };
const txParams = {
...txMeta.txParams,
chainId,
gasLimit: txMeta.txParams.gas,
};
// sign tx
const fromAddress = txParams.from;
const ethTx = new Transaction(txParams);
await this.signEthTx(ethTx, fromAddress);
const common = this.getCommonConfiguration();
const unsignedEthTx = TransactionFactory.fromTxData(txParams, { common });
const signedEthTx = await this.signEthTx(unsignedEthTx, fromAddress);
// add r,s,v values for provider request purposes see createMetamaskMiddleware
// and JSON rpc standard for further explanation
txMeta.r = bufferToHex(ethTx.r);
txMeta.s = bufferToHex(ethTx.s);
txMeta.v = bufferToHex(ethTx.v);
txMeta.r = bufferToHex(signedEthTx.r);
txMeta.s = bufferToHex(signedEthTx.s);
txMeta.v = bufferToHex(signedEthTx.v);
this.txStateManager.updateTransaction(
txMeta,
@ -580,7 +646,7 @@ export default class TransactionController extends EventEmitter {
// set state to signed
this.txStateManager.setTxStatusSigned(txMeta.id);
const rawTx = bufferToHex(ethTx.serialize());
const rawTx = bufferToHex(signedEthTx.serialize());
return rawTx;
}
@ -615,6 +681,11 @@ export default class TransactionController extends EventEmitter {
this.setTxHash(txId, txHash);
this.txStateManager.setTxStatusSubmitted(txId);
const { gas } = txMeta.txParams;
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.SUBMITTED, {
gas_limit: gas,
});
}
/**
@ -647,6 +718,29 @@ export default class TransactionController extends EventEmitter {
this.txStateManager.setTxStatusConfirmed(txId);
this._markNonceDuplicatesDropped(txId);
const { submittedTime } = txMeta;
const { blockNumber } = txReceipt;
const metricsParams = { gas_used: gasUsed };
const completionTime = await this._getTransactionCompletionTime(
blockNumber,
submittedTime,
);
if (completionTime) {
metricsParams.completion_time = completionTime;
}
if (txReceipt.status === '0x0') {
metricsParams.status = 'failed on-chain';
// metricsParams.error = TODO: figure out a way to get the on-chain failure reason
}
this._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.FINALIZED,
metricsParams,
);
this.txStateManager.updateTransaction(
txMeta,
'transactions#confirmTransaction - add txReceipt',
@ -680,7 +774,9 @@ export default class TransactionController extends EventEmitter {
@returns {Promise<void>}
*/
async cancelTransaction(txId) {
const txMeta = this.txStateManager.getTransaction(txId);
this.txStateManager.setTxStatusRejected(txId);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.REJECTED);
}
/**
@ -763,7 +859,7 @@ export default class TransactionController extends EventEmitter {
txMeta,
'failed to estimate gas during boot cleanup.',
);
this.txStateManager.setTxStatusFailed(txMeta.id, error);
this._failTransaction(txMeta.id, error);
});
});
@ -777,7 +873,7 @@ export default class TransactionController extends EventEmitter {
const txSignError = new Error(
'Transaction found as "approved" during boot - possibly stuck during signing',
);
this.txStateManager.setTxStatusFailed(txMeta.id, txSignError);
this._failTransaction(txMeta.id, txSignError);
});
}
@ -797,17 +893,15 @@ export default class TransactionController extends EventEmitter {
'transactions/pending-tx-tracker#event: tx:warning',
);
});
this.pendingTxTracker.on(
'tx:failed',
this.txStateManager.setTxStatusFailed.bind(this.txStateManager),
);
this.pendingTxTracker.on('tx:failed', (txId, error) => {
this._failTransaction(txId, error);
});
this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) =>
this.confirmTransaction(txId, transactionReceipt),
);
this.pendingTxTracker.on(
'tx:dropped',
this.txStateManager.setTxStatusDropped.bind(this.txStateManager),
);
this.pendingTxTracker.on('tx:dropped', (txId) => {
this._dropTransaction(txId);
});
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
if (!txMeta.firstRetryBlockNumber) {
txMeta.firstRetryBlockNumber = latestBlockNumber;
@ -917,7 +1011,7 @@ export default class TransactionController extends EventEmitter {
txMeta,
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
);
this.txStateManager.setTxStatusDropped(otherTxMeta.id);
this._dropTransaction(otherTxMeta.id);
});
}
@ -1010,4 +1104,71 @@ export default class TransactionController extends EventEmitter {
}
}
}
/**
* Extracts relevant properties from a transaction meta
* object and uses them to create and send metrics for various transaction
* events.
* @param {Object} txMeta - the txMeta object
* @param {string} event - the name of the transaction event
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
*/
_trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
const {
type,
time,
status,
chainId,
origin: referrer,
txParams: { gasPrice },
metamaskNetworkId: network,
} = txMeta;
const source = referrer === 'metamask' ? 'user' : 'dapp';
this._trackMetaMetricsEvent({
event,
category: 'Transactions',
sensitiveProperties: {
type,
status,
referrer,
source,
network,
chain_id: chainId,
gas_price: gasPrice,
first_seen: time,
...extraParams,
},
});
}
async _getTransactionCompletionTime(blockNumber, submittedTime) {
const transactionBlock = await this.query.getBlockByNumber(
blockNumber.toString(16),
false,
);
if (!transactionBlock) {
return '';
}
return new BigNumber(transactionBlock.timestamp, 10)
.minus(submittedTime / 1000)
.round()
.toString(10);
}
_failTransaction(txId, error) {
this.txStateManager.setTxStatusFailed(txId, error);
const txMeta = this.txStateManager.getTransaction(txId);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED, {
error: error.message,
});
}
_dropTransaction(txId) {
this.txStateManager.setTxStatusDropped(txId);
const txMeta = this.txStateManager.getTransaction(txId);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED);
}
}

@ -1,7 +1,7 @@
import { strict as assert } from 'assert';
import EventEmitter from 'events';
import { toBuffer } from 'ethereumjs-util';
import EthTx from 'ethereumjs-tx';
import { TransactionFactory } from '@ethereumjs/tx';
import { ObservableStore } from '@metamask/obs-store';
import sinon from 'sinon';
@ -15,11 +15,14 @@ import {
} from '../../../../shared/constants/transaction';
import { SECOND } from '../../../../shared/constants/time';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import TransactionController from '.';
import TransactionController, { TRANSACTION_EVENTS } from '.';
const noop = () => true;
const currentNetworkId = '42';
const currentChainId = '0x2a';
const providerConfig = {
type: 'kovan',
};
const VALID_ADDRESS = '0x0000000000000000000000000000000000000000';
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
@ -36,6 +39,7 @@ describe('Transaction Controller', function () {
};
provider = createTestProviderTools({ scaffold: providerResultStub })
.provider;
fromAccount = getTestAccounts()[0];
const blockTrackerStub = new EventEmitter();
blockTrackerStub.getCurrentBlock = noop;
@ -50,12 +54,13 @@ describe('Transaction Controller', function () {
blockTracker: blockTrackerStub,
signTransaction: (ethTx) =>
new Promise((resolve) => {
ethTx.sign(fromAccount.key);
resolve();
resolve(ethTx.sign(fromAccount.key));
}),
getProviderConfig: () => providerConfig,
getPermittedAccounts: () => undefined,
getCurrentChainId: () => currentChainId,
getParticipateInMetrics: () => false,
trackMetaMetricsEvent: () => undefined,
});
txController.nonceTracker.getNonceLock = () =>
Promise.resolve({ nextNonce: 0, releaseLock: noop });
@ -414,6 +419,19 @@ describe('Transaction Controller', function () {
});
describe('#addTransaction', function () {
let trackTransactionMetricsEventSpy;
beforeEach(function () {
trackTransactionMetricsEventSpy = sinon.spy(
txController,
'_trackTransactionMetricsEvent',
);
});
afterEach(function () {
trackTransactionMetricsEventSpy.restore();
});
it('should emit updates', function (done) {
const txMeta = {
id: '1',
@ -451,6 +469,37 @@ describe('Transaction Controller', function () {
.catch(done);
txController.addTransaction(txMeta);
});
it('should call _trackTransactionMetricsEvent with the correct params', function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: 'sentEther',
origin: 'metamask',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
txController.addTransaction(txMeta);
assert.equal(trackTransactionMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackTransactionMetricsEventSpy.getCall(0).args[0],
txMeta,
);
assert.equal(
trackTransactionMetricsEventSpy.getCall(0).args[1],
TRANSACTION_EVENTS.ADDED,
);
});
});
describe('#approveTransaction', function () {
@ -519,8 +568,8 @@ describe('Transaction Controller', function () {
noop,
);
const rawTx = await txController.signTransaction('1');
const ethTx = new EthTx(toBuffer(rawTx));
assert.equal(ethTx.getChainId(), 42);
const ethTx = TransactionFactory.fromSerializedData(toBuffer(rawTx));
assert.equal(ethTx.common.chainIdBN().toNumber(), 42);
});
});
@ -723,7 +772,8 @@ describe('Transaction Controller', function () {
});
describe('#publishTransaction', function () {
let hash, txMeta;
let hash, txMeta, trackTransactionMetricsEventSpy;
beforeEach(function () {
hash =
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
@ -731,12 +781,21 @@ describe('Transaction Controller', function () {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
gas: '0x7b0d',
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
};
providerResultStub.eth_sendRawTransaction = hash;
trackTransactionMetricsEventSpy = sinon.spy(
txController,
'_trackTransactionMetricsEvent',
);
});
afterEach(function () {
trackTransactionMetricsEventSpy.restore();
});
it('should publish a tx, updates the rawTx when provided a one', async function () {
@ -764,6 +823,25 @@ describe('Transaction Controller', function () {
);
assert.equal(publishedTx.status, TRANSACTION_STATUSES.SUBMITTED);
});
it('should call _trackTransactionMetricsEvent with the correct params', async function () {
const rawTx =
'0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c';
txController.txStateManager.addTransaction(txMeta);
await txController.publishTransaction(txMeta.id, rawTx);
assert.equal(trackTransactionMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackTransactionMetricsEventSpy.getCall(0).args[0],
txMeta,
);
assert.equal(
trackTransactionMetricsEventSpy.getCall(0).args[1],
TRANSACTION_EVENTS.SUBMITTED,
);
assert.deepEqual(trackTransactionMetricsEventSpy.getCall(0).args[2], {
gas_limit: txMeta.txParams.gas,
});
});
});
describe('#_markNonceDuplicatesDropped', function () {
@ -1105,4 +1183,154 @@ describe('Transaction Controller', function () {
);
});
});
describe('#_trackTransactionMetricsEvent', function () {
let trackMetaMetricsEventSpy;
beforeEach(function () {
trackMetaMetricsEventSpy = sinon.spy(
txController,
'_trackMetaMetricsEvent',
);
});
afterEach(function () {
trackMetaMetricsEventSpy.restore();
});
it('should call _trackMetaMetricsEvent with the correct payload (user source)', function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: 'sentEther',
origin: 'metamask',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
category: 'Transactions',
sensitiveProperties: {
chain_id: '0x2a',
gas_price: '0x77359400',
first_seen: 1624408066355,
network: '42',
referrer: 'metamask',
source: 'user',
status: 'unapproved',
type: 'sentEther',
},
};
txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (dapp source)', function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: 'sentEther',
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
category: 'Transactions',
sensitiveProperties: {
chain_id: '0x2a',
gas_price: '0x77359400',
first_seen: 1624408066355,
network: '42',
referrer: 'other',
source: 'dapp',
status: 'unapproved',
type: 'sentEther',
},
};
txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', function () {
const txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: 'sentEther',
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
};
const expectedPayload = {
event: 'Transaction Added',
category: 'Transactions',
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
chain_id: '0x2a',
gas_price: '0x77359400',
first_seen: 1624408066355,
network: '42',
referrer: 'other',
source: 'dapp',
status: 'unapproved',
type: 'sentEther',
},
};
txController._trackTransactionMetricsEvent(
txMeta,
TRANSACTION_EVENTS.ADDED,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackMetaMetricsEventSpy.getCall(0).args[0],
expectedPayload,
);
});
});
});

@ -1,5 +1,6 @@
import { strict as assert } from 'assert';
import Transaction from 'ethereumjs-tx';
import { TransactionFactory } from '@ethereumjs/tx';
import Common from '@ethereumjs/common';
import { hexToBn, bnToHex } from '../../lib/util';
import TxUtils from './tx-gas-utils';
@ -31,8 +32,14 @@ describe('txUtils', function () {
nonce: '0x3',
chainId: 42,
};
const ethTx = new Transaction(txParams);
assert.equal(ethTx.getChainId(), 42, 'chainId is set from tx params');
const ethTx = TransactionFactory.fromTxData(txParams, {
common: new Common({ chain: 'kovan' }),
});
assert.equal(
ethTx.common.chainIdBN().toNumber(),
42,
'chainId is set from tx params',
);
});
});

@ -1,3 +1,6 @@
import log from 'loglevel';
import { METASWAP_CHAINID_API_HOST_MAP } from '../../../shared/constants/swaps';
import {
GOERLI_CHAIN_ID,
KOVAN_CHAIN_ID,
@ -5,6 +8,54 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import { TRANSAK_API_KEY } from '../constants/on-ramp';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
/**
* Create a Wyre purchase URL.
* @param {String} address Ethereum destination address
* @returns String
*/
const createWyrePurchaseUrl = async (address) => {
const fiatOnRampUrlApi = `${METASWAP_CHAINID_API_HOST_MAP[MAINNET_CHAIN_ID]}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${address}`;
const wyrePurchaseUrlFallback = `https://pay.sendwyre.com/purchase?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`;
try {
const response = await fetchWithTimeout(fiatOnRampUrlApi, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
});
const parsedResponse = await response.json();
if (response.ok && parsedResponse.url) {
return parsedResponse.url;
}
log.warn('Failed to create a Wyre purchase URL', parsedResponse);
} catch (err) {
log.warn('Failed to create a Wyre purchase URL', err);
}
return wyrePurchaseUrlFallback; // In case the API call would fail, we return a fallback URL for Wyre's Checkout.
};
/**
* Create a Transak Checkout URL.
* API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238
* @param {String} address Ethereum destination address
* @returns String
*/
const createTransakUrl = (address) => {
const queryParams = new URLSearchParams({
apiKey: TRANSAK_API_KEY,
hostURL: 'https://metamask.io',
defaultCryptoCurrency: 'ETH',
walletAddress: address,
});
return `https://global.transak.com/?${queryParams}`;
};
/**
* Gives the caller a url at which the user can acquire eth, depending on the network they are in
@ -16,7 +67,7 @@ import {
* chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
*
*/
export default function getBuyEthUrl({ chainId, address, service }) {
export default async function getBuyEthUrl({ chainId, address, service }) {
// default service by network if not specified
if (!service) {
// eslint-disable-next-line no-param-reassign
@ -25,7 +76,9 @@ export default function getBuyEthUrl({ chainId, address, service }) {
switch (service) {
case 'wyre':
return `https://pay.sendwyre.com/purchase?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`;
return await createWyrePurchaseUrl(address);
case 'transak':
return createTransakUrl(address);
case 'metamask-faucet':
return 'https://faucet.metamask.io/';
case 'rinkeby-faucet':

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

@ -36,7 +36,6 @@ export const SENTRY_STATE = {
isInitialized: true,
isUnlocked: true,
metaMetricsId: true,
metaMetricsSendCount: true,
nativeCurrency: true,
network: true,
nextNonce: true,

@ -1,5 +1,5 @@
import EventEmitter from 'events';
import assert from 'assert';
import { strict as assert } from 'assert';
import { ObservableStore } from '@metamask/obs-store';
import { ethErrors } from 'eth-rpc-errors';
import { typedSignatureHash, TYPED_MESSAGE_SCHEMA } from 'eth-sig-util';
@ -177,7 +177,7 @@ export default class TypedMessageManager extends EventEmitter {
break;
case 'V3':
case 'V4': {
assert.strictEqual(
assert.equal(
typeof params.data,
'string',
'"params.data" must be a string.',
@ -191,18 +191,21 @@ export default class TypedMessageManager extends EventEmitter {
data.primaryType in data.types,
`Primary type of "${data.primaryType}" has no type definition.`,
);
assert.strictEqual(
assert.equal(
validation.errors.length,
0,
'Signing data must conform to EIP-712 schema. See https://git.io/fNtcx.',
);
const { chainId } = data.domain;
let { chainId } = data.domain;
if (chainId) {
const activeChainId = parseInt(this._getCurrentChainId(), 16);
assert.ok(
!Number.isNaN(activeChainId),
`Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`,
);
if (typeof chainId === 'string') {
chainId = parseInt(chainId, 16);
}
assert.equal(
chainId,
activeChainId,

@ -1,4 +1,3 @@
import { strict as assert } from 'assert';
import extension from 'extensionizer';
import { stripHexPrefix } from 'ethereumjs-util';
import BN from 'bn.js';
@ -70,39 +69,6 @@ const getPlatform = (_) => {
return PLATFORM_FIREFOX;
};
/**
* Checks whether a given balance of ETH, represented as a hex string, is sufficient to pay a value plus a gas fee
*
* @param {Object} txParams - Contains data about a transaction
* @param {string} txParams.gas - The gas for a transaction
* @param {string} txParams.gasPrice - The price per gas for the transaction
* @param {string} txParams.value - The value of ETH to send
* @param {string} hexBalance - A balance of ETH represented as a hex string
* @returns {boolean} Whether the balance is greater than or equal to the value plus the value of gas times gasPrice
*
*/
function sufficientBalance(txParams, hexBalance) {
// validate hexBalance is a hex string
assert.equal(
typeof hexBalance,
'string',
'sufficientBalance - hexBalance is not a hex string',
);
assert.equal(
hexBalance.slice(0, 2),
'0x',
'sufficientBalance - hexBalance is not a hex string',
);
const balance = hexToBn(hexBalance);
const value = hexToBn(txParams.value);
const gasLimit = hexToBn(txParams.gas);
const gasPrice = hexToBn(txParams.gasPrice);
const maxCost = value.add(gasLimit.mul(gasPrice));
return balance.gte(maxCost);
}
/**
* Converts a hex string to a BN object
*
@ -183,7 +149,6 @@ function bnToHex(inputBn) {
export {
getPlatform,
getEnvironmentType,
sufficientBalance,
hexToBn,
BnMultiplyByFraction,
checkForError,

@ -7,7 +7,7 @@ import {
ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_BACKGROUND,
} from '../../../shared/constants/app';
import { getEnvironmentType, sufficientBalance } from './util';
import { getEnvironmentType } from './util';
describe('app utils', function () {
describe('getEnvironmentType', function () {
@ -68,44 +68,6 @@ describe('app utils', function () {
});
});
describe('SufficientBalance', function () {
it('returns true if max tx cost is equal to balance.', function () {
const tx = {
value: '0x1',
gas: '0x2',
gasPrice: '0x3',
};
const balance = '0x8';
const result = sufficientBalance(tx, balance);
assert.ok(result, 'sufficient balance found.');
});
it('returns true if max tx cost is less than balance.', function () {
const tx = {
value: '0x1',
gas: '0x2',
gasPrice: '0x3',
};
const balance = '0x9';
const result = sufficientBalance(tx, balance);
assert.ok(result, 'sufficient balance found.');
});
it('returns false if max tx cost is more than balance.', function () {
const tx = {
value: '0x1',
gas: '0x2',
gasPrice: '0x3',
};
const balance = '0x6';
const result = sufficientBalance(tx, balance);
assert.ok(!result, 'insufficient balance found.');
});
});
describe('isPrefixedFormattedHexString', function () {
it('should return true for valid hex strings', function () {
assert.equal(

@ -132,11 +132,17 @@ export default class MetamaskController extends EventEmitter {
this.networkController = new NetworkController(initState.NetworkController);
this.networkController.setInfuraProjectId(opts.infuraProjectId);
// now we can initialize the RPC provider, which other controllers require
this.initializeProvider();
this.provider = this.networkController.getProviderAndBlockTracker().provider;
this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker;
this.preferencesController = new PreferencesController({
initState: initState.PreferencesController,
initLangCode: opts.initLangCode,
openPopup: opts.openPopup,
network: this.networkController,
provider: this.provider,
migrateAddressBookState: this.migrateAddressBookState.bind(this),
});
@ -183,11 +189,6 @@ export default class MetamaskController extends EventEmitter {
initState.NotificationController,
);
// now we can initialize the RPC provider, which other controllers require
this.initializeProvider();
this.provider = this.networkController.getProviderAndBlockTracker().provider;
this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker;
// token exchange rate tracker
this.tokenRatesController = new TokenRatesController({
preferences: this.preferencesController.store,
@ -322,6 +323,9 @@ export default class MetamaskController extends EventEmitter {
getPermittedAccounts: this.permissionsController.getAccounts.bind(
this.permissionsController,
),
getProviderConfig: this.networkController.getProviderConfig.bind(
this.networkController,
),
networkStore: this.networkController.networkStore,
getCurrentChainId: this.networkController.getCurrentChainId.bind(
this.networkController,
@ -676,7 +680,6 @@ export default class MetamaskController extends EventEmitter {
setUsePhishDetect: this.setUsePhishDetect.bind(this),
setIpfsGateway: this.setIpfsGateway.bind(this),
setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this),
setMetaMetricsSendCount: this.setMetaMetricsSendCount.bind(this),
setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this),
setCurrentLocale: this.setCurrentLocale.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this),
@ -728,6 +731,10 @@ export default class MetamaskController extends EventEmitter {
preferencesController,
),
addToken: nodeify(preferencesController.addToken, preferencesController),
updateTokenType: nodeify(
preferencesController.updateTokenType,
preferencesController,
),
removeToken: nodeify(
preferencesController.removeToken,
preferencesController,
@ -2760,18 +2767,6 @@ export default class MetamaskController extends EventEmitter {
}
}
setMetaMetricsSendCount(val, cb) {
try {
this.metaMetricsController.setMetaMetricsSendCount(val);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
return;
}
}
/**
* Sets the type of first time flow the user wishes to follow: create or import
* @param {string} type - Indicates the type of first time flow the user wishes to follow

@ -21,6 +21,11 @@ const firstTimeState = {
rpcUrl: 'http://localhost:8545',
chainId: '0x539',
},
networkDetails: {
EIPS: {
1559: false,
},
},
},
};

@ -0,0 +1,28 @@
import { cloneDeep } from 'lodash';
const version = 62;
/**
* Removes metaMetricsSendCount from MetaMetrics controller
*/
export default {
version,
async migrate(originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
const state = versionedData.data;
const newState = transformState(state);
versionedData.data = newState;
return versionedData;
},
};
function transformState(state) {
if (state.MetaMetricsController) {
const { metaMetricsSendCount } = state.MetaMetricsController;
if (metaMetricsSendCount !== undefined) {
delete state.MetaMetricsController.metaMetricsSendCount;
}
}
return state;
}

@ -0,0 +1,80 @@
import { strict as assert } from 'assert';
import migration62 from './062';
describe('migration #62', function () {
it('should update the version metadata', async function () {
const oldStorage = {
meta: {
version: 61,
},
data: {},
};
const newStorage = await migration62.migrate(oldStorage);
assert.deepEqual(newStorage.meta, {
version: 62,
});
});
it('should remove metaMetricsSendCount from MetaMetricsController', async function () {
const oldStorage = {
meta: {},
data: {
MetaMetricsController: {
metaMetricsSendCount: 1,
bar: 'baz',
},
foo: 'bar',
},
};
const newStorage = await migration62.migrate(oldStorage);
assert.deepStrictEqual(newStorage.data, {
MetaMetricsController: {
bar: 'baz',
},
foo: 'bar',
});
});
it('should remove metaMetricsSendCount from MetaMetricsController (falsey but defined)', async function () {
const oldStorage = {
meta: {},
data: {
MetaMetricsController: {
metaMetricsSendCount: 0,
bar: 'baz',
},
foo: 'bar',
},
};
const newStorage = await migration62.migrate(oldStorage);
assert.deepStrictEqual(newStorage.data, {
MetaMetricsController: {
bar: 'baz',
},
foo: 'bar',
});
});
it('should not modify MetaMetricsController when metaMetricsSendCount is undefined', async function () {
const oldStorage = {
meta: {},
data: {
MetaMetricsController: {
bar: 'baz',
},
foo: 'bar',
},
};
const newStorage = await migration62.migrate(oldStorage);
assert.deepStrictEqual(newStorage.data, {
MetaMetricsController: {
bar: 'baz',
},
foo: 'bar',
});
});
});

@ -66,6 +66,7 @@ const migrations = [
require('./059').default,
require('./060').default,
require('./061').default,
require('./062').default,
];
export default migrations;

@ -44,7 +44,7 @@ const materialUIDependencies = ['@material-ui/core'];
const reactDepenendencies = dependencies.filter((dep) => dep.match(/react/u));
const externalDependenciesMap = {
background: ['3box'],
background: ['3box', '@ethereumjs/common', 'unicode-confusables'],
ui: [...materialUIDependencies, ...reactDepenendencies],
};
@ -433,6 +433,7 @@ function getEnvironmentVariables({ devMode, testing }) {
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
CONF: devMode ? metamaskrc : {},
SHOW_EIP_1559_UI: process.env.SHOW_EIP_1559_UI === '1',
SENTRY_DSN: process.env.SENTRY_DSN,
SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV,
INFURA_PROJECT_ID: testing

@ -76,7 +76,7 @@ for (const tag of languageTags) {
const copyTargetsDev = [
...copyTargets,
{
src: './app/scripts/',
src: './development',
pattern: '/chromereload.js',
dest: ``,
},

@ -0,0 +1,16 @@
/**
* Exit the process with an error message.
*
* Note that this should be called before the process ends, but it will not
* itself end the process. This is because the Node.js documentation strongly
* advises against calling `process.exit` directly.
*
* @param {string} errorMessage - The error message that is causing the non-
* zero exit code.
*/
function exitWithError(errorMessage) {
console.error(errorMessage);
process.exitCode = 1;
}
module.exports = { exitWithError };

@ -0,0 +1,23 @@
/**
* Run the given function, retrying it upon failure until reaching the
* specified number of retries.
*
* @param {number} retries - The number of retries upon failure to attempt.
* @param {function} functionToRetry - The function that will be retried upon failure.
*/
async function retry(retries, functionToRetry) {
let attempts = 0;
while (attempts <= retries) {
try {
await functionToRetry();
return;
} catch (error) {
console.error(error);
} finally {
attempts += 1;
}
}
throw new Error('Retry limit reached');
}
module.exports = { retry };

@ -2,7 +2,11 @@ module.exports = {
restoreMocks: true,
coverageDirectory: 'jest-coverage/',
collectCoverageFrom: ['<rootDir>/ui/**/swaps/**'],
coveragePathIgnorePatterns: ['.stories.js', '.snap'],
coveragePathIgnorePatterns: [
'.stories.js',
'.snap',
'**/shared/**/?(*.)+(test).js',
],
coverageThreshold: {
global: {
branches: 32.75,
@ -13,5 +17,5 @@ module.exports = {
},
setupFiles: ['./test/setup.js', './test/env.js'],
setupFilesAfterEnv: ['./test/jest/setup.js'],
testMatch: ['**/ui/**/?(*.)+(test).js'],
testMatch: ['ui/**/?(*.)+(test).js', '**/shared/**/?(*.)+(test).js'],
};

@ -23,20 +23,21 @@
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010",
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'",
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './{app,shared}/**/*.test.js'",
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/**/*.test.js'",
"test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js",
"test:unit:jest": "jest",
"test:unit:jest:watch": "jest --watch",
"test:unit:jest:watch:silent": "jest --watch --silent",
"test:unit:jest:ci": "jest --maxWorkers=2",
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --recursive './{app,shared}/**/*.test.js'",
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --recursive './app/**/*.test.js'",
"test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/scripts/controllers/permissions/*.test.js'",
"test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive",
"test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/run-all.sh",
"test:e2e:chrome:metrics": "SELENIUM_BROWSER=chrome mocha test/e2e/metrics.spec.js",
"test:e2e:firefox": "SELENIUM_BROWSER=firefox test/e2e/run-all.sh",
"test:e2e:firefox:metrics": "SELENIUM_BROWSER=firefox mocha test/e2e/metrics.spec.js",
"test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js",
"test:e2e:chrome:metrics": "SELENIUM_BROWSER=chrome node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
"test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js",
"test:e2e:firefox:metrics": "SELENIUM_BROWSER=firefox node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
"test:coverage": "nyc --silent --check-coverage yarn test:unit:strict && nyc --silent --no-clean yarn test:unit:lax && nyc report --reporter=text --reporter=html",
"test:e2e:single": "node test/e2e/run-e2e-test.js",
"test:coverage:jest": "jest --coverage --maxWorkers=2",
"test:coverage:strict": "nyc --check-coverage yarn test:unit:strict",
"test:coverage:path": "nyc --check-coverage yarn test:unit:path",
@ -53,7 +54,7 @@
"verify-locales": "node ./development/verify-locale-strings.js",
"verify-locales:fix": "node ./development/verify-locale-strings.js --fix",
"mozilla-lint": "addons-linter dist/firefox",
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/**/*.test.js\" \"shared/**/*.test.js\"",
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/**/*.test.js\"",
"devtools:react": "react-devtools",
"devtools:redux": "remotedev --hostname=localhost --port=8000",
"start:dev": "concurrently -k -n build,react,redux yarn:start yarn:devtools:react yarn:devtools:redux",
@ -92,13 +93,15 @@
"3box": "^1.10.2",
"@babel/runtime": "^7.5.5",
"@download/blockies": "^1.0.3",
"@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.2.1",
"@formatjs/intl-relativetimeformat": "^5.2.6",
"@fortawesome/fontawesome-free": "^5.13.0",
"@lavamoat/preinstall-always-fail": "^1.0.0",
"@material-ui/core": "^4.11.0",
"@metamask/contract-metadata": "^1.26.0",
"@metamask/controllers": "^9.0.0",
"@metamask/eth-ledger-bridge-keyring": "^0.5.0",
"@metamask/controllers": "^10.0.0",
"@metamask/eth-ledger-bridge-keyring": "^0.6.0",
"@metamask/eth-token-tracker": "^3.0.1",
"@metamask/etherscan-link": "^2.1.0",
"@metamask/jazzicon": "^2.0.0",
@ -134,10 +137,9 @@
"eth-query": "^2.1.2",
"eth-rpc-errors": "^4.0.2",
"eth-sig-util": "^3.0.0",
"eth-trezor-keyring": "^0.6.0",
"eth-trezor-keyring": "^0.7.0",
"ethereum-ens-network-map": "^1.0.2",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-tx": "1.3.7",
"ethereumjs-util": "^7.0.10",
"ethereumjs-wallet": "^0.6.4",
"ethers": "^5.0.8",
@ -151,6 +153,7 @@
"fast-safe-stringify": "^2.0.7",
"fuse.js": "^3.2.0",
"globalthis": "^1.0.1",
"human-standard-collectible-abi": "^1.0.2",
"human-standard-token-abi": "^2.0.0",
"immer": "^8.0.1",
"json-rpc-engine": "^6.1.0",
@ -312,7 +315,8 @@
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"watchify": "^3.11.1",
"webpack": "^4.41.6"
"webpack": "^4.41.6",
"yargs": "^17.0.1"
},
"engines": {
"node": "^14.15.1",

@ -0,0 +1,19 @@
diff --git a/node_modules/selenium-webdriver/chromium.js b/node_modules/selenium-webdriver/chromium.js
index d828ce5..87176f4 100644
--- a/node_modules/selenium-webdriver/chromium.js
+++ b/node_modules/selenium-webdriver/chromium.js
@@ -197,6 +197,14 @@ class ServiceBuilder extends remote.DriverService.Builder {
return this.addArguments('--log-path=' + path);
}
+ /**
+ * Enables Chrome logging.
+ * @returns {!ServiceBuilder} A self reference.
+ */
+ enableChromeLogging() {
+ return this.addArguments('--enable-chrome-logs');
+ }
+
/**
* Enables verbose logging.
* @return {!ServiceBuilder} A self reference.

@ -2,7 +2,11 @@
const path = require('path');
const { promises: fs, constants: fsConstants } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const ttest = require('ttest');
const { retry } = require('../../development/lib/retry');
const { exitWithError } = require('../../development/lib/exit-with-error');
const { withFixtures } = require('./helpers');
const { PAGES } = require('./webdriver/driver');
@ -38,6 +42,9 @@ const minResult = calculateResult((array) => Math.min(...array));
const maxResult = calculateResult((array) => Math.max(...array));
const averageResult = calculateResult((array) => calculateAverage(array));
const standardDeviationResult = calculateResult((array) => {
if (array.length === 1) {
return 0;
}
const average = calculateAverage(array);
const squareDiffs = array.map((value) => Math.pow(value - average, 2));
return Math.sqrt(calculateAverage(squareDiffs));
@ -46,15 +53,19 @@ const standardDeviationResult = calculateResult((array) => {
const calculateMarginOfError = (array) =>
ttest(array).confidence()[1] - calculateAverage(array);
const marginOfErrorResult = calculateResult((array) =>
calculateMarginOfError(array),
array.length === 1 ? 0 : calculateMarginOfError(array),
);
async function profilePageLoad(pages, numSamples) {
async function profilePageLoad(pages, numSamples, retries) {
const results = {};
for (const pageName of pages) {
const runResults = [];
for (let i = 0; i < numSamples; i += 1) {
runResults.push(await measurePage(pageName));
let result;
await retry(retries, async () => {
result = await measurePage(pageName);
});
runResults.push(result);
}
if (runResults.some((result) => result.navigation.lenth > 1)) {
@ -126,66 +137,63 @@ async function getFirstParentDirectoryThatExists(directory) {
}
async function main() {
const args = process.argv.slice(2);
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs
.option('pages', {
array: true,
default: ['home'],
description:
'Set the page(s) to be benchmarked. This flag can accept multiple values (space-separated).',
choices: ALL_PAGES,
})
.option('samples', {
default: DEFAULT_NUM_SAMPLES,
description: 'The number of times the benchmark should be run.',
type: 'number',
})
.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
})
.option('retries', {
default: 0,
description:
'Set how many times each benchmark sample should be retried upon failure.',
type: 'number',
}),
);
const { pages, samples, out, retries } = argv;
let pages = ['home'];
let numSamples = DEFAULT_NUM_SAMPLES;
let outputPath;
let outputDirectory;
let existingParentDirectory;
while (args.length) {
if (/^(--pages|-p)$/u.test(args[0])) {
if (args[1] === undefined) {
throw new Error('Missing pages argument');
}
pages = args[1].split(',');
for (const page of pages) {
if (!ALL_PAGES.includes(page)) {
throw new Error(`Invalid page: '${page}`);
}
}
args.splice(0, 2);
} else if (/^(--samples|-s)$/u.test(args[0])) {
if (args[1] === undefined) {
throw new Error('Missing number of samples');
}
numSamples = parseInt(args[1], 10);
if (isNaN(numSamples)) {
throw new Error(`Invalid 'samples' argument given: '${args[1]}'`);
}
args.splice(0, 2);
} else if (/^(--out|-o)$/u.test(args[0])) {
if (args[1] === undefined) {
throw new Error('Missing output filename');
}
outputPath = path.resolve(args[1]);
outputDirectory = path.dirname(outputPath);
existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error(`Specified directory is not writable: '${args[1]}'`);
}
args.splice(0, 2);
} else {
throw new Error(`Unrecognized argument: '${args[0]}'`);
if (out) {
outputDirectory = path.dirname(out);
existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
}
const results = await profilePageLoad(pages, numSamples);
const results = await profilePageLoad(pages, samples, retries);
if (outputPath) {
if (out) {
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(outputPath, JSON.stringify(results, null, 2));
await fs.writeFile(out, JSON.stringify(results, null, 2));
} else {
console.log(JSON.stringify(results, null, 2));
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
main().catch((error) => {
exitWithError(error);
});

@ -128,7 +128,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true

@ -138,7 +138,6 @@
},
"completedOnboarding": true,
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"ipfsGateway": "dweb.link",
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
},

@ -129,7 +129,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true

@ -121,7 +121,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true

@ -125,8 +125,7 @@
},
"MetaMetricsController": {
"participateInMetaMetrics": false,
"metaMetricsId": null,
"metaMetricsSendCount": 1
"metaMetricsId": null
},
"PermissionsController": {
"permissionsRequests": [],

@ -114,7 +114,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true

@ -114,7 +114,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"showFiatInTestnets": true,

@ -138,7 +138,6 @@
},
"completedOnboarding": true,
"metaMetricsId": "fake-metrics-id",
"metaMetricsSendCount": 0,
"ipfsGateway": "dweb.link",
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
},

@ -115,7 +115,6 @@
"knownMethodData": {},
"lostIdentities": {},
"metaMetricsId": null,
"metaMetricsSendCount": 0,
"participateInMetaMetrics": false,
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true

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

Loading…
Cancel
Save