aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml2
-rw-r--r--CHANGELOG.md28
-rw-r--r--README.md2
-rw-r--r--app/_locales/cs/messages.json4
-rw-r--r--app/_locales/de/messages.json14
-rw-r--r--app/_locales/en/messages.json82
-rw-r--r--app/_locales/es/messages.json14
-rw-r--r--app/_locales/fr/messages.json6
-rw-r--r--app/_locales/ht/messages.json2545
-rw-r--r--app/_locales/index.json41
-rw-r--r--app/_locales/it/messages.json509
-rw-r--r--app/_locales/ja/messages.json2
-rw-r--r--app/_locales/ko/messages.json604
-rw-r--r--app/_locales/nl/messages.json4
-rw-r--r--app/_locales/pl/messages.json1213
-rw-r--r--app/_locales/pt/messages.json6
-rw-r--r--app/_locales/ru/messages.json2
-rw-r--r--app/_locales/sl/messages.json767
-rw-r--r--app/_locales/th/messages.json2
-rw-r--r--app/_locales/tml/messages.json4
-rw-r--r--app/_locales/tr/messages.json1818
-rw-r--r--app/_locales/zh_CN/messages.json14
-rw-r--r--app/_locales/zh_TW/messages.json2
-rw-r--r--app/images/eth.svg14
-rw-r--r--app/loading.html12
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/background.js25
-rw-r--r--app/scripts/contentscript.js19
-rw-r--r--app/scripts/controllers/blacklist.js25
-rw-r--r--app/scripts/controllers/currency.js80
-rw-r--r--app/scripts/controllers/network/createMetamaskMiddleware.js2
-rw-r--r--app/scripts/controllers/network/network.js76
-rw-r--r--app/scripts/controllers/preferences.js98
-rw-r--r--app/scripts/controllers/transactions/index.js39
-rw-r--r--app/scripts/controllers/transactions/tx-gas-utils.js35
-rw-r--r--app/scripts/controllers/transactions/tx-state-manager.js5
-rw-r--r--app/scripts/inpage.js2
-rw-r--r--app/scripts/lib/ens-ipfs/contracts/registrar.js (renamed from app/scripts/lib/contracts/registrar.js)0
-rw-r--r--app/scripts/lib/ens-ipfs/contracts/resolver.js (renamed from app/scripts/lib/contracts/resolver.js)0
-rw-r--r--app/scripts/lib/ens-ipfs/resolver.js54
-rw-r--r--app/scripts/lib/ens-ipfs/setup.js63
-rw-r--r--app/scripts/lib/ipfsContent.js46
-rw-r--r--app/scripts/lib/reportFailedTxToSentry.js6
-rw-r--r--app/scripts/lib/resolver.js71
-rw-r--r--app/scripts/lib/setupFetchDebugging.js36
-rw-r--r--app/scripts/lib/setupSentry.js (renamed from app/scripts/lib/setupRaven.js)75
-rw-r--r--app/scripts/metamask-controller.js54
-rw-r--r--app/scripts/ui.js14
-rw-r--r--development/sentry-publish.js38
-rw-r--r--development/states/add-token.json5
-rw-r--r--development/states/confirm-sig-requests.json5
-rw-r--r--development/states/currency-localization.json5
-rw-r--r--development/states/first-time.json5
-rw-r--r--development/states/send-new-ui.json5
-rw-r--r--development/states/tx-list-items.json5
-rw-r--r--gulpfile.js4
-rw-r--r--mascara/src/app/first-time/index.css2
-rw-r--r--old-ui/app/app.js2
-rw-r--r--old-ui/app/components/app-bar.js15
-rw-r--r--old-ui/app/components/balance.js11
-rw-r--r--old-ui/app/components/eth-balance.js12
-rw-r--r--old-ui/app/components/pending-tx.js16
-rw-r--r--old-ui/app/config.js76
-rw-r--r--old-ui/app/util.js8
-rw-r--r--package-lock.json933
-rw-r--r--package.json13
-rw-r--r--test/data/2-state.json70
-rw-r--r--test/data/mock-state.json4
-rw-r--r--test/e2e/beta/from-import-beta-ui.spec.js4
-rw-r--r--test/e2e/beta/metamask-beta-ui.spec.js44
-rwxr-xr-xtest/e2e/beta/run-drizzle.sh2
-rw-r--r--test/integration/lib/add-token.js140
-rw-r--r--test/integration/lib/currency-localization.js2
-rw-r--r--test/integration/lib/send-new-ui.js22
-rw-r--r--test/unit/app/controllers/network-contoller-test.js2
-rw-r--r--test/unit/app/controllers/preferences-controller-test.js24
-rw-r--r--test/unit/app/controllers/transactions/tx-controller-test.js30
-rw-r--r--test/unit/components/balance-component-test.js44
-rw-r--r--test/unit/ui/app/actions.spec.js1468
-rw-r--r--ui/app/actions.js54
-rw-r--r--ui/app/app.js8
-rw-r--r--ui/app/components/account-dropdowns.js3
-rw-r--r--ui/app/components/account-menu/index.js13
-rw-r--r--ui/app/components/account-panel.js2
-rw-r--r--ui/app/components/add-token-button/add-token-button.component.js34
-rw-r--r--ui/app/components/add-token-button/index.js1
-rw-r--r--ui/app/components/add-token-button/index.scss26
-rw-r--r--ui/app/components/app-header/app-header.component.js2
-rw-r--r--ui/app/components/balance-component.js38
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js66
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/index.scss12
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js38
-rw-r--r--ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js7
-rw-r--r--ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js19
-rw-r--r--ui/app/components/confirm-page-container/confirm-page-container.component.js5
-rw-r--r--ui/app/components/currency-display/currency-display.component.js26
-rw-r--r--ui/app/components/currency-display/currency-display.container.js35
-rw-r--r--ui/app/components/currency-display/index.scss14
-rw-r--r--ui/app/components/currency-display/tests/currency-display.container.test.js52
-rw-r--r--ui/app/components/currency-input/currency-input.component.js121
-rw-r--r--ui/app/components/currency-input/currency-input.container.js28
-rw-r--r--ui/app/components/currency-input/index.js1
-rw-r--r--ui/app/components/currency-input/index.scss7
-rw-r--r--ui/app/components/currency-input/tests/currency-input.component.test.js251
-rw-r--r--ui/app/components/currency-input/tests/currency-input.container.test.js60
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js8
-rw-r--r--ui/app/components/dropdowns/network-dropdown.js35
-rw-r--r--ui/app/components/dropdowns/tests/network-dropdown.test.js4
-rw-r--r--ui/app/components/eth-balance.js12
-rw-r--r--ui/app/components/identicon.js124
-rw-r--r--ui/app/components/identicon/identicon.component.js99
-rw-r--r--ui/app/components/identicon/identicon.container.js12
-rw-r--r--ui/app/components/identicon/index.js1
-rw-r--r--ui/app/components/identicon/index.scss7
-rw-r--r--ui/app/components/identicon/tests/identicon.component.test.js (renamed from test/unit/ui/app/components/identicon.spec.js)33
-rw-r--r--ui/app/components/index.scss10
-rw-r--r--ui/app/components/jazzicon/index.js1
-rw-r--r--ui/app/components/jazzicon/jazzicon.component.js69
-rw-r--r--ui/app/components/modals/account-modal-container.js2
-rw-r--r--ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js12
-rw-r--r--ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js9
-rw-r--r--ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js2
-rw-r--r--ui/app/components/modals/hide-token-confirmation-modal.js2
-rw-r--r--ui/app/components/modals/modal.js14
-rw-r--r--ui/app/components/modals/transaction-details/index.js1
-rw-r--r--ui/app/components/modals/transaction-details/transaction-details.component.js54
-rw-r--r--ui/app/components/modals/transaction-details/transaction-details.container.js4
-rw-r--r--ui/app/components/network-display/network-display.component.js4
-rw-r--r--ui/app/components/network.js5
-rw-r--r--ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js2
-rw-r--r--ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js59
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js89
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js8
-rw-r--r--ui/app/components/pages/create-account/import-account/index.js2
-rw-r--r--ui/app/components/pages/settings/settings-tab/index.scss30
-rw-r--r--ui/app/components/pages/settings/settings-tab/settings-tab.component.js151
-rw-r--r--ui/app/components/pages/settings/settings-tab/settings-tab.container.js11
-rw-r--r--ui/app/components/qr-code.js2
-rw-r--r--ui/app/components/send/account-list-item/account-list-item.component.js29
-rw-r--r--ui/app/components/send/account-list-item/account-list-item.container.js2
-rw-r--r--ui/app/components/send/account-list-item/tests/account-list-item-component.test.js17
-rw-r--r--ui/app/components/send/account-list-item/tests/account-list-item-container.test.js2
-rw-r--r--ui/app/components/send/currency-display/currency-display.js186
-rw-r--r--ui/app/components/send/currency-display/index.js1
-rw-r--r--ui/app/components/send/currency-display/tests/currency-display.test.js91
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js34
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js9
-rw-r--r--ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js45
-rw-r--r--ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js26
-rw-r--r--ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js35
-rw-r--r--ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js12
-rw-r--r--ui/app/components/send/send.selectors.js5
-rw-r--r--ui/app/components/send/send.utils.js4
-rw-r--r--ui/app/components/send/tests/send-selectors-test-data.js1
-rw-r--r--ui/app/components/send/tests/send-selectors.test.js10
-rw-r--r--ui/app/components/send/to-autocomplete/to-autocomplete.js3
-rw-r--r--ui/app/components/sender-to-recipient/sender-to-recipient.component.js17
-rw-r--r--ui/app/components/shift-list-item.js5
-rw-r--r--ui/app/components/signature-request.js4
-rw-r--r--ui/app/components/token-cell.js2
-rw-r--r--ui/app/components/token-input/index.js1
-rw-r--r--ui/app/components/token-input/tests/token-input.component.test.js308
-rw-r--r--ui/app/components/token-input/tests/token-input.container.test.js129
-rw-r--r--ui/app/components/token-input/token-input.component.js136
-rw-r--r--ui/app/components/token-input/token-input.container.js27
-rw-r--r--ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js3
-rw-r--r--ui/app/components/transaction-activity-log/transaction-activity-log.component.js21
-rw-r--r--ui/app/components/transaction-activity-log/transaction-activity-log.container.js3
-rw-r--r--ui/app/components/transaction-activity-log/transaction-activity-log.util.js17
-rw-r--r--ui/app/components/transaction-breakdown/index.js2
-rw-r--r--ui/app/components/transaction-breakdown/transaction-breakdown.component.js40
-rw-r--r--ui/app/components/transaction-breakdown/transaction-breakdown.container.js11
-rw-r--r--ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js17
-rw-r--r--ui/app/components/transaction-list-item/index.scss2
-rw-r--r--ui/app/components/transaction-list-item/transaction-list-item.component.js36
-rw-r--r--ui/app/components/transaction-list-item/transaction-list-item.container.js10
-rw-r--r--ui/app/components/transaction-list/index.scss3
-rw-r--r--ui/app/components/transaction-status/index.scss7
-rw-r--r--ui/app/components/transaction-view-balance/index.scss9
-rw-r--r--ui/app/components/transaction-view-balance/tests/token-view-balance.component.test.js4
-rw-r--r--ui/app/components/transaction-view-balance/transaction-view-balance.component.js14
-rw-r--r--ui/app/components/transaction-view-balance/transaction-view-balance.container.js3
-rw-r--r--ui/app/components/transaction-view/index.scss1
-rw-r--r--ui/app/components/unit-input/index.js1
-rw-r--r--ui/app/components/unit-input/index.scss44
-rw-r--r--ui/app/components/unit-input/tests/unit-input.component.test.js146
-rw-r--r--ui/app/components/unit-input/unit-input.component.js104
-rw-r--r--ui/app/components/user-preferenced-currency-display/index.js1
-rw-r--r--ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js34
-rw-r--r--ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js115
-rw-r--r--ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js46
-rw-r--r--ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js54
-rw-r--r--ui/app/components/user-preferenced-currency-input/index.js1
-rw-r--r--ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js32
-rw-r--r--ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js31
-rw-r--r--ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js20
-rw-r--r--ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js13
-rw-r--r--ui/app/components/user-preferenced-token-input/index.js1
-rw-r--r--ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js32
-rw-r--r--ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js31
-rw-r--r--ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js20
-rw-r--r--ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js13
-rw-r--r--ui/app/components/wallet-view.js33
-rw-r--r--ui/app/constants/common.js3
-rw-r--r--ui/app/constants/error-keys.js1
-rw-r--r--ui/app/css/itcss/components/buttons.scss5
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss12
-rw-r--r--ui/app/css/itcss/components/request-signature.scss2
-rw-r--r--ui/app/css/itcss/components/wallet-balance.scss5
-rw-r--r--ui/app/ducks/confirm-transaction.duck.js69
-rw-r--r--ui/app/ducks/tests/confirm-transaction.duck.test.js44
-rw-r--r--ui/app/helpers/confirm-transaction/util.js8
-rw-r--r--ui/app/helpers/conversions.util.js29
-rw-r--r--ui/app/helpers/tests/transactions.util.test.js35
-rw-r--r--ui/app/helpers/transactions.util.js33
-rw-r--r--ui/app/reducers.js26
-rw-r--r--ui/app/reducers/metamask.js9
-rw-r--r--ui/app/selectors.js10
-rw-r--r--ui/app/selectors/confirm-transaction.js1
-rw-r--r--ui/app/util.js8
-rw-r--r--ui/i18n-helper.js2
221 files changed, 11298 insertions, 4475 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 00ba9ffa2..60867e181 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -324,7 +324,7 @@ jobs:
command: >
git config user.name metamaskbot &&
git config user.email admin@metamask.io &&
- gh-pages -d docs/jsdocs
+ npm run publish-docs
test-unit:
docker:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aef455127..37d9f26b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,36 @@
## Current Develop Branch
+- [#5283](https://github.com/MetaMask/metamask-extension/pull/5283): Fix bug when eth.getCode() called with no contract
+- [#5563](https://github.com/MetaMask/metamask-extension/pull/5563#pullrequestreview-166769174) Feature: improve Hatian Creole translations
+- [#5559](https://github.com/MetaMask/metamask-extension/pull/5559) Localize language names in translation select list
+
+## 4.16.0 Wednesday October 17 2018
+
+- Feature: Add toggle for primary currency (eth/fiat)
+- Feature: add tooltip for view etherscan tx
+- Feature: add Polish translations
+- Feature: improve Korean translations
+- Feature: improve Italian translations
+- Bug Fix: Fix bug with "pending" block reference
+- Bug Fix: Force AccountTracker to update balances on network change
+- Bug Fix: Fix document extension check when injecting web3
+- Bug Fix: Fix some support links
+
+## 4.15.0 Thursday October 11 2018
+
+- A rollback release, equivalent to `v4.11.1` to be deployed in the case that `v4.14.0` is found to have bugs.
+
+## 4.14.0 Thursday October 11 2018
+
- Update transaction statuses when switching networks.
- [#5470](https://github.com/MetaMask/metamask-extension/pull/5470) 100% coverage in French locale, fixed the procedure to verify proposed locale.
+- Added rudimentary support for the subscription API to support web3 1.0 and Truffle's Drizzle.
+- [#5502](https://github.com/MetaMask/metamask-extension/pull/5502) Update Italian translation.
+
+## 4.13.0
+
+- A rollback release, equivalent to `v4.11.1` to be deployed in the case that `v4.12.0` is found to have bugs.
## 4.12.0 Thursday September 27 2018
diff --git a/README.md b/README.md
index b85f32bb3..e785d5ed1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# MetaMask Browser Extension
-[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](https://waffle.io/MetaMask/metamask-extension)
+[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](https://waffle.io/MetaMask/metamask-extension)
## Support
diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json
index 55344f3e1..ae2413ad9 100644
--- a/app/_locales/cs/messages.json
+++ b/app/_locales/cs/messages.json
@@ -372,7 +372,7 @@
"message": "Import účtu"
},
"importAccountMsg": {
- "message":"Importované účty nebudou spojeny s vaší původní MetaMaskovou klíčovou frází. Zjistěte více o importovaných účtech "
+ "message": "Importované účty nebudou spojeny s vaší původní MetaMaskovou klíčovou frází. Zjistěte více o importovaných účtech "
},
"importAnAccount": {
"message": "Import účtu"
@@ -730,7 +730,7 @@
"message": "Nastavení"
},
"info": {
- "message": "Informace"
+ "message": "Informace"
},
"shapeshiftBuy": {
"message": "Nakoupit na ShapeShift"
diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json
index 352d5ad7d..9e1eb9eac 100644
--- a/app/_locales/de/messages.json
+++ b/app/_locales/de/messages.json
@@ -68,13 +68,13 @@
"message": "Muss größer oder gleich $1 und kleiner oder gleich $2 sein.",
"description": "Helfer für die Eingabe von hex als dezimal"
},
- "blockiesIdenticon": {
+ "blockiesIdenticon": {
"message": "Blockies Identicon verwenden"
},
"borrowDharma": {
"message": "Mit Dharma ausleihen (Beta)"
},
- "builtInCalifornia": {
+ "builtInCalifornia": {
"message": "MetaMask wurde in Kalifornien entwickelt und gebaut."
},
"buy": {
@@ -86,13 +86,13 @@
"buyCoinbaseExplainer": {
"message": "Coinbase ist die weltweit bekannteste Art und Weise um Bitcoin, Ethereum und Litecoin zu kaufen und verkaufen."
},
- "ok": {
+ "ok": {
"message": "Ok"
},
"cancel": {
"message": "Abbrechen"
},
- "classicInterface": {
+ "classicInterface": {
"message": "Klassische Oberfläche verwenden"
},
"clickCopy": {
@@ -101,7 +101,7 @@
"confirm": {
"message": "Bestätigen"
},
- "confirmed": {
+ "confirmed": {
"message": "Bestätigt"
},
"confirmContract": {
@@ -369,7 +369,7 @@
"message": "Account importieren"
},
"importAccountMsg": {
- "message":" Importierte Accounts werden nicht mit der Seed-Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts."
+ "message": " Importierte Accounts werden nicht mit der Seed-Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts."
},
"importAnAccount": {
"message": "Einen Account importieren"
@@ -709,7 +709,7 @@
"message": "Einstellungen"
},
"info": {
- "message": "Info"
+ "message": "Info"
},
"shapeshiftBuy": {
"message": "Mit Shapeshift kaufen"
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 97fc402fa..26d0422cb 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -14,6 +14,9 @@
"accountName": {
"message": "Account Name"
},
+ "accountOptions": {
+ "message": "Account Options"
+ },
"accountSelectionRequired": {
"message": "You need to select an account!"
},
@@ -137,10 +140,13 @@
"clickCopy": {
"message": "Click to Copy"
},
+ "clickToAdd": {
+ "message": "Click on $1 to add them to your account"
+ },
"close": {
"message": "Close"
},
- "chromeRequiredForHardwareWallets":{
+ "chromeRequiredForHardwareWallets": {
"message": "You need to use MetaMask on Google Chrome in order to connect to your Hardware Wallet."
},
"confirm": {
@@ -358,6 +364,9 @@
"enterPasswordContinue": {
"message": "Enter password to continue"
},
+ "eth": {
+ "message": "ETH"
+ },
"etherscanView": {
"message": "View account on Etherscan"
},
@@ -377,7 +386,7 @@
"message": "Failed"
},
"fiat": {
- "message": "FIAT",
+ "message": "Fiat",
"description": "Exchange type"
},
"fileImportFail": {
@@ -421,6 +430,9 @@
"gasLimitTooLow": {
"message": "Gas limit must be at least 21000"
},
+ "gasUsed": {
+ "message": "Gas Used"
+ },
"generatingSeed": {
"message": "Generating Seed..."
},
@@ -501,7 +513,7 @@
"message": "Import Account"
},
"importAccountMsg": {
- "message":" Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
+ "message": " Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
},
"importAnAccount": {
"message": "Import an account"
@@ -632,6 +644,9 @@
"min": {
"message": "Minimum"
},
+ "missingYourTokens": {
+ "message": "Don't see your tokens?"
+ },
"myAccounts": {
"message": "My Accounts"
},
@@ -677,9 +692,27 @@
"newRecipient": {
"message": "New Recipient"
},
- "newRPC": {
+ "newNetwork": {
+ "message": "New Network"
+ },
+ "rpcURL": {
"message": "New RPC URL"
},
+ "showAdvancedOptions": {
+ "message": "Show Advanced Options"
+ },
+ "hideAdvancedOptions": {
+ "message": "Hide Advanced Options"
+ },
+ "optionalChainId": {
+ "message": "ChainID (optional)"
+ },
+ "optionalSymbol": {
+ "message": "Symbol (optional)"
+ },
+ "optionalNickname": {
+ "message": "Nickname (optional)"
+ },
"next": {
"message": "Next"
},
@@ -689,7 +722,7 @@
"noDeposits": {
"message": "No deposits received"
},
- "noConversionRateAvailable":{
+ "noConversionRateAvailable": {
"message": "No Conversion Rate Available"
},
"noTransactionHistory": {
@@ -726,9 +759,6 @@
"openInTab": {
"message": "Open in tab"
},
- "accountOptions": {
- "message": "Account Options"
- },
"or": {
"message": "or",
"description": "choice between creating or importing a new account"
@@ -745,22 +775,22 @@
"parameters": {
"message": "Parameters"
},
- "passwordNotLongEnough": {
- "message": "Password not long enough"
- },
- "passwordsDontMatch": {
- "message": "Passwords Don't Match"
- },
"password": {
"message": "Password"
},
"passwordCorrect": {
"message": "Please make sure your password is correct."
},
+ "passwordsDontMatch": {
+ "message": "Passwords Don't Match"
+ },
"passwordMismatch": {
"message": "passwords don't match",
"description": "in password creation process, the two new password fields did not match"
},
+ "passwordNotLongEnough": {
+ "message": "Password not long enough"
+ },
"passwordShort": {
"message": "password not long enough",
"description": "in password creation process, the password is not long enough to be secure"
@@ -787,6 +817,12 @@
"prev": {
"message": "Prev"
},
+ "primaryCurrencySetting": {
+ "message": "Primary Currency"
+ },
+ "primaryCurrencySettingDescription": {
+ "message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency."
+ },
"privacyMsg": {
"message": "Privacy Policy"
},
@@ -795,7 +831,7 @@
"description": "select this type of file to use to import an account"
},
"privateKeyWarning": {
- "message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account."
+ "message": "Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account."
},
"privateNetwork": {
"message": "Private Network"
@@ -863,9 +899,6 @@
"retryWithMoreGas": {
"message": "Retry with a higher gas price here"
},
- "walletSeed": {
- "message": "Wallet Seed"
- },
"restore": {
"message": "Restore"
},
@@ -1154,12 +1187,18 @@
"transactionUpdatedGas": {
"message": "Transaction updated with a gas price of $1 on $2."
},
+ "transactionErrored": {
+ "message": "Transaction encountered an error."
+ },
"transactions": {
"message": "transactions"
},
"transactionError": {
"message": "Transaction Error. Exception thrown in contract code."
},
+ "transactionErrorNoContract": {
+ "message": "Trying to call a function on a non-contract address."
+ },
"transactionMemo": {
"message": "Transaction memo (optional)"
},
@@ -1189,7 +1228,7 @@
"message": "These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret."
},
"typePassword": {
- "message": "Type Your Password"
+ "message": "Type your MetaMask password"
},
"uiWelcome": {
"message": "Welcome to the New UI (Beta)"
@@ -1225,7 +1264,7 @@
"message": "Ooops! Something went wrong...."
},
"unknownCameraError": {
- "message": "There was an error while trying to access you camera. Please try again..."
+ "message": "There was an error while trying to access your camera. Please try again..."
},
"unlock": {
"message": "Unlock"
@@ -1264,6 +1303,9 @@
"visitWebSite": {
"message": "Visit our web site"
},
+ "walletSeed": {
+ "message": "Wallet Seed"
+ },
"warning": {
"message": "Warning"
},
diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json
index 3e43a7b43..be2a29ab5 100644
--- a/app/_locales/es/messages.json
+++ b/app/_locales/es/messages.json
@@ -156,7 +156,7 @@
"message": " Copiar "
},
"copyPrivateKey": {
- "message": "Ésta es tu llave privada (haz click para copiar)"
+ "message": "Ésta es tu clave privada (haz click para copiar)"
},
"copyToClipboard": {
"message": "Copiar al portapapeles"
@@ -278,10 +278,10 @@
"message": "Tipo de cambio"
},
"exportPrivateKey": {
- "message": "Exportar llave privada"
+ "message": "Exportar clave privada"
},
"exportPrivateKeyWarning": {
- "message": "Exportar llaves privadas bajo TU PROPIO riesgo"
+ "message": "Exportar claves privadas bajo TU PROPIO riesgo"
},
"failed": {
"message": "Fallo"
@@ -579,8 +579,8 @@
"description": "En el proceso de creación de contraseña, esta no es lo suficientemente larga para ser segura"
},
"pastePrivateKey": {
- "message": "Pega tu llave privada aqui",
- "description": "Para importar una cuenta desde una llave privada"
+ "message": "Pega tu clave privada aqui",
+ "description": "Para importar una cuenta desde una clave privada"
},
"pasteSeed": {
"message": "¡Pega tu frase semilla aquí!"
@@ -595,7 +595,7 @@
"message": "Política de privacidad"
},
"privateKey": {
- "message": "Llave privada",
+ "message": "Clave privada",
"description": "Selecciona este tupo de archivo para importar una cuenta"
},
"privateKeyWarning": {
@@ -712,7 +712,7 @@
"message": "Comprar con ShapeShift"
},
"showPrivateKeys": {
- "message": "Mostrar llaves privadas"
+ "message": "Mostrar claves privadas"
},
"showQRCode": {
"message": "Mostrar codigo QR"
diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json
index 64ba13b5d..d418cd9aa 100644
--- a/app/_locales/fr/messages.json
+++ b/app/_locales/fr/messages.json
@@ -140,7 +140,7 @@
"close": {
"message": "Fermer"
},
- "chromeRequiredForHardwareWallets":{
+ "chromeRequiredForHardwareWallets": {
"message": "Pour connecter votre portefeuille hardware, vous devez utiliser MetaMask pour Google Chrome."
},
"confirm": {
@@ -498,7 +498,7 @@
"message": "Importer un compte"
},
"importAccountMsg": {
- "message":" Les comptes importés ne seront pas associés avec votre phrase Seed que vous avez créé au départ dans MetaMask. Obtenir plus d'information sur les comptes importés"
+ "message": " Les comptes importés ne seront pas associés avec votre phrase Seed que vous avez créé au départ dans MetaMask. Obtenir plus d'information sur les comptes importés"
},
"importAnAccount": {
"message": "Importer un compte"
@@ -686,7 +686,7 @@
"noDeposits": {
"message": "Aucun dépôt reçu"
},
- "noConversionRateAvailable":{
+ "noConversionRateAvailable": {
"message": "Aucun taux de conversion disponible"
},
"noTransactionHistory": {
diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json
index 50a0ec2bb..81ce18018 100644
--- a/app/_locales/ht/messages.json
+++ b/app/_locales/ht/messages.json
@@ -1,1237 +1,1312 @@
{
- "accept": {
- "message": "Aksepte"
- },
- "accessingYourCamera": {
- "message": "Aksè a Kamera"
- },
- "account": {
- "message": "Kont"
- },
- "accountDetails": {
- "message": "Detay Kont"
- },
- "accountName": {
- "message": "Non Kont"
- },
- "accountSelectionRequired": {
- "message": "Ou bezwen chwazi yon kont!"
- },
- "activityLog": {
- "message": "aktivite ki fèt"
- },
- "address": {
- "message": "Adrès"
- },
- "addCustomToken": {
- "message": "Ajoute token"
- },
- "addToken": {
- "message": "Ajoute Token"
- },
- "addTokens": {
- "message": "Ajoute Token"
- },
- "addSuggestedTokens": {
- "message": "Ajoute Token Yo Sikjere W"
- },
- "addAcquiredTokens": {
- "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask"
- },
- "amount": {
- "message": "Kantite lajan"
- },
- "amountPlusGas": {
- "message": "Kantite lajan + Gaz"
- },
- "appDescription": {
- "message": "Ethereum Ekstansyon Navigatè",
- "description": "The description of the application"
- },
- "appName": {
- "message": "MetaMask",
- "description": "The name of the application"
- },
- "approve": {
- "message": "Apwouve"
- },
- "approved": {
- "message": "Apwouve"
- },
- "attemptingConnect": {
- "message": "Eseye konekte nan blockchain."
- },
- "attributions": {
- "message": "Atribisyon"
- },
- "available": {
- "message": "Disponib"
- },
- "back": {
- "message": "Retounen"
- },
- "balance": {
- "message": "Balans"
- },
- "balances": {
- "message": "Balans Token"
- },
- "balanceIsInsufficientGas": {
- "message": "Ensifizan balans pou total gaz aktyèl la"
- },
- "beta": {
- "message": "BETA"
- },
- "betweenMinAndMax": {
- "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.",
- "description": "helper for inputting hex as decimal input"
- },
- "blockiesIdenticon": {
- "message": "Itilize Blockies Identicon"
- },
- "borrowDharma": {
- "message": "Prete Avèk Dharma (Beta)"
- },
- "browserNotSupported": {
- "message": "Navigatè ou a pa sipòte..."
- },
- "builtInCalifornia": {
- "message": "MetaMask fèt e bati nan California."
- },
- "buy": {
- "message": "Achte"
- },
- "buyCoinbase": {
- "message": "Achte sou Coinbase"
- },
- "buyCoinbaseExplainer": {
- "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin."
- },
- "bytes": {
- "message": "Bytes"
- },
- "ok": {
- "message": "Oke"
- },
- "cancel": {
- "message": "Anile"
- },
- "classicInterface": {
- "message": "Sèvi ak fas klasik la"
- },
- "clickCopy": {
- "message": "Klike sou kopi"
- },
- "close": {
- "message": "Fèmen"
- },
- "chromeRequiredForHardwareWallets": {
- "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet."
- },
- "confirm": {
- "message": "Konfime"
- },
- "confirmed": {
- "message": "Konfime"
- },
- "confirmContract": {
- "message": "Konfime Kontra"
- },
- "confirmPassword": {
- "message": "Konfime Modpas"
- },
- "confirmTransaction": {
- "message": "Konfime Tranzaksyon"
- },
- "connectHardwareWallet": {
- "message": "Konekte Hardware Wallet"
- },
- "connect": {
- "message": "Konekte"
- },
- "connecting": {
- "message": "Koneksyon..."
- },
- "connectToLedger": {
- "message": "Konekte ak Ledger"
- },
- "connectToTrezor": {
- "message": "Konekte ak Trezor"
- },
- "continue": {
- "message": "Kontinye"
- },
- "continueToCoinbase": {
- "message": "Kontinye Coinbase"
- },
- "contractDeployment": {
- "message": "Kontra Deplwaman"
- },
- "conversionProgress": {
- "message": "Konvèsyon nan Pwogrè"
- },
- "copiedButton": {
- "message": "Kopye"
- },
- "copiedClipboard": {
- "message": "Kopi nan Clipboard"
- },
- "copiedExclamation": {
- "message": "Kopye!"
- },
- "copiedSafe": {
- "message": "Mwen te kopye li yon kote ki san danje"
- },
- "copy": {
- "message": "Kopye"
- },
- "copyAddress": {
- "message": "Kopi adrès clipboard"
- },
- "copyToClipboard": {
- "message": "Kopi clipboard"
- },
- "copyButton": {
- "message": " Kopi "
- },
- "copyPrivateKey": {
- "message": "Sa a se kle prive ou (klike pou ou kopye)"
- },
- "create": {
- "message": "Kreye"
- },
- "createAccount": {
- "message": "Kreye Kont"
- },
- "createDen": {
- "message": "Kreye"
- },
- "crypto": {
- "message": "Crypto",
- "description": "Change tip (cryptocurrencies)"
- },
- "currentConversion": {
- "message": "Konvèsyon aktyèl"
- },
- "currentNetwork": {
- "message": "Rezo aktyèl"
- },
- "customGas": {
- "message": "Koutim Gaz"
- },
- "customToken": {
- "message": "Koutim Token"
- },
- "customize": {
- "message": "Koutim"
- },
- "customRPC": {
- "message": "Koutim RPC"
- },
- "decimalsMustZerotoTen": {
- "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36."
- },
- "decimal": {
- "message": "Presizyon desimal la"
- },
- "defaultNetwork": {
- "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet."
- },
- "denExplainer": {
- "message": "DEN ou se depo modpas avèk chif ou nan MetaMask."
- },
- "deposit": {
- "message": "Depo"
- },
- "depositBTC": {
- "message": "Depoze BTC ou nan adrès ki anba a:"
- },
- "depositCoin": {
- "message": "Depoze $1 ou nan adrès ki anba a",
- "description": "Tells the user what coin they have selected to deposit with shapeshift"
- },
- "depositEth": {
- "message": "Depo Eth"
- },
- "depositEther": {
- "message": "Depo Ether"
- },
- "depositFiat": {
- "message": "Depo ak Fiat"
- },
- "depositFromAccount": {
- "message": "Depo nan yon lòt kont"
- },
- "depositShapeShift": {
- "message": "Depo avèk ShapeShift"
- },
- "depositShapeShiftExplainer": {
- "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè."
- },
- "details": {
- "message": "Detay yo"
- },
- "directDeposit": {
- "message": "Depo Dirèk"
- },
- "directDepositEther": {
- "message": "Dirèkteman Depo Ether"
- },
- "directDepositEtherExplainer": {
- "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk."
- },
- "done": {
- "message": "Fini"
- },
- "downloadGoogleChrome": {
- "message": "Telechaje Google Chrome"
- },
- "downloadStateLogs": {
- "message": "Telechaje State Logs"
- },
- "dontHaveAHardwareWallet": {
- "message": "Pa gen yon materyèl bous?"
- },
- "dropped": {
- "message": "Tonbe"
- },
- "edit": {
- "message": "Korije"
- },
- "editAccountName": {
- "message": "Korije Non Kont"
- },
- "editingTransaction": {
- "message": "Fè chanjman nan tranzaksyon ou"
- },
- "emailUs": {
- "message": "Imèl nou!"
- },
- "encryptNewDen": {
- "message": "Ankripte nouvo DEN ou"
- },
- "ensNameNotFound": {
- "message": "Nou pa jwenn non ENS ou a"
- },
- "enterPassword": {
- "message": "Mete modpas"
- },
- "enterPasswordConfirm": {
- "message": "Antre nan modpas ou a konfime"
- },
- "enterPasswordContinue": {
- "message": "Mete modpas pou kontinye"
- },
- "parameters": {
- "message": "Paramèt"
- },
- "passwordNotLongEnough": {
- "message": "Modpas la pa ase"
- },
- "passwordsDontMatch": {
- "message": "Modpas Pa Koresponn ak"
- },
- "etherscanView": {
- "message": "Gade kont sou Etherscan"
- },
- "exchangeRate": {
- "message": "Chanje to"
- },
- "exportPrivateKey": {
- "message": "Voye Kòd Prive"
- },
- "exportPrivateKeyWarning": {
- "message": "Voye kle prive ak pwòp risk ou."
- },
- "failed": {
- "message": "Tonbe"
- },
- "fiat": {
- "message": "FIAT",
- "description": "Exchange type"
- },
- "fileImportFail": {
- "message": "Enpòte dosye ki pa travay? Klike la a!",
- "description": "Helps user import their account from a JSON file"
- },
- "followTwitter": {
- "message": "Swiv nou sou Twitter"
- },
- "forgetDevice": {
- "message": "Bliye aparèy sa a"
- },
- "from": {
- "message": "Soti nan"
- },
- "fromToSame": {
- "message": "Adrès orijinal le ak sa ou resevwa pake menm"
- },
- "fromShapeShift": {
- "message": "Soti nan ShapeShift"
- },
- "functionType": {
- "message": "Kalite Fonksyon"
- },
- "gas": {
- "message": "Gaz",
- "description": "Short indication of gas cost"
- },
- "gasFee": {
- "message": "Frè gaz"
- },
- "gasLimit": {
- "message": "Limit gaz"
- },
- "gasLimitCalculation": {
- "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a."
- },
- "gasLimitRequired": {
- "message": "Limit gaz nesesè"
- },
- "gasLimitTooLow": {
- "message": "Limit gaz dwe omwen 21000"
- },
- "generatingSeed": {
- "message": "Génération Seed..."
- },
- "gasPrice": {
- "message": "Pri gaz (GWEI)"
- },
- "gasPriceCalculation": {
- "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo."
- },
- "gasPriceRequired": {
- "message": "Pri Gaz la Egzije"
- },
- "generatingTransaction": {
- "message": "Tranzaksyon kap fè"
- },
- "getEther": {
- "message": "Jwenn Ether"
- },
- "getEtherFromFaucet": {
- "message": "Jwenn Ether nan yon tiyo pou $1 la",
- "description": "Displays network name for Ether faucet"
- },
- "getHelp": {
- "message": "Jwenn èd."
- },
- "greaterThanMin": {
- "message": "dwe pi gran pase oswa egal a $ 1.",
- "description": "helper for inputting hex as decimal input"
- },
- "hardware": {
- "message": "hardware"
- },
- "hardwareWalletConnected": {
- "message": "Hardware Wallet konekte"
- },
- "hardwareWallets": {
- "message": "Hardware Wallet konekte"
- },
- "hardwareWalletsMsg": {
- "message": "Chwazi yon Hardware Wallet ou ta renmen itilize ak MetaMask"
- },
- "havingTroubleConnecting": {
- "message": "Èske w gen pwoblèm pou konekte?"
- },
- "here": {
- "message": "isit la",
- "description": "as in -click here- for more information (goes with troubleTokenBalances)"
- },
- "hereList": {
- "message": "Isit la nan yon lis !!!!"
- },
- "hexData": {
- "message": "Hex Data"
- },
- "hide": {
- "message": "Kache"
- },
- "hideToken": {
- "message": "Kache Token"
- },
- "hideTokenPrompt": {
- "message": "Kache Token?"
- },
- "history": {
- "message": "Istwa"
- },
- "howToDeposit": {
- "message": "Ki jan ou ta renmen depo Ether?"
- },
- "holdEther": {
- "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon."
- },
- "import": {
- "message": "Pòte",
- "description": "Button to import an account from a selected file"
- },
- "importAccount": {
- "message": "Pòte Kont"
- },
- "importAccountMsg": {
- "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte "
- },
- "importAnAccount": {
- "message": "Pòte yon kont"
- },
- "importDen": {
- "message": "Pòte ki deja egziste DEN"
- },
- "imported": {
- "message": "Pòte",
- "description": "status showing that an account has been fully loaded into the keyring"
- },
- "importUsingSeed": {
- "message": "Pòte lè sèvi avèk seed fraz"
- },
- "infoHelp": {
- "message": "Enfo & Èd"
- },
- "initialTransactionConfirmed": {
- "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen."
- },
- "insufficientFunds": {
- "message": "Lajan ensifizan."
- },
- "insufficientTokens": {
- "message": "Tokens pa valab."
- },
- "invalidAddress": {
- "message": "Adrès pa valab"
- },
- "invalidAddressRecipient": {
- "message": "Moun ki resevwa adrès la pa valab"
- },
- "invalidGasParams": {
- "message": "Gaz Paramèt la pa valab"
- },
- "invalidInput": {
- "message": "Sa ou rantre a pa valab"
- },
- "invalidRequest": {
- "message": "Demann pa valab"
- },
- "invalidRPC": {
- "message": "RPC URI pa valab"
- },
- "invalidSeedPhrase": {
- "message": "Seed fraz pa valab"
- },
- "jsonFail": {
- "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate."
- },
- "jsonFile": {
- "message": "JSON Dosye",
- "description": "format for importing an account"
- },
- "keepTrackTokens": {
- "message": "Gade tokens yo ou te achte ak kont MetaMask ou."
- },
- "kovan": {
- "message": "Kovan Tès Rezo"
- },
- "knowledgeDataBase": {
- "message": "Vizite baz nou an"
- },
- "max": {
- "message": "Maksimòm"
- },
- "learnMore": {
- "message": "Aprann plis"
- },
- "ledgerAccountRestriction": {
- "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo."
- },
- "lessThanMax": {
- "message": "dwe mwens pase oswa egal a $ 1.",
- "description": "helper for inputting hex as decimal input"
- },
- "likeToAddTokens": {
- "message": "Èske ou ta renmen ajoute sa nan tokens?"
- },
- "links": {
- "message": "Lyen"
- },
- "limit": {
- "message": "Limitasyon"
- },
- "loading": {
- "message": "Telechaje..."
- },
- "loadingTokens": {
- "message": "Telechaje Tokens..."
- },
- "localhost": {
- "message": "Localhost 8545"
- },
- "login": {
- "message": "Ouvri"
- },
- "logout": {
- "message": "Dekonekte"
- },
- "loose": {
- "message": "Pèdi"
- },
- "loweCaseWords": {
- "message": "seed mo sèlman gen karaktè miniskil"
- },
- "mainnet": {
- "message": "Main Ethereum Network"
- },
- "menu": {
- "message": "Opsyon"
- },
- "message": {
- "message": "Mesaje"
- },
- "metamaskDescription": {
- "message": "MetaMask sekirize idantite pou Ethereum."
- },
- "metamaskSeedWords": {
- "message": "MetaMask Seed Mo"
- },
- "min": {
- "message": "Minimòm"
- },
- "myAccounts": {
- "message": "Kont mwen"
- },
- "mustSelectOne": {
- "message": "Ou dwe chwazi omwen 1 token."
- },
- "needEtherInWallet": {
- "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou."
- },
- "needImportFile": {
- "message": "Ou dwe chwazi yon dosye pou enpòte.",
- "description": "User is important an account and needs to add a file to continue"
- },
- "needImportPassword": {
- "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.",
- "description": "Password and file needed to import an account"
- },
- "negativeETH": {
- "message": "Pa ka voye kantite lajan negatif ETH."
- },
- "networks": {
- "message": "Rezo"
- },
- "nevermind": {
- "message": "Pa pwoblèm"
- },
- "newAccount": {
- "message": "Nouvo Kont"
- },
- "newAccountNumberName": {
- "message": "Kont $1",
- "description": "Default name of next account to be created on create account screen"
- },
- "newContract": {
- "message": "Nouvo Kontra"
- },
- "newPassword": {
- "message": "Nouvo modpas (minit 8)"
- },
- "newRecipient": {
- "message": "Nouvo Benefisyè"
- },
- "newRPC": {
- "message": "Nouvo RPC URL"
- },
- "next": {
- "message": "Aprè sa"
- },
- "noAddressForName": {
- "message": "Pa gen adrès ki etabli pou non sa a."
- },
- "noDeposits": {
- "message": "Pa gen depo ou te resevwa"
- },
- "noConversionRateAvailable": {
- "message": "Pa gen okenn Konvèsyon Disponib"
- },
- "noTransactionHistory": {
- "message": "Pa gen istwa tranzaksyon."
- },
- "noTransactions": {
- "message": "Pa gen tranzaksyon"
- },
- "notFound": {
- "message": "Pa jwenn"
- },
- "notStarted": {
- "message": "Pa kòmanse"
- },
- "noWebcamFoundTitle": {
- "message": "Pa jwenn webcam"
- },
- "noWebcamFound": {
- "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò."
- },
- "oldUI": {
- "message": "Ansyen Itilizatè kouòdone"
- },
- "oldUIMessage": {
- "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la."
- },
- "openInTab": {
- "message": "Louvri nan etikèt"
- },
- "or": {
- "message": "oubyen",
- "description": "choice between creating or importing a new account"
- },
- "origin": {
- "message": "Orijin"
- },
- "password": {
- "message": "Modpas"
- },
- "passwordCorrect": {
- "message": "Tanpri asire ke modpas ou kòrèk."
- },
- "passwordMismatch": {
- "message": "modpas sa pa menm",
- "description": "in password creation process, the two new password fields did not match"
- },
- "passwordShort": {
- "message": "modpas pa sifi",
- "description": "in password creation process, the password is not long enough to be secure"
- },
- "pastePrivateKey": {
- "message": "Kole fraz prive ou a la:",
- "description": "For importing an account from a private key"
- },
- "pasteSeed": {
- "message": "Kole seed fraz ou a la!"
- },
- "pending": {
- "message": "l ap mache"
- },
- "personalAddressDetected": {
- "message": "Adrès pèsonèl detekte. Antre adrès kontra token la."
- },
- "pleaseReviewTransaction": {
- "message": "Tanpri revize tranzaksyon ou."
- },
- "popularTokens": {
- "message": "Popilè Tokens"
- },
- "prev": {
- "message": "Avan"
- },
- "privacyMsg": {
- "message": "Règleman sou enfòmasyon prive"
- },
- "privateKey": {
- "message": "Prive kle",
- "description": "select this type of file to use to import an account"
- },
- "privateKeyWarning": {
- "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a."
- },
- "privateNetwork": {
- "message": "Rezo Prive"
- },
- "qrCode": {
- "message": "Montre QR Kòd"
- },
- "queue": {
- "message": "Queue"
- },
- "readdToken": {
- "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an."
- },
- "readMore": {
- "message": "Li plis isit la."
- },
- "readMore2": {
- "message": "Li plis isit la."
- },
- "receive": {
- "message": "Resevwa"
- },
- "recipientAddress": {
- "message": "Adrès pou resevwa"
- },
- "refundAddress": {
- "message": "Adrès pou resevwa"
- },
- "rejected": {
- "message": "Rejte"
- },
- "reset": {
- "message": "Repwograme"
- },
- "resetAccount": {
- "message": "Repwograme Kont"
- },
- "resetAccountDescription": {
- "message": "Repwograme kont a netwaye tranzaksyon ou yo."
- },
- "restoreFromSeed": {
- "message": "Restore kont?"
- },
- "restoreVault": {
- "message": "Retabli kazye"
- },
- "restoreAccountWithSeed": {
- "message": "Retabli kont ou avèk yo Seed Fraz"
- },
- "required": {
- "message": "Egzije"
- },
- "retryWithMoreGas": {
- "message": "Reseye ak yon pri gaz pi wo isit la"
- },
- "walletSeed": {
- "message": "Wallet Seed"
- },
- "restore": {
- "message": "Retabli"
- },
- "revealSeedWords": {
- "message": "Revele Seed Mo Yo"
- },
- "revealSeedWordsTitle": {
- "message": "Seed Fraz"
- },
- "revealSeedWordsDescription": {
- "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè."
- },
- "revealSeedWordsWarningTitle": {
- "message": "PA pataje fraz sa a avèk nenpòt moun!"
- },
- "revealSeedWordsWarning": {
- "message": "Yo ka itilize mo sa pou vòlè kont ou."
- },
- "revert": {
- "message": "Retounen"
- },
- "remove": {
- "message": "retire"
- },
- "removeAccount": {
- "message": "Retire kont"
- },
- "removeAccountDescription": {
- "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an."
- },
- "readyToConnect": {
- "message": "Pare pou konekte?"
- },
- "rinkeby": {
- "message": "Rinkeby Tès Rezo"
- },
- "ropsten": {
- "message": "Ropsten Tès Rezo"
- },
- "rpc": {
- "message": "Koutim RPC"
- },
- "currentRpc": {
- "message": "Kounya RPC"
- },
- "connectingToMainnet": {
- "message": "Konekte ak Main (Prensipal) Ethereum Rezo a"
- },
- "connectingToRopsten": {
- "message": "Konekte ak Ropsten Tès Rezo a"
- },
- "connectingToKovan": {
- "message": "Konekte nan Kovan Tès Rezo a"
- },
- "connectingToRinkeby": {
- "message": "Konekte nan Rinkeby Tès Rezo a"
- },
- "connectingToUnknown": {
- "message": "Konekte nan rezo enkoni"
- },
- "sampleAccountName": {
- "message": "Pa egzanp, Nouvo kont mwen an",
- "description": "Help user understand concept of adding a human-readable name to their account"
- },
- "save": {
- "message": "Sove"
- },
- "speedUp": {
- "message": "pi vit"
- },
- "speedUpTitle": {
- "message": "Monte vitès tranzaksyon"
- },
- "speedUpSubtitle": {
- "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit"
- },
- "saveAsCsvFile": {
- "message": "Sove kòm dosye CSV"
- },
- "saveAsFile": {
- "message": "Sove kòm dosye",
- "description": "Account export process"
- },
- "saveSeedAsFile": {
- "message": "Sove pawòl seed kòm dosye"
- },
- "search": {
- "message": "Rechèch"
- },
- "searchResults": {
- "message": "Rezilta rechèch"
- },
- "secretPhrase": {
- "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a."
- },
- "showHexData": {
- "message": "Montre Hex Data"
- },
- "showHexDataDescription": {
- "message": "Pran sa pouw ka montre chan entèfas hex data a"
- },
- "newPassword8Chars": {
- "message": "Nouvo modpas (pou pi pit 8)"
- },
- "seedPhraseReq": {
- "message": "Seed fraz yo se 12 long mo"
- },
- "select": {
- "message": "Chwazi"
- },
- "selectCurrency": {
- "message": "Chwazi Lajan"
- },
- "selectService": {
- "message": "Chwazi Sèvis"
- },
- "selectType": {
- "message": "Chwazi Kalite"
- },
- "send": {
- "message": "Voye"
- },
- "sendETH": {
- "message": "Voye ETH"
- },
- "sendTokens": {
- "message": "Voye Tokens"
- },
- "sentEther": {
- "message": "Voye ether"
- },
- "sentTokens": {
- "message": "tokens deja voye"
- },
- "separateEachWord": {
- "message": "Separe chak mo ak yon sèl espas"
- },
- "onlySendToEtherAddress": {
- "message": "Sèlman voye ETH nan yon adrès Ethereum."
- },
- "onlySendTokensToAccountAddress": {
- "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.",
- "description": "displays token symbol"
- },
- "orderOneHere": {
- "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt."
- },
- "outgoing": {
- "message": "Ap kite"
- },
- "searchTokens": {
- "message": "Rechèch Tokens"
- },
- "selectAnAddress": {
- "message": "Chwazi yon adrès"
- },
- "selectAnAccount": {
- "message": "Chwazi yon kont"
- },
- "selectAnAccountHelp": {
- "message": "Chwazi kont pou wè nan MetaMask"
- },
- "selectHdPath": {
- "message": "Chwazi chemen HD"
- },
- "selectPathHelp": {
- "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\""
- },
- "sendTokensAnywhere": {
- "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum"
- },
- "settings": {
- "message": "Paramèt"
- },
- "step1HardwareWallet": {
- "message": "1. Konekte Materyèl bous"
- },
- "step1HardwareWalletMsg": {
- "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou."
- },
- "step2HardwareWallet": {
- "message": "2. Chwazi yon kont"
- },
- "step2HardwareWalletMsg": {
- "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman."
- },
- "step3HardwareWallet": {
- "message": "3. Kòmanse itilize dApps ak plis ankò!"
- },
- "step3HardwareWalletMsg": {
- "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties."
- },
- "info": {
- "message": "Enfòmasyon"
- },
- "scanInstructions": {
- "message": "Mete kòd QR la devan kamera ou"
- },
- "scanQrCode": {
- "message": "Enspeksyon QR Kòd"
- },
- "shapeshiftBuy": {
- "message": "Achte avèk Shapeshift"
- },
- "showPrivateKeys": {
- "message": "Montre Kle Prive"
- },
- "showQRCode": {
- "message": "Montre Kòd QR"
- },
- "sign": {
- "message": "Siyen"
- },
- "signatureRequest": {
- "message": "Siyati Mande"
- },
- "signed": {
- "message": "Te Siyen"
- },
- "signMessage": {
- "message": "Siyen mesaj"
- },
- "signNotice": {
- "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. "
- },
- "sigRequest": {
- "message": "Demann Siyati"
- },
- "sigRequested": {
- "message": "Demann Siyati"
- },
- "spaceBetween": {
- "message": "ka gen sèlman yon espas ant mo yo"
- },
- "status": {
- "message": "Kondisyon"
- },
- "stateLogs": {
- "message": "State Logs"
- },
- "stateLogsDescription": {
- "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo."
- },
- "stateLogError": {
- "message": "Erè nan retwouve State Logs yo."
- },
- "submit": {
- "message": "Soumèt"
- },
- "submitted": {
- "message": "Te Soumèt"
- },
- "supportCenter": {
- "message": "Vizite Sant Sipò Nou"
- },
- "symbolBetweenZeroTen": {
- "message": "Senbòl yo dwe ant 0 ak 10 karaktè."
- },
- "takesTooLong": {
- "message": "Pran twò lontan?"
- },
- "terms": {
- "message": "Tèm pou itilize"
- },
- "testFaucet": {
- "message": "Tès Tiyo"
- },
- "to": {
- "message": "Pou"
- },
- "toETHviaShapeShift": {
- "message": "$1 pou ETH pa ShapeShift",
- "description": "system will fill in deposit type in start of message"
- },
- "token": {
- "message": "Token"
- },
- "tokenAddress": {
- "message": "Adrès Token"
- },
- "tokenAlreadyAdded": {
- "message": "Ou te deja ajoute token."
- },
- "tokenBalance": {
- "message": "Balans Token ou se:"
- },
- "tokenSelection": {
- "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an."
- },
- "tokenSymbol": {
- "message": "Token Senbòl"
- },
- "tokenWarning1": {
- "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la."
- },
- "total": {
- "message": "Total"
- },
- "transactions": {
- "message": "tranzaksyon yo"
- },
- "transactionConfirmed": {
- "message": "Tranzaksyon ou te konfime pou $2."
- },
- "transactionCreated": {
- "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2."
- },
- "transactionDropped": {
- "message": "Tranzaksyon ou te tonbe a $2."
- },
- "transactionSubmitted": {
- "message": "Tranzaksyon ou te soumèt a $2."
- },
- "transactionUpdated": {
- "message": "Tranzaksyon ou te aktyalize a $2."
- },
- "transactionUpdatedGas": {
- "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2."
- },
- "transactionError": {
- "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra."
- },
- "transactionMemo": {
- "message": "Memo tranzaksyon (opsyonèl)"
- },
- "transactionNumber": {
- "message": "Nimewo Tranzaksyon"
- },
- "transfer": {
- "message": "Transfè"
- },
- "transfers": {
- "message": "Transfè yo"
- },
- "trezorHardwareWallet": {
- "message": "TREZOR Materyèl Bous"
- },
- "troubleTokenBalances": {
- "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ",
- "description": "Followed by a link (here) to view token balances"
- },
- "tryAgain": {
- "message": "Eseye anko"
- },
- "twelveWords": {
- "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè."
- },
- "typePassword": {
- "message": "Tape modpas ou"
- },
- "uiWelcome": {
- "message": "Byenveni nan New itilizatè koòdone (Beta)"
- },
- "uiWelcomeMessage": {
- "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a."
- },
- "unapproved": {
- "message": "Pa apwouve"
- },
- "unavailable": {
- "message": "Pa disponib"
- },
- "units": {
- "message": "inite yo"
- },
- "unknown": {
- "message": "Enkoni"
- },
- "unknownFunction": {
- "message": "Fonksyon enkoni"
- },
- "unknownNetwork": {
- "message": "Rezo Prive Enkoni"
- },
- "unknownNetworkId": {
- "message": "Rezo ID Enkoni"
- },
- "unknownQrCode": {
- "message": "Erè: Nou pa t kapab idantifye QR kòd sa"
- },
- "unknownCameraErrorTitle": {
- "message": "Ooops! Yon bagay te ale mal...."
- },
- "unknownCameraError": {
- "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..."
- },
- "unlock": {
- "message": "Debloke"
- },
- "unlockMessage": {
- "message": "Entènèt desantralize a ap tann"
- },
- "uriErrorMsg": {
- "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a."
- },
- "usaOnly": {
- "message": "USA sèlman",
- "description": "Using this exchange is limited to people inside the USA"
- },
- "usedByClients": {
- "message": "Itilize pa yon varyete de kliyan diferan"
- },
- "useOldUI": {
- "message": "Itilizasyon ansyen UI (itilizatè koòdone)"
- },
- "validFileImport": {
- "message": "Ou dwe chwazi yon dosye ki valab pou enpòte."
- },
- "vaultCreated": {
- "message": "Kòf Kreye"
- },
- "viewAccount": {
- "message": "Wè Kont"
- },
- "viewOnEtherscan": {
- "message": "Wè sou Etherscan"
- },
- "visitWebSite": {
- "message": "Vizite sit entènèt nou an"
- },
- "warning": {
- "message": "Avètisman"
- },
- "welcomeBack": {
- "message": "Bon retou!"
- },
- "welcomeBeta": {
- "message": "Byenveni nan MetaMask Beta"
- },
- "whatsThis": {
- "message": "Kisa sa ye?"
- },
- "youNeedToAllowCameraAccess": {
- "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa."
- },
- "yourSigRequested": {
- "message": "Yo mande siyati ou"
- },
- "youSign": {
- "message": "Ou ap siyen kounya"
- },
- "yourPrivateSeedPhrase": {
- "message": "Seed fraz prive ou a"
- }
+ "accept": {
+ "message": "Aksepte"
+ },
+ "accessingYourCamera": {
+ "message": "Aksè a Kamera"
+ },
+ "account": {
+ "message": "Kont"
+ },
+ "accountDetails": {
+ "message": "Detay Kont"
+ },
+ "accountName": {
+ "message": "Non Kont"
+ },
+ "accountOptions": {
+ "message": "Opsyon kont"
+ },
+ "accountSelectionRequired": {
+ "message": "Ou bezwen chwazi yon kont!"
+ },
+ "activityLog": {
+ "message": "aktivite ki fèt"
+ },
+ "address": {
+ "message": "Adrès"
+ },
+ "addCustomToken": {
+ "message": "Ajoute token"
+ },
+ "addToken": {
+ "message": "Ajoute Token"
+ },
+ "addTokens": {
+ "message": "Ajoute Token"
+ },
+ "addSuggestedTokens": {
+ "message": "Ajoute Token Yo Sikjere W"
+ },
+ "addAcquiredTokens": {
+ "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask"
+ },
+ "amount": {
+ "message": "Kantite lajan"
+ },
+ "amountPlusGas": {
+ "message": "Kantite lajan + Gaz"
+ },
+ "appDescription": {
+ "message": "Ekstansyon Navigatè Ethereum",
+ "description": "The description of the application"
+ },
+ "appName": {
+ "message": "MetaMask",
+ "description": "The name of the application"
+ },
+ "approve": {
+ "message": "Apwouve"
+ },
+ "approved": {
+ "message": "Apwouve"
+ },
+ "attemptingConnect": {
+ "message": "Eseye konekte nan blockchain."
+ },
+ "attemptToCancel": {
+ "message": "Eseye anile?"
+ },
+ "attemptToCancelDescription": {
+ "message": "Soumèt tantativ sa a pa garanti ke yo pral anile tranzaksyon ou anile. Si tantativ anile an gen siksè, ou pral chaje frè yo tranzaksyon pi wo a."
+ },
+ "attributions": {
+ "message": "Atribisyon"
+ },
+ "available": {
+ "message": "Disponib"
+ },
+ "back": {
+ "message": "Retounen"
+ },
+ "balance": {
+ "message": "Balans"
+ },
+ "balances": {
+ "message": "Balans Token"
+ },
+ "balanceIsInsufficientGas": {
+ "message": "Ensifizan balans pou total gaz aktyèl la"
+ },
+ "beta": {
+ "message": "BETA"
+ },
+ "betweenMinAndMax": {
+ "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.",
+ "description": "helper for inputting hex as decimal input"
+ },
+ "blockiesIdenticon": {
+ "message": "Itilize Blockies Identicon"
+ },
+ "borrowDharma": {
+ "message": "Prete Avèk Dharma (Beta)"
+ },
+ "browserNotSupported": {
+ "message": "Navigatè ou a pa sipòte..."
+ },
+ "builtInCalifornia": {
+ "message": "MetaMask fèt e bati nan California."
+ },
+ "buy": {
+ "message": "Achte"
+ },
+ "buyCoinbase": {
+ "message": "Achte sou Coinbase"
+ },
+ "buyCoinbaseExplainer": {
+ "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin."
+ },
+ "bytes": {
+ "message": "Bytes"
+ },
+ "ok": {
+ "message": "Oke"
+ },
+ "cancel": {
+ "message": "Anile"
+ },
+ "cancelAttempt": {
+ "message": "Teste Anile"
+ },
+ "cancellationGasFee": {
+ "message": "Anilasyon Gaz Chaj"
+ },
+ "cancelN": {
+ "message": "Anile tout $ 1 tranzaksyon"
+ },
+ "classicInterface": {
+ "message": "Sèvi ak fas klasik la"
+ },
+ "clickCopy": {
+ "message": "Klike sou kopi"
+ },
+ "clickToAdd": {
+ "message": "Klike sou $ 1 pou ajoute yo nan kont ou"
+ },
+ "close": {
+ "message": "Fèmen"
+ },
+ "chromeRequiredForHardwareWallets": {
+ "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet."
+ },
+ "confirm": {
+ "message": "Konfime"
+ },
+ "confirmed": {
+ "message": "Konfime"
+ },
+ "confirmContract": {
+ "message": "Konfime Kontra"
+ },
+ "confirmPassword": {
+ "message": "Konfime Modpas"
+ },
+ "confirmTransaction": {
+ "message": "Konfime Tranzaksyon"
+ },
+ "connectHardwareWallet": {
+ "message": "Konekte Materyèl Wallet"
+ },
+ "connect": {
+ "message": "Konekte"
+ },
+ "connecting": {
+ "message": "Koneksyon..."
+ },
+ "connectingToKovan": {
+ "message": "Konekte nan Kovan Tès Rezo a"
+ },
+ "connectingToMainnet": {
+ "message": "Konekte ak Prensipal Ethereum Rezo a"
+ },
+ "connectingToRopsten": {
+ "message": "Konekte ak Ropsten Tès Rezo a"
+ },
+ "connectingToRinkeby": {
+ "message": "Konekte nan Rinkeby Tès Rezo a"
+ },
+ "connectingToUnknown": {
+ "message": "Konekte nan rezo enkoni"
+ },
+ "connectToLedger": {
+ "message": "Konekte ak Ledger"
+ },
+ "connectToTrezor": {
+ "message": "Konekte ak Trezor"
+ },
+ "continue": {
+ "message": "Kontinye"
+ },
+ "continueToCoinbase": {
+ "message": "Kontinye Coinbase"
+ },
+ "contractDeployment": {
+ "message": "Kontra Deplwaman"
+ },
+ "conversionProgress": {
+ "message": "Konvèsyon nan Pwogrè"
+ },
+ "copiedButton": {
+ "message": "Kopye"
+ },
+ "copiedClipboard": {
+ "message": "Kopi nan Clipboard"
+ },
+ "copiedExclamation": {
+ "message": "Kopye!"
+ },
+ "copiedSafe": {
+ "message": "Mwen te kopye li yon kote ki san danje"
+ },
+ "copy": {
+ "message": "Kopye"
+ },
+ "copyAddress": {
+ "message": "Kopi adrès clipboard"
+ },
+ "copyToClipboard": {
+ "message": "Kopi clipboard"
+ },
+ "copyButton": {
+ "message": " Kopi "
+ },
+ "copyPrivateKey": {
+ "message": "Sa a se kle prive ou (klike pou ou kopye)"
+ },
+ "create": {
+ "message": "Kreye"
+ },
+ "createAccount": {
+ "message": "Kreye Kont"
+ },
+ "createDen": {
+ "message": "Kreye"
+ },
+ "crypto": {
+ "message": "Crypto",
+ "description": "Exchange type (cryptocurrencies)"
+ },
+ "currentConversion": {
+ "message": "Konvèsyon aktyèl"
+ },
+ "currentLanguage": {
+ "message": "Lang Aktyèl"
+ },
+ "currentNetwork": {
+ "message": "Rezo aktyèl"
+ },
+ "currentRpc": {
+ "message": "Aktyèl RPC"
+ },
+ "customGas": {
+ "message": "Koutim Gaz"
+ },
+ "customToken": {
+ "message": "Koutim Token"
+ },
+ "customize": {
+ "message": "Koutim"
+ },
+ "customRPC": {
+ "message": "Koutim RPC"
+ },
+ "decimalsMustZerotoTen": {
+ "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36."
+ },
+ "decimal": {
+ "message": "Presizyon desimal la"
+ },
+ "defaultNetwork": {
+ "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet."
+ },
+ "denExplainer": {
+ "message": "DEN ou se depo modpas avèk chif ou nan MetaMask."
+ },
+ "deposit": {
+ "message": "Depo"
+ },
+ "depositBTC": {
+ "message": "Depoze BTC ou nan adrès ki anba a:"
+ },
+ "depositCoin": {
+ "message": "Depoze $1 ou nan adrès ki anba a",
+ "description": "Tells the user what coin they have selected to deposit with shapeshift"
+ },
+ "depositEth": {
+ "message": "Depo Eth"
+ },
+ "depositEther": {
+ "message": "Depo Ether"
+ },
+ "depositFiat": {
+ "message": "Depo ak Fiat"
+ },
+ "depositFromAccount": {
+ "message": "Depo nan yon lòt kont"
+ },
+ "depositShapeShift": {
+ "message": "Depo avèk ShapeShift"
+ },
+ "depositShapeShiftExplainer": {
+ "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè."
+ },
+ "details": {
+ "message": "Detay yo"
+ },
+ "directDeposit": {
+ "message": "Depo Dirèk"
+ },
+ "directDepositEther": {
+ "message": "Dirèkteman Depo Ether"
+ },
+ "directDepositEtherExplainer": {
+ "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk."
+ },
+ "done": {
+ "message": "Fini"
+ },
+ "downloadGoogleChrome": {
+ "message": "Telechaje Google Chrome"
+ },
+ "downloadStateLogs": {
+ "message": "Telechaje State Logs"
+ },
+ "dontHaveAHardwareWallet": {
+ "message": "Pa gen yon materyèl bous?"
+ },
+ "dropped": {
+ "message": "Tonbe"
+ },
+ "edit": {
+ "message": "Korije"
+ },
+ "editAccountName": {
+ "message": "Korije Non Kont"
+ },
+ "editingTransaction": {
+ "message": "Fè chanjman nan tranzaksyon ou"
+ },
+ "emailUs": {
+ "message": "Imèl nou!"
+ },
+ "encryptNewDen": {
+ "message": "Ankripte nouvo DEN ou"
+ },
+ "ensNameNotFound": {
+ "message": "Nou pa jwenn non ENS ou a"
+ },
+ "enterPassword": {
+ "message": "Mete modpas"
+ },
+ "enterPasswordConfirm": {
+ "message": "Antre nan modpas ou a konfime"
+ },
+ "enterPasswordContinue": {
+ "message": "Mete modpas pou kontinye"
+ },
+ "eth": {
+ "message": "ETH"
+ },
+ "etherscanView": {
+ "message": "Gade kont sou Etherscan"
+ },
+ "exchangeRate": {
+ "message": "Chanje to"
+ },
+ "expandView": {
+ "message": "Elaji Wè"
+ },
+ "exportPrivateKey": {
+ "message": "Voye Kòd Prive"
+ },
+ "exportPrivateKeyWarning": {
+ "message": "Voye kle prive ak pwòp risk ou."
+ },
+ "failed": {
+ "message": "Tonbe"
+ },
+ "fiat": {
+ "message": "FIAT",
+ "description": "Exchange type"
+ },
+ "fileImportFail": {
+ "message": "Enpòte dosye ki pa travay? Klike la a!",
+ "description": "Helps user import their account from a JSON file"
+ },
+ "followTwitter": {
+ "message": "Swiv nou sou Twitter"
+ },
+ "forgetDevice": {
+ "message": "Bliye aparèy sa a"
+ },
+ "from": {
+ "message": "Soti nan"
+ },
+ "fromToSame": {
+ "message": "Adrès orijinal le ak sa ou resevwa pake menm"
+ },
+ "fromShapeShift": {
+ "message": "Soti nan ShapeShift"
+ },
+ "functionType": {
+ "message": "Kalite Fonksyon"
+ },
+ "gas": {
+ "message": "Gaz",
+ "description": "Short indication of gas cost"
+ },
+ "gasFee": {
+ "message": "Frè gaz"
+ },
+ "gasLimit": {
+ "message": "Limit gaz"
+ },
+ "gasLimitCalculation": {
+ "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a."
+ },
+ "gasLimitRequired": {
+ "message": "Limit gaz nesesè"
+ },
+ "gasLimitTooLow": {
+ "message": "Limit gaz dwe omwen 21000"
+ },
+ "gasUsed": {
+ "message": "Gaz yo Itilize"
+ },
+ "generatingSeed": {
+ "message": "Grenn jenerasyon..."
+ },
+ "gasPrice": {
+ "message": "Pri gaz (GWEI)"
+ },
+ "gasPriceCalculation": {
+ "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo."
+ },
+ "gasPriceRequired": {
+ "message": "Pri Gaz la Egzije"
+ },
+ "generatingTransaction": {
+ "message": "Tranzaksyon kap fè"
+ },
+ "getEther": {
+ "message": "Jwenn Ether"
+ },
+ "getEtherFromFaucet": {
+ "message": "Jwenn Ether nan yon tiyo pou $1 la",
+ "description": "Displays network name for Ether faucet"
+ },
+ "getHelp": {
+ "message": "Jwenn èd."
+ },
+ "greaterThanMin": {
+ "message": "dwe pi gran pase oswa egal a $ 1.",
+ "description": "helper for inputting hex as decimal input"
+ },
+ "hardware": {
+ "message": "materyèl"
+ },
+ "hardwareWalletConnected": {
+ "message": "Materyèl Wallet konekte"
+ },
+ "hardwareWallets": {
+ "message": "Materyèl Wallet konekte"
+ },
+ "hardwareWalletsMsg": {
+ "message": "Chwazi yon Materyèl Wallet ou ta renmen itilize ak MetaMask"
+ },
+ "havingTroubleConnecting": {
+ "message": "Èske w gen pwoblèm pou konekte?"
+ },
+ "here": {
+ "message": "isit la",
+ "description": "as in -click here- for more information (goes with troubleTokenBalances)"
+ },
+ "hereList": {
+ "message": "Isit la nan yon lis !!!!"
+ },
+ "hexData": {
+ "message": "Hex Data"
+ },
+ "hide": {
+ "message": "Kache"
+ },
+ "hideToken": {
+ "message": "Kache Token"
+ },
+ "hideTokenPrompt": {
+ "message": "Kache Token?"
+ },
+ "history": {
+ "message": "Istwa"
+ },
+ "howToDeposit": {
+ "message": "Ki jan ou ta renmen depo Ether?"
+ },
+ "holdEther": {
+ "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon."
+ },
+ "import": {
+ "message": "Pòte",
+ "description": "Button to import an account from a selected file"
+ },
+ "importAccount": {
+ "message": "Pòte Kont"
+ },
+ "importAccountMsg": {
+ "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte "
+ },
+ "importAnAccount": {
+ "message": "Pòte yon kont"
+ },
+ "importDen": {
+ "message": "Pòte ki deja egziste DEN"
+ },
+ "imported": {
+ "message": "Pòte",
+ "description": "status showing that an account has been fully loaded into the keyring"
+ },
+ "importUsingSeed": {
+ "message": "Pòte lè sèvi avèk seed fraz"
+ },
+ "info": {
+ "message": "Enfo"
+ },
+ "infoHelp": {
+ "message": "Enfo & Èd"
+ },
+ "initialTransactionConfirmed": {
+ "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen."
+ },
+ "insufficientFunds": {
+ "message": "Lajan ensifizan."
+ },
+ "insufficientTokens": {
+ "message": "Tokens pa valab."
+ },
+ "invalidAddress": {
+ "message": "Adrès pa valab"
+ },
+ "invalidAddressRecipient": {
+ "message": "Moun ki resevwa adrès la pa valab"
+ },
+ "invalidGasParams": {
+ "message": "Gaz Paramèt la pa valab"
+ },
+ "invalidInput": {
+ "message": "Sa ou rantre a pa valab"
+ },
+ "invalidRequest": {
+ "message": "Demann pa valab"
+ },
+ "invalidRPC": {
+ "message": "RPC URI pa valab"
+ },
+ "invalidSeedPhrase": {
+ "message": "Seed fraz pa valab"
+ },
+ "jsonFail": {
+ "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate."
+ },
+ "jsonFile": {
+ "message": "JSON Dosye",
+ "description": "format for importing an account"
+ },
+ "keepTrackTokens": {
+ "message": "Gade tokens yo ou te achte ak kont MetaMask ou."
+ },
+ "kovan": {
+ "message": "Kovan Tès Rezo"
+ },
+ "knowledgeDataBase": {
+ "message": "Vizite baz nou an"
+ },
+ "max": {
+ "message": "Maksimòm"
+ },
+ "learnMore": {
+ "message": "Aprann plis"
+ },
+ "ledgerAccountRestriction": {
+ "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo."
+ },
+ "lessThanMax": {
+ "message": "dwe mwens pase oswa egal a $ 1.",
+ "description": "helper for inputting hex as decimal input"
+ },
+ "likeToAddTokens": {
+ "message": "Èske ou ta renmen ajoute sa nan tokens?"
+ },
+ "links": {
+ "message": "Lyen"
+ },
+ "limit": {
+ "message": "Limitasyon"
+ },
+ "loading": {
+ "message": "Telechaje..."
+ },
+ "loadingTokens": {
+ "message": "Telechaje Tokens..."
+ },
+ "localhost": {
+ "message": "Localhost 8545"
+ },
+ "login": {
+ "message": "Ouvri"
+ },
+ "logout": {
+ "message": "Dekonekte"
+ },
+ "loose": {
+ "message": "Pèdi"
+ },
+ "loweCaseWords": {
+ "message": "seed mo sèlman gen karaktè miniskil"
+ },
+ "mainnet": {
+ "message": "Prensipal Ethereum Rezo a"
+ },
+ "menu": {
+ "message": "Opsyon"
+ },
+ "message": {
+ "message": "Mesaje"
+ },
+ "metamaskDescription": {
+ "message": "MetaMask sekirize idantite pou Ethereum."
+ },
+ "metamaskSeedWords": {
+ "message": "MetaMask Seed Mo"
+ },
+ "metamaskVersion": {
+ "message": "MetaMask Vèsyon"
+ },
+ "min": {
+ "message": "Minimòm"
+ },
+ "missingYourTokens": {
+ "message": "Ou pa wè token ou a?"
+ },
+ "myAccounts": {
+ "message": "Kont mwen"
+ },
+ "mustSelectOne": {
+ "message": "Ou dwe chwazi omwen 1 token."
+ },
+ "needEtherInWallet": {
+ "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou."
+ },
+ "needImportFile": {
+ "message": "Ou dwe chwazi yon dosye pou enpòte.",
+ "description": "User is important an account and needs to add a file to continue"
+ },
+ "needImportPassword": {
+ "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.",
+ "description": "Password and file needed to import an account"
+ },
+ "negativeETH": {
+ "message": "Pa ka voye kantite lajan negatif ETH."
+ },
+ "networks": {
+ "message": "Rezo"
+ },
+ "nevermind": {
+ "message": "Pa pwoblèm"
+ },
+ "newAccount": {
+ "message": "Nouvo Kont"
+ },
+ "newAccountNumberName": {
+ "message": "Kont $1",
+ "description": "Default name of next account to be created on create account screen"
+ },
+ "newContract": {
+ "message": "Nouvo Kontra"
+ },
+ "newPassword": {
+ "message": "Nouvo modpas (minit 8)"
+ },
+ "newPassword8Chars": {
+ "message": "Nouvo modpas (minit 8)"
+ },
+ "newRecipient": {
+ "message": "Nouvo Benefisyè"
+ },
+ "newRPC": {
+ "message": "Nouvo RPC URL"
+ },
+ "next": {
+ "message": "Aprè sa"
+ },
+ "noAddressForName": {
+ "message": "Pa gen adrès ki etabli pou non sa a."
+ },
+ "noDeposits": {
+ "message": "Pa gen depo ou te resevwa"
+ },
+ "noConversionRateAvailable": {
+ "message": "Pa gen okenn Konvèsyon Disponib"
+ },
+ "noTransactionHistory": {
+ "message": "Pa gen istwa tranzaksyon."
+ },
+ "noTransactions": {
+ "message": "Pa gen tranzaksyon"
+ },
+ "notFound": {
+ "message": "Pa jwenn"
+ },
+ "notStarted": {
+ "message": "Pa kòmanse"
+ },
+ "noWebcamFoundTitle": {
+ "message": "Pa jwenn webcam"
+ },
+ "noWebcamFound": {
+ "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò."
+ },
+ "oldUI": {
+ "message": "Ansyen Itilizatè kouòdone"
+ },
+ "oldUIMessage": {
+ "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la."
+ },
+ "onlySendToEtherAddress": {
+ "message": "Sèlman voye ETH nan yon adrès Ethereum."
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.",
+ "description": "displays token symbol"
+ },
+ "openInTab": {
+ "message": "Louvri nan etikèt"
+ },
+ "or": {
+ "message": "oubyen",
+ "description": "choice between creating or importing a new account"
+ },
+ "orderOneHere": {
+ "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt."
+ },
+ "origin": {
+ "message": "Orijin"
+ },
+ "outgoing": {
+ "message": "Ap kite"
+ },
+ "parameters": {
+ "message": "Paramèt"
+ },
+ "password": {
+ "message": "Modpas"
+ },
+ "passwordCorrect": {
+ "message": "Tanpri asire ke modpas ou kòrèk."
+ },
+ "passwordsDontMatch": {
+ "message": "Modpas pa matche"
+ },
+ "passwordMismatch": {
+ "message": "modpas sa pa menm",
+ "description": "in password creation process, the two new password fields did not match"
+ },
+ "passwordNotLongEnough": {
+ "message": "Modpas pa lontan ase"
+ },
+ "passwordShort": {
+ "message": "modpas pa sifi",
+ "description": "in password creation process, the password is not long enough to be secure"
+ },
+ "pastePrivateKey": {
+ "message": "Kole fraz prive ou a la:",
+ "description": "For importing an account from a private key"
+ },
+ "pasteSeed": {
+ "message": "Kole seed fraz ou a la!"
+ },
+ "pending": {
+ "message": "l ap mache"
+ },
+ "personalAddressDetected": {
+ "message": "Adrès pèsonèl detekte. Antre adrès kontra token la."
+ },
+ "pleaseReviewTransaction": {
+ "message": "Tanpri revize tranzaksyon ou."
+ },
+ "popularTokens": {
+ "message": "Popilè Tokens"
+ },
+ "prev": {
+ "message": "Avan"
+ },
+ "primaryCurrencySetting": {
+ "message": "Lajan ou itilize pi plis la"
+ },
+ "primaryCurrencySettingDescription": {
+ "message": "Chwazi ETH pou bay priyorite montre valè nan ETH. Chwazi Fiat priyorite montre valè nan lajan ou chwazi a."
+ },
+ "privacyMsg": {
+ "message": "Règleman sou enfòmasyon prive"
+ },
+ "privateKey": {
+ "message": "Prive kle",
+ "description": "select this type of file to use to import an account"
+ },
+ "privateKeyWarning": {
+ "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a."
+ },
+ "privateNetwork": {
+ "message": "Rezo Prive"
+ },
+ "qrCode": {
+ "message": "Montre QR Kòd"
+ },
+ "queue": {
+ "message": "Queue"
+ },
+ "readdToken": {
+ "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an."
+ },
+ "readMore": {
+ "message": "Li plis isit la."
+ },
+ "readMore2": {
+ "message": "Li plis isit la."
+ },
+ "receive": {
+ "message": "Resevwa"
+ },
+ "recipientAddress": {
+ "message": "Adrès pou resevwa"
+ },
+ "refundAddress": {
+ "message": "Adrès pou resevwa"
+ },
+ "reject": {
+ "message": "Rejte"
+ },
+ "rejectAll": {
+ "message": "Rejte Tout"
+ },
+ "rejectTxsN": {
+ "message": "Rejete $ 1 tranzaksyon"
+ },
+ "rejectTxsDescription": {
+ "message": "Ou se sou rejte $ 1 yon anpil nan tranzaksyon yo."
+ },
+ "rejected": {
+ "message": "Rejete"
+ },
+ "reset": {
+ "message": "Repwograme"
+ },
+ "resetAccount": {
+ "message": "Repwograme Kont"
+ },
+ "resetAccountDescription": {
+ "message": "Repwograme kont a netwaye tranzaksyon ou yo."
+ },
+ "restoreFromSeed": {
+ "message": "Restore kont?"
+ },
+ "restoreVault": {
+ "message": "Retabli kazye"
+ },
+ "restoreAccountWithSeed": {
+ "message": "Retabli kont ou avèk yo Seed Fraz"
+ },
+ "required": {
+ "message": "Egzije"
+ },
+ "retryWithMoreGas": {
+ "message": "Reseye ak yon pri gaz pi wo isit la"
+ },
+ "restore": {
+ "message": "Retabli"
+ },
+ "revealSeedWords": {
+ "message": "Revele Seed Mo Yo"
+ },
+ "revealSeedWordsTitle": {
+ "message": "Seed Fraz"
+ },
+ "revealSeedWordsDescription": {
+ "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè."
+ },
+ "revealSeedWordsWarningTitle": {
+ "message": "PA pataje fraz sa a avèk nenpòt moun!"
+ },
+ "revealSeedWordsWarning": {
+ "message": "Yo ka itilize mo sa pou vòlè kont ou."
+ },
+ "revert": {
+ "message": "Retounen"
+ },
+ "remove": {
+ "message": "retire"
+ },
+ "removeAccount": {
+ "message": "Retire kont"
+ },
+ "removeAccountDescription": {
+ "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an."
+ },
+ "readyToConnect": {
+ "message": "Pare pou konekte?"
+ },
+ "rinkeby": {
+ "message": "Rinkeby Tès Rezo"
+ },
+ "ropsten": {
+ "message": "Ropsten Tès Rezo"
+ },
+ "rpc": {
+ "message": "Koutim RPC"
+ },
+ "sampleAccountName": {
+ "message": "Pa egzanp, Nouvo kont mwen an",
+ "description": "Help user understand concept of adding a human-readable name to their account"
+ },
+ "save": {
+ "message": "Sove"
+ },
+ "saveAsCsvFile": {
+ "message": "Sove kòm dosye CSV"
+ },
+ "saveAsFile": {
+ "message": "Sove kòm dosye",
+ "description": "Account export process"
+ },
+ "saveSeedAsFile": {
+ "message": "Sove pawòl seed kòm dosye"
+ },
+ "scanInstructions": {
+ "message": "Mete kòd QR la devan kamera ou"
+ },
+ "scanQrCode": {
+ "message": "Enspeksyon QR Kòd"
+ },
+ "search": {
+ "message": "Rechèch"
+ },
+ "searchResults": {
+ "message": "Rezilta rechèch"
+ },
+ "secretPhrase": {
+ "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a."
+ },
+ "seedPhraseReq": {
+ "message": "Seed fraz yo se 12 long mo"
+ },
+ "select": {
+ "message": "Chwazi"
+ },
+ "selectCurrency": {
+ "message": "Chwazi Lajan"
+ },
+ "selectLocale": {
+ "message": "Chwazi Lokasyon"
+ },
+ "selectService": {
+ "message": "Chwazi Sèvis"
+ },
+ "selectType": {
+ "message": "Chwazi Kalite"
+ },
+ "send": {
+ "message": "Voye"
+ },
+ "sendETH": {
+ "message": "Voye ETH"
+ },
+ "sendTokens": {
+ "message": "Voye Tokens"
+ },
+ "sentEther": {
+ "message": "Voye ether"
+ },
+ "sentTokens": {
+ "message": "tokens deja voye"
+ },
+ "separateEachWord": {
+ "message": "Separe chak mo ak yon sèl espas"
+ },
+ "searchTokens": {
+ "message": "Rechèch Tokens"
+ },
+ "selectAnAddress": {
+ "message": "Chwazi yon adrès"
+ },
+ "selectAnAccount": {
+ "message": "Chwazi yon kont"
+ },
+ "selectAnAccountHelp": {
+ "message": "Chwazi kont pou wè nan MetaMask"
+ },
+ "selectHdPath": {
+ "message": "Chwazi chemen HD"
+ },
+ "selectPathHelp": {
+ "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\""
+ },
+ "sendTokensAnywhere": {
+ "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum"
+ },
+ "settings": {
+ "message": "Paramèt"
+ },
+ "shapeshiftBuy": {
+ "message": "Achte avèk Shapeshift"
+ },
+ "showPrivateKeys": {
+ "message": "Montre Kle Prive"
+ },
+ "showQRCode": {
+ "message": "Montre Kòd QR"
+ },
+ "showHexData": {
+ "message": "Montre Hex Data"
+ },
+ "showHexDataDescription": {
+ "message": "Pran sa pouw ka montre chan entèfas hex data a"
+ },
+ "sign": {
+ "message": "Siyen"
+ },
+ "signatureRequest": {
+ "message": "Siyati Mande"
+ },
+ "signed": {
+ "message": "Te Siyen"
+ },
+ "signMessage": {
+ "message": "Siyen mesaj"
+ },
+ "signNotice": {
+ "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. "
+ },
+ "sigRequest": {
+ "message": "Demann Siyati"
+ },
+ "sigRequested": {
+ "message": "Demann Siyati"
+ },
+ "spaceBetween": {
+ "message": "ka gen sèlman yon espas ant mo yo"
+ },
+ "speedUp": {
+ "message": "pi vit"
+ },
+ "speedUpTitle": {
+ "message": "Monte vitès tranzaksyon"
+ },
+ "speedUpSubtitle": {
+ "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit"
+ },
+ "status": {
+ "message": "Kondisyon"
+ },
+ "stateLogs": {
+ "message": "State Logs"
+ },
+ "stateLogsDescription": {
+ "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo."
+ },
+ "stateLogError": {
+ "message": "Erè nan retwouve State Logs yo."
+ },
+ "step1HardwareWallet": {
+ "message": "1. Konekte Materyèl bous"
+ },
+ "step1HardwareWalletMsg": {
+ "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou."
+ },
+ "step2HardwareWallet": {
+ "message": "2. Chwazi yon kont"
+ },
+ "step2HardwareWalletMsg": {
+ "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman."
+ },
+ "step3HardwareWallet": {
+ "message": "3. Kòmanse itilize dApps ak plis ankò!"
+ },
+ "step3HardwareWalletMsg": {
+ "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties."
+ },
+ "submit": {
+ "message": "Soumèt"
+ },
+ "submitted": {
+ "message": "Te Soumèt"
+ },
+ "supportCenter": {
+ "message": "Vizite Sant Sipò Nou"
+ },
+ "symbolBetweenZeroTen": {
+ "message": "Senbòl yo dwe ant 0 ak 10 karaktè."
+ },
+ "takesTooLong": {
+ "message": "Pran twò lontan?"
+ },
+ "terms": {
+ "message": "Tèm pou itilize"
+ },
+ "testFaucet": {
+ "message": "Tès Tiyo"
+ },
+ "to": {
+ "message": "Pou"
+ },
+ "toETHviaShapeShift": {
+ "message": "$1 pou ETH pa ShapeShift",
+ "description": "system will fill in deposit type in start of message"
+ },
+ "token": {
+ "message": "Token"
+ },
+ "tokenAddress": {
+ "message": "Adrès Token"
+ },
+ "tokenAlreadyAdded": {
+ "message": "Ou te deja ajoute token."
+ },
+ "tokenBalance": {
+ "message": "Balans Token ou se:"
+ },
+ "tokenSelection": {
+ "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an."
+ },
+ "tokenSymbol": {
+ "message": "Token Senbòl"
+ },
+ "tokenWarning1": {
+ "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la."
+ },
+ "total": {
+ "message": "Total"
+ },
+ "transaction": {
+ "message": "tranzaksyon yo"
+ },
+ "transactionConfirmed": {
+ "message": "Tranzaksyon ou te konfime pou $2."
+ },
+ "transactionCreated": {
+ "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2."
+ },
+ "transactionWithNonce": {
+ "message": "Tranzaksyon $1"
+ },
+ "transactionDropped": {
+ "message": "Tranzaksyon ou te tonbe a $2."
+ },
+ "transactionSubmitted": {
+ "message": "Tranzaksyon ou te soumèt a $2."
+ },
+ "transactionUpdated": {
+ "message": "Tranzaksyon ou te aktyalize a $2."
+ },
+ "transactionUpdatedGas": {
+ "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2."
+ },
+ "transactions": {
+ "message": "transactions"
+ },
+ "transactionError": {
+ "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra."
+ },
+ "transactionMemo": {
+ "message": "Memo tranzaksyon (opsyonèl)"
+ },
+ "transactionNumber": {
+ "message": "Nimewo Tranzaksyon"
+ },
+ "transfer": {
+ "message": "Transfè"
+ },
+ "transferFrom": {
+ "message": "Transfer From"
+ },
+ "transfers": {
+ "message": "Transfè yo"
+ },
+ "trezorHardwareWallet": {
+ "message": "TREZOR Materyèl Bous"
+ },
+ "troubleTokenBalances": {
+ "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ",
+ "description": "Followed by a link (here) to view token balances"
+ },
+ "tryAgain": {
+ "message": "Eseye anko"
+ },
+ "twelveWords": {
+ "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè."
+ },
+ "typePassword": {
+ "message": "Tape modpas ou"
+ },
+ "uiWelcome": {
+ "message": "Byenveni nan New itilizatè koòdone (Beta)"
+ },
+ "uiWelcomeMessage": {
+ "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a."
+ },
+ "unapproved": {
+ "message": "Pa apwouve"
+ },
+ "unavailable": {
+ "message": "Pa disponib"
+ },
+ "units": {
+ "message": "inite yo"
+ },
+ "unknown": {
+ "message": "Enkoni"
+ },
+ "unknownFunction": {
+ "message": "Fonksyon enkoni"
+ },
+ "unknownNetwork": {
+ "message": "Rezo Prive Enkoni"
+ },
+ "unknownNetworkId": {
+ "message": "Rezo ID Enkoni"
+ },
+ "unknownQrCode": {
+ "message": "Erè: Nou pa t kapab idantifye QR kòd sa"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "Ooops! Yon bagay te ale mal...."
+ },
+ "unknownCameraError": {
+ "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..."
+ },
+ "unlock": {
+ "message": "Debloke"
+ },
+ "unlockMessage": {
+ "message": "Entènèt desantralize a ap tann"
+ },
+ "updatedWithDate": {
+ "message": "Mete ajou $1"
+ },
+ "uriErrorMsg": {
+ "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a."
+ },
+ "usaOnly": {
+ "message": "USA sèlman",
+ "description": "Using this exchange is limited to people inside the USA"
+ },
+ "usedByClients": {
+ "message": "Itilize pa yon varyete de kliyan diferan"
+ },
+ "useOldUI": {
+ "message": "Itilizasyon ansyen UI (itilizatè koòdone)"
+ },
+ "validFileImport": {
+ "message": "Ou dwe chwazi yon dosye ki valab pou enpòte."
+ },
+ "vaultCreated": {
+ "message": "Kòf Kreye"
+ },
+ "viewAccount": {
+ "message": "Wè Kont"
+ },
+ "viewOnEtherscan": {
+ "message": "Wè sou Etherscan"
+ },
+ "visitWebSite": {
+ "message": "Vizite sit entènèt nou an"
+ },
+ "walletSeed": {
+ "message": "Bous Seed"
+ },
+ "warning": {
+ "message": "Avètisman"
+ },
+ "welcomeBack": {
+ "message": "Bon Retou!"
+ },
+ "welcomeBeta": {
+ "message": "Byenveni nan MetaMask Beta"
+ },
+ "whatsThis": {
+ "message": "Kisa sa ye?"
+ },
+ "yesLetsTry": {
+ "message": "Wi, ann eseye"
+ },
+ "youNeedToAllowCameraAccess": {
+ "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa."
+ },
+ "yourSigRequested": {
+ "message": "Yo mande siyati ou"
+ },
+ "youSign": {
+ "message": "Ou ap siyen kounya"
+ },
+ "yourPrivateSeedPhrase": {
+ "message": "Seed fraz prive ou a"
+ }
}
diff --git a/app/_locales/index.json b/app/_locales/index.json
index 0598aa9ec..234215e39 100644
--- a/app/_locales/index.json
+++ b/app/_locales/index.json
@@ -1,23 +1,24 @@
[
- { "code": "cs", "name": "Czech" },
- { "code": "de", "name": "German" },
+ { "code": "cs", "name": "Čeština" },
+ { "code": "de", "name": "Deutsche" },
{ "code": "en", "name": "English" },
- { "code": "es", "name": "Spanish" },
- { "code": "fr", "name": "French" },
- { "code": "ht", "name": "Haitian Creole" },
- { "code": "hn", "name": "Hindi" },
- { "code": "it", "name": "Italian" },
- { "code": "ja", "name": "Japanese" },
- { "code": "ko", "name": "Korean" },
- { "code": "nl", "name": "Dutch" },
- { "code": "ph", "name": "Tagalog" },
- { "code": "pt", "name": "Portuguese" },
- { "code": "ru", "name": "Russian" },
- { "code": "sl", "name": "Slovenian" },
- { "code": "th", "name": "Thai" },
- { "code": "tml", "name": "Tamil" },
- { "code": "tr", "name": "Turkish" },
- { "code": "vi", "name": "Vietnamese" },
- { "code": "zh_CN", "name": "Chinese (Simplified)" },
- { "code": "zh_TW", "name": "Chinese (Traditional)" }
+ { "code": "es", "name": "Español" },
+ { "code": "fr", "name": "Français" },
+ { "code": "ht", "name": "Kreyòl ayisyen" },
+ { "code": "hn", "name": "हिन्दी" },
+ { "code": "it", "name": "Italiano" },
+ { "code": "ja", "name": "日本語" },
+ { "code": "ko", "name": "한국어" },
+ { "code": "nl", "name": "Nederlands" },
+ { "code": "ph", "name": "Pilipino" },
+ { "code": "pl", "name": "Polskie" },
+ { "code": "pt", "name": "Português" },
+ { "code": "ru", "name": "Русский" },
+ { "code": "sl", "name": "Slovenščina" },
+ { "code": "th", "name": "ไทย" },
+ { "code": "tml", "name": "தமிழ்" },
+ { "code": "tr", "name": "Türkçe" },
+ { "code": "vi", "name": "Tiếng Việt" },
+ { "code": "zh_CN", "name": "中文(简体)" },
+ { "code": "zh_TW", "name": "中文(繁體)" }
]
diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json
index 2ae5fae72..06e3dc855 100644
--- a/app/_locales/it/messages.json
+++ b/app/_locales/it/messages.json
@@ -2,6 +2,9 @@
"accept": {
"message": "Accetta"
},
+ "accessingYourCamera": {
+ "message": "Accesso alla fotocamera..."
+ },
"account": {
"message": "Account"
},
@@ -11,6 +14,15 @@
"accountName": {
"message": "Nome Account"
},
+ "accountOptions": {
+ "message": "Account Options"
+ },
+ "accountSelectionRequired": {
+ "message": "Devi selezionare un account!"
+ },
+ "activityLog": {
+ "message": "log attività"
+ },
"address": {
"message": "Indirizzo"
},
@@ -23,6 +35,12 @@
"addTokens": {
"message": "Aggiungi più token"
},
+ "addSuggestedTokens": {
+ "message": "Aggiungi Token Suggeriti"
+ },
+ "addAcquiredTokens": {
+ "message": "Aggiungi i token che hai acquistato usando MetaMask"
+ },
"amount": {
"message": "Importo"
},
@@ -37,9 +55,21 @@
"message": "MetaMask",
"description": "Il nome dell'applicazione"
},
+ "approve": {
+ "message": "Approva"
+ },
+ "approved": {
+ "message": "Approvato"
+ },
"attemptingConnect": {
"message": "Tentativo di connessione alla blockchain."
},
+ "attemptToCancel": {
+ "message": "Tentativo di Annullamento?"
+ },
+ "attemptToCancelDescription": {
+ "message": "Tentare di annullare non garantisce che la transazione verrà annullata. Se annullata, è comunque richiesto pagare alla rete la commissione sulla transazione."
+ },
"attributions": {
"message": "Attribuzioni"
},
@@ -71,8 +101,11 @@
"borrowDharma": {
"message": "Prendi in presisito con Dharma (Beta)"
},
+ "browserNotSupported": {
+ "message": "Il tuo Browser non è supportato..."
+ },
"builtInCalifornia": {
- "message": "MetaMask è progettato e costruito in California."
+ "message": "MetaMask è progettato e realizzato in California."
},
"buy": {
"message": "Compra"
@@ -83,8 +116,23 @@
"buyCoinbaseExplainer": {
"message": "Coinbase è il servizio più popolare al mondo per comprare e vendere Bitcoin, Ethereum e Litecoin."
},
+ "bytes": {
+ "message": "Bytes"
+ },
+ "ok": {
+ "message": "Ok"
+ },
"cancel": {
- "message": "Cancella"
+ "message": "Annulla"
+ },
+ "cancelAttempt": {
+ "message": "Tentativo di Annullamento"
+ },
+ "cancellationGasFee": {
+ "message": "Commissione di Annullamento in Gas"
+ },
+ "cancelN": {
+ "message": "Cancel all $1 transactions"
},
"classicInterface": {
"message": "Usa l'interfaccia classica"
@@ -92,9 +140,18 @@
"clickCopy": {
"message": "Clicca per Copiare"
},
+ "close": {
+ "message": "Chiudi"
+ },
+ "chromeRequiredForHardwareWallets": {
+ "message": "Devi usare MetaMask con Google Chrome per connettere il tuo Portafoglio Hardware"
+ },
"confirm": {
"message": "Conferma"
},
+ "confirmed": {
+ "message": "Confermata"
+ },
"confirmContract": {
"message": "Conferma Contratto"
},
@@ -104,6 +161,36 @@
"confirmTransaction": {
"message": "Conferma Transazione"
},
+ "connectHardwareWallet": {
+ "message": "Connetti Portafoglio Hardware"
+ },
+ "connect": {
+ "message": "Connetti"
+ },
+ "connecting": {
+ "message": "Connessione..."
+ },
+ "connectingToKovan": {
+ "message": "Connessione alla Rete di test Kovan"
+ },
+ "connectingToMainnet": {
+ "message": "Connessione alla Rete Ethereum Principale"
+ },
+ "connectingToRopsten": {
+ "message": "Connessione alla Rete di test Ropsten"
+ },
+ "connectingToRinkeby": {
+ "message": "Connessione alla Rete di test Rinkeby"
+ },
+ "connectingToUnknown": {
+ "message": "Connessione ad una Rete Sconosciuta"
+ },
+ "connectToLedger": {
+ "message": "Connettersi al Ledger"
+ },
+ "connectToTrezor": {
+ "message": "Connettersi al Trezor"
+ },
"continue": {
"message": "Continua"
},
@@ -126,11 +213,14 @@
"message": "Copiato!"
},
"copiedSafe": {
- "message": "Le ho copiate in un posto sicuro"
+ "message": "Le ho copiate in un posto sicuro"
},
"copy": {
"message": "Copia"
},
+ "copyAddress": {
+ "message": "Copia l'indirizzo"
+ },
"copyToClipboard": {
"message": "Copia negli appunti"
},
@@ -156,12 +246,21 @@
"currentConversion": {
"message": "Cambio Corrente"
},
+ "currentLanguage": {
+ "message": "Lingua Corrente"
+ },
"currentNetwork": {
"message": "Rete Corrente"
},
+ "currentRpc": {
+ "message": "RPC Corrente"
+ },
"customGas": {
"message": "Personalizza Gas"
},
+ "customToken": {
+ "message": "Token Personalizzato"
+ },
"customize": {
"message": "Personalizza"
},
@@ -169,11 +268,11 @@
"message": "RPC Personalizzata"
},
"decimalsMustZerotoTen": {
- "message": "Il numero di decimali deve essere almeno 0, e non oltre 36."
+ "message": "Il numero di decimali deve essere almeno 0, e non oltre 36."
},
"decimal": {
"message": "Precisione Decimali"
- },
+ },
"defaultNetwork": {
"message": "La rete predefinita per transazioni in Ether è la Rete Ethereum Principale."
},
@@ -218,38 +317,59 @@
"message": "Deposita Direttamente Ether"
},
"directDepositEtherExplainer": {
- "message": "Se possiedi già degli Ether, questa è la via più veloce per aggiungere Ether al tuo portafoglio con un deposito diretto."
+ "message": "Se possiedi già degli Ether, questa è la via più veloce per aggiungere Ether al tuo portafoglio con un deposito diretto."
},
"done": {
"message": "Finito"
},
+ "downloadGoogleChrome": {
+ "message": "Scarica Google Chrome"
+ },
"downloadStateLogs": {
"message": "Scarica i log di Stato"
},
+ "dontHaveAHardwareWallet": {
+ "message": "Non hai un portafoglio hardware?"
+ },
+ "dropped": {
+ "message": "Abbandonata"
+ },
"edit": {
"message": "Modifica"
},
"editAccountName": {
"message": "Modifica Nome Account"
},
+ "editingTransaction": {
+ "message": "Modifica la transazione"
+ },
"emailUs": {
"message": "Mandaci una mail!"
},
"encryptNewDen": {
"message": "Cripta il tuo nuovo DEN"
},
+ "ensNameNotFound": {
+ "message": "Nome ENS non trovato"
+ },
"enterPassword": {
"message": "Inserisci password"
},
"enterPasswordConfirm": {
"message": "Inserisci la tua password per confermare"
},
+ "enterPasswordContinue": {
+ "message": "Inserisci la tua password per continuare"
+ },
"etherscanView": {
"message": "Vedi account su Etherscan"
},
"exchangeRate": {
"message": "Tasso di cambio"
},
+ "expandView": {
+ "message": "Expand View"
+ },
"exportPrivateKey": {
"message": "Esporta Chiave Privata"
},
@@ -257,7 +377,7 @@
"message": "Esporta chiave privata a tuo rischio."
},
"failed": {
- "message": "Fallito"
+ "message": "Fallita"
},
"fiat": {
"message": "FIAT",
@@ -270,6 +390,9 @@
"followTwitter": {
"message": "Seguici su Twitter"
},
+ "forgetDevice": {
+ "message": "Dimentica questo dispositivo"
+ },
"from": {
"message": "Da"
},
@@ -279,6 +402,9 @@
"fromShapeShift": {
"message": "Da ShapeShift"
},
+ "functionType": {
+ "message": "Tipo della Funzione"
+ },
"gas": {
"message": "Gas",
"description": "Piccola indicazione del costo del gas"
@@ -310,6 +436,9 @@
"gasPriceRequired": {
"message": "Prezzo Gas Richiesto"
},
+ "generatingTransaction": {
+ "message": "Generando la transazione"
+ },
"getEther": {
"message": "Ottieni Ether"
},
@@ -317,10 +446,28 @@
"message": "Ottieni Get Ether da un faucet per $1",
"description": "Visualizza il nome della rete per il faucet Ether"
},
+ "getHelp": {
+ "message": "Aiuto."
+ },
"greaterThanMin": {
"message": "deve essere maggiore o uguale a $1.",
"description": "aiuto per inserire un input esadecimale come decimale"
},
+ "hardware": {
+ "message": "hardware"
+ },
+ "hardwareWalletConnected": {
+ "message": "Portafoglio hardware connesso"
+ },
+ "hardwareWallets": {
+ "message": "Connetti portafoglio hardware"
+ },
+ "hardwareWalletsMsg": {
+ "message": "Selezione un portafoglio hardware che vuoi utilizzare con MetaMask"
+ },
+ "havingTroubleConnecting": {
+ "message": "Problemi di connessione?"
+ },
"here": {
"message": "qui",
"description": "per intendere -clicca qui- per maggiori informazioni (va con troubleTokenBalances)"
@@ -328,6 +475,9 @@
"hereList": {
"message": "Questa è una lista!!!!"
},
+ "hexData": {
+ "message": "Dati Hex"
+ },
"hide": {
"message": "Nascondi"
},
@@ -337,11 +487,14 @@
"hideTokenPrompt": {
"message": "Nascondi Token?"
},
+ "history": {
+ "message": "Storico"
+ },
"howToDeposit": {
"message": "Come vuoi depositare Ether?"
},
"holdEther": {
- "message": "Ti permette di tenere ether & token, e serve da ponte per le applicazioni decentralizzate."
+ "message": "Ti permette di tenere ether & token, e serve da ponte per le applicazioni decentralizzate."
},
"import": {
"message": "Importa",
@@ -351,7 +504,7 @@
"message": "Importa Account"
},
"importAccountMsg": {
- "message":" Gli account importati non saranno associati alla frase seed originariamente creata con MetaMask. Impara di più sugli account importati "
+ "message": " Gli account importati non saranno associati alla frase seed originariamente creata con MetaMask. Impara di più sugli account importati "
},
"importAnAccount": {
"message": "Importa un account"
@@ -363,9 +516,18 @@
"message": "Importato",
"description": "stato che conferma che un account è stato totalmente caricato nel portachiavi"
},
+ "importUsingSeed": {
+ "message": "Importa account con frase seed"
+ },
+ "info": {
+ "message": "Informazioni"
+ },
"infoHelp": {
"message": "Informazioni & Aiuto"
},
+ "initialTransactionConfirmed": {
+ "message": "La transazione iniziale è stata confermata dalla rete. Clicca OK per tornare indietro."
+ },
"insufficientFunds": {
"message": "Fondi non sufficienti."
},
@@ -390,19 +552,34 @@
"invalidRPC": {
"message": "URI RPC invalido"
},
+ "invalidSeedPhrase": {
+ "message": "Frase seed non valida"
+ },
"jsonFail": {
- "message": "Qualcosa è andato storto. Assicurati che il file JSON sia formattato correttamente."
+ "message": "Qualcosa è andato storto. Assicurati che il file JSON sia formattato correttamente."
},
"jsonFile": {
"message": "File JSON",
"description": "formato per importare un account"
},
+ "keepTrackTokens": {
+ "message": "Tieni traccia dei tokens che hai acquistato con il tuo account MetaMask."
+ },
"kovan": {
"message": "Rete di test Kovan"
},
"knowledgeDataBase": {
"message": "Visita la nostra Knowledge Base"
},
+ "max": {
+ "message": "Massimo"
+ },
+ "learnMore": {
+ "message": "Scopri di più"
+ },
+ "ledgerAccountRestriction": {
+ "message": "E' necessario utilizzare l'ultimo account prima di poterne aggiungere uno nuovo."
+ },
"lessThanMax": {
"message": "deve essere minore o uguale a $1.",
"description": "aiuto per inserire un input esadecimale come decimale"
@@ -410,6 +587,9 @@
"likeToAddTokens": {
"message": "Vorresti aggiungere questi token?"
},
+ "links": {
+ "message": "Collegamenti"
+ },
"limit": {
"message": "Limite"
},
@@ -437,17 +617,26 @@
"mainnet": {
"message": "Rete Ethereum Principale"
},
+ "menu": {
+ "message": "Menu"
+ },
"message": {
"message": "Messaggio"
},
"metamaskDescription": {
"message": "MetaMask è una cassaforte sicura per identità su Ethereum."
},
+ "metamaskSeedWords": {
+ "message": "Parole Seed di MetaMask"
+ },
+ "metamaskVersion": {
+ "message": "versione di MetaMask"
+ },
"min": {
"message": "Minimo"
},
"myAccounts": {
- "message": "Account Miei"
+ "message": "Miei Account"
},
"mustSelectOne": {
"message": "Devi selezionare almeno un token."
@@ -469,6 +658,9 @@
"networks": {
"message": "Reti"
},
+ "nevermind": {
+ "message": "Non importa"
+ },
"newAccount": {
"message": "Nuovo Account"
},
@@ -482,6 +674,9 @@
"newPassword": {
"message": "Nuova Password (minimo 8 caratteri)"
},
+ "newPassword8Chars": {
+ "message": "Nuova Password (minimo 8 caratteri)"
+ },
"newRecipient": {
"message": "Nuovo Destinatario"
},
@@ -489,7 +684,7 @@
"message": "Nuovo URL RPC"
},
"next": {
- "message": "Prossimo"
+ "message": "Avanti"
},
"noAddressForName": {
"message": "Nessun indirizzo è stato impostato per questo nome."
@@ -497,32 +692,75 @@
"noDeposits": {
"message": "Nessun deposito ricevuto"
},
+ "noConversionRateAvailable": {
+ "message": "Tasso di Conversione non Disponibile"
+ },
"noTransactionHistory": {
"message": "Nessuna cronologia delle transazioni."
},
"noTransactions": {
"message": "Nessuna Transazione"
},
+ "notFound": {
+ "message": "Non Trovata"
+ },
"notStarted": {
"message": "Non Iniziato"
},
+ "noWebcamFoundTitle": {
+ "message": "Webcam non trovata"
+ },
+ "noWebcamFound": {
+ "message": "La webcam del tuo computer non è stata trovata. Per favore riprovaci."
+ },
"oldUI": {
"message": "Vecchia interfaccia"
},
"oldUIMessage": {
"message": "Sei ritornato alla vecchia interfaccia. Puoi ritornare alla nuova interfaccia tramite l'opzione nel menu a discesa in alto a destra."
},
+ "onlySendToEtherAddress": {
+ "message": "Invia ETH solamente ad un account Ethereum."
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "Invia solamente $1 ad un account Ethereum.",
+ "description": "mostra il simbolo del token"
+ },
+ "openInTab": {
+ "message": "Apri in una scheda"
+ },
"or": {
"message": "o",
"description": "scelta tra creare o importare un nuovo account"
},
+ "orderOneHere": {
+ "message": "Compra un Trezor o un Ledger e tieni i tuoi soldi al sicuro"
+ },
+ "origin": {
+ "message": "Origine"
+ },
+ "outgoing": {
+ "message": "In Uscita"
+ },
+ "parameters": {
+ "message": "Parametri"
+ },
+ "password": {
+ "message": "Password"
+ },
"passwordCorrect": {
"message": "Assicurati che la password sia corretta."
},
+ "passwordsDontMatch": {
+ "message": "Le Password Non Corrispondonos"
+ },
"passwordMismatch": {
"message": "le password non corrispondono",
"description": "nella creazione della password, le due password all'interno dei campi non corrispondono"
},
+ "passwordNotLongEnough": {
+ "message": "Password non abbastanza lunga"
+ },
"passwordShort": {
"message": "password non sufficientemente lunga",
"description": "nella creazione della password, la password non è lunga abbastanza"
@@ -534,12 +772,21 @@
"pasteSeed": {
"message": "Incolla la tua frase seed qui!"
},
+ "pending": {
+ "message": "in corso"
+ },
"personalAddressDetected": {
"message": "Rilevato indirizzo personale. Inserisci l'indirizzo del contratto del token."
},
"pleaseReviewTransaction": {
"message": "Ricontrolla la tua transazione."
},
+ "popularTokens": {
+ "message": "Tokens Popolari"
+ },
+ "prev": {
+ "message": "Precedente"
+ },
"privacyMsg": {
"message": "Politica sulla Privacy"
},
@@ -556,8 +803,11 @@
"qrCode": {
"message": "Mostra Codice QR"
},
+ "queue": {
+ "message": "Coda"
+ },
"readdToken": {
- "message": "Puoi aggiungere nuovamente questo token in futuro andando in “Aggiungi token” nel menu delle opzioni del tuo account."
+ "message": "Puoi aggiungere nuovamente questo token in futuro andando in “Aggiungi token” nel menu delle opzioni del tuo account."
},
"readMore": {
"message": "Leggi di più qui."
@@ -574,36 +824,87 @@
"refundAddress": {
"message": "Indirizzo di Rimborso"
},
+ "reject": {
+ "message": "Reject"
+ },
+ "rejectAll": {
+ "message": "Reject All"
+ },
+ "rejectTxsN": {
+ "message": "Reject $1 transactions"
+ },
+ "rejectTxsDescription": {
+ "message": "You are about to batch reject $1 transactions."
+ },
"rejected": {
"message": "Respinta"
},
+ "reset": {
+ "message": "Reset"
+ },
"resetAccount": {
"message": "Resetta Account"
},
+ "resetAccountDescription": {
+ "message": "Resettare il tuo account cancellerà lo storico delle transazioni."
+ },
"restoreFromSeed": {
"message": "Ripristina da una frase seed"
},
+ "restoreVault": {
+ "message": "Ripristina Cassaforte"
+ },
+ "restoreAccountWithSeed": {
+ "message": "Ripristina Account con la Frase Seed"
+ },
"required": {
"message": "Richiesto"
},
"retryWithMoreGas": {
"message": "Riprova con un prezzo del Gas maggiore qui"
},
+ "restore": {
+ "message": "Ripristina"
+ },
"revealSeedWords": {
"message": "Rivela Frase Seed"
},
+ "revealSeedWordsTitle": {
+ "message": "Frase Seed"
+ },
+ "revealSeedWordsDescription": {
+ "message": "Se cambierai browser o computer, ti servirà questa frase seed per accedere ai tuoi account. Salvala in un posto sicuro e segreto."
+ },
+ "revealSeedWordsWarningTitle": {
+ "message": "NON CONDIVIDERE questa frase con nessuno!"
+ },
"revealSeedWordsWarning": {
"message": "Non ripristinare la tua frase seed in pubblico!. Queste parole possono essere usate per rubare il tuo account."
},
"revert": {
"message": "Annulla"
},
+ "remove": {
+ "message": "rimuovi"
+ },
+ "removeAccount": {
+ "message": "Rimuovi account"
+ },
+ "removeAccountDescription": {
+ "message": "Questo account sarà rimosso dal tuo portafoglio. Per favore assicurati che hai la frase seed originale o la chiave privata per questo account importato prima di continuare. Puoi nuovamente importare o creare un account dal menù a tendina. "
+ },
+ "readyToConnect": {
+ "message": "Pronto a Connetterti?"
+ },
"rinkeby": {
"message": "Rete di test Rinkeby"
},
"ropsten": {
"message": "Rete di test Ropsten"
},
+ "rpc": {
+ "message": "RPC Personalizzata"
+ },
"sampleAccountName": {
"message": "Es: Il mio nuovo account",
"description": "Aiuta l'utente a capire il concetto di aggiungere un nome leggibile al loro account"
@@ -611,6 +912,9 @@
"save": {
"message": "Salva"
},
+ "saveAsCsvFile": {
+ "message": "Salva Come File CSV"
+ },
"saveAsFile": {
"message": "Salva come File",
"description": "Processo per esportare un account"
@@ -618,9 +922,18 @@
"saveSeedAsFile": {
"message": "Salva la Frase Seed come File"
},
+ "scanInstructions": {
+ "message": "Posizione il codice QR davanti alla fotocamera"
+ },
+ "scanQrCode": {
+ "message": "Scansiona Codice QR"
+ },
"search": {
"message": "Cerca"
},
+ "searchResults": {
+ "message": "Risultati Ricerca"
+ },
"secretPhrase": {
"message": "Inserisci la tua frase segreta di dodici parole per ripristinare la cassaforte."
},
@@ -633,6 +946,9 @@
"selectCurrency": {
"message": "Seleziona Moneta"
},
+ "selectLocale": {
+ "message": "Selezione Lingua"
+ },
"selectService": {
"message": "Seleziona Servizio"
},
@@ -648,6 +964,33 @@
"sendTokens": {
"message": "Invia Tokens"
},
+ "sentEther": {
+ "message": "ether inviati"
+ },
+ "sentTokens": {
+ "message": "tokens inviati"
+ },
+ "separateEachWord": {
+ "message": "Separa ogni parola con un solo spazio"
+ },
+ "searchTokens": {
+ "message": "Cerca Tokens"
+ },
+ "selectAnAddress": {
+ "message": "Seleziona un Indirizzo"
+ },
+ "selectAnAccount": {
+ "message": "Seleziona un Account"
+ },
+ "selectAnAccountHelp": {
+ "message": "Selezione l'account da visualizzare in MetaMask"
+ },
+ "selectHdPath": {
+ "message": "Seleziona Percorso HD"
+ },
+ "selectPathHelp": {
+ "message": "Se non vedi il tuo account Ledger esistente di seguito, prova a cambiare il percorso in \"Legacy (MEW / MyCrypto)\""
+ },
"sendTokensAnywhere": {
"message": "Invia Tokens a chiunque abbia un account Ethereum"
},
@@ -663,14 +1006,26 @@
"showQRCode": {
"message": "Mostra Codie QR"
},
+ "showHexData": {
+ "message": "Mostra Dati Hex"
+ },
+ "showHexDataDescription": {
+ "message": "Seleziona per mostrare il campo dei dati hex nella schermata di invio"
+ },
"sign": {
"message": "Firma"
},
+ "signatureRequest": {
+ "message": "Firma Richiesta"
+ },
+ "signed": {
+ "message": "Firmata"
+ },
"signMessage": {
"message": "Firma Messaggio"
},
"signNotice": {
- "message": "Firmare questo messaggio può avere effetti collaterali pericolosi. \nFirma messaggi da siti di cui ti fidi totalmente. \nQuesto metodo pericoloso sarà rimosso in versioni future."
+ "message": "Firmare questo messaggio può avere effetti collaterali pericolosi. \nFirma messaggi da siti di cui ti fidi totalmente. \nQuesto metodo pericoloso sarà rimosso in versioni future."
},
"sigRequest": {
"message": "Firma Richiesta"
@@ -681,6 +1036,15 @@
"spaceBetween": {
"message": "ci può essere solo uno spazio tra le parole"
},
+ "speedUp": {
+ "message": "velocizza"
+ },
+ "speedUpTitle": {
+ "message": "Velocizza Transazione"
+ },
+ "speedUpSubtitle": {
+ "message": "Aumenta il prezzo del gas per tentare di sovrascrivere e velocizzare la transazione"
+ },
"status": {
"message": "Stato"
},
@@ -690,9 +1054,33 @@
"stateLogsDescription": {
"message": "I log di stato contengono i tuoi indirizzi pubblici e le transazioni effettuate."
},
+ "stateLogError": {
+ "message": "Errore nel recupero dei log di stato."
+ },
+ "step1HardwareWallet": {
+ "message": "1. Connetti Portafoglio Hardware"
+ },
+ "step1HardwareWalletMsg": {
+ "message": "Connetti il tuo portafoglio hardware al tuo computer."
+ },
+ "step2HardwareWallet": {
+ "message": "2. Seleziona un Account"
+ },
+ "step2HardwareWalletMsg": {
+ "message": "Selezione l'account che vuoi vedere. Puoi selezionarne solo uno alla volta."
+ },
+ "step3HardwareWallet": {
+ "message": "3. Inizia a usare dApps e molto altro ancora!"
+ },
+ "step3HardwareWalletMsg": {
+ "message": "Usa il tuo account hardware come utilizzeresti qualsiasi account Ethereum. Accedi alle dApps, invia Eth, compra e conserva token ERC20 e token non fungibili come CryptoKitties"
+ },
"submit": {
"message": "Invia"
},
+ "submitted": {
+ "message": "Inviata"
+ },
"supportCenter": {
"message": "Visita il nostro Centro di Supporto"
},
@@ -715,6 +1103,9 @@
"message": "$1 a ETH via ShapeShift",
"description": "il sistema riempirà il tipo di deposito all'inizio del messaggio"
},
+ "token": {
+ "message": "Token"
+ },
"tokenAddress": {
"message": "Indirizzo Token"
},
@@ -736,23 +1127,62 @@
"total": {
"message": "Totale"
},
+ "transaction": {
+ "message": "transazione"
+ },
+ "transactionConfirmed": {
+ "message": "Transazione confermata il $2."
+ },
+ "transactionCreated": {
+ "message": "Transazione di valore $1 creata il $2."
+ },
+ "transactionWithNonce": {
+ "message": "Transazione $1"
+ },
+ "transactionDropped": {
+ "message": "Transazione abbandonata il $2."
+ },
+ "transactionSubmitted": {
+ "message": "Transazione inviata il $2."
+ },
+ "transactionUpdated": {
+ "message": "Transazione aggiornata il $2."
+ },
+ "transactionUpdatedGas": {
+ "message": "Transazione aggiornata con un prezzo del gas di $1 il $2."
+ },
"transactions": {
"message": "transazioni"
},
+ "transactionError": {
+ "message": "Errore Transazione. Eccceziona generata nel codice del contratto."
+ },
"transactionMemo": {
"message": "Promemoria Transazione (opzionale)"
},
"transactionNumber": {
"message": "Numero Transazione"
},
+ "transfer": {
+ "message": "Trasferisci"
+ },
+ "transferFrom": {
+ "message": "Transfer From"
+ },
"transfers": {
"message": "Trasferimenti"
},
+ "trezorHardwareWallet": {
+ "message": "TREZOR Portafoglio Hardware"
+ },
"troubleTokenBalances": {
"message": "Abbiamo avuto un problema a caricare il bilancio dei tuoi token. Puoi vederlo ",
"description": "Seguito da un link (qui) per vedere il bilancio dei token"
},
- "twelveWords": {
+ "tryAgain": {
+ "message": "Prova di nuovo"
+ },
+ "twelveWords": {
"message": "Queste 12 parole sono l'unico modo per ripristinare i tuoi account MetaMask. \nSalvale in un posto sicuro e segreto."
},
"typePassword": {
@@ -762,20 +1192,47 @@
"message": "Benvenuto alla nuova interfaccia (Beta)"
},
"uiWelcomeMessage": {
- "message": "Stai utilizzanto la nuova interfaccia di MetaMask. Guarda in giro, prova nuove funzionalità come inviare token, e facci sapere se hai dei problemi."
+ "message": "Stai utilizzanto la nuova interfaccia di MetaMask. Guarda in giro, prova nuove funzionalità come inviare token, e facci sapere se hai dei problemi."
+ },
+ "unapproved": {
+ "message": "Non approvata"
},
"unavailable": {
"message": "Non Disponibile"
},
+ "units": {
+ "message": "unità"
+ },
"unknown": {
"message": "Sconosciuto"
},
+ "unknownFunction": {
+ "message": "Funzione Sconosciuta"
+ },
"unknownNetwork": {
"message": "Rete Privata Sconosciuta"
},
"unknownNetworkId": {
"message": "ID rete sconosciuto"
},
+ "unknownQrCode": {
+ "message": "Errore: Non siamo riusciti a identificare il codice QR"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "Ooops! Qualcosa è andato storto...."
+ },
+ "unknownCameraError": {
+ "message": "C'è stato un errore nel tentativo di accedere alla fotocamera. Per favore prova di nuovo..."
+ },
+ "unlock": {
+ "message": "Sblocca"
+ },
+ "unlockMessage": {
+ "message": "Il web decentralizzato ti attende"
+ },
+ "updatedWithDate": {
+ "message": "Aggiornata $1"
+ },
"uriErrorMsg": {
"message": "Gli URI richiedono un prefisso HTTP/HTTPS."
},
@@ -798,22 +1255,40 @@
"viewAccount": {
"message": "Vedi Account"
},
+ "viewOnEtherscan": {
+ "message": "Vedi su Etherscan"
+ },
"visitWebSite": {
"message": "Visita il nostro sito web"
- },
+ },
+ "walletSeed": {
+ "message": "Seed del Portafoglio"
+ },
"warning": {
"message": "Attenzione"
},
+ "welcomeBack": {
+ "message": "Bentornato!"
+ },
"welcomeBeta": {
"message": "Benvenuto nella Beta di MetaMask"
},
"whatsThis": {
"message": "Cos'è questo?"
},
+ "yesLetsTry": {
+ "message": "Si, proviamo"
+ },
+ "youNeedToAllowCameraAccess": {
+ "message": "Devi consentire l'accesso alla fotocamera per usare questa funzionalità."
+ },
"yourSigRequested": {
"message": "E' richiesta la tua firma"
},
"youSign": {
"message": "Ti stai connettendo"
+ },
+ "yourPrivateSeedPhrase": {
+ "message": "La tua frase seed privata"
}
}
diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json
index 2088ae270..7b25f386a 100644
--- a/app/_locales/ja/messages.json
+++ b/app/_locales/ja/messages.json
@@ -315,7 +315,7 @@
"message": "アカウントのインポート"
},
"importAccountMsg": {
- "message":"追加したアカウントはMetaMaskのアカウントパスフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
+ "message": "追加したアカウントはMetaMaskのアカウントパスフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
},
"importAnAccount": {
"message": "アカウントをインポート"
diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json
index 5bc539e70..c8d470188 100644
--- a/app/_locales/ko/messages.json
+++ b/app/_locales/ko/messages.json
@@ -2,6 +2,9 @@
"accept": {
"message": "수락"
},
+ "accessingYourCamera": {
+ "message": "카메라에 접근 중..."
+ },
"account": {
"message": "계정"
},
@@ -11,6 +14,15 @@
"accountName": {
"message": "계정 이름"
},
+ "accountOptions": {
+ "message": "계정 옵션"
+ },
+ "accountSelectionRequired": {
+ "message": "계정을 선택하셔야 합니다!"
+ },
+ "activityLog": {
+ "message": "활동 로그"
+ },
"address": {
"message": "주소"
},
@@ -23,6 +35,9 @@
"addTokens": {
"message": "토큰 추가"
},
+ "addSuggestedTokens": {
+ "message": "제안된 토큰 추가"
+ },
"addAcquiredTokens": {
"message": "메타마스크를 통해 획득한 토큰 추가"
},
@@ -40,12 +55,18 @@
"message": "메타마스크",
"description": "애플리케이션 이름"
},
+ "approve": {
+ "message": "수락"
+ },
"approved": {
"message": "수락"
},
"attemptingConnect": {
"message": "블록체인에 접속을 시도하는 중입니다."
},
+ "attemptToCancel": {
+ "message": "취소 하시겠습니까?"
+ },
"attributions": {
"message": "속성"
},
@@ -75,7 +96,10 @@
"message": "Blockies 아이덴티콘 사용"
},
"borrowDharma": {
- "message": "Dharma에서 대여하기(Beta)"
+ "message": "Dharma에서 대출받기 (Beta)"
+ },
+ "browserNotSupported": {
+ "message": "브라우저를 지원하지 않습니다..."
},
"builtInCalifornia": {
"message": "메타마스크는 캘리포니아에서 디자인되고 만들어졌습니다."
@@ -89,12 +113,24 @@
"buyCoinbaseExplainer": {
"message": "코인베이스는 비트코인, 이더리움, 라이트코인을 거래할 수 있는 유명한 거래소입니다."
},
+ "bytes": {
+ "message": "바이트"
+ },
"ok": {
"message": "확인"
},
"cancel": {
"message": "취소"
},
+ "cancelAttempt": {
+ "message": "취소 시도"
+ },
+ "cancellationGasFee": {
+ "message": "취소 가스 수수료"
+ },
+ "cancelN": {
+ "message": "모든 $1 트랜잭션 취소"
+ },
"classicInterface": {
"message": "예전 인터페이스"
},
@@ -104,6 +140,9 @@
"close": {
"message": "닫기"
},
+ "chromeRequiredForHardwareWallets": {
+ "message": "하드웨어 지갑을 연결하기 위해서는 구글 크롬에서 메타마스크를 사용하셔야 합니다."
+ },
"confirm": {
"message": "승인"
},
@@ -119,6 +158,36 @@
"confirmTransaction": {
"message": "트랜잭션 승인"
},
+ "connectHardwareWallet": {
+ "message": "하드웨어 지갑 연결"
+ },
+ "connect": {
+ "message": "연결"
+ },
+ "connecting": {
+ "message": "연결 중..."
+ },
+ "connectingToMainnet": {
+ "message": "이더리움 메인넷 접속 중"
+ },
+ "connectingToRopsten": {
+ "message": "Ropsten 테스트넷 접속 중"
+ },
+ "connectingToKovan": {
+ "message": "Kovan 테스트넷 접속 중"
+ },
+ "connectingToRinkeby": {
+ "message": "Rinkeby 테스트넷 접속 중"
+ },
+ "connectingToUnknown": {
+ "message": "알 수 없는 네트워크 접속 중"
+ },
+ "connectToLedger": {
+ "message": "Ledger 연결"
+ },
+ "connectToTrezor": {
+ "message": "Trezor 연결"
+ },
"continue": {
"message": "계속"
},
@@ -129,7 +198,7 @@
"message": "컨트랙트 배포"
},
"conversionProgress": {
- "message": "변환 진행중"
+ "message": "변환 진행 중"
},
"copiedButton": {
"message": "복사됨"
@@ -146,6 +215,9 @@
"copy": {
"message": "복사"
},
+ "copyAddress": {
+ "message": "클립보드로 주소 복사"
+ },
"copyToClipboard": {
"message": "클립보드로 복사"
},
@@ -169,11 +241,17 @@
"description": "거래 유형 (암호화폐)"
},
"currentConversion": {
- "message": "선택된 단위"
+ "message": "현재 통화"
+ },
+ "currentLanguage": {
+ "message": "현재 언어"
},
"currentNetwork": {
"message": "현재 네트워크"
},
+ "currentRpc": {
+ "message": "현재 RPC"
+ },
"customGas": {
"message": "가스 설정"
},
@@ -181,7 +259,7 @@
"message": "사용자 정의 토큰"
},
"customize": {
- "message": "맞춤화 하기"
+ "message": "맞춤화하기"
},
"customRPC": {
"message": "사용자 정의 RPC"
@@ -224,7 +302,7 @@
"message": "ShapeShift를 통해 입금하기"
},
"depositShapeShiftExplainer": {
- "message": "다른 암호화폐를 가지고 있으면, 계정을 생성할 필요없이 메타마스크 지갑에 이더리움을 바로 거래하거나 입금할 수 있습니다."
+ "message": "다른 암호화폐를 가지고 있으면, 계정을 생성할 필요 없이 메타마스크 지갑에 이더리움을 바로 거래하거나 입금할 수 있습니다."
},
"details": {
"message": "세부사항"
@@ -241,9 +319,15 @@
"done": {
"message": "완료"
},
+ "downloadGoogleChrome": {
+ "message": "구글 크롬 다운로드"
+ },
"downloadStateLogs": {
"message": "상태 로그 다운로드"
},
+ "dontHaveAHardwareWallet": {
+ "message": "하드웨어 지갑이 없나요?"
+ },
"dropped": {
"message": "중단됨"
},
@@ -254,7 +338,7 @@
"message": "계정 이름 수정"
},
"editingTransaction": {
- "message": "트랜젝션을 변경합니다"
+ "message": "트랜잭션을 변경합니다"
},
"emailUs": {
"message": "저자에게 메일 보내기!"
@@ -262,6 +346,9 @@
"encryptNewDen": {
"message": "새로운 DEN을 암호화"
},
+ "ensNameNotFound": {
+ "message": "ENS 이름을 찾을 수 없습니다"
+ },
"enterPassword": {
"message": "비밀번호를 입력해주세요"
},
@@ -271,18 +358,15 @@
"enterPasswordContinue": {
"message": "계속하기 위해 비밀번호 입력"
},
- "passwordNotLongEnough": {
- "message": "비밀번호가 충분히 길지 않습니다"
- },
- "passwordsDontMatch": {
- "message": "비밀번호가 맞지 않습니다"
- },
"etherscanView": {
"message": "이더스캔에서 계정보기"
},
"exchangeRate": {
"message": "환율"
},
+ "expandView": {
+ "message": "큰 화면으로 보기"
+ },
"exportPrivateKey": {
"message": "개인키 내보내기"
},
@@ -303,14 +387,20 @@
"followTwitter": {
"message": "트위터에서 팔로우하세요"
},
+ "forgetDevice": {
+ "message": "장치 연결 해제"
+ },
"from": {
"message": "보내는 이"
},
"fromToSame": {
- "message": "보내고 받는 주소는 동일할 수 없습니다"
+ "message": "보내고 받는 주소는 같을 수 없습니다"
},
"fromShapeShift": {
- "message": "ShapeShift로 부터"
+ "message": "ShapeShift로부터"
+ },
+ "functionType": {
+ "message": "함수 유형"
},
"gas": {
"message": "가스",
@@ -329,10 +419,10 @@
"message": "가스 한도가 필요합니다."
},
"gasLimitTooLow": {
- "message": "가스 한도는 최소 21000 이상이여야 합니다."
+ "message": "가스 한도는 최소 21000 이상이어야 합니다."
},
"generatingSeed": {
- "message": "시드 생성중..."
+ "message": "시드 생성 중..."
},
"gasPrice": {
"message": "가스 가격 (GWEI)"
@@ -344,7 +434,7 @@
"message": "가스 가격이 필요합니다."
},
"generatingTransaction": {
- "message": "트랜잭션 생성중"
+ "message": "트랜잭션 생성 중"
},
"getEther": {
"message": "이더 얻기"
@@ -353,10 +443,28 @@
"message": "파우셋에서 $1에 달하는 이더를 얻으세요.",
"description": "이더 파우셋에 대한 네트워크 이름을 표시합니다"
},
+ "getHelp": {
+ "message": "도움말"
+ },
"greaterThanMin": {
"message": "$1 이상이어야 합니다.",
"description": "10진수 입력으로 hex값 입력을 도와줍니다"
},
+ "hardware": {
+ "message": "하드웨어"
+ },
+ "hardwareWalletConnected": {
+ "message": "하드웨어 지갑이 연결됨"
+ },
+ "hardwareWallets": {
+ "message": "하드웨어 지갑 연결"
+ },
+ "hardwareWalletsMsg": {
+ "message": "메타마스크에서 사용할 하드웨어 지갑을 선택해주세요"
+ },
+ "havingTroubleConnecting": {
+ "message": "연결에 문제가 있나요?"
+ },
"here": {
"message": "여기",
"description": "as in -click here- for more information (goes with troubleTokenBalances)"
@@ -364,6 +472,9 @@
"hereList": {
"message": "리스트가 있습니다!!!!"
},
+ "hexData": {
+ "message": "Hex 데이터"
+ },
"hide": {
"message": "숨기기"
},
@@ -373,6 +484,9 @@
"hideTokenPrompt": {
"message": "토큰 숨기기?"
},
+ "history": {
+ "message": "히스토리"
+ },
"howToDeposit": {
"message": "어떤 방법으로 이더를 입금하시겠습니까?"
},
@@ -397,16 +511,19 @@
},
"imported": {
"message": "가져온 계정",
- "description": "이 상태는 해당 계정이 keyring으로 완전히 적재된 상태임을 표시합니다"
+ "description": "이 상태는 해당 계정이 keyring으로 완전히 로드된 상태임을 표시합니다"
},
"importUsingSeed": {
"message": "계정 시드 구문으로 가져오기"
},
+ "info": {
+ "message": "정보"
+ },
"infoHelp": {
"message": "정보 및 도움말"
},
"initialTransactionConfirmed": {
- "message": "초기 트랜잭션이 네트워크를 통해 확정되었습니다. 확인을 누르고 이전으로 돌아갑니다."
+ "message": "초기 트랜잭션이 네트워크를 통해 확정되었습니다. 확인을 누르면 이전으로 돌아갑니다."
},
"insufficientFunds": {
"message": "충분하지 않은 자금."
@@ -432,6 +549,9 @@
"invalidRPC": {
"message": "올바르지 않은 RPC URI"
},
+ "invalidSeedPhrase": {
+ "message": "잘못된 시드 구문"
+ },
"jsonFail": {
"message": "이상이 있습니다. JSON 파일이 올바른 파일인지 확인해주세요."
},
@@ -452,7 +572,10 @@
"message": "최대"
},
"learnMore": {
- "message": "더 배우기."
+ "message": "더 알아보기."
+ },
+ "ledgerAccountRestriction": {
+ "message": "새 계정을 추가하려면 최소 마지막 계정을 사용해야 합니다."
},
"lessThanMax": {
"message": "$1 이하여야합니다.",
@@ -491,12 +614,18 @@
"mainnet": {
"message": "이더리움 메인넷"
},
+ "menu": {
+ "message": "메뉴"
+ },
"message": {
"message": "메시지"
},
"metamaskDescription": {
"message": "메타마스크는 이더리움을 위한 안전한 신분 저장소입니다."
},
+ "metamaskVersion": {
+ "message": "메타마스크 버전"
+ },
"metamaskSeedWords": {
"message": "메타마스크 시드 단어"
},
@@ -517,7 +646,7 @@
"description": "사용자는 계정을 가져오기 위해서 파일을 추가후 계속 진행해야 합니다"
},
"needImportPassword": {
- "message": "선택 된 파일에 대한 비밀번호를 입력해주세요.",
+ "message": "선택된 파일에 대한 비밀번호를 입력해주세요.",
"description": "계정을 가져오기 위해서 비밀번호와 파일이 필요합니다."
},
"negativeETH": {
@@ -527,14 +656,14 @@
"message": "네트워크"
},
"nevermind": {
- "message": "상관안함"
+ "message": "상관 안 함"
},
"newAccount": {
"message": "새 계정"
},
"newAccountNumberName": {
"message": "새 계정 $1",
- "description": "계정 생성시 볼 수 있는 새 계정의 기본 이름"
+ "description": "계정 생성 시 볼 수 있는 새 계정의 기본 이름"
},
"newContract": {
"message": "새 컨트랙트"
@@ -557,24 +686,55 @@
"noDeposits": {
"message": "입금 내역이 없습니다."
},
+ "noConversionRateAvailable": {
+ "message": "변환 비율을 찾을 수 없습니다"
+ },
"noTransactionHistory": {
"message": "트랜잭션 기록이 없습니다."
},
"noTransactions": {
"message": "트랜잭션이 없습니다"
},
+ "notFound": {
+ "message": "찾을 수 없음"
+ },
"notStarted": {
- "message": "시작 안됨"
+ "message": "시작 안 됨"
+ },
+ "noWebcamFound": {
+ "message": "컴퓨터의 웹캠을 찾을 수 없습니다. 다시 시도해보세요."
+ },
+ "noWebcamFoundTitle": {
+ "message": "웹캠이 없습니다"
},
"oldUI": {
"message": "구버전 UI"
},
"oldUIMessage": {
- "message": "구버전 UI로 변경하셨습니다. 우 상단 드롭다운 메뉴에서 새 UI로 변경하실 수 있습니다."
+ "message": "구버전 UI로 변경하셨습니다. 오른쪽 위 드롭다운 메뉴에서 새 UI로 변경하실 수 있습니다."
+ },
+ "onlySendToEtherAddress": {
+ "message": "이더리움 주소로 ETH만 송금하세요."
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "이더리움 계정 주소로 $1만 보내기.",
+ "description": "토큰 심볼 보이기"
+ },
+ "openInTab": {
+ "message": "탭으로 열기"
},
"or": {
"message": "또는",
- "description": "새 계정을 만들거나 가져오기중에 선택하기"
+ "description": "새 계정을 만들거나 가져오기 중에 선택하기"
+ },
+ "orderOneHere": {
+ "message": "Trezor 혹은 Ledger를 구입하고 자금을 콜드 스토리지에 저장합니다"
+ },
+ "origin": {
+ "message": "Origin"
+ },
+ "parameters": {
+ "message": "매개변수"
},
"password": {
"message": "비밀번호"
@@ -582,9 +742,15 @@
"passwordCorrect": {
"message": "비밀번호가 맞는지 확인해주세요."
},
+ "passwordsDontMatch": {
+ "message": "비밀번호가 맞지 않습니다"
+ },
"passwordMismatch": {
"message": "비밀번호가 일치하지 않습니다.",
- "description": "비밀번호를 생성하는 과정에서 두개의 새 비밀번호 입력란이 일치하지 않습니다"
+ "description": "비밀번호를 생성하는 과정에서 두 개의 새 비밀번호 입력란이 일치하지 않습니다"
+ },
+ "passwordNotLongEnough": {
+ "message": "비밀번호가 충분히 길지 않습니다"
},
"passwordShort": {
"message": "비밀번호가 짧습니다.",
@@ -595,7 +761,10 @@
"description": "개인키로부터 계정을 가져오는 것입니다"
},
"pasteSeed": {
- "message": "시드 구문을 이곳에 붙여넣어주세요!"
+ "message": "시드 구문을 이곳에 붙여넣어 주세요!"
+ },
+ "pending": {
+ "message": "펜딩 중"
},
"personalAddressDetected": {
"message": "개인 주소가 탐지됨. 토큰 컨트랙트 주소를 입력하세요."
@@ -606,6 +775,9 @@
"popularTokens": {
"message": "인기있는 토큰"
},
+ "prev": {
+ "message": "이전"
+ },
"privacyMsg": {
"message": "개인정보 보호 정책"
},
@@ -614,7 +786,7 @@
"description": "이 형식의 파일을 선택하여 계정을 가져올 수 있습니다"
},
"privateKeyWarning": {
- "message": " 절대 이 키를 노출하지 마십시오. 개인키가 노출되면 누구나 당신의 계정에서 자산을 빼갈 수 있습니다."
+ "message": "절대 이 키를 노출하지 마십시오. 개인키가 노출되면 누구나 당신의 계정에서 자산을 빼갈 수 있습니다."
},
"privateNetwork": {
"message": "프라이빗 네트워크"
@@ -622,6 +794,9 @@
"qrCode": {
"message": "QR 코드 보기"
},
+ "queue": {
+ "message": "큐"
+ },
"readdToken": {
"message": "옵션 메뉴에서 “토큰 추가”를 눌러서 추후에 다시 이 토큰을 추가하실 수 있습니다."
},
@@ -640,6 +815,18 @@
"refundAddress": {
"message": "환불받을 주소"
},
+ "reject": {
+ "message": "거부"
+ },
+ "rejectAll": {
+ "message": "모두 거부"
+ },
+ "rejectTxsN": {
+ "message": "$1 트랜잭션 거부"
+ },
+ "rejectTxsDescription": {
+ "message": "$1 트랜잭션을 거부합니다."
+ },
"rejected": {
"message": "거부됨"
},
@@ -658,14 +845,17 @@
"restoreVault": {
"message": "저장소 복구"
},
+ "restoreAccountWithSeed": {
+ "message": "시드 구문으로 계정 복구하기"
+ },
"required": {
"message": "필요함"
},
"retryWithMoreGas": {
"message": "더 높은 가스 가격으로 다시 시도해주세요"
},
- "walletSeed": {
- "message": "지갑 시드값"
+ "restore": {
+ "message": "복구"
},
"revealSeedWords": {
"message": "시드 단어 보이기"
@@ -677,14 +867,26 @@
"message": "브라우저를 바꾸거나 컴퓨터를 옮기는 경우 이 시드 구문이 필요하며 이를 통해 계정에 접근할 수 있습니다. 시드 구문을 안전한 곳에 보관하세요."
},
"revealSeedWordsWarningTitle": {
- "message": "이 구문을 다른사람과 절대로 공유하지 마세요!"
+ "message": "이 구문을 다른 사람과 절대로 공유하지 마세요!"
},
"revealSeedWordsWarning": {
- "message": "이 단어모음은 당신의 모든 계정을 훔치는데 사용할 수 있습니다."
+ "message": "이 단어 모음은 당신의 모든 계정을 훔치는데 사용할 수 있습니다."
},
"revert": {
"message": "되돌림"
},
+ "remove": {
+ "message": "제거"
+ },
+ "removeAccount": {
+ "message": "계정 제거"
+ },
+ "removeAccountDescription": {
+ "message": "이 계정은 지갑에서 삭제될 것입니다. 지우기 전에 이 계정에 대한 개인 키 혹은 시드 구문을 가지고 있는지 확인하세요. 계정 드롭다운 메뉴를 통해서 계정을 가져오거나 생성할 수 있습니다."
+ },
+ "readyToConnect": {
+ "message": "접속 준비되었나요?"
+ },
"rinkeby": {
"message": "Rinkeby 테스트넷"
},
@@ -694,24 +896,6 @@
"rpc": {
"message": "사용자 정의 RPC"
},
- "currentRpc": {
- "message": "현재 RPC"
- },
- "connectingToMainnet": {
- "message": "이더리움 메인넷 접속중"
- },
- "connectingToRopsten": {
- "message": "Ropsten 테스트넷 접속중"
- },
- "connectingToKovan": {
- "message": "Kovan 테스트넷 접속중"
- },
- "connectingToRinkeby": {
- "message": "Rinkeby 테스트넷 접속중"
- },
- "connectingToUnknown": {
- "message": "알려지지 않은 네트워크 접속중"
- },
"sampleAccountName": {
"message": "예) 나의 새 계정",
"description": "각 계정에 대해서 구별하기 쉬운 이름을 지정하여 사용자가 쉽게 이해할 수 있게 합니다"
@@ -723,7 +907,7 @@
"message": "트랜잭션 속도 향상하기"
},
"speedUpSubtitle": {
- "message": "트랜잭션 가스 가격을 늘려서 해당 트랙잭션에 덮어쓰기 하여 속도를 빠르게 합니다"
+ "message": "트랜잭션 가스 가격을 올려서 해당 트랜잭션에 덮어쓰고 속도를 빠르게 합니다"
},
"saveAsCsvFile": {
"message": "CSV 파일로 저장"
@@ -735,6 +919,12 @@
"saveSeedAsFile": {
"message": "시드 단어를 파일로 저장하기"
},
+ "scanInstructions": {
+ "message": "QR 코드를 카메라 앞에 가져다 놓아주세요"
+ },
+ "scanQrCode": {
+ "message": "QR 코드 스캔"
+ },
"search": {
"message": "검색"
},
@@ -756,6 +946,9 @@
"selectCurrency": {
"message": "통화 선택"
},
+ "selectLocale": {
+ "message": "언어 선택"
+ },
"selectService": {
"message": "서비스 선택"
},
@@ -771,25 +964,39 @@
"sendTokens": {
"message": "토큰 전송"
},
- "onlySendToEtherAddress": {
- "message": "이더리움 주소로 ETH만 송금하세요."
+ "sentEther": {
+ "message": "전송된 이더"
},
- "onlySendTokensToAccountAddress": {
- "message": "이더리움계정 주소로 $1 만 보내기.",
- "description": "토큰 심볼 보이기"
+ "sentTokens": {
+ "message": "전송된 토큰"
+ },
+ "separateEachWord": {
+ "message": "각 단어는 공백 한칸으로 분리합니다"
},
"searchTokens": {
"message": "토큰 검색"
},
+ "selectAnAddress": {
+ "message": "주소 선택"
+ },
+ "selectAnAccount": {
+ "message": "계정 선택"
+ },
+ "selectAnAccountHelp": {
+ "message": "메타마스크에서 보기 위한 계정 선택"
+ },
+ "selectHdPath": {
+ "message": "HD 경로 지정"
+ },
+ "selectPathHelp": {
+ "message": "하단에서 Ledger 지갑 계정을 찾지 못하겠으면 \"Legacy (MEW / MyCrypto)\" 경로로 바꿔보세요"
+ },
"sendTokensAnywhere": {
- "message": "이더 계정로 토큰 전송"
+ "message": "이더 계정으로 토큰 전송"
},
"settings": {
"message": "설정"
},
- "info": {
- "message": "정보"
- },
"shapeshiftBuy": {
"message": "Shapeshift를 통해서 구매하기"
},
@@ -799,12 +1006,21 @@
"showQRCode": {
"message": "QR 코드 보기"
},
+ "showHexData": {
+ "message": "Hex 데이터 보기"
+ },
+ "showHexDataDescription": {
+ "message": "선택하면 전송화면의 hex 데이터 필드 값을 보여줍니다."
+ },
"sign": {
"message": "서명"
},
"signed": {
"message": "서명됨"
},
+ "signatureRequest": {
+ "message": "서명 요청"
+ },
"signMessage": {
"message": "메시지 서명"
},
@@ -832,6 +1048,24 @@
"stateLogError": {
"message": "상태 로그 받기 실패."
},
+ "step1HardwareWallet": {
+ "message": "1. 하드웨어 지갑 연결"
+ },
+ "step1HardwareWalletMsg": {
+ "message": "하드웨어 지갑을 컴퓨터에 연결해주세요."
+ },
+ "step2HardwareWallet": {
+ "message": "2. 계정 선택"
+ },
+ "step2HardwareWalletMsg": {
+ "message": "보고 싶은 계정을 선택합니다. 한 번에 하나의 계정만 선택할 수 있습니다."
+ },
+ "step3HardwareWallet": {
+ "message": "3. dApps을 사용하거나 다른 것을 합니다!"
+ },
+ "step3HardwareWalletMsg": {
+ "message": "다른 이더리움 계정을 사용하듯 하드웨어 계정을 사용합니다. dApps을 로그인하거나, 이더를 보내거나, ERC20 토큰 혹은 대체 가능하지 않은 토큰 (예를 들어 CryptoKitties)을 사거나 저장하거나 합니다."
+ },
"submit": {
"message": "제출"
},
@@ -879,11 +1113,14 @@
"message": "토큰 기호"
},
"tokenWarning1": {
- "message": "메타마스크 계좌를 통해 구입한 토큰을 추적합니다. 다른 계정으로 토큰을 구입한 경우 이곳에 나타나지 않습니다."
+ "message": "메타마스크 계정을 통해 구입한 토큰을 추적합니다. 다른 계정으로 토큰을 구입한 경우 이곳에 나타나지 않습니다."
},
"total": {
"message": "합계"
},
+ "transaction": {
+ "message": "트랜잭션"
+ },
"transactions": {
"message": "트랜잭션"
},
@@ -896,13 +1133,22 @@
"transactionNumber": {
"message": "트랜잭션 번호"
},
+ "transfer": {
+ "message": "전송"
+ },
"transfers": {
"message": "전송"
},
+ "trezorHardwareWallet": {
+ "message": "TREZOR 하드웨어 지갑"
+ },
"troubleTokenBalances": {
"message": "토큰 잔액을 가져오는 데에 문제가 생겼습니다. 링크에서 상세내용을 볼 수 있습니다.",
"description": "토큰 잔액을 보려면 (here) 링크를 따라가세요"
},
+ "tryAgain": {
+ "message": "다시 시도하세요"
+ },
"twelveWords": {
"message": "12개의 단어는 메타마스크 계정을 복구하기 위한 유일한 방법입니다.\n안전한 장소에 보관하시기 바랍니다."
},
@@ -916,19 +1162,37 @@
"message": "새로운 메타마스크 UI를 사용하고 계십니다. 토큰 전송과 같은 새 기능들을 사용해보시면서 문제가 있다면 알려주세요."
},
"unapproved": {
- "message": "허가안됨"
+ "message": "허가 안 됨"
},
"unavailable": {
- "message": "유효하지 않음"
+ "message": "이용할 수 없음"
+ },
+ "units": {
+ "message": "단위"
},
"unknown": {
- "message": "알려지지 않음"
+ "message": "알 수 없음"
+ },
+ "unknownFunction": {
+ "message": "알 수 없는 함수"
},
"unknownNetwork": {
- "message": "알려지지 않은 프라이빗 네트워크"
+ "message": "알 수 없는 프라이빗 네트워크"
},
"unknownNetworkId": {
- "message": "알려지지 않은 네트워크 ID"
+ "message": "알 수 없는 네트워크 ID"
+ },
+ "unknownQrCode": {
+ "message": "오류: QR 코드를 확인할 수 없습니다"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "이런! 뭔가 잘못되었습니다...."
+ },
+ "unknownCameraError": {
+ "message": "카메라에 접근하는 중 오류가 발생했습니다. 다시 시도해 주세요..."
+ },
+ "unlock": {
+ "message": "잠금 해제"
},
"unlockMessage": {
"message": "우리가 기다리던 분권형 웹입니다"
@@ -938,7 +1202,7 @@
},
"usaOnly": {
"message": "USA 거주자 한정",
- "description": "해당 거래소는 USA거주자에 한해서만 사용가능합니다"
+ "description": "해당 거래소는 USA 거주자에 한해서만 사용 가능합니다"
},
"usedByClients": {
"message": "다양한 클라이언트에서 사용되고 있습니다"
@@ -956,11 +1220,14 @@
"message": "계정 보기"
},
"viewOnEtherscan": {
- "message": "이터스캔에서 보기"
+ "message": "이더스캔에서 보기"
},
"visitWebSite": {
"message": "웹사이트 방문"
},
+ "walletSeed": {
+ "message": "지갑 시드값"
+ },
"warning": {
"message": "경고"
},
@@ -973,207 +1240,18 @@
"whatsThis": {
"message": "이것은 무엇인가요?"
},
+ "yesLetsTry": {
+ "message": "네, 시도해보겠습니다."
+ },
"yourSigRequested": {
- "message": "서명이 요청되고 있습니다."
+ "message": "서명을 요청 중입니다."
},
"youSign": {
- "message": "서명 중입니다"
+ "message": "서명합니다"
},
"yourPrivateSeedPhrase": {
"message": "개인 시드 구문"
},
- "accessingYourCamera": {
- "message": "카메라 접근중..."
- },
- "accountSelectionRequired": {
- "message": "계정을 선택하셔야 합니다!"
- },
- "approve": {
- "message": "수락"
- },
- "browserNotSupported": {
- "message": "브라우저가 지원하지 않습니다..."
- },
- "bytes": {
- "message": "바이트"
- },
- "chromeRequiredForHardwareWallets": {
- "message": "하드웨어 지갑을 연결하기 위해서는 구글 크롬에서 메타마스크를 사용하셔야 합니다."
- },
- "connectHardwareWallet": {
- "message": "하드웨어 지갑 연결"
- },
- "connect": {
- "message": "연결"
- },
- "connecting": {
- "message": "연결중..."
- },
- "connectToLedger": {
- "message": "Ledger 연결"
- },
- "connectToTrezor": {
- "message": "Trezor 연결"
- },
- "copyAddress": {
- "message": "클립보드로 주소 복사"
- },
- "downloadGoogleChrome": {
- "message": "구글 크롬 다운로드"
- },
- "dontHaveAHardwareWallet": {
- "message": "하드웨어 지갑이 없나요?"
- },
- "ensNameNotFound": {
- "message": "ENS 이름을 찾을 수 없습니다"
- },
- "parameters": {
- "message": "매개변수"
- },
- "forgetDevice": {
- "message": "장치 연결 해제"
- },
- "functionType": {
- "message": "함수 유형"
- },
- "getHelp": {
- "message": "도움말"
- },
- "hardware": {
- "message": "하드웨어"
- },
- "hardwareWalletConnected": {
- "message": "하드웨어 지갑이 연결됨"
- },
- "hardwareWallets": {
- "message": "하드웨어 지갑 연결"
- },
- "hardwareWalletsMsg": {
- "message": "메타마스크에서 사용할 하드웨어 지갑을 선택해주세요"
- },
- "havingTroubleConnecting": {
- "message": "연결에 문제가 있나요?"
- },
- "hexData": {
- "message": "Hex 데이터"
- },
- "invalidSeedPhrase": {
- "message": "잘못된 시드 구문"
- },
- "ledgerAccountRestriction": {
- "message": "새 계정을 추가하려면 최소 마지막 계정을 사용해야 합니다."
- },
- "menu": {
- "message": "메뉴"
- },
- "noConversionRateAvailable": {
- "message": "변환 비율을 찾을 수 없습니다"
- },
- "notFound": {
- "message": "찾을 수 없음"
- },
- "noWebcamFoundTitle": {
- "message": "웹캠이 없습니다"
- },
- "noWebcamFound": {
- "message": "컴퓨터의 웹캠을 찾을 수 없습니다. 다시 시도해보세요."
- },
- "openInTab": {
- "message": "탭으로 열기"
- },
- "origin": {
- "message": "Origin"
- },
- "prev": {
- "message": "이전"
- },
- "restoreAccountWithSeed": {
- "message": "시드 구문으로 계정 복구하기"
- },
- "restore": {
- "message": "복구"
- },
- "remove": {
- "message": "제거"
- },
- "removeAccount": {
- "message": "계정 제거"
- },
- "removeAccountDescription": {
- "message": "이 계정한 지갑에서 삭제될 것입니다. 지우기 전에 이 계정에 대한 개인 키 혹은 시드 구문을 가지고 있는지 확인하세요. 계정 드랍다운 메뉴를 통해서 계정을 가져오거나 생성할 수 있습니다."
- },
- "readyToConnect": {
- "message": "접속 준비되었나요?"
- },
- "separateEachWord": {
- "message": "각 단어는 공백 한칸으로 분리합니다"
- },
- "orderOneHere": {
- "message": "Trezor 혹은 Ledger를 구입하고 자금을 콜드 스토리지에 저장합니다"
- },
- "selectAnAddress": {
- "message": "주소 선택"
- },
- "selectAnAccount": {
- "message": "계정 선택"
- },
- "selectAnAccountHelp": {
- "message": "메타마스크에서 보기위한 계정 선택"
- },
- "selectHdPath": {
- "message": "HD 경로 지정"
- },
- "selectPathHelp": {
- "message": "하단에서 Ledger지갑 계정을 찾지 못하겠으면 \"Legacy (MEW / MyCrypto)\" 경로로 바꿔보세요"
- },
- "step1HardwareWallet": {
- "message": "1. 하드웨어 지갑 연결"
- },
- "step1HardwareWalletMsg": {
- "message": "하드웨어 지갑을 컴퓨터에 연결해주세요."
- },
- "step2HardwareWallet": {
- "message": "2. 계정 선택"
- },
- "step2HardwareWalletMsg": {
- "message": "보고 싶은 계정을 선택합니다. 한번에 하나의 계정만 선택할 수 있습니다."
- },
- "step3HardwareWallet": {
- "message": "3. dApps을 사용하거나 다른 것을 합니다!"
- },
- "step3HardwareWalletMsg": {
- "message": "다른 이더리움 계정을 사용하듯 하드웨어 계정을 사용합니다. dApps을 로그인하거나, 이더를 보내거나, ERC20토큰 혹은 대체가능하지 않은 토큰 (예를 들어 CryptoKitties)을 사거나 저장하거나 합니다."
- },
- "scanInstructions": {
- "message": "QR 코드를 카메라 앞에 가져다 놓아주세요"
- },
- "scanQrCode": {
- "message": "QR 코드 스캔"
- },
- "transfer": {
- "message": "전송"
- },
- "trezorHardwareWallet": {
- "message": "TREZOR 하드웨어 지갑"
- },
- "tryAgain": {
- "message": "다시 시도하세요"
- },
- "unknownFunction": {
- "message": "알 수 없는 함수"
- },
- "unknownQrCode": {
- "message": "오류: QR 코드를 확인할 수 없습니다"
- },
- "unknownCameraErrorTitle": {
- "message": "이런! 뭔가 잘못되었습니다...."
- },
- "unknownCameraError": {
- "message": "카메라를 접근하는 중 오류가 발생했습니다. 다시 시도해 주세요..."
- },
- "unlock": {
- "message": "잠금 해제"
- },
"youNeedToAllowCameraAccess": {
"message": "이 기능을 사용하려면 카메라 접근을 허용해야 합니다."
}
diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json
index 46847f1bf..fc3450290 100644
--- a/app/_locales/nl/messages.json
+++ b/app/_locales/nl/messages.json
@@ -351,7 +351,7 @@
"message": "Account importeren"
},
"importAccountMsg": {
- "message":" Geïmporteerde accounts worden niet gekoppeld aan de seedphrase van uw oorspronkelijk gemaakte MetaMask-account. Meer informatie over geïmporteerde accounts"
+ "message": " Geïmporteerde accounts worden niet gekoppeld aan de seedphrase van uw oorspronkelijk gemaakte MetaMask-account. Meer informatie over geïmporteerde accounts"
},
"importAnAccount": {
"message": "Importeer een account"
@@ -435,7 +435,7 @@
"message": "back-up woorden hebben alleen kleine letters"
},
"mainnet": {
- "message": "belangrijkste Ethereum-netwerk"
+ "message": "Main Netwerk"
},
"message": {
"message": "Bericht"
diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json
new file mode 100644
index 000000000..c6d797c34
--- /dev/null
+++ b/app/_locales/pl/messages.json
@@ -0,0 +1,1213 @@
+{
+ "accept": {
+ "message": "Akceptacja"
+ },
+ "accessingYourCamera": {
+ "message": "Uruchamianie kamery..."
+ },
+ "account": {
+ "message": "Konto"
+ },
+ "accountDetails": {
+ "message": "Szczegóły konta"
+ },
+ "accountName": {
+ "message": "Nazwa konta"
+ },
+ "accountSelectionRequired": {
+ "message": "Należy wybrać konto!"
+ },
+ "address": {
+ "message": "Adres"
+ },
+ "addCustomToken": {
+ "message": "Dodaj token"
+ },
+ "addToken": {
+ "message": "Dodaj token"
+ },
+ "addTokens": {
+ "message": "Dodaj tokeny"
+ },
+ "addSuggestedTokens": {
+ "message": "Dodaj sugerowane tokeny."
+ },
+ "addAcquiredTokens": {
+ "message": "Dodaj tokeny pozyskane przy pomocy MetaMask"
+ },
+ "amount": {
+ "message": "Ilość"
+ },
+ "amountPlusGas": {
+ "message": "Ilość + gaz"
+ },
+ "appDescription": {
+ "message": "Wtyczka przeglądarki do Ethereum",
+ "description": "Opis aplikacji"
+ },
+ "appName": {
+ "message": "MetaMask",
+ "description": "Nazwa aplikacji"
+ },
+ "approve": {
+ "message": "Zatwierdź"
+ },
+ "approved": {
+ "message": "Zatwierdzone"
+ },
+ "attemptingConnect": {
+ "message": "Próba połączenia z blockchainem."
+ },
+ "attributions": {
+ "message": "Atrybuty"
+ },
+ "available": {
+ "message": "Dostępne"
+ },
+ "back": {
+ "message": "Wstecz"
+ },
+ "balance": {
+ "message": "Ilość środków"
+ },
+ "balances": {
+ "message": "Ilość tokenów"
+ },
+ "balanceIsInsufficientGas": {
+ "message": "Niewystarczająca ilość środków na opłatę za gaz"
+ },
+ "beta": {
+ "message": "BETA"
+ },
+ "betweenMinAndMax": {
+ "message": "musi być większe lub równe $1 i mniejsze lub równe $2,",
+ "description": "pomoc przy wpisywaniu hex jako dane dziesiętne"
+ },
+ "blockiesIdenticon": {
+ "message": "Użyj Blockies Identicon"
+ },
+ "borrowDharma": {
+ "message": "Pożycz z Dharma (Beta)"
+ },
+ "browserNotSupported": {
+ "message": "Twoja przeglądarka nie jest obsługiwana..."
+ },
+ "builtInCalifornia": {
+ "message": "MetaMask został zaprojektowany i stworzony w Kaliforni."
+ },
+ "buy": {
+ "message": "Kup"
+ },
+ "buyCoinbase": {
+ "message": "Kup na Coinbase"
+ },
+ "buyCoinbaseExplainer": {
+ "message": "Coinbase to najpopularniejszy sposób na kupno i sprzedaż Bitcoin, Ethereum i Litecoin."
+ },
+ "bytes": {
+ "message": "Bajty"
+ },
+ "ok": {
+ "message": "Ok"
+ },
+ "cancel": {
+ "message": "Anuluj"
+ },
+ "classicInterface": {
+ "message": "Użyj klasycznego interfejsu"
+ },
+ "clickCopy": {
+ "message": "Kliknij żeby skopiować"
+ },
+ "close": {
+ "message": "Zamknij"
+ },
+ "chromeRequiredForHardwareWallets": {
+ "message": "Żeby połączyć się z portfelem sprzętowym, należy uruchomić MetaMask z przeglądarką Google Chrome."
+ },
+ "confirm": {
+ "message": "Potwierdź"
+ },
+ "confirmed": {
+ "message": "Potwierdzone"
+ },
+ "confirmContract": {
+ "message": "Zatwierdź kontrakt"
+ },
+ "confirmPassword": {
+ "message": "Potwierdź hasło"
+ },
+ "confirmTransaction": {
+ "message": "Potwierdź transakcję"
+ },
+ "connectHardwareWallet": {
+ "message": "Podłącz portfel sprzętowy"
+ },
+ "connect": {
+ "message": "Połącz"
+ },
+ "connecting": {
+ "message": "Łączenie..."
+ },
+ "connectToLedger": {
+ "message": "Połącz z Ledger"
+ },
+ "connectToTrezor": {
+ "message": "Połącz z Trezor"
+ },
+ "continue": {
+ "message": "Kontynuuj"
+ },
+ "continueToCoinbase": {
+ "message": "Przejdź do Coinbase"
+ },
+ "contractDeployment": {
+ "message": "Uruchomienie kontraktu"
+ },
+ "conversionProgress": {
+ "message": "Przeliczanie w toku"
+ },
+ "copiedButton": {
+ "message": "Skopiowane"
+ },
+ "copiedClipboard": {
+ "message": "Skopiowane do schowka"
+ },
+ "copiedExclamation": {
+ "message": "Skopiowane!"
+ },
+ "copiedSafe": {
+ "message": "Skopiowałem to w bezpieczne miejsce"
+ },
+ "copy": {
+ "message": "Skopiuj"
+ },
+ "copyContractAddress": {
+ "message": "Skopiuj adres kontaktowy"
+ },
+ "copyAddress": {
+ "message": "Skopiuj adres do schowka"
+ },
+ "copyToClipboard": {
+ "message": "Skopiuj do schowka"
+ },
+ "copyButton": {
+ "message": " Skopiuj "
+ },
+ "copyPrivateKey": {
+ "message": "To jest Twój prywatny klucz (kliknij żeby skopiować)"
+ },
+ "create": {
+ "message": "Utwórz"
+ },
+ "createAccount": {
+ "message": "Utwórz konto"
+ },
+ "createDen": {
+ "message": "Utwórz"
+ },
+ "crypto": {
+ "message": "Krypto",
+ "description": "Tym platformy wymiany (kryptowaluty)"
+ },
+ "currentConversion": {
+ "message": "Obecny kurs"
+ },
+ "currentNetwork": {
+ "message": "Bieżąca sieć"
+ },
+ "customGas": {
+ "message": "Ustaw gaz"
+ },
+ "customToken": {
+ "message": "Własny token"
+ },
+ "customize": {
+ "message": "Ustaw"
+ },
+ "customRPC": {
+ "message": "Własne RPC"
+ },
+ "decimalsMustZerotoTen": {
+ "message": "Liczb po przecinku musi być co najmniej 0 i nie więcej niż 36."
+ },
+ "decimal": {
+ "message": "Dokładność liczb po przecinku"
+ },
+ "defaultNetwork": {
+ "message": "Domyślna sieć dla Eteru to Main Net."
+ },
+ "denExplainer": {
+ "message": "Twój DEN to chroniony hasłem schowek w MetaMasku."
+ },
+ "deposit": {
+ "message": "Zdeponuj"
+ },
+ "depositBTC": {
+ "message": "Zdeponuj swoje BTC na poniższy adres:"
+ },
+ "depositCoin": {
+ "message": "Zdeponuj $1 na poniższy adres",
+ "description": "Pokazuje użytkownikowi jakie waluty wybrał do zdeponowania w ShapeShift"
+ },
+ "depositEth": {
+ "message": "Zdeponuj Eth"
+ },
+ "depositEther": {
+ "message": "Zdeponuj Eter"
+ },
+ "depositFiat": {
+ "message": "Zdeponuj w Fiat"
+ },
+ "depositFromAccount": {
+ "message": "Zdeponuj z innego konta"
+ },
+ "depositShapeShift": {
+ "message": "Zdeponuj przez ShapeShift"
+ },
+ "depositShapeShiftExplainer": {
+ "message": "Jeśli posiadasz inne kryptowaluty, możesz nimi handlować i deponować Eter bezpośrednio do swojego portfela MetaMask. Nie trzeba żadnego konta."
+ },
+ "details": {
+ "message": "Szczegóły"
+ },
+ "directDeposit": {
+ "message": "Bezpośredni depozyt"
+ },
+ "directDepositEther": {
+ "message": "Zdeponuj Eter bezpośrednio"
+ },
+ "directDepositEtherExplainer": {
+ "message": "Jeśli już masz Eter, najszybciej umieścisz go w swoim nowym portfelu przy pomocy bezpośredniego depozytu."
+ },
+ "done": {
+ "message": "Gotowe"
+ },
+ "downloadGoogleChrome": {
+ "message": "Ściągnij Google Chrome"
+ },
+ "downloadStateLogs": {
+ "message": "Załaduj logi stanów"
+ },
+ "dontHaveAHardwareWallet": {
+ "message": "Nie masz portfela sprzętowego?"
+ },
+ "dropped": {
+ "message": "Odrzucone"
+ },
+ "edit": {
+ "message": "Edytuj"
+ },
+ "editAccountName": {
+ "message": "Edytuj nazwę konta"
+ },
+ "editingTransaction": {
+ "message": "Dokonaj zmian w swojej transakcji"
+ },
+ "emailUs": {
+ "message": "Napisz do nas!"
+ },
+ "encryptNewDen": {
+ "message": "Zaszyfruj swój nowy DEN"
+ },
+ "ensNameNotFound": {
+ "message": "Nie znaleziono nazwy ENS"
+ },
+ "enterPassword": {
+ "message": "Wpisz hasło"
+ },
+ "enterPasswordConfirm": {
+ "message": "Wpisz hasło żeby potwierdzić"
+ },
+ "enterPasswordContinue": {
+ "message": "Podaj hasło żeby kontynuować"
+ },
+ "parameters": {
+ "message": "Parametry"
+ },
+ "passwordNotLongEnough": {
+ "message": "Hasło jest za krótkie"
+ },
+ "passwordsDontMatch": {
+ "message": "Hasła są niezgodne"
+ },
+ "etherscanView": {
+ "message": "Zobacz konto na Etherscan"
+ },
+ "exchangeRate": {
+ "message": "Kurs wymiany"
+ },
+ "exportPrivateKey": {
+ "message": "Eksportuj klucz prywatny"
+ },
+ "exportPrivateKeyWarning": {
+ "message": "Eksportujesz prywatne klucze na własne ryzyko."
+ },
+ "failed": {
+ "message": "Nie udało się"
+ },
+ "fiat": {
+ "message": "FIAT",
+ "description": "Rodzaj wymiany"
+ },
+ "fileImportFail": {
+ "message": "Importowanie pliku nie działa? Kliknij tutaj!",
+ "description": "Wspomaga użytkowników przy importowaniu ich konta z pliku JSON"
+ },
+ "followTwitter": {
+ "message": "Śledź nas na Twitterze"
+ },
+ "forgetDevice": {
+ "message": "Usuń to urządzenie."
+ },
+ "from": {
+ "message": "Z"
+ },
+ "fromToSame": {
+ "message": "Adresy Z i Do nie mogą być identyczne"
+ },
+ "fromShapeShift": {
+ "message": "Z ShapeShift"
+ },
+ "functionType": {
+ "message": "Typ funkcji"
+ },
+ "gas": {
+ "message": "Gaz",
+ "description": "Krótkie oznaczenie kosztu gazu"
+ },
+ "gasFee": {
+ "message": "Opłata za gaz"
+ },
+ "gasLimit": {
+ "message": "Limit gazu"
+ },
+ "gasLimitCalculation": {
+ "message": "Obliczamy sugerowany limit gazu na podstawie danych z transakcji w sieci."
+ },
+ "gasLimitRequired": {
+ "message": "Limit gazu jest wymagany"
+ },
+ "gasLimitTooLow": {
+ "message": "Limit gazu musi wynosić co najmniej 21000"
+ },
+ "generatingSeed": {
+ "message": "Generowanie seed..."
+ },
+ "gasPrice": {
+ "message": "Cena gazu (GWEI)"
+ },
+ "gasPriceCalculation": {
+ "message": "Obliczamy ceny gazu na podstawie danych z transakcji w sieci."
+ },
+ "gasPriceRequired": {
+ "message": "Wymagana cena gazu"
+ },
+ "generatingTransaction": {
+ "message": "Generowanie transakcji"
+ },
+ "getEther": {
+ "message": "Zdobądź Eter"
+ },
+ "getEtherFromFaucet": {
+ "message": "Zdobądź Eter ze źródła za $1",
+ "description": "Wyświetla nazwę sieci dla źródła Eteru"
+ },
+ "getHelp": {
+ "message": "Po pomoc."
+ },
+ "greaterThanMin": {
+ "message": "musi być większe lub równe $1.",
+ "description": "pomoc przy wpisywaniu hex jako dane dziesiętne"
+ },
+ "hardware": {
+ "message": "sprzęt"
+ },
+ "hardwareWalletConnected": {
+ "message": "Podłączono sprzętowy portfel"
+ },
+ "hardwareWallets": {
+ "message": "Podłącz sprzętowy portfel"
+ },
+ "hardwareWalletsMsg": {
+ "message": "Wybierz portfel sprzętowy, którego chcesz użyć z MetaMaskiem"
+ },
+ "havingTroubleConnecting": {
+ "message": "Problem z połączeniem?"
+ },
+ "here": {
+ "message": "tutaj",
+ "description": "jak w -kliknij tutaj- po więcej informacji (połączone z troubleTokenBalances)"
+ },
+ "hereList": {
+ "message": "Oto lista!!!"
+ },
+ "hexData": {
+ "message": "Dane Hex"
+ },
+ "hide": {
+ "message": "Schowaj"
+ },
+ "hideToken": {
+ "message": "Schowaj token"
+ },
+ "hideTokenPrompt": {
+ "message": "Schować token?"
+ },
+ "history": {
+ "message": "Historia"
+ },
+ "howToDeposit": {
+ "message": "Jak chcesz zdeponować Eter?"
+ },
+ "holdEther": {
+ "message": "Umożliwia przechowywanie eteru i tokenów oraz służy jako łącznik do zdecentralizowanych aplikacji."
+ },
+ "import": {
+ "message": "Importuj",
+ "description": "Przycisk do importowania konta z wybranego pliku."
+ },
+ "importAccount": {
+ "message": "Importuj konto"
+ },
+ "importAccountMsg": {
+ "message": " Importowane konta nie będą powiązane z Twoją pierwotną frazą seed MetaMask. Dowiedz się więcej o importowaniu kont "
+ },
+ "importAnAccount": {
+ "message": "Importuj konto"
+ },
+ "importDen": {
+ "message": "Importuj istniejące DEN"
+ },
+ "imported": {
+ "message": "Zaimportowane",
+ "description": "status pokazujący, że konto zostało w pełni załadowane na keyring"
+ },
+ "importUsingSeed": {
+ "message": "Importuj przy pomocy frazy seed konta"
+ },
+ "infoHelp": {
+ "message": "Info & pomoc"
+ },
+ "initialTransactionConfirmed": {
+ "message": "Twoja transakcja została potwierdzona w sieci. Kliknij OK żeby wrócić."
+ },
+ "insufficientFunds": {
+ "message": "Niewystarczające środki."
+ },
+ "insufficientTokens": {
+ "message": "Niewystarczająca liczba tokenów."
+ },
+ "invalidAddress": {
+ "message": "Nieprawidłowy adres"
+ },
+ "invalidAddressRecipient": {
+ "message": "Nieprawidłowy adres odbiorcy"
+ },
+ "invalidGasParams": {
+ "message": "Nieprawidłowe parametry gazu"
+ },
+ "invalidInput": {
+ "message": "Nieprawidłowe dane."
+ },
+ "invalidRequest": {
+ "message": "Nieprawidłowe zapytanie"
+ },
+ "invalidRPC": {
+ "message": "Nieprawidłowe RPC URI"
+ },
+ "invalidSeedPhrase": {
+ "message": "Nieprawidłowa fraza seed"
+ },
+ "jsonFail": {
+ "message": "Coś poszło nie tak. Upewnij się, że plik JSON jest prawidłowo sformatowany."
+ },
+ "jsonFile": {
+ "message": "Plik JSON",
+ "description": "formatuj do importowania konta"
+ },
+ "keepTrackTokens": {
+ "message": "Monitoruj stan tokenów kupionych przy pomocy konta MetaMask."
+ },
+ "kovan": {
+ "message": "Sieć testowa Kovan"
+ },
+ "knowledgeDataBase": {
+ "message": "Sprawdź naszą Bazę wiedzy."
+ },
+ "max": {
+ "message": "Maks."
+ },
+ "learnMore": {
+ "message": "Dowiedz się więcej"
+ },
+ "ledgerAccountRestriction": {
+ "message": "Musisz użyć swojego poprzedniego konta zanim dodasz kolejne."
+ },
+ "lessThanMax": {
+ "message": "musi być mniejsze lub równe $1.",
+ "description": "pomoc przy wpisywaniu hex jako dane dziesiętne"
+ },
+ "likeToAddTokens": {
+ "message": "Czy chcesz dodać te tokeny?"
+ },
+ "links": {
+ "message": "Łącza"
+ },
+ "limit": {
+ "message": "Limit"
+ },
+ "loading": {
+ "message": "Ładowanie..."
+ },
+ "loadingTokens": {
+ "message": "Ładowanie tokenów..."
+ },
+ "localhost": {
+ "message": "Serwer lokalny 8545"
+ },
+ "login": {
+ "message": "Zaloguj się"
+ },
+ "logout": {
+ "message": "Wyloguj się"
+ },
+ "loose": {
+ "message": "Porzuć"
+ },
+ "loweCaseWords": {
+ "message": "słowa seed mogą być pisane wyłącznie małymi literami"
+ },
+ "mainnet": {
+ "message": "Główna sieć Ethereum"
+ },
+ "menu": {
+ "message": "Menu"
+ },
+ "message": {
+ "message": "Wiadomość"
+ },
+ "metamaskDescription": {
+ "message": "MetaMask to bezpieczny portfel dla Ethereum."
+ },
+ "metamaskSeedWords": {
+ "message": "Słowa Seed MetaMask"
+ },
+ "min": {
+ "message": "Minimum"
+ },
+ "myAccounts": {
+ "message": "Moje konta"
+ },
+ "mustSelectOne": {
+ "message": "Należy wybrać co najmniej 1 token."
+ },
+ "needEtherInWallet": {
+ "message": "Żeby skorzystać ze zdecentraliowanych aplikacji (dApps) przy pomocy MetaMask, potrzebujesz Eteru w swoim portfelu."
+ },
+ "needImportFile": {
+ "message": "Musisz wybrać plik do zaimportowania.",
+ "description": "Użytkownik importuje konto i musi dodać plik, żeby kontynuować"
+ },
+ "needImportPassword": {
+ "message": "Musisz podać hasło dla wybranego pliku.",
+ "description": "Hasło i plik niezbędne do zaimportowania konta"
+ },
+ "negativeETH": {
+ "message": "Nie można wysłać ujemnych ilości ETH."
+ },
+ "networks": {
+ "message": "Sieci"
+ },
+ "nevermind": {
+ "message": "Nie ważne"
+ },
+ "newAccount": {
+ "message": "Nowe konto"
+ },
+ "newAccountNumberName": {
+ "message": "Konto $1",
+ "description": "Automatyczna nazwa kolejnego konta utworzonego w widoku Utwórz konto"
+ },
+ "newContract": {
+ "message": "Nowy kontrakt"
+ },
+ "newPassword": {
+ "message": "Nowe hasło (min. 8 znaków)"
+ },
+ "newRecipient": {
+ "message": "Nowy odbiorca"
+ },
+ "newRPC": {
+ "message": "Nowy RPC URL"
+ },
+ "next": {
+ "message": "Dalej"
+ },
+ "noAddressForName": {
+ "message": "Nie wybrano żadnego adresu dla tej nazwy."
+ },
+ "noDeposits": {
+ "message": "Brak otrzymanych depozytów"
+ },
+ "noConversionRateAvailable": {
+ "message": "Brak kursu waluty"
+ },
+ "noTransactionHistory": {
+ "message": "Brak historii transakcji."
+ },
+ "noTransactions": {
+ "message": "Nie ma transakcji"
+ },
+ "notFound": {
+ "message": "Nie znaleziono"
+ },
+ "notStarted": {
+ "message": "Nie rozpoczęto"
+ },
+ "noWebcamFoundTitle": {
+ "message": "Nie znaleziono kamery"
+ },
+ "noWebcamFound": {
+ "message": "Twoja kamera nie została znaleziona. Spróbuj ponownie."
+ },
+ "oldUI": {
+ "message": "Stary interfejs"
+ },
+ "oldUIMessage": {
+ "message": "Wróciłeś do starego interfejsu. Możesz włączyć nowy interfejs przez opcje w rozwijanym menu w prawym górnym rogu."
+ },
+ "openInTab": {
+ "message": "Otwórz w zakładce"
+ },
+ "or": {
+ "message": "lub",
+ "description": "wybór między tworzeniem i importowaniem nowego konta"
+ },
+ "origin": {
+ "message": "Pochodzenie"
+ },
+ "password": {
+ "message": "Hasło"
+ },
+ "passwordCorrect": {
+ "message": "Upewnij się, że Twoje hasło jest poprawne."
+ },
+ "passwordMismatch": {
+ "message": "hasła nie są takie same",
+ "description": "podczas tworzenia hasła, tekst w dwóch polach haseł nie był taki sam"
+ },
+ "passwordShort": {
+ "message": "hasło za krótkie",
+ "description": "podczas tworzenia hasła, hasło nie jest bezpieczne, ponieważ nie jest wystarczająco długie"
+ },
+ "pastePrivateKey": {
+ "message": "Tutaj wklej swój prywatny klucz:",
+ "description": "Do importowania konta z prywatnego klucza"
+ },
+ "pasteSeed": {
+ "message": "Tutaj wklej swoją frazę seed!"
+ },
+ "pending": {
+ "message": "oczekiwanie"
+ },
+ "personalAddressDetected": {
+ "message": "Wykryto osobisty adres. Wprowadź adres kontraktu tokenów."
+ },
+ "pleaseReviewTransaction": {
+ "message": "Proszę, sprawdź transakcję."
+ },
+ "popularTokens": {
+ "message": "Popularne tokeny"
+ },
+ "prev": {
+ "message": "Poprzednie"
+ },
+ "privacyMsg": {
+ "message": "Polityka prywatności"
+ },
+ "privateKey": {
+ "message": "Klucz prywatny",
+ "description": "wybierz ten typ pliku żeby importować konto"
+ },
+ "privateKeyWarning": {
+ "message": "Uwaga: Nie ujawniaj nikomu tego klucza. Ktokolwiek posiadający Twoje prywatne klucze może użyć środków znajdujących się na Twoim koncie."
+ },
+ "privateNetwork": {
+ "message": "Sieć prywatna"
+ },
+ "qrCode": {
+ "message": "Pokaż kod QR"
+ },
+ "queue": {
+ "message": "Kolejka"
+ },
+ "readdToken": {
+ "message": "Możesz później ponownie dodać ten token poprzez \"Dodaj token\" w opcjach menu swojego konta."
+ },
+ "readMore": {
+ "message": "Dowiedz się więcej tutaj."
+ },
+ "readMore2": {
+ "message": "Dowiedz się więcej."
+ },
+ "receive": {
+ "message": "Otrzymaj"
+ },
+ "recipientAddress": {
+ "message": "Adres odbiorcy"
+ },
+ "refundAddress": {
+ "message": "Twój adres na zwroty"
+ },
+ "rejected": {
+ "message": "Odrzucone"
+ },
+ "reset": {
+ "message": "Reset"
+ },
+ "resetAccount": {
+ "message": "Resetuj konto"
+ },
+ "resetAccountDescription": {
+ "message": "Zresetowanie konta wyczyści Twoją historię transakcji."
+ },
+ "restoreFromSeed": {
+ "message": "Przywrócić konto?"
+ },
+ "restoreVault": {
+ "message": "Przywróć schowek"
+ },
+ "restoreAccountWithSeed": {
+ "message": "Przywróć konto frazą seed"
+ },
+ "required": {
+ "message": "Wymagane"
+ },
+ "retryWithMoreGas": {
+ "message": "Spróbuj ponownie z większą ceną gazu"
+ },
+ "walletSeed": {
+ "message": "Seed portfela"
+ },
+ "restore": {
+ "message": "Przywróć"
+ },
+ "revealSeedWords": {
+ "message": "Pokaż słowa seed"
+ },
+ "revealSeedWordsTitle": {
+ "message": "Fraza seed"
+ },
+ "revealSeedWordsDescription": {
+ "message": "Jeśli kiedyś zmienisz przeglądarkę lub komputer, będziesz potrzebować tej frazy seed, żeby dostać się do swoich kont. Zapisz ją w bezpiecznym miejscu."
+ },
+ "revealSeedWordsWarningTitle": {
+ "message": "NIE pokazuj tej frazy nikomu!"
+ },
+ "revealSeedWordsWarning": {
+ "message": "Te słowa mogą być użyte żeby ukraść Twoje konta."
+ },
+ "revert": {
+ "message": "Wycofaj"
+ },
+ "remove": {
+ "message": "usuń"
+ },
+ "removeAccount": {
+ "message": "Usuń konto"
+ },
+ "removeAccountDescription": {
+ "message": "To konto będzie usunięte z Twojego portfela. Zanim przejdziesz dalej, upewnij się, że masz frazę seed i klucz prywatny do tego importowanego konta. Możesz później importować lub utworzyć nowe konta z rozwijanego menu kont. "
+ },
+ "readyToConnect": {
+ "message": "Gotowy na połączenie?"
+ },
+ "rinkeby": {
+ "message": "Sieć testowa Rinkeby"
+ },
+ "ropsten": {
+ "message": "Sieć testowa Ropsten"
+ },
+ "rpc": {
+ "message": "Indywidualne RPC"
+ },
+ "currentRpc": {
+ "message": "Obecne RPC"
+ },
+ "connectingToMainnet": {
+ "message": "Łączenie z główną siecią Ethereum"
+ },
+ "connectingToRopsten": {
+ "message": "Łączenie z siecią testową Ropsten"
+ },
+ "connectingToKovan": {
+ "message": "Łączenie z siecią testową Kovan"
+ },
+ "connectingToRinkeby": {
+ "message": "Łączenie z siecią testową Rinkeby"
+ },
+ "connectingToUnknown": {
+ "message": "Łączenie z nieznaną siecią"
+ },
+ "sampleAccountName": {
+ "message": "Np. Moje nowe konto",
+ "description": "Umożliwia użytkownikom zrozumieć ideę dodawania własnej nazwy to ich konta"
+ },
+ "save": {
+ "message": "Zapisz"
+ },
+ "speedUpTitle": {
+ "message": "Przyspiesz transakcję"
+ },
+ "speedUpSubtitle": {
+ "message": "Zwiększ cenę gazu żeby nadpisać i przyspieszyć transakcję"
+ },
+ "saveAsCsvFile": {
+ "message": "Zapisz jako plik CSV"
+ },
+ "saveAsFile": {
+ "message": "Zapisz jako",
+ "description": "Proces eksportu konta"
+ },
+ "saveSeedAsFile": {
+ "message": "Zapisz słowa seed jako plik"
+ },
+ "search": {
+ "message": "Szukaj"
+ },
+ "searchResults": {
+ "message": "Wyniki wyszukiwania"
+ },
+ "secretPhrase": {
+ "message": "Żeby otworzyć schowek, wpisz tutaj swoją frazę dwunastu słów."
+ },
+ "showHexData": {
+ "message": "Pokaż dane hex"
+ },
+ "showHexDataDescription": {
+ "message": "Wybierz to żeby pokazać pole danych hex na ekranie wysyłania"
+ },
+ "newPassword8Chars": {
+ "message": "Nowe hasło (min. 8 znaków)"
+ },
+ "seedPhraseReq": {
+ "message": "Frazy seed mają 12 słów"
+ },
+ "select": {
+ "message": "Wybierz"
+ },
+ "selectCurrency": {
+ "message": "Wybierz walutę"
+ },
+ "selectService": {
+ "message": "Wybierz usługę"
+ },
+ "selectType": {
+ "message": "Wybierz rodzaj"
+ },
+ "send": {
+ "message": "Wyślij"
+ },
+ "sendETH": {
+ "message": "Wyślij ETH"
+ },
+ "sendTokens": {
+ "message": "Wyślij tokeny"
+ },
+ "sentEther": {
+ "message": "wyślij eter"
+ },
+ "sentTokens": {
+ "message": "wysłane tokeny"
+ },
+ "separateEachWord": {
+ "message": "Oddziel słowa pojedynczą spacją"
+ },
+ "onlySendToEtherAddress": {
+ "message": "Na adres Ethereum wysyłaj tylko ETH."
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "Wyślij tylko $1 na adres konta Ethereum.",
+ "description": "wyświetla symbol tokena"
+ },
+ "orderOneHere": {
+ "message": "Zamów Trezor lub Ledger i trzymaj swoje środki w portfelu sprzętowym."
+ },
+ "outgoing": {
+ "message": "Wychodzące"
+ },
+ "searchTokens": {
+ "message": "Szukaj tokenów"
+ },
+ "selectAnAddress": {
+ "message": "Wybierz adres"
+ },
+ "selectAnAccount": {
+ "message": "Wybierz konto"
+ },
+ "selectAnAccountHelp": {
+ "message": "Wybierz konto do przeglądania w MetaMask"
+ },
+ "selectHdPath": {
+ "message": "Wybierz ścieżkę HD"
+ },
+ "selectPathHelp": {
+ "message": "Jeśli nie widzisz poniżej swoich kont Ledger, spróbuj przełączyć się na \"Legacy (MEW / MyCrypto)\""
+ },
+ "sendTokensAnywhere": {
+ "message": "Wyślij tokeny do kogoś z adresem Ethereum"
+ },
+ "settings": {
+ "message": "Ustawienia"
+ },
+ "step1HardwareWallet": {
+ "message": "1. Podłącz portfel sprzętowy"
+ },
+ "step1HardwareWalletMsg": {
+ "message": "Połącz swój portfel sprzętowy z komputerem."
+ },
+ "step2HardwareWallet": {
+ "message": "2. Wybierz konto"
+ },
+ "step2HardwareWalletMsg": {
+ "message": "Wybierz konto, które chcesz przeglądać. Możesz wybrać tylko jedno konto w danym momencie."
+ },
+ "step3HardwareWallet": {
+ "message": "3. Zacznij używać dystrybuowanych aplikacji (dApps) i wiele więcej!"
+ },
+ "step3HardwareWalletMsg": {
+ "message": "Używaj swojego konta sprzętowego tak, jak używasz jakiegokolwiek konta z Ethereum. Loguj się do dystrybuowanych aplikacji (dApps), wysyłaj Eth, kupuj i przechowaj tokeny ERC20 i niewymienne tokeny, jak np. CryptoKitties."
+ },
+ "info": {
+ "message": "Info"
+ },
+ "scanInstructions": {
+ "message": "Umieść kod QR na wprost kamery"
+ },
+ "scanQrCode": {
+ "message": "Skanuj kod QR"
+ },
+ "shapeshiftBuy": {
+ "message": "Kup w ShapeShift"
+ },
+ "showPrivateKeys": {
+ "message": "Pokaż prywatne klucze"
+ },
+ "showQRCode": {
+ "message": "Pokaż kod QR"
+ },
+ "sign": {
+ "message": "Podpisz"
+ },
+ "signatureRequest": {
+ "message": "Prośba o podpis"
+ },
+ "signed": {
+ "message": "Podpisane"
+ },
+ "signMessage": {
+ "message": "Podpisz wiadomość"
+ },
+ "signNotice": {
+ "message": "Podpisanie tej wiadomości może mieć \nniebezpieczne skutki uboczne. Podpisuj wiadomości \ntylko ze stron, którym chcesz udostępnić swoje konto.\nTa niebezpieczna metoda będzie usunięta w przyszłych wersjach. "
+ },
+ "sigRequest": {
+ "message": "Prośba o podpis"
+ },
+ "sigRequested": {
+ "message": "Podpis wymagany"
+ },
+ "spaceBetween": {
+ "message": "między słowami może być tylko pojedyncza spacja"
+ },
+ "status": {
+ "message": "Status"
+ },
+ "stateLogs": {
+ "message": "Logi stanów"
+ },
+ "stateLogsDescription": {
+ "message": "Logi stanów zawierają Twoje publiczne adresy kont i wykonanych transakcji."
+ },
+ "stateLogError": {
+ "message": "Błąd podczas pobierania logów stanów."
+ },
+ "submit": {
+ "message": "Wyślij"
+ },
+ "submitted": {
+ "message": "Wysłane"
+ },
+ "supportCenter": {
+ "message": "Odwiedź nasze Centrum Pomocy"
+ },
+ "symbolBetweenZeroTen": {
+ "message": "Symbol musi mieć od 0 do 10 znaków."
+ },
+ "takesTooLong": {
+ "message": "Trwa zbyt długo?"
+ },
+ "terms": {
+ "message": "Regulamin"
+ },
+ "testFaucet": {
+ "message": "Źródło testowego ETH"
+ },
+ "to": {
+ "message": "Do"
+ },
+ "toETHviaShapeShift": {
+ "message": "$1 na ETH przez ShapeShift",
+ "description": "system uzupełni typ depozytu na początku wiadomości"
+ },
+ "token": {
+ "message": "Token"
+ },
+ "tokenAddress": {
+ "message": "Adres tokena"
+ },
+ "tokenAlreadyAdded": {
+ "message": "Token jest już dodany."
+ },
+ "tokenBalance": {
+ "message": "Liczba Twoich tokenów:"
+ },
+ "tokenSelection": {
+ "message": "Szukaj tokenów lub wybierz z naszej listy popularnych tokenów."
+ },
+ "tokenSymbol": {
+ "message": "Symbol tokena"
+ },
+ "tokenWarning1": {
+ "message": "Monitoruj stan tokenów kupionych przy pomocy konta MetaMask. Jeśli masz tokeny kupione przy pomocy innych kont, nie pojawią się tutaj."
+ },
+ "total": {
+ "message": "Suma"
+ },
+ "transactions": {
+ "message": "transakcje"
+ },
+ "transactionError": {
+ "message": "Błąd transakcji. Wyjątek w kodzie kontraktu."
+ },
+ "transactionMemo": {
+ "message": "Memo transakcji (opcjonalnie)"
+ },
+ "transactionNumber": {
+ "message": "Numer transakcji"
+ },
+ "transfer": {
+ "message": "Przelew"
+ },
+ "transfers": {
+ "message": "Przelewy"
+ },
+ "trezorHardwareWallet": {
+ "message": "Sprzętowy portfel TREZOR"
+ },
+ "troubleTokenBalances": {
+ "message": "Wystąpił problem z załadowaniem informacji o Twoich tokenach. Można je zobaczyć ",
+ "description": "Z linkiem (tutaj) do informacji o stanie tokenów"
+ },
+ "tryAgain": {
+ "message": "Spróbuj ponownie"
+ },
+ "twelveWords": {
+ "message": "Tych 12 słów to jedyny sposób, żeby odzyskać konta w MetaMasku. Zapisz je w bezpiecznym miejscu."
+ },
+ "typePassword": {
+ "message": "Wpisz hasło"
+ },
+ "uiWelcome": {
+ "message": "Witamy w nowym interfejsie (Beta)"
+ },
+ "uiWelcomeMessage": {
+ "message": "Używasz teraz nowego interfejsu MetaMask."
+ },
+ "unapproved": {
+ "message": "Niezatwierdzone"
+ },
+ "unavailable": {
+ "message": "Niedostępne"
+ },
+ "unknown": {
+ "message": "Nieznane"
+ },
+ "unknownFunction": {
+ "message": "Nieznana funkcja"
+ },
+ "unknownNetwork": {
+ "message": "Nieznana sieć prywatna"
+ },
+ "unknownNetworkId": {
+ "message": "Nieznane sieciowe ID"
+ },
+ "unknownQrCode": {
+ "message": "Błąd: nie mogliśmy odczytać tego kodu QR"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "Ups! Coś poszło nie tak..."
+ },
+ "unknownCameraError": {
+ "message": "Podczas łączenia się z kamerą wystąpił błąd. Spróbuj ponownie..."
+ },
+ "unlock": {
+ "message": "Odblokuj"
+ },
+ "unlockMessage": {
+ "message": "Zdecentralizowana sieć oczekuje"
+ },
+ "uriErrorMsg": {
+ "message": "URI wymaga prawidłowego prefiksu HTTP/HTTPS."
+ },
+ "usaOnly": {
+ "message": "Tylko USA",
+ "description": "Ta platforma wymiany jest dostępna tylko dla osób mieszkających w USA"
+ },
+ "usedByClients": {
+ "message": "Używany przez różnych klientów"
+ },
+ "useOldUI": {
+ "message": "Przełącz na stary interfejs"
+ },
+ "validFileImport": {
+ "message": "Należy wybrać prawidłowy plik do zaimportowania."
+ },
+ "vaultCreated": {
+ "message": "Schowek utworzony"
+ },
+ "viewAccount": {
+ "message": "Zobacz konto"
+ },
+ "viewOnEtherscan": {
+ "message": "Zobacz na Etherscan"
+ },
+ "visitWebSite": {
+ "message": "Odwiedź naszą stronę"
+ },
+ "warning": {
+ "message": "Uwaga"
+ },
+ "welcomeBack": {
+ "message": "Witaj z powrotem!"
+ },
+ "welcomeBeta": {
+ "message": "Witaj w MetaMask Beta"
+ },
+ "whatsThis": {
+ "message": "Co to jest?"
+ },
+ "youNeedToAllowCameraAccess": {
+ "message": "Żeby użyć tej opcji należy podłączyć kamerę"
+ },
+ "yourSigRequested": {
+ "message": "Twój podpis jest wymagany"
+ },
+ "youSign": {
+ "message": "Podpisujesz"
+ },
+ "yourPrivateSeedPhrase": {
+ "message": "Twoja prywatna fraza seed"
+ }
+} \ No newline at end of file
diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json
index 6f0bb1584..287ae0400 100644
--- a/app/_locales/pt/messages.json
+++ b/app/_locales/pt/messages.json
@@ -173,7 +173,7 @@
},
"decimal": {
"message": "Precisão em Decimais"
- },
+ },
"defaultNetwork": {
"message": "A rede pré definida para transações em Ether é a Main Net."
},
@@ -351,7 +351,7 @@
"message": "Importar Conta"
},
"importAccountMsg": {
- "message":"Contas importadas não irão ser associadas com a frase seed da conta criada originalmente pelo MetaMask. Saiba mais sobre contas importadas."
+ "message": "Contas importadas não irão ser associadas com a frase seed da conta criada originalmente pelo MetaMask. Saiba mais sobre contas importadas."
},
"importAnAccount": {
"message": "Importar uma conta"
@@ -800,7 +800,7 @@
},
"visitWebSite": {
"message": "Visite o nosso site"
- },
+ },
"warning": {
"message": "Aviso"
},
diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json
index 6344e1beb..45bb09683 100644
--- a/app/_locales/ru/messages.json
+++ b/app/_locales/ru/messages.json
@@ -366,7 +366,7 @@
"message": "Импортировать счет"
},
"importAccountMsg": {
- "message":" Импортированные счета не будут ассоциированы с вашей ключевой фразой, созданной MetaMask. Узнать больше про импорт счетов "
+ "message": " Импортированные счета не будут ассоциированы с вашей ключевой фразой, созданной MetaMask. Узнать больше про импорт счетов "
},
"importAnAccount": {
"message": "Импортировать аккаунт"
diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json
index 25bd0bcbb..242cf66bf 100644
--- a/app/_locales/sl/messages.json
+++ b/app/_locales/sl/messages.json
@@ -1,6 +1,48 @@
{
+ "privacyMode": {
+ "message": "Način zasebnosti"
+ },
+ "privacyModeDescription": {
+ "message": "Spletne strani morajo zahtevati dostop za ogled podatkov o vašem računu."
+ },
+ "exposeAccounts": {
+ "message": "Razkrij račune"
+ },
+ "exposeDescription": {
+ "message": "Razkrij račune trenutni spletni strani. Priporočeno za starejše dApps."
+ },
+ "confirmExpose": {
+ "message": "Ste prepričani da želite razkriti račune trenutni spletni strani?"
+ },
+ "confirmClear": {
+ "message": "Ste prepričani da želite počistiti odobrene spletne strani?"
+ },
+ "clearApprovalDataSuccess": {
+ "message": "Odobrene spletne strani uspešno počiščene."
+ },
+ "approvalData": {
+ "message": "Zasebni podatki"
+ },
+ "approvalDataDescription": {
+ "message": "Počistite zasebne podatke, tako da bodo morale vse spletne strani ponovno zahtevati dovoljenje."
+ },
+ "clearApprovalData": {
+ "message": "Počisti zasebne podatke"
+ },
+ "providerAPIRequest": {
+ "message": "Zahteva za Ethereum API"
+ },
+ "reviewProviderRequest": {
+ "message": "Preglejte zahtevo za Ethereum API."
+ },
+ "providerRequestInfo": {
+ "message": "Domena zahteva dostop do verige blokov in ogled vašega računa. Pred potrditvjo vedno preverite ali ste na želeni spletni strani."
+ },
"accept": {
- "message": "Sprejmi"
+ "message": "Potrdi"
+ },
+ "accessingYourCamera": {
+ "message": "Dostopanje do vaše kamere ..."
},
"account": {
"message": "Račun"
@@ -11,6 +53,15 @@
"accountName": {
"message": "Ime računa"
},
+ "accountOptions": {
+ "message": "Možnosti računa"
+ },
+ "accountSelectionRequired": {
+ "message": "Izbrati morate račun!"
+ },
+ "activityLog": {
+ "message": "dnevnik dejavnosti"
+ },
"address": {
"message": "Naslov"
},
@@ -23,6 +74,12 @@
"addTokens": {
"message": "Dodaj žetone"
},
+ "addSuggestedTokens": {
+ "message": "Dodaj priporočene žetone"
+ },
+ "addAcquiredTokens": {
+ "message": "Dodaj žetone pridobljene z MetaMask"
+ },
"amount": {
"message": "Znesek"
},
@@ -37,9 +94,21 @@
"message": "MetaMask",
"description": "The name of the application"
},
+ "approve": {
+ "message": "Potrdi"
+ },
+ "approved": {
+ "message": "Potrjeno"
+ },
"attemptingConnect": {
"message": "Povezovanje z verigo blokov ..."
},
+ "attemptToCancel": {
+ "message": "Želite preklicati?"
+ },
+ "attemptToCancelDescription": {
+ "message": "Če pošljete ta poskus, ne boste zagotovili, da bo vaša prvotna transakcija preklicana. Če bo poskus preklica uspešen, se bo zaračunala zgornja transakcija."
+ },
"attributions": {
"message": "Dodelitve"
},
@@ -50,13 +119,13 @@
"message": "Nazaj"
},
"balance": {
- "message": "Znesek:"
+ "message": "Znesek"
},
"balances": {
- "message": "Vaš znesek"
+ "message": "Znesek žetonov"
},
"balanceIsInsufficientGas": {
- "message": "Napačen znesek za skupno gas vrednost"
+ "message": "Nezadnosten znesek za trenutni gas"
},
"beta": {
"message": "BETA"
@@ -66,13 +135,16 @@
"description": "helper for inputting hex as decimal input"
},
"blockiesIdenticon": {
- "message": "Uporabite Blockies Identicon"
+ "message": "Uporabi identifikacijo Blockies"
},
"borrowDharma": {
"message": "Izposoja z Dharma (Beta)"
},
+ "browserNotSupported": {
+ "message": "Vaš brskalnik ni podptrt ..."
+ },
"builtInCalifornia": {
- "message": "MetaMask je ustvarjen v Kaliforniji."
+ "message": "MetaMask je zasnovan in ustvarjen v Kaliforniji."
},
"buy": {
"message": "Kupi"
@@ -83,18 +155,45 @@
"buyCoinbaseExplainer": {
"message": "Coinbase je najpopularnejši načun za kupovanje in prodajo bitcoinov, ethereuma, in litecoina."
},
+ "bytes": {
+ "message": "Bajti"
+ },
+ "ok": {
+ "message": "V redu"
+ },
"cancel": {
"message": "Prekliči"
},
+ "cancelAttempt": {
+ "message": "Prekliči poskus"
+ },
+ "cancellationGasFee": {
+ "message": "Preklicani znesek gas"
+ },
+ "cancelN": {
+ "message": "Prekliči vseh $1 transakcij"
+ },
"classicInterface": {
- "message": "Uporabi navaden način"
+ "message": "Uporabi klasični vmesnik"
},
"clickCopy": {
"message": "Kliknite za kopiranje"
},
+ "clickToAdd": {
+ "message": "Kliknite na $1 za dodajo v vaš račun"
+ },
+ "close": {
+ "message": "Zapri"
+ },
+ "chromeRequiredForHardwareWallets": {
+ "message": "Za uporabo strojne denarnice potrebujete Google Chrome."
+ },
"confirm": {
"message": "Potrdi"
},
+ "confirmed": {
+ "message": "Potrjeno"
+ },
"confirmContract": {
"message": "Potrdi pogodbo"
},
@@ -104,6 +203,36 @@
"confirmTransaction": {
"message": "Potrdi transakcijo"
},
+ "connectHardwareWallet": {
+ "message": "Poveži strojno denarnico"
+ },
+ "connect": {
+ "message": "Poveži"
+ },
+ "connecting": {
+ "message": "Povezovanje ..."
+ },
+ "connectingToKovan": {
+ "message": "Povezovanje na testno omrežje Kovan"
+ },
+ "connectingToMainnet": {
+ "message": "Povezovanje na glavno omrežje"
+ },
+ "connectingToRopsten": {
+ "message": "Povezovanje na testno omrežje Ropsten"
+ },
+ "connectingToRinkeby": {
+ "message": "Povezovanje na testno omrežje Rinkeby"
+ },
+ "connectingToUnknown": {
+ "message": "Povezovanje na neznano omrežje"
+ },
+ "connectToLedger": {
+ "message": "Poveži z Ledger"
+ },
+ "connectToTrezor": {
+ "message": "Poveži z Trezor"
+ },
"continue": {
"message": "Nadaljuj"
},
@@ -114,23 +243,26 @@
"message": "Ustvarjanje pogodbe"
},
"conversionProgress": {
- "message": "Poteka pretvorba"
+ "message": "Pretvorba v teku"
},
"copiedButton": {
"message": "Kopirano"
},
"copiedClipboard": {
- "message": "Kopirano v odložišče"
+ "message": "Kopirano v odložišče!"
},
"copiedExclamation": {
"message": "Kopirano!"
},
"copiedSafe": {
- "message": "Prilepil sem ga na varno!"
+ "message": "Prilepil sem ga na varno"
},
"copy": {
"message": "Kopiraj"
},
+ "copyAddress": {
+ "message": "Kopiraj naslov v odložišče"
+ },
"copyToClipboard": {
"message": "Kopiraj v odložišče"
},
@@ -154,31 +286,40 @@
"description": "Exchange type (cryptocurrencies)"
},
"currentConversion": {
- "message": "Trenutna cena"
+ "message": "Trenutna pretvorba"
+ },
+ "currentLanguage": {
+ "message": "Trenutni jezik"
},
"currentNetwork": {
"message": "Trenutno omrežje"
},
+ "currentRpc": {
+ "message": "Trenutni RPC"
+ },
"customGas": {
"message": "Prilagodi gas"
},
+ "customToken": {
+ "message": "Žeton po meri"
+ },
"customize": {
"message": "Prilagodi"
},
"customRPC": {
- "message": "Poljuben RPC"
+ "message": "RPC po meri"
},
"decimalsMustZerotoTen": {
- "message": "Decimalk mora biti vsaj 0, in ne več kot 36."
+ "message": "Decimalk mora biti med 0 in 36."
},
"decimal": {
- "message": "Decimalke natančnosti"
- },
+ "message": "Decimalna natančnost"
+ },
"defaultNetwork": {
- "message": "Privzeto omrežje za transakcije je Main Net."
+ "message": "Privzeto omrežje za transkacije je glavno omrežje."
},
"denExplainer": {
- "message": "DEN je vaša šifrirana shramba v MetaMasku."
+ "message": "Vaš DEN je z geslom šifrirana shramba v MetaMask."
},
"deposit": {
"message": "Vplačaj"
@@ -187,14 +328,14 @@
"message": "Vplačajte vaš BTC na spodnji naslov:"
},
"depositCoin": {
- "message": "Vplačajte $1 na spodnji naslov",
+ "message": "Vplačajte vaš $1 na spodnji naslov",
"description": "Tells the user what coin they have selected to deposit with shapeshift"
},
"depositEth": {
"message": "Vplačilo ETH"
},
"depositEther": {
- "message": "Vplačilo ethera"
+ "message": "Vplačilo ethra"
},
"depositFiat": {
"message": "Vplačilo s klasičnimi valutami"
@@ -206,25 +347,34 @@
"message": "Vplačilo z ShapeShift"
},
"depositShapeShiftExplainer": {
- "message": "Če imate druge kriptovalute, lahko vpačate ether neposredno v MetaMask. Brez računov."
+ "message": "Če imate druge kriptovalute, lahko Ether vplačate neposredno v MetaMask. Brez računov."
},
"details": {
"message": "Podrobnosti"
},
"directDeposit": {
- "message": "Direktno vplačilo"
+ "message": "Neposredno vplačilo"
},
"directDepositEther": {
- "message": "Direktno vplačilo ehera"
+ "message": "Neposredno vplačilo ehera"
},
"directDepositEtherExplainer": {
- "message": "Če že imate ether, ga lahko najhitreje dobite v MetaMask z direktnim vplačilom."
+ "message": "Če že imate Ether, ga lahko najhitreje dobite v MetaMask z neposrednim vplačilom."
},
"done": {
"message": "Končano"
},
+ "downloadGoogleChrome": {
+ "message": "Prenesi Google Chrome"
+ },
"downloadStateLogs": {
- "message": "Prenesi state dnevnike"
+ "message": "Prenesi dnevnike state"
+ },
+ "dontHaveAHardwareWallet": {
+ "message": "Nimate strojne denarnice?"
+ },
+ "dropped": {
+ "message": "Izpusti"
},
"edit": {
"message": "Uredi"
@@ -232,62 +382,83 @@
"editAccountName": {
"message": "Uredi ime računa"
},
+ "editingTransaction": {
+ "message": "Uredite transakcijo"
+ },
"emailUs": {
"message": "Pišite nam!"
},
"encryptNewDen": {
- "message": "Šifrirajte DEN"
+ "message": "Šifrirajte vaš DEN"
+ },
+ "ensNameNotFound": {
+ "message": "Ime ENS ni najdeno"
},
"enterPassword": {
- "message": "Vpišite geslo"
+ "message": "Vnesite geslo"
},
"enterPasswordConfirm": {
"message": "Potrdite geslo"
},
+ "enterPasswordContinue": {
+ "message": "Za nadaljevanje vnesite geslo"
+ },
+ "eth": {
+ "message": "ETH"
+ },
"etherscanView": {
- "message": "Poglejte račun na Etherscan"
+ "message": "Poglej račun na Etherscan"
},
"exchangeRate": {
"message": "Menjalni tečaj"
},
+ "expandView": {
+ "message": "Razširi pogled"
+ },
"exportPrivateKey": {
"message": "Izvozi zasebni ključ"
},
"exportPrivateKeyWarning": {
- "message": "Izvažanje zasebnih ključev je na lastno odgovornost."
+ "message": "Izvoz zasebnega ključa na lastno odgovornost."
},
"failed": {
"message": "Ni uspelo"
},
"fiat": {
- "message": "FIAT",
+ "message": "Klasične",
"description": "Exchange type"
},
"fileImportFail": {
- "message": "Uvoz z datoteko ni uspel? Kliknite tukaj!",
+ "message": "Uvoz z datoteko ne deluje? Kliknite tukaj!",
"description": "Helps user import their account from a JSON file"
},
"followTwitter": {
"message": "Sledite nam na Twitterju"
},
+ "forgetDevice": {
+ "message": "Pozabi to napravo"
+ },
"from": {
"message": "Od"
},
"fromToSame": {
- "message": "From and To address cannot be the same"
+ "message": "Naslova pošiljatelja in prejemnika ne smeta biti enaka"
},
"fromShapeShift": {
"message": "Od ShapeShift"
},
+ "functionType": {
+ "message": "Vrsta funkcije"
+ },
"gas": {
"message": "Gas",
"description": "Short indication of gas cost"
},
"gasFee": {
- "message": "Gas fee"
+ "message": "Gas Fee"
},
"gasLimit": {
- "message": "Gas limit"
+ "message": "Gas Limit"
},
"gasLimitCalculation": {
"message": "Priporočen gas limit je izračunan glede na omrežje."
@@ -296,37 +467,64 @@
"message": "Gas limit je zahtevan"
},
"gasLimitTooLow": {
- "message": "Gas limit mora biti najmanj 21000"
+ "message": "Gas limit mora biti vsaj 21000"
+ },
+ "gasUsed": {
+ "message": "Uporabljen gas"
},
"generatingSeed": {
"message": "Ustvarjenje seed ..."
},
"gasPrice": {
- "message": "Gas price (GWEI)"
+ "message": "Gas Price (GWEI)"
},
"gasPriceCalculation": {
- "message": "Priporočen gas price je izračunan glede na omrežje"
+ "message": "Priporočen gas price je izračunan glede na omrežje."
},
"gasPriceRequired": {
"message": "Gas price je zahtevan"
},
+ "generatingTransaction": {
+ "message": "Ustvarjanje transakcije"
+ },
"getEther": {
- "message": "Pridobite ether"
+ "message": "Pridobi Ether"
},
"getEtherFromFaucet": {
- "message": "Pridobite ether iz fauceta za $1",
+ "message": "Pridobite Ether iz fauceta za $1",
"description": "Displays network name for Ether faucet"
},
+ "getHelp": {
+ "message": "Get Help."
+ },
"greaterThanMin": {
- "message": "mora biti višji ali enak $1.",
+ "message": "mora biti večji ali enak $1.",
"description": "helper for inputting hex as decimal input"
},
+ "hardware": {
+ "message": "strojna"
+ },
+ "hardwareWalletConnected": {
+ "message": "Strojna denarnica povezana"
+ },
+ "hardwareWallets": {
+ "message": "Poveži strojno denarnico"
+ },
+ "hardwareWalletsMsg": {
+ "message": "Izberite vrsto strojne denarnice"
+ },
+ "havingTroubleConnecting": {
+ "message": "Imate težave?"
+ },
"here": {
"message": "tukaj",
"description": "as in -click here- for more information (goes with troubleTokenBalances)"
},
"hereList": {
- "message": "Tukaj je seznam!!!"
+ "message": "Tukaj je seznam!!!!"
+ },
+ "hexData": {
+ "message": "Hex Data"
},
"hide": {
"message": "Skrij"
@@ -337,24 +535,27 @@
"hideTokenPrompt": {
"message": "Skrijem žeton?"
},
+ "history": {
+ "message": "Zgodovina"
+ },
"howToDeposit": {
- "message": "Kako želite vplačati ether?"
+ "message": "Kako želite vplačati Ether?"
},
"holdEther": {
- "message": "Omogoča vam, da imate eter in žetone in služi kot most za decentralizirane aplikacije."
+ "message": "Omogoča vam shranjevanje ethra in žetonov ter povezovanje decentraliziranih aplikacij."
},
"import": {
- "message": "Uvozi",
+ "message": "Uvoz",
"description": "Button to import an account from a selected file"
},
"importAccount": {
- "message": "Uvozi račun"
+ "message": "Uvoz računa"
},
"importAccountMsg": {
- "message":" Uvoženi računi ne bodo povezani s prvotnim seedphaseom. Preberite več o uvoženih računih "
+ "message": " Uvoženi računa ne bodo povezani s prvotnim seed phase. Preberite več o uvoženih računih "
},
"importAnAccount": {
- "message": "Uvozi račun"
+ "message": "IUvozi račun"
},
"importDen": {
"message": "Uvozi DEN"
@@ -363,9 +564,18 @@
"message": "Uvoženo",
"description": "status showing that an account has been fully loaded into the keyring"
},
+ "importUsingSeed": {
+ "message": "Uvozi z seed phase"
+ },
+ "info": {
+ "message": "Info"
+ },
"infoHelp": {
"message": "Info & Pomoč"
},
+ "initialTransactionConfirmed": {
+ "message": "Vaša prvotna transakcija je bila potrjena. Pritisnite V redu in se vrnite nazaj."
+ },
"insufficientFunds": {
"message": "Nezadostna sredstva."
},
@@ -373,45 +583,63 @@
"message": "Nezadostni žetoni."
},
"invalidAddress": {
- "message": "Nepravilen naslov"
+ "message": "Neveljaven naslov"
},
"invalidAddressRecipient": {
- "message": "Prejemnikov naslov je neveljaven"
+ "message": "Neveljaven nasklov prejemnika"
},
"invalidGasParams": {
- "message": "Nepravilno nastavljen gas"
+ "message": "Neveljavne gas nastavitve"
},
"invalidInput": {
- "message": "Napačen vnos."
+ "message": "Neveljaven vnos."
},
"invalidRequest": {
- "message": "Napačna zahteva"
+ "message": "Neveljavna zahteva"
},
"invalidRPC": {
- "message": "Napačen RPC URI"
+ "message": "Neveljaven RPC URL"
+ },
+ "invalidSeedPhrase": {
+ "message": "Neveljavna seed phrase"
},
"jsonFail": {
- "message": "Nekaj je bilo narobe. Prepričajte se, da je JSON datoteka pravilno oblikovana."
+ "message": "Nekaj je bilo narobe. Prepričajte se, da je datoteka JSON pravilno oblikovana."
},
"jsonFile": {
- "message": "JSON datoteka",
+ "message": "Datoteka JSON",
"description": "format for importing an account"
},
+ "keepTrackTokens": {
+ "message": "Sledite žetonom, ki ste jih pridobili z MetaMask."
+ },
"kovan": {
"message": "Testno omrežje Kovan"
},
"knowledgeDataBase": {
"message": "Obiščite našo pomoč"
},
+ "max": {
+ "message": "Max"
+ },
+ "learnMore": {
+ "message": "Preberite več"
+ },
+ "ledgerAccountRestriction": {
+ "message": "Za dodajanje novega računa morate uporabiti zadnji račun."
+ },
"lessThanMax": {
- "message": "mora biti večji ali enak $1.",
+ "message": "mora biti manjši ali enak $1.",
"description": "helper for inputting hex as decimal input"
},
"likeToAddTokens": {
"message": "Želite dodati te žetone?"
},
+ "links": {
+ "message": "Povezave"
+ },
"limit": {
- "message": "Omejitev"
+ "message": "Meja"
},
"loading": {
"message": "Nalaganje ..."
@@ -432,20 +660,32 @@
"message": "Loose"
},
"loweCaseWords": {
- "message": "seed words imajo lahko le male črke"
+ "message": "seed words lahko vsebujejo samo male črke"
},
"mainnet": {
"message": "Glavno omrežje"
},
+ "menu": {
+ "message": "Meni"
+ },
"message": {
"message": "Sporočilo"
},
"metamaskDescription": {
"message": "MetaMask je varen identitetni sklad za Ethereum."
},
+ "metamaskSeedWords": {
+ "message": "Seed Words"
+ },
+ "metamaskVersion": {
+ "message": "Različica"
+ },
"min": {
"message": "Najmanj"
},
+ "missingYourTokens": {
+ "message": "Ne vidite vaših žetonov?"
+ },
"myAccounts": {
"message": "Moji računi"
},
@@ -453,7 +693,7 @@
"message": "Izbran mora biti vsaj 1 žeton."
},
"needEtherInWallet": {
- "message": "Za interakcijo z decentraliziranimi aplikacijami, ki uporabljajo MetaMask, boste v svoji denarnici potrebovali eter."
+ "message": "Za interakcijo z decentraliziranimi aplikacijami boste v svoji denarnici potrebovali Eter."
},
"needImportFile": {
"message": "Za uvoz morate izbrati datoteko.",
@@ -464,11 +704,14 @@
"description": "Password and file needed to import an account"
},
"negativeETH": {
- "message": "Ni mogoče poslati negativne vsote ETH."
+ "message": "Negativnih zneskov ETH ni mogoče poslati."
},
"networks": {
"message": "Omrežja"
},
+ "nevermind": {
+ "message": "Pozabi"
+ },
"newAccount": {
"message": "Nov račun"
},
@@ -480,31 +723,64 @@
"message": "Nova pogodba"
},
"newPassword": {
- "message": "Novo geslo (min. 8. črk)"
+ "message": "Novo geslo (min 8 znakov)"
+ },
+ "newPassword8Chars": {
+ "message": "Novo geslo (min 8 znakov)"
},
"newRecipient": {
"message": "Nov prejemnik"
},
- "newRPC": {
+ "newNetwork": {
+ "message": "Novo omrežje"
+ },
+ "rpcURL": {
"message": "Nov RPC URL"
},
+ "showAdvancedOptions": {
+ "message": "Pokaži napredne možnosti"
+ },
+ "hideAdvancedOptions": {
+ "message": "Skrij napredne možnosti"
+ },
+ "optionalChainId": {
+ "message": "ChainID (nezahtevano)"
+ },
+ "optionalSymbol": {
+ "message": "Simbol (nezahtevano)"
+ },
+ "optionalNickname": {
+ "message": "Uporabniško ime (nezahtevano)"
+ },
"next": {
"message": "Naprej"
},
"noAddressForName": {
- "message": "Za to ime ni bil nastavljen noben naslov."
+ "message": "Za to ime ni naslovov."
},
"noDeposits": {
- "message": "Ni prejetih vplačil"
+ "message": "Prejetih ni nič vplačil"
+ },
+ "noConversionRateAvailable": {
+ "message": "Menjalni tečaj ni na voljo"
},
"noTransactionHistory": {
"message": "Ni zgodovine transakcij."
},
"noTransactions": {
- "message": "Ni transakcij"
+ "message": "Nimate transakcij"
+ },
+ "notFound": {
+ "message": "Ni najdeno"
},
"notStarted": {
- "message": "Ni se začelo"
+ "message": "Ni začeto"
+ },
+ "noWebcamFoundTitle": {
+ "message": "Spletna kamera ni najdena"
+ },
+ "noWebcamFound": {
+ "message": "Spletna kamera ni najdena. Poskusite znova kasneje."
},
"oldUI": {
"message": "Star UI"
@@ -512,43 +788,89 @@
"oldUIMessage": {
"message": "Vrnili ste se v star uporabniški vmesnik. V novega se lahko vrnete z možnostjo v spustnem meniju v zgornjem desnem kotu."
},
+ "onlySendToEtherAddress": {
+ "message": "Na Ethereum naslov pošljute samo ETH."
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "Na Ethereum naslov pošljute samo $1.",
+ "description": "displays token symbol"
+ },
+ "openInTab": {
+ "message": "Odpri v zavihku"
+ },
"or": {
"message": "ali",
"description": "choice between creating or importing a new account"
},
+ "orderOneHere": {
+ "message": "Naročite Trezor ali Ledger i n zavarujte svoje premoženje s strojno denarnico"
+ },
+ "origin": {
+ "message": "Izvor"
+ },
+ "outgoing": {
+ "message": "Odhodni"
+ },
+ "parameters": {
+ "message": "Parametri"
+ },
+ "password": {
+ "message": "Geslo"
+ },
"passwordCorrect": {
"message": "Prepričajte se, da je geslo pravilno."
},
+ "passwordsDontMatch": {
+ "message": "Gesli se ne ujemata"
+ },
"passwordMismatch": {
"message": "gesli se ne ujemata",
"description": "in password creation process, the two new password fields did not match"
},
+ "passwordNotLongEnough": {
+ "message": "Geslo ni dovolj dolgo"
+ },
"passwordShort": {
"message": "geslo ni dovolj dolgo",
"description": "in password creation process, the password is not long enough to be secure"
},
"pastePrivateKey": {
- "message": "Tukaj prilepite zasebni ključ:",
+ "message": "Tukaj prilepite vaš zasebni ključ:",
"description": "For importing an account from a private key"
},
"pasteSeed": {
- "message": "Tukaj prilepite seed phrase!"
+ "message": "Tukaj prilepite seed phase!"
+ },
+ "pending": {
+ "message": "v obdelavi"
},
"personalAddressDetected": {
- "message": "Osebni naslov je zaznan. Vnesite naslov žetona."
+ "message": "Zaznan je osebni naslov. Vnesite naslov pogodbe žetona."
},
"pleaseReviewTransaction": {
- "message": "Preglejte transakcijo."
+ "message": "Preglejte vašo transakcijo."
+ },
+ "popularTokens": {
+ "message": "Priljubljeni žetoni"
+ },
+ "prev": {
+ "message": "Prej"
+ },
+ "primaryCurrencySetting": {
+ "message": "Glavna valuta"
+ },
+ "primaryCurrencySettingDescription": {
+ "message": "Izberite Native za prikaz vrednosti v privzeti valuti verige (npr. ETH). Izberite Klasične za prikaz vrednosti v izbrani klasični valuti."
},
"privacyMsg": {
- "message": "Politika zasebnosti"
+ "message": "Zasebnost"
},
"privateKey": {
- "message": "Zasebni ključ",
+ "message": "Zasebni lljuč",
"description": "select this type of file to use to import an account"
},
"privateKeyWarning": {
- "message": "Opozorilo: Nikoli ne razkrijte tega ključa. Vsakdo s svojimi zasebnimi ključi lahko ukrade vse premoženje v računu."
+ "message": "Opozorilo: Nikoli ne razkrijte tega ključa. Kdorkoli lahko z njim ukrade vse vaše premoženje v računu."
},
"privateNetwork": {
"message": "Zasebno omrežje"
@@ -556,47 +878,98 @@
"qrCode": {
"message": "Prikaži QR kodo"
},
+ "queue": {
+ "message": "Čakalna vrsta"
+ },
"readdToken": {
- "message": "Ta žeton lahko dodate tudi v prihodnosti, tako da odprete možnost »Dodaj žeton« v meniju z računi."
+ "message": "Ta žeton lahko dodate tudi kasneje z uporabo gumba “Dodaj žeton” v možnostih vašega računa."
},
"readMore": {
- "message": "Preberite več."
+ "message": "Tukaj preberite več."
},
"readMore2": {
"message": "Preberite več."
},
"receive": {
- "message": "Prejmite"
+ "message": "Prejmi"
},
"recipientAddress": {
"message": "Prejemnikov naslov"
},
"refundAddress": {
- "message": "Vaš naslov za vračilo"
+ "message": "Naslov za vračilo."
+ },
+ "reject": {
+ "message": "Zavrni"
+ },
+ "rejectAll": {
+ "message": "Zavrni vse"
+ },
+ "rejectTxsN": {
+ "message": "Zavrni $1 transakcij"
+ },
+ "rejectTxsDescription": {
+ "message": "Zavrnili boste $1 transakcij."
},
"rejected": {
"message": "Zavrnjeno"
},
+ "reset": {
+ "message": "Ponastavi"
+ },
"resetAccount": {
"message": "Ponastavi račun"
},
+ "resetAccountDescription": {
+ "message": "Ponastavljanje računa bo izbrisalo zgodovino transakcij."
+ },
"restoreFromSeed": {
- "message": "Obnovi iz seed phrase"
+ "message": "Obnovim račun?"
+ },
+ "restoreVault": {
+ "message": "Obnovi shrambo"
+ },
+ "restoreAccountWithSeed": {
+ "message": "Obnovi račun z seed phrase"
},
"required": {
"message": "Zahtevano"
},
"retryWithMoreGas": {
- "message": "Poskusi z višjim gas price"
+ "message": "Poskusite z večjim gas price"
+ },
+ "restore": {
+ "message": "Obnovi"
},
"revealSeedWords": {
- "message": "Prikaži seed words"
+ "message": "Razkrij seed words"
+ },
+ "revealSeedWordsTitle": {
+ "message": "Seed Phrase"
+ },
+ "revealSeedWordsDescription": {
+ "message": "Če želite zamenjati brskalnik ali računalnik, potrebujete vaš seed phase za dostop do računa. Shranite ga na varno skrito mesto."
+ },
+ "revealSeedWordsWarningTitle": {
+ "message": "Tega ne delite z nikomer!"
},
"revealSeedWordsWarning": {
- "message": "Ne obnovite seed words na javnem mestu! Te besede se lahko uporabijo za krajo vseh vaših računov."
+ "message": "S temi besedami lahko kdorkoli ukrade vse vaše račune."
},
"revert": {
- "message": "Povrni"
+ "message": "Obnovi"
+ },
+ "remove": {
+ "message": "izbriši"
+ },
+ "removeAccount": {
+ "message": "Izbriši račun"
+ },
+ "removeAccountDescription": {
+ "message": "Ta račun bo izbrisan. Prepričajte se, da imate seed phase ali zasebni ključ tega računa, da ga boste lahko kasneje obnovili. "
+ },
+ "readyToConnect": {
+ "message": "Pripravljeni na povezovanje?"
},
"rinkeby": {
"message": "Testno omrežje Rinkeby"
@@ -604,13 +977,19 @@
"ropsten": {
"message": "Testno omrežje Ropsten"
},
+ "rpc": {
+ "message": "RPC po meri"
+ },
"sampleAccountName": {
- "message": "npr. Moj nov račun",
+ "message": "npr. Moj račun",
"description": "Help user understand concept of adding a human-readable name to their account"
},
"save": {
"message": "Shrani"
},
+ "saveAsCsvFile": {
+ "message": "Shrani kot CSV datoteko"
+ },
"saveAsFile": {
"message": "Shrani kot datoteko",
"description": "Account export process"
@@ -618,14 +997,23 @@
"saveSeedAsFile": {
"message": "Shrani seed words kot datoteko"
},
+ "scanInstructions": {
+ "message": "Postavite QR kodo pred vašo kamero"
+ },
+ "scanQrCode": {
+ "message": "Skeniraj QR kodo"
+ },
"search": {
"message": "Iskanje"
},
+ "searchResults": {
+ "message": "Rezultati iskanja"
+ },
"secretPhrase": {
- "message": "Tukaj vnesite svoje seed words, da obnovite svoje račune."
+ "message": "Vnesite vaših dvanajst besed za obnovitev vaših računov."
},
"seedPhraseReq": {
- "message": "seed phrases so dolgi 12 besed"
+ "message": "Seed phrase mora biti dolg 12 besed"
},
"select": {
"message": "Izberi"
@@ -633,6 +1021,9 @@
"selectCurrency": {
"message": "Izberi valuto"
},
+ "selectLocale": {
+ "message": "Izberi jezik"
+ },
"selectService": {
"message": "Izberi storitev"
},
@@ -648,24 +1039,63 @@
"sendTokens": {
"message": "Pošlji žetone"
},
+ "sentEther": {
+ "message": "poslani ether"
+ },
+ "sentTokens": {
+ "message": "poslani žetoni"
+ },
+ "separateEachWord": {
+ "message": "Vsako besedo ločite z enim presledkom"
+ },
+ "searchTokens": {
+ "message": "Iskanje žetonov"
+ },
+ "selectAnAddress": {
+ "message": "Izberi naslov"
+ },
+ "selectAnAccount": {
+ "message": "Izberi račun"
+ },
+ "selectAnAccountHelp": {
+ "message": "Izberi račun za prikaz v MetaMask"
+ },
+ "selectHdPath": {
+ "message": "Izberi HD Path"
+ },
+ "selectPathHelp": {
+ "message": "Če obstoječih Ledger ne vidite, poskusite izbrati \"Legacy (MEW / MyCrypto)\""
+ },
"sendTokensAnywhere": {
- "message": "Pošljite žetone vsem, ki imajo Ethereum račun"
+ "message": "Pošljite žetone komurkoli z Ethereum naslovom"
},
"settings": {
"message": "Nastavitve"
},
"shapeshiftBuy": {
- "message": "Kupite z Shapeshift"
+ "message": "Kupi z Shapeshift"
},
"showPrivateKeys": {
- "message": "Prikaži zasebne ključe"
+ "message": "Pokaži zasebni ključ"
},
"showQRCode": {
- "message": "Prikaži QR kodo"
+ "message": "Pokaži QR kodo"
+ },
+ "showHexData": {
+ "message": "Pokaži Hex Data"
+ },
+ "showHexDataDescription": {
+ "message": "Izberite za prikaz hex podatkov na zaslonu za pošiljanje"
},
"sign": {
"message": "Podpiši"
},
+ "signatureRequest": {
+ "message": "Zahteva za podpis"
+ },
+ "signed": {
+ "message": "Podpisano"
+ },
"signMessage": {
"message": "Podpiši sporočilo"
},
@@ -676,11 +1106,20 @@
"message": "Zahteva za podpis"
},
"sigRequested": {
- "message": "Podpis je zahtevan"
+ "message": "Podpis zahtevan"
},
"spaceBetween": {
"message": "med besedami je lahko samo presledek"
},
+ "speedUp": {
+ "message": "pospeši"
+ },
+ "speedUpTitle": {
+ "message": "Pospeši transakcijo"
+ },
+ "speedUpSubtitle": {
+ "message": "Povečajte gas prise za pospešitev transakcije"
+ },
"status": {
"message": "Status"
},
@@ -688,19 +1127,43 @@
"message": "State dnevniki"
},
"stateLogsDescription": {
- "message": "State dnevniki vsebujejo naslove vašega računa in poslane transakcije.."
+ "message": "State vsebujejo vaš javni nasklov in zgodovino transakcij."
+ },
+ "stateLogError": {
+ "message": "Napaka pri pridobivanju state dnevnikov."
+ },
+ "step1HardwareWallet": {
+ "message": "1. Povežite strojno denarnico"
+ },
+ "step1HardwareWalletMsg": {
+ "message": "Z računalnikom povežite strojno denarnico."
+ },
+ "step2HardwareWallet": {
+ "message": "2. Izberite račun"
+ },
+ "step2HardwareWalletMsg": {
+ "message": "Izberite račun, ki ga želute uporabiti. Trenutno lahko izberete le en račun na enkrat."
+ },
+ "step3HardwareWallet": {
+ "message": "3. Začnite uporabljati dApps in več!"
+ },
+ "step3HardwareWalletMsg": {
+ "message": "Uporabite strojno denarnico kot katerikoli drug Ethereum račun. Prijavite se v dApps, pošljite Ether in ERC20 žetone in žetone kot CryptoKitties."
},
"submit": {
"message": "Potrdi"
},
+ "submitted": {
+ "message": "Potrjeno"
+ },
"supportCenter": {
- "message": "Obiščite našo podporo"
+ "message": "Obiščite naše središče za podporo"
},
"symbolBetweenZeroTen": {
- "message": "Simbol mora biti dolg od 0 do 10 znakov."
+ "message": "Simbol mora imeti med 0 in 10 znakov."
},
"takesTooLong": {
- "message": "Traja predolgo?"
+ "message": "Trava predolgo?"
},
"terms": {
"message": "Pogoji uporabe"
@@ -715,79 +1178,151 @@
"message": "$1 v ETH prek ShapeShift",
"description": "system will fill in deposit type in start of message"
},
+ "token": {
+ "message": "Žeton"
+ },
"tokenAddress": {
"message": "Naslov žetona"
},
"tokenAlreadyAdded": {
- "message": "Žeton je že bil dodan."
+ "message": "Žeton je bil že dodan."
},
"tokenBalance": {
- "message": "Vaš znesek žetona:"
+ "message": "Vaš znesek žetonov je:"
},
"tokenSelection": {
- "message": "Poiščite žetone ali jih izberite z našega seznama priljubljenih žetonov."
+ "message": "Iščite žetone ali pa jih izberite iz seznama priljubljenih."
},
"tokenSymbol": {
"message": "Simbol žetona"
},
"tokenWarning1": {
- "message": "Spremljajte žetone, ki ste jih kupili s svojim MetaMask računom. Če ste kupili žetone z drugačnim računom, ti žetoni ne bodo prikazani tukaj."
+ "message": "Sledite žetonom, ki ste jih kupili z MetaMask metamask računom. Če ste jih kupili drugje, ne bodo prikazani tukaj."
},
"total": {
"message": "Skupno"
},
+ "transaction": {
+ "message": "transakcija"
+ },
+ "transactionConfirmed": {
+ "message": "Transakcija potrjena na $2."
+ },
+ "transactionCreated": {
+ "message": "Transakcija z vrednostjo $1 ustvarjena na $2."
+ },
+ "transactionWithNonce": {
+ "message": "Transakcija $1"
+ },
+ "transactionDropped": {
+ "message": "Transakcija na $2 preklicana."
+ },
+ "transactionSubmitted": {
+ "message": "Transakcija na $2 oddana."
+ },
+ "transactionUpdated": {
+ "message": "Transakcija na $2 spremenjena."
+ },
+ "transactionUpdatedGas": {
+ "message": "Transakcija spremenjena z gas price $1 na $2."
+ },
+ "transactionErrored": {
+ "message": "Napaka pri transakciji."
+ },
"transactions": {
"message": "transakcije"
},
+ "transactionError": {
+ "message": "Napaka pri transakciji. Izjema sprožena v kodi pogodbe."
+ },
"transactionMemo": {
- "message": "Opis transakcije (ni zahtevano)"
+ "message": "Opomba transakcije (nezahtevano)"
},
"transactionNumber": {
"message": "Številka transakcije"
},
+ "transfer": {
+ "message": "Prenesi"
+ },
+ "transferFrom": {
+ "message": "Prenesi od"
+ },
"transfers": {
"message": "Prenosi"
},
+ "trezorHardwareWallet": {
+ "message": "Strojna denarnica TREZOR"
+ },
"troubleTokenBalances": {
- "message": "Imeli smo težave pri nalaganju vaših žetonov. Ogledate si jih lahko ",
+ "message": "Če imate težave pri ogledu zneskov žetonov si jih lahko ogledate ",
"description": "Followed by a link (here) to view token balances"
},
+ "tryAgain": {
+ "message": "Poskusi znova"
+ },
"twelveWords": {
"message": "Edini način za obnovitev MetaMask računa, je teh 12 besed.\nShranite jih na varno in skrivno mesto."
},
"typePassword": {
- "message": "Vpišite vaše geslo"
+ "message": "Vnesite vaše MetaMask geslo"
},
"uiWelcome": {
"message": "Dobrodošli v nov UI (Beta)"
},
"uiWelcomeMessage": {
- "message": "Zdaj uporabljate novi MetaMask uporabniški vmesnik. Razglejte se, preizkusite nove funkcije, kot so pošiljanje žetonov, in nas obvestite, če imate kakšne težave."
+ "message": "Uporabljate nov uporabniški vmesnik."
+ },
+ "unapproved": {
+ "message": "Neodobreno"
},
"unavailable": {
"message": "Ni na voljo"
},
+ "units": {
+ "message": "enote"
+ },
"unknown": {
"message": "Neznano"
},
+ "unknownFunction": {
+ "message": "Neznana funkcija"
+ },
"unknownNetwork": {
"message": "Neznano zasebno omrežje"
},
"unknownNetworkId": {
"message": "Neznan ID omrežja"
},
+ "unknownQrCode": {
+ "message": "Napaka: Te QR kode ni bilo mogoče prepoznati"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "Ooops! Nekaj je šlo narobe ...."
+ },
+ "unknownCameraError": {
+ "message": "Pri dostopanju do vaše kamere je prišlo do napake. Poskusite znova kasneje ..."
+ },
+ "unlock": {
+ "message": "Odkleni"
+ },
+ "unlockMessage": {
+ "message": "Decentralizirana spletna denarnica"
+ },
+ "updatedWithDate": {
+ "message": "Posodobljeno $1"
+ },
"uriErrorMsg": {
- "message": "URI-ji zahtevajo ustrezno HTTP/HTTPS predpono."
+ "message": "URI zahtevajo ustrezno HTTP/HTTPS predpono."
},
"usaOnly": {
"message": "Samo za ZDA",
"description": "Using this exchange is limited to people inside the USA"
},
"usedByClients": {
- "message": "Uporablja jih več različnih odjemalcev"
+ "message": "Uporabljen s strani večih različnih odjemalcev"
},
"useOldUI": {
- "message": "Uporabi star uporabniški vmesnik"
+ "message": "Uporabi star UI"
},
"validFileImport": {
"message": "Za uvoz morate izbrati pravilno datoteko."
@@ -798,22 +1333,40 @@
"viewAccount": {
"message": "Poglej račun"
},
+ "viewOnEtherscan": {
+ "message": "Poglej na Etherscan"
+ },
"visitWebSite": {
"message": "Obiščite našo spletno stran"
- },
+ },
+ "walletSeed": {
+ "message": "Wallet Seed"
+ },
"warning": {
"message": "Opozorilo"
},
+ "welcomeBack": {
+ "message": "Dobrodošli nazaj!"
+ },
"welcomeBeta": {
"message": "Dobrodošli v MetaMask Beta"
},
"whatsThis": {
"message": "Kaj je to?"
},
+ "yesLetsTry": {
+ "message": "Pa poskusimo"
+ },
+ "youNeedToAllowCameraAccess": {
+ "message": "Za uporabo te funkcije boste potrebovali dostop do kamere."
+ },
"yourSigRequested": {
- "message": "Vaš podpis je bil zahtevan"
+ "message": "Zahtevan je bil vaš podpis"
},
"youSign": {
- "message": "Podpisani ste"
+ "message": "Podpisali boste"
+ },
+ "yourPrivateSeedPhrase": {
+ "message": "Vaš zasebni seed phrase"
}
}
diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json
index c9aaa0394..a9f2f1022 100644
--- a/app/_locales/th/messages.json
+++ b/app/_locales/th/messages.json
@@ -351,7 +351,7 @@
"message": "นำเข้าบัญชี"
},
"importAccountMsg": {
- "message":"บัญชีที่นำเข้าจะไม่ถูกรวมกับบัญชีที่สร้างด้วยคำเเริ่มต้นบนเมต้ามาร์สในตอนแรก เรียนรู้เพิ่มเติมเกี่ยวกับบัญชีที่นำเข้า"
+ "message": "บัญชีที่นำเข้าจะไม่ถูกรวมกับบัญชีที่สร้างด้วยคำเเริ่มต้นบนเมต้ามาร์สในตอนแรก เรียนรู้เพิ่มเติมเกี่ยวกับบัญชีที่นำเข้า"
},
"importAnAccount": {
"message": "นำเข้าบัญชี"
diff --git a/app/_locales/tml/messages.json b/app/_locales/tml/messages.json
index 4f733458e..8dc242c10 100644
--- a/app/_locales/tml/messages.json
+++ b/app/_locales/tml/messages.json
@@ -372,7 +372,7 @@
"message": "கணக்கை இறக்குமதி செய்க"
},
"importAccountMsg": {
- "message":" இறக்குமதி செய்யப்பட்ட கணக்கு உங்கள் முதலில் உருவாக்கப்பட்ட மெட்டாமாஸ்க் கணக்கு விதை மூலம் தொடர்புடையதாக இருக்காது. இறக்குமதி செய்யப்பட்ட கணக்குகள் பற்றி மேலும் அறிக "
+ "message": " இறக்குமதி செய்யப்பட்ட கணக்கு உங்கள் முதலில் உருவாக்கப்பட்ட மெட்டாமாஸ்க் கணக்கு விதை மூலம் தொடர்புடையதாக இருக்காது. இறக்குமதி செய்யப்பட்ட கணக்குகள் பற்றி மேலும் அறிக "
},
"importAnAccount": {
"message": "ஒரு கணக்கை இறக்குமதி செய்க"
@@ -730,7 +730,7 @@
"message": "அமைப்புகள்"
},
"info": {
- "message": "தகவல்"
+ "message": "தகவல்"
},
"shapeshiftBuy": {
"message": "Shapeshift உடன் வாங்கவும்"
diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json
index 8be695108..0dac139dd 100644
--- a/app/_locales/tr/messages.json
+++ b/app/_locales/tr/messages.json
@@ -1,912 +1,912 @@
{
- "accept": {
- "message": "Kabul et"
- },
- "account": {
- "message": "Hesap"
- },
- "accountDetails": {
- "message": "Hesap Detayları"
- },
- "accountName": {
- "message": "Hesap İsmi"
- },
- "address": {
- "message": "Adres"
- },
- "addCustomToken": {
- "message": "Özel jeton ekle"
- },
- "addToken": {
- "message": "Jeton ekle"
- },
- "addTokens": {
- "message": "Jetonlar ekle"
- },
- "amount": {
- "message": "Tutar"
- },
- "amountPlusGas": {
- "message": "Tutar + Gas"
- },
- "appDescription": {
- "message": "Ethereum Tarayıcı Uzantısı",
- "description": "Uygulama açıklaması"
- },
- "appName": {
- "message": "MetaMask",
- "description": "Uygulama ismi"
- },
- "approved": {
- "message": "Onaylandı"
- },
- "attemptingConnect": {
- "message": "Blockchain'e bağlanmayı deniyor"
- },
- "attributions": {
- "message": "Atıflar"
- },
- "available": {
- "message": "Müsait"
- },
- "back": {
- "message": "Geri"
- },
- "balance": {
- "message": "Bakiye:"
- },
- "balances": {
- "message": "Jeton bakiyesi"
- },
- "balanceIsInsufficientGas": {
- "message": "Toplam gas için yetersiz bakiye"
- },
- "beta": {
- "message": "BETA"
- },
- "betweenMinAndMax": {
- "message": "$1'e eşit veya daha büyük olmalı ve $2'den küçük veya eşit olmalı",
- "description": "Onaltılık sayının ondalık sayı olarak girişi için yardımcı"
- },
- "blockiesIdenticon": {
- "message": "Blockies Identicon kullan"
- },
- "borrowDharma": {
- "message": "Dharma (Beta) ile ödünç al"
- },
- "builtInCalifornia": {
- "message": "MetaMask California'da tasarlandı ve yaratıldı"
- },
- "buy": {
- "message": "Satın al"
- },
- "buyCoinbase": {
- "message": "Coinbase'de satın al"
- },
- "buyCoinbaseExplainer": {
- "message": "Coinbase Bitcoin, Ethereum, and Litecoin alıp satmanın dünyadaki en popüler yolu"
- },
- "ok": {
- "message": "Tamam"
- },
- "cancel": {
- "message": "Vazgeç"
- },
- "classicInterface": {
- "message": "Klasik arayüzü kullan"
- },
- "clickCopy": {
- "message": "Kopyalamak için tıkla"
- },
- "confirm": {
- "message": "Onayla"
- },
- "confirmed": {
- "message": "Onaylandı"
- },
- "confirmContract": {
- "message": "Sözleşmeyi onayla"
- },
- "confirmPassword": {
- "message": "Şifreyi onayla"
- },
- "confirmTransaction": {
- "message": "İşlemi onayla"
- },
- "continue": {
- "message": "Devam et"
- },
- "continueToCoinbase": {
- "message": "Coinbase'e devam et"
- },
- "contractDeployment": {
- "message": "Sözleşme kurulumu"
- },
- "conversionProgress": {
- "message": "Çevirim devam ediyor"
- },
- "copiedButton": {
- "message": "Kopyalandı"
- },
- "copiedClipboard": {
- "message": "Panoya kopyalandı"
- },
- "copiedExclamation": {
- "message": "Kopyalandı!"
- },
- "copiedSafe": {
- "message": "Güvenli bir yere kopyaladım"
- },
- "copy": {
- "message": "Kopyala"
- },
- "copyToClipboard": {
- "message": "Panoya kopyala"
- },
- "copyButton": {
- "message": " Kopyala "
- },
- "copyPrivateKey": {
- "message": "Bu sizin özel anahtarınız (kopyalamak için tıklayın)"
- },
- "create": {
- "message": "Yarat"
- },
- "createAccount": {
- "message": "Hesap Oluştur"
- },
- "createDen": {
- "message": "Yarat"
- },
- "crypto": {
- "message": "Kripto",
- "description": "Kambiyo tipi (kripto para)"
- },
- "currentConversion": {
- "message": "Geçerli çevirme"
- },
- "currentNetwork": {
- "message": "Geçerli Ağ"
- },
- "customGas": {
- "message": "Gas'i özelleştir"
- },
- "customToken": {
- "message": "Özel Jeton"
- },
- "customize": {
- "message": "Özelleştir"
- },
- "customRPC": {
- "message": "Özel RPC"
- },
- "decimalsMustZerotoTen": {
- "message": "Ondalıklar en azından 0 olmalı ve 36'dan büyük olmamalı."
- },
- "decimal": {
- "message": "Ondalık hassasiyeti"
- },
- "defaultNetwork": {
- "message": "Ether işlemleri için varsayılan ağ Main Net."
- },
- "denExplainer": {
- "message": "DEN'iniz MetaMask içersinde parola-şifrelenmiş deponuzdur."
- },
- "deposit": {
- "message": "Yatır"
- },
- "depositBTC": {
- "message": "BTC'inizi aşağıdaki adrese yatırın:"
- },
- "depositCoin": {
- "message": "$1'nızı aşağıdaki adrese yatırın",
- "description": "Kullanıcıya hangi jetonu seçtiyse onu yatırmasını shapeshift ile söyler."
- },
- "depositEth": {
- "message": "Eth yatır"
- },
- "depositEther": {
- "message": "Ether yatır"
- },
- "depositFiat": {
- "message": "Para yatır"
- },
- "depositFromAccount": {
- "message": "Başka bir hesaptan yatır"
- },
- "depositShapeShift": {
- "message": "ShapeShift ile yatır"
- },
- "depositShapeShiftExplainer": {
- "message": "Eğer başka kripto paralara sahipseniz, MetaMask cüzdanınıza direk olarak Ether yatırabilirsiniz. Hesaba gerek yoktur."
- },
- "details": {
- "message": "Ayrıntılar"
- },
- "directDeposit": {
- "message": "Direk Yatırma"
- },
- "directDepositEther": {
- "message": "Direk Ether Yatırma"
- },
- "directDepositEtherExplainer": {
- "message": "Eğer çoktan Etheriniz varsa, yeni hesabınıza Ether aktarmanın en kolay yolu direk yatırmadır."
- },
- "done": {
- "message": "Bitti"
- },
- "downloadStateLogs": {
- "message": "Durum kayıtlarını indir"
- },
- "dropped": {
- "message": "Bırakıldı"
- },
- "edit": {
- "message": "Düzenle"
- },
- "editAccountName": {
- "message": "Hesap ismini düzenle"
- },
- "emailUs": {
- "message": "Bize e-posta atın!"
- },
- "encryptNewDen": {
- "message": "Yeni DEN'inizi şifreleyin"
- },
- "enterPassword": {
- "message": "Parolanızı girin"
- },
- "enterPasswordConfirm": {
- "message": "Onaylamak için parolanızı girin"
- },
- "passwordNotLongEnough": {
- "message": "Parola yeterince uzun değil"
- },
- "passwordsDontMatch": {
- "message": "Parolalar eşleşmiyor"
- },
- "etherscanView": {
- "message": "Hesabı Etherscan üzerinde izle"
- },
- "exchangeRate": {
- "message": "Döviz kuru"
- },
- "exportPrivateKey": {
- "message": "Özel anahtarı ver"
- },
- "exportPrivateKeyWarning": {
- "message": "Özel anahtarınızı vermek sizin sorumluluğunuzdadır."
- },
- "failed": {
- "message": "Başarısız oldu"
- },
- "fiat": {
- "message": "Para",
- "description": "Döviz türü"
- },
- "fileImportFail": {
- "message": "Dosya alma çalışmıyor mu? Buraya tıklayın!",
- "description": "Kullanıcıların hesaplarını JSON dosyasından almalarına yardım eder"
- },
- "followTwitter": {
- "message": "Bizi twitter'da takip edin"
- },
- "from": {
- "message": "Kimden"
- },
- "fromToSame": {
- "message": "Kimden ve kime adresi aynı olamaz"
- },
- "fromShapeShift": {
- "message": "ShapeShift'den"
- },
- "gas": {
- "message": "Gas",
- "description": "Gas maliyetinin kısa indikatörü"
- },
- "gasFee": {
- "message": "Gas Ücreti"
- },
- "gasLimit": {
- "message": "Gas Limiti"
- },
- "gasLimitCalculation": {
- "message": "Önerilen gas limitini ağ başarı oranını baz alarak hesaplıyoruz."
- },
- "gasLimitRequired": {
- "message": "Gas limiti gereklidir"
- },
- "gasLimitTooLow": {
- "message": "Gas limiti en az 21000 olmalıdır"
- },
- "generatingSeed": {
- "message": "Kaynak Oluşturuyor..."
- },
- "gasPrice": {
- "message": "Gas Fiyatı (GWEI)"
- },
- "gasPriceCalculation": {
- "message": "Önerilen gas fiyatını ağ başarı oranını baz alarak hesaplıyoruz."
- },
- "gasPriceRequired": {
- "message": "Gas Fiyatı Gereklidir"
- },
- "getEther": {
- "message": "Ether Al"
- },
- "getEtherFromFaucet": {
- "message": "Musluktan $1 karşılığı Ether alın",
- "description": "Ether musluğunun ağ ismini gösterir"
- },
- "greaterThanMin": {
- "message": "must be greater than or equal to $1.",
- "description": "helper for inputting hex as decimal input"
- },
- "here": {
- "message": "burada",
- "description": "daha fazla bilgi için -buraya tıklayın- (troubleTokenBalances ile gidiyor)"
- },
- "hereList": {
- "message": "İşte bir liste!!!!"
- },
- "hide": {
- "message": "Gizle"
- },
- "hideToken": {
- "message": "Jetonu gizle"
- },
- "hideTokenPrompt": {
- "message": "Jetonu gizle?"
- },
- "howToDeposit": {
- "message": "Ether'i nasıl yatırmak istersiniz?"
- },
- "holdEther": {
- "message": "Ether ve jeton tutmanızı sağlar ve merkezi olmayan uygulamalar ve sizin aranızda köprü vazifesi görür."
- },
- "import": {
- "message": "Al",
- "description": "Seçilen dosyadan hesap alma düğmesi. "
- },
- "importAccount": {
- "message": "Hesap Al"
- },
- "importAccountMsg": {
- "message":" Alınan hesaplar orjinal kaynakifadenizle yarattığınız MetaMask hesabınızla ilişkilendirilmez. Alınan hesaplar ile ilgili daha fazla bilgi edinin "
- },
- "importAnAccount": {
- "message": "Hesap al"
- },
- "importDen": {
- "message": "Varolan DEN al"
- },
- "imported": {
- "message": "Alındı",
- "description": "Hesabın keyringe başarı ile alındığını gösteren durum"
- },
- "infoHelp": {
- "message": "Bilgi ve yardım"
- },
- "insufficientFunds": {
- "message": "Yetersiz kaynak."
- },
- "insufficientTokens": {
- "message": "Yetersiz Jeton."
- },
- "invalidAddress": {
- "message": "Geçersiz adres"
- },
- "invalidAddressRecipient": {
- "message": "Alıcı adresi geçersiz"
- },
- "invalidGasParams": {
- "message": "Geçersiz gas parametreleri"
- },
- "invalidInput": {
- "message": "Geçersiz giriş."
- },
- "invalidRequest": {
- "message": "Geçersiz istek"
- },
- "invalidRPC": {
- "message": "Geçersiz RPC URI"
- },
- "jsonFail": {
- "message": "Birşeyler yanlış gitti. JSON dosyanızın düzgün derlendiğinden emin olun."
- },
- "jsonFile": {
- "message": "JSON Dosyası",
- "description": "Hesap alımı için düzenle"
- },
- "keepTrackTokens": {
- "message": "MetaMask hesabınızla satın aldığınız jetonların kaydını tutun."
- },
- "kovan": {
- "message": "Kovan Test Ağı"
- },
- "knowledgeDataBase": {
- "message": "Bilgi veritabanımızı ziyaret edin"
- },
- "max": {
- "message": "Maksimum"
- },
- "learnMore": {
- "message": "Daha fazla bilgi."
- },
- "lessThanMax": {
- "message": "$1'den az veya eşit olmalıdır.",
- "description": "Onaltılık sayıyı ondalık olarak girmek için yardımcı"
- },
- "likeToAddTokens": {
- "message": "Bu jetonlara adres eklemek ister misiniz?"
- },
- "links": {
- "message": "Bağlantılar"
- },
- "limit": {
- "message": "Limit"
- },
- "loading": {
- "message": "Yükleniyor..."
- },
- "loadingTokens": {
- "message": "Jetonlar yükleniyor..."
- },
- "localhost": {
- "message": "Localhost 8545"
- },
- "login": {
- "message": "Giriş yap"
- },
- "logout": {
- "message": "Çıkış"
- },
- "loose": {
- "message": "Gevşek"
- },
- "loweCaseWords": {
- "message": "kaynak kelimeleri sadece küçük harflerden oluşabilir."
- },
- "mainnet": {
- "message": "Main Ethereum Ağı"
- },
- "message": {
- "message": "Mesaj"
- },
- "metamaskDescription": {
- "message": "MetaMask Ethereum için güvenli bir kimlik kasasıdır."
- },
- "min": {
- "message": "Minimum"
- },
- "myAccounts": {
- "message": "Hesaplarım"
- },
- "mustSelectOne": {
- "message": "En az bir jeton seçilmeli"
- },
- "needEtherInWallet": {
- "message": "MetaMask kullanarak merkezi olamayan uygulamalarla etkileşmek için cüzdanınızda Ether bulunmalıdır."
- },
- "needImportFile": {
- "message": "Almak için bir dosya seçmelisiniz.",
- "description": "Kullanıcı bir hesap alır ve devam etmek içinbir dosya seçmelidir."
- },
- "needImportPassword": {
- "message": "Seçilen dosya için bir parola girmelisiniz.",
- "description": "Hesap almak için parola ve dosya gerekiyor."
- },
- "negativeETH": {
- "message": "Negatif ETH miktarları gönderilemez."
- },
- "networks": {
- "message": "Ağlar"
- },
- "newAccount": {
- "message": "Yeni Hesap"
- },
- "newAccountNumberName": {
- "message": "Hesap $1",
- "description": "Hesap yaratma ekranındaki bir sonraki hesabın varsayılan ismi"
- },
- "newContract": {
- "message": "Yeni Sözleşme"
- },
- "newPassword": {
- "message": "Yeni Parola (min 8 karakter)"
- },
- "newRecipient": {
- "message": "Yeni alıcı"
- },
- "newRPC": {
- "message": "Yeni RPC URL"
- },
- "next": {
- "message": "Sonraki"
- },
- "noAddressForName": {
- "message": "Bu isim için bir adres tanımlanmamış."
- },
- "noDeposits": {
- "message": "Yatırma alınmadı"
- },
- "noTransactionHistory": {
- "message": "İşlem geçmişi yok."
- },
- "noTransactions": {
- "message": "İşlem yok"
- },
- "notStarted": {
- "message": "Başlamadı"
- },
- "oldUI": {
- "message": "Eski UI"
- },
- "oldUIMessage": {
- "message": "Eski UI'a döndünüz. Yeni UI'a üst sağ sekme menüsündeki seçenek ile dönebilirsiniz."
- },
- "or": {
- "message": "veya",
- "description": "Yeni bir hesap yaratmak veya almak arasındaki seçim"
- },
- "passwordCorrect": {
- "message": "Lütfen parolanın doğru olduğuna emin olun."
- },
- "passwordMismatch": {
- "message": "parolalar eşleşmiyor",
- "description": "parola yaratma işleminde, iki yeni parola alanı eşleşmiyor."
- },
- "passwordShort": {
- "message": "parola yeterince uzun değil",
- "description": "parola yaratma işleminde, parola güvenli olacak kadar uzun değil."
- },
- "pastePrivateKey": {
- "message": "Özel anahtar dizinizi buraya yapıştırın:",
- "description": "Özel anahtardan hesap almak için"
- },
- "pasteSeed": {
- "message": "Kaynak ifadenizi buraya yapıştırın!"
- },
- "personalAddressDetected": {
- "message": "Kişisel adres tespit edilidi. Jeton sözleşme adresini girin."
- },
- "pleaseReviewTransaction": {
- "message": "Lütfen işleminizi gözden geçirin."
- },
- "popularTokens": {
- "message": "Popüler Jetonlar"
- },
- "privacyMsg": {
- "message": "Gizlilik Şartları"
- },
- "privateKey": {
- "message": "Özel Anahtar",
- "description": "Hesap alırken bu tip bir dosya seçin"
- },
- "privateKeyWarning": {
- "message": "Uyarı: Bu anahtarı kimse ile paylaşmayın. Özel anahtarlarınıza sahip herkes hesaplarınızıdaki tüm varlığınızı çalabilir."
- },
- "privateNetwork": {
- "message": "Özel Ağ"
- },
- "qrCode": {
- "message": "QR Kodunu göster"
- },
- "readdToken": {
- "message": "Gelecekte Bu jetonu hesap seçenekleri menüsünde “Jeton ekle”'ye giderek geri ekleyebilirsiniz."
- },
- "readMore": {
- "message": "Burada daha fazla okuyun."
- },
- "readMore2": {
- "message": "Daha fazla okuyun."
- },
- "receive": {
- "message": "Al"
- },
- "recipientAddress": {
- "message": "Alıcı adresi"
- },
- "refundAddress": {
- "message": "İade adresiniz"
- },
- "rejected": {
- "message": "Rededildi"
- },
- "resetAccount": {
- "message": "Hesabı sıfıla"
- },
- "restoreFromSeed": {
- "message": "Kaynak ifadeden geri getir. Restore from seed phrase"
- },
- "restoreVault": {
- "message": "Kasayı geri getir"
- },
- "required": {
- "message": "Gerekli"
- },
- "retryWithMoreGas": {
- "message": "Daha yüksek bir gas fiyatı ile tekrar dene"
- },
- "walletSeed": {
- "message": "Cüzdan Kaynağı"
- },
- "revealSeedWords": {
- "message": "Kaynak kelimelerini göster"
- },
- "revealSeedWordsWarning": {
- "message": "Açık bir yerde kaynak kelimeliriniz geri getirmeyin! Bu kelimeler tüm hesaplarınızı çalmak için kullanılabilir."
- },
- "revert": {
- "message": "Geri döndür"
- },
- "rinkeby": {
- "message": "Rinkeby Test Ağı"
- },
- "ropsten": {
- "message": "Ropsten Test Ağı"
- },
- "currentRpc": {
- "message": "Geçerli RPC"
- },
- "connectingToMainnet": {
- "message": "Main Ethereum Ağına bağlanıyor"
- },
- "connectingToRopsten": {
- "message": "Ropsten Test Ağına bağlanıyor"
- },
- "connectingToKovan": {
- "message": "Kovan Test Ağına bağlanıyor"
- },
- "connectingToRinkeby": {
- "message": "Rinkeby Test Ağına bağlanıyor"
- },
- "connectingToUnknown": {
- "message": "Bilinmeyen Ağa bağlanıyor"
- },
- "sampleAccountName": {
- "message": "E.g. Yeni hesabım",
- "description": "Kullanıcının hesabına okunabilir isim ekleme konseptini anlamasına yardımcı olmak."
- },
- "save": {
- "message": "Kaydet"
- },
- "reprice_title": {
- "message": "İşlemi Yeniden Fiyatlandır"
- },
- "reprice_subtitle": {
- "message": "İşlemizi hızlandırmayı denemek için gas fiyatınızı yükseltin."
- },
- "saveAsFile": {
- "message": "Dosya olarak kaydet",
- "description": "Hesap verme işlemi"
- },
- "saveSeedAsFile": {
- "message": "Kaynak Kelimelerini Dosya olarak Kaydet"
- },
- "search": {
- "message": "Ara"
- },
- "secretPhrase": {
- "message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
- },
- "newPassword8Chars": {
- "message": "Yeni Parola (minumum 8 karakter)"
- },
- "seedPhraseReq": {
- "message": "Kaynak ifadeleri 12 kelimedir."
- },
- "select": {
- "message": "Seç"
- },
- "selectCurrency": {
- "message": "Döviz Seç"
- },
- "selectService": {
- "message": "Servis Seç"
- },
- "selectType": {
- "message": "Tip Seç"
- },
- "send": {
- "message": "Gönder"
- },
- "sendETH": {
- "message": "ETH Gönder"
- },
- "sendTokens": {
- "message": "Jeton Gönder"
- },
- "onlySendToEtherAddress": {
- "message": "Ethereum adresine sadece ETH gönder."
- },
- "searchTokens": {
- "message": "Jeton ara"
- },
- "sendTokensAnywhere": {
- "message": "Ethereum hesabı olan birine Jeton gönder"
- },
- "settings": {
- "message": "Ayarlar"
- },
- "info": {
+ "accept": {
+ "message": "Kabul et"
+ },
+ "account": {
+ "message": "Hesap"
+ },
+ "accountDetails": {
+ "message": "Hesap Detayları"
+ },
+ "accountName": {
+ "message": "Hesap İsmi"
+ },
+ "address": {
+ "message": "Adres"
+ },
+ "addCustomToken": {
+ "message": "Özel jeton ekle"
+ },
+ "addToken": {
+ "message": "Jeton ekle"
+ },
+ "addTokens": {
+ "message": "Jetonlar ekle"
+ },
+ "amount": {
+ "message": "Tutar"
+ },
+ "amountPlusGas": {
+ "message": "Tutar + Gas"
+ },
+ "appDescription": {
+ "message": "Ethereum Tarayıcı Uzantısı",
+ "description": "Uygulama açıklaması"
+ },
+ "appName": {
+ "message": "MetaMask",
+ "description": "Uygulama ismi"
+ },
+ "approved": {
+ "message": "Onaylandı"
+ },
+ "attemptingConnect": {
+ "message": "Blockchain'e bağlanmayı deniyor"
+ },
+ "attributions": {
+ "message": "Atıflar"
+ },
+ "available": {
+ "message": "Müsait"
+ },
+ "back": {
+ "message": "Geri"
+ },
+ "balance": {
+ "message": "Bakiye:"
+ },
+ "balances": {
+ "message": "Jeton bakiyesi"
+ },
+ "balanceIsInsufficientGas": {
+ "message": "Toplam gas için yetersiz bakiye"
+ },
+ "beta": {
+ "message": "BETA"
+ },
+ "betweenMinAndMax": {
+ "message": "$1'e eşit veya daha büyük olmalı ve $2'den küçük veya eşit olmalı",
+ "description": "Onaltılık sayının ondalık sayı olarak girişi için yardımcı"
+ },
+ "blockiesIdenticon": {
+ "message": "Blockies Identicon kullan"
+ },
+ "borrowDharma": {
+ "message": "Dharma (Beta) ile ödünç al"
+ },
+ "builtInCalifornia": {
+ "message": "MetaMask California'da tasarlandı ve yaratıldı"
+ },
+ "buy": {
+ "message": "Satın al"
+ },
+ "buyCoinbase": {
+ "message": "Coinbase'de satın al"
+ },
+ "buyCoinbaseExplainer": {
+ "message": "Coinbase Bitcoin, Ethereum, and Litecoin alıp satmanın dünyadaki en popüler yolu"
+ },
+ "ok": {
+ "message": "Tamam"
+ },
+ "cancel": {
+ "message": "Vazgeç"
+ },
+ "classicInterface": {
+ "message": "Klasik arayüzü kullan"
+ },
+ "clickCopy": {
+ "message": "Kopyalamak için tıkla"
+ },
+ "confirm": {
+ "message": "Onayla"
+ },
+ "confirmed": {
+ "message": "Onaylandı"
+ },
+ "confirmContract": {
+ "message": "Sözleşmeyi onayla"
+ },
+ "confirmPassword": {
+ "message": "Şifreyi onayla"
+ },
+ "confirmTransaction": {
+ "message": "İşlemi onayla"
+ },
+ "continue": {
+ "message": "Devam et"
+ },
+ "continueToCoinbase": {
+ "message": "Coinbase'e devam et"
+ },
+ "contractDeployment": {
+ "message": "Sözleşme kurulumu"
+ },
+ "conversionProgress": {
+ "message": "Çevirim devam ediyor"
+ },
+ "copiedButton": {
+ "message": "Kopyalandı"
+ },
+ "copiedClipboard": {
+ "message": "Panoya kopyalandı"
+ },
+ "copiedExclamation": {
+ "message": "Kopyalandı!"
+ },
+ "copiedSafe": {
+ "message": "Güvenli bir yere kopyaladım"
+ },
+ "copy": {
+ "message": "Kopyala"
+ },
+ "copyToClipboard": {
+ "message": "Panoya kopyala"
+ },
+ "copyButton": {
+ "message": " Kopyala "
+ },
+ "copyPrivateKey": {
+ "message": "Bu sizin özel anahtarınız (kopyalamak için tıklayın)"
+ },
+ "create": {
+ "message": "Yarat"
+ },
+ "createAccount": {
+ "message": "Hesap Oluştur"
+ },
+ "createDen": {
+ "message": "Yarat"
+ },
+ "crypto": {
+ "message": "Kripto",
+ "description": "Kambiyo tipi (kripto para)"
+ },
+ "currentConversion": {
+ "message": "Geçerli çevirme"
+ },
+ "currentNetwork": {
+ "message": "Geçerli Ağ"
+ },
+ "customGas": {
+ "message": "Gas'i özelleştir"
+ },
+ "customToken": {
+ "message": "Özel Jeton"
+ },
+ "customize": {
+ "message": "Özelleştir"
+ },
+ "customRPC": {
+ "message": "Özel RPC"
+ },
+ "decimalsMustZerotoTen": {
+ "message": "Ondalıklar en azından 0 olmalı ve 36'dan büyük olmamalı."
+ },
+ "decimal": {
+ "message": "Ondalık hassasiyeti"
+ },
+ "defaultNetwork": {
+ "message": "Ether işlemleri için varsayılan ağ Main Net."
+ },
+ "denExplainer": {
+ "message": "DEN'iniz MetaMask içersinde parola-şifrelenmiş deponuzdur."
+ },
+ "deposit": {
+ "message": "Yatır"
+ },
+ "depositBTC": {
+ "message": "BTC'inizi aşağıdaki adrese yatırın:"
+ },
+ "depositCoin": {
+ "message": "$1'nızı aşağıdaki adrese yatırın",
+ "description": "Kullanıcıya hangi jetonu seçtiyse onu yatırmasını shapeshift ile söyler."
+ },
+ "depositEth": {
+ "message": "Eth yatır"
+ },
+ "depositEther": {
+ "message": "Ether yatır"
+ },
+ "depositFiat": {
+ "message": "Para yatır"
+ },
+ "depositFromAccount": {
+ "message": "Başka bir hesaptan yatır"
+ },
+ "depositShapeShift": {
+ "message": "ShapeShift ile yatır"
+ },
+ "depositShapeShiftExplainer": {
+ "message": "Eğer başka kripto paralara sahipseniz, MetaMask cüzdanınıza direk olarak Ether yatırabilirsiniz. Hesaba gerek yoktur."
+ },
+ "details": {
+ "message": "Ayrıntılar"
+ },
+ "directDeposit": {
+ "message": "Direk Yatırma"
+ },
+ "directDepositEther": {
+ "message": "Direk Ether Yatırma"
+ },
+ "directDepositEtherExplainer": {
+ "message": "Eğer çoktan Etheriniz varsa, yeni hesabınıza Ether aktarmanın en kolay yolu direk yatırmadır."
+ },
+ "done": {
+ "message": "Bitti"
+ },
+ "downloadStateLogs": {
+ "message": "Durum kayıtlarını indir"
+ },
+ "dropped": {
+ "message": "Bırakıldı"
+ },
+ "edit": {
+ "message": "Düzenle"
+ },
+ "editAccountName": {
+ "message": "Hesap ismini düzenle"
+ },
+ "emailUs": {
+ "message": "Bize e-posta atın!"
+ },
+ "encryptNewDen": {
+ "message": "Yeni DEN'inizi şifreleyin"
+ },
+ "enterPassword": {
+ "message": "Parolanızı girin"
+ },
+ "enterPasswordConfirm": {
+ "message": "Onaylamak için parolanızı girin"
+ },
+ "passwordNotLongEnough": {
+ "message": "Parola yeterince uzun değil"
+ },
+ "passwordsDontMatch": {
+ "message": "Parolalar eşleşmiyor"
+ },
+ "etherscanView": {
+ "message": "Hesabı Etherscan üzerinde izle"
+ },
+ "exchangeRate": {
+ "message": "Döviz kuru"
+ },
+ "exportPrivateKey": {
+ "message": "Özel anahtarı ver"
+ },
+ "exportPrivateKeyWarning": {
+ "message": "Özel anahtarınızı vermek sizin sorumluluğunuzdadır."
+ },
+ "failed": {
+ "message": "Başarısız oldu"
+ },
+ "fiat": {
+ "message": "Para",
+ "description": "Döviz türü"
+ },
+ "fileImportFail": {
+ "message": "Dosya alma çalışmıyor mu? Buraya tıklayın!",
+ "description": "Kullanıcıların hesaplarını JSON dosyasından almalarına yardım eder"
+ },
+ "followTwitter": {
+ "message": "Bizi twitter'da takip edin"
+ },
+ "from": {
+ "message": "Kimden"
+ },
+ "fromToSame": {
+ "message": "Kimden ve kime adresi aynı olamaz"
+ },
+ "fromShapeShift": {
+ "message": "ShapeShift'den"
+ },
+ "gas": {
+ "message": "Gas",
+ "description": "Gas maliyetinin kısa indikatörü"
+ },
+ "gasFee": {
+ "message": "Gas Ücreti"
+ },
+ "gasLimit": {
+ "message": "Gas Limiti"
+ },
+ "gasLimitCalculation": {
+ "message": "Önerilen gas limitini ağ başarı oranını baz alarak hesaplıyoruz."
+ },
+ "gasLimitRequired": {
+ "message": "Gas limiti gereklidir"
+ },
+ "gasLimitTooLow": {
+ "message": "Gas limiti en az 21000 olmalıdır"
+ },
+ "generatingSeed": {
+ "message": "Kaynak Oluşturuyor..."
+ },
+ "gasPrice": {
+ "message": "Gas Fiyatı (GWEI)"
+ },
+ "gasPriceCalculation": {
+ "message": "Önerilen gas fiyatını ağ başarı oranını baz alarak hesaplıyoruz."
+ },
+ "gasPriceRequired": {
+ "message": "Gas Fiyatı Gereklidir"
+ },
+ "getEther": {
+ "message": "Ether Al"
+ },
+ "getEtherFromFaucet": {
+ "message": "Musluktan $1 karşılığı Ether alın",
+ "description": "Ether musluğunun ağ ismini gösterir"
+ },
+ "greaterThanMin": {
+ "message": "must be greater than or equal to $1.",
+ "description": "helper for inputting hex as decimal input"
+ },
+ "here": {
+ "message": "burada",
+ "description": "daha fazla bilgi için -buraya tıklayın- (troubleTokenBalances ile gidiyor)"
+ },
+ "hereList": {
+ "message": "İşte bir liste!!!!"
+ },
+ "hide": {
+ "message": "Gizle"
+ },
+ "hideToken": {
+ "message": "Jetonu gizle"
+ },
+ "hideTokenPrompt": {
+ "message": "Jetonu gizle?"
+ },
+ "howToDeposit": {
+ "message": "Ether'i nasıl yatırmak istersiniz?"
+ },
+ "holdEther": {
+ "message": "Ether ve jeton tutmanızı sağlar ve merkezi olmayan uygulamalar ve sizin aranızda köprü vazifesi görür."
+ },
+ "import": {
+ "message": "Al",
+ "description": "Seçilen dosyadan hesap alma düğmesi. "
+ },
+ "importAccount": {
+ "message": "Hesap Al"
+ },
+ "importAccountMsg": {
+ "message": " Alınan hesaplar orjinal kaynakifadenizle yarattığınız MetaMask hesabınızla ilişkilendirilmez. Alınan hesaplar ile ilgili daha fazla bilgi edinin "
+ },
+ "importAnAccount": {
+ "message": "Hesap al"
+ },
+ "importDen": {
+ "message": "Varolan DEN al"
+ },
+ "imported": {
+ "message": "Alındı",
+ "description": "Hesabın keyringe başarı ile alındığını gösteren durum"
+ },
+ "infoHelp": {
+ "message": "Bilgi ve yardım"
+ },
+ "insufficientFunds": {
+ "message": "Yetersiz kaynak."
+ },
+ "insufficientTokens": {
+ "message": "Yetersiz Jeton."
+ },
+ "invalidAddress": {
+ "message": "Geçersiz adres"
+ },
+ "invalidAddressRecipient": {
+ "message": "Alıcı adresi geçersiz"
+ },
+ "invalidGasParams": {
+ "message": "Geçersiz gas parametreleri"
+ },
+ "invalidInput": {
+ "message": "Geçersiz giriş."
+ },
+ "invalidRequest": {
+ "message": "Geçersiz istek"
+ },
+ "invalidRPC": {
+ "message": "Geçersiz RPC URI"
+ },
+ "jsonFail": {
+ "message": "Birşeyler yanlış gitti. JSON dosyanızın düzgün derlendiğinden emin olun."
+ },
+ "jsonFile": {
+ "message": "JSON Dosyası",
+ "description": "Hesap alımı için düzenle"
+ },
+ "keepTrackTokens": {
+ "message": "MetaMask hesabınızla satın aldığınız jetonların kaydını tutun."
+ },
+ "kovan": {
+ "message": "Kovan Test Ağı"
+ },
+ "knowledgeDataBase": {
+ "message": "Bilgi veritabanımızı ziyaret edin"
+ },
+ "max": {
+ "message": "Maksimum"
+ },
+ "learnMore": {
+ "message": "Daha fazla bilgi."
+ },
+ "lessThanMax": {
+ "message": "$1'den az veya eşit olmalıdır.",
+ "description": "Onaltılık sayıyı ondalık olarak girmek için yardımcı"
+ },
+ "likeToAddTokens": {
+ "message": "Bu jetonlara adres eklemek ister misiniz?"
+ },
+ "links": {
+ "message": "Bağlantılar"
+ },
+ "limit": {
+ "message": "Limit"
+ },
+ "loading": {
+ "message": "Yükleniyor..."
+ },
+ "loadingTokens": {
+ "message": "Jetonlar yükleniyor..."
+ },
+ "localhost": {
+ "message": "Localhost 8545"
+ },
+ "login": {
+ "message": "Giriş yap"
+ },
+ "logout": {
+ "message": "Çıkış"
+ },
+ "loose": {
+ "message": "Gevşek"
+ },
+ "loweCaseWords": {
+ "message": "kaynak kelimeleri sadece küçük harflerden oluşabilir."
+ },
+ "mainnet": {
+ "message": "Main Ethereum Ağı"
+ },
+ "message": {
+ "message": "Mesaj"
+ },
+ "metamaskDescription": {
+ "message": "MetaMask Ethereum için güvenli bir kimlik kasasıdır."
+ },
+ "min": {
+ "message": "Minimum"
+ },
+ "myAccounts": {
+ "message": "Hesaplarım"
+ },
+ "mustSelectOne": {
+ "message": "En az bir jeton seçilmeli"
+ },
+ "needEtherInWallet": {
+ "message": "MetaMask kullanarak merkezi olamayan uygulamalarla etkileşmek için cüzdanınızda Ether bulunmalıdır."
+ },
+ "needImportFile": {
+ "message": "Almak için bir dosya seçmelisiniz.",
+ "description": "Kullanıcı bir hesap alır ve devam etmek içinbir dosya seçmelidir."
+ },
+ "needImportPassword": {
+ "message": "Seçilen dosya için bir parola girmelisiniz.",
+ "description": "Hesap almak için parola ve dosya gerekiyor."
+ },
+ "negativeETH": {
+ "message": "Negatif ETH miktarları gönderilemez."
+ },
+ "networks": {
+ "message": "Ağlar"
+ },
+ "newAccount": {
+ "message": "Yeni Hesap"
+ },
+ "newAccountNumberName": {
+ "message": "Hesap $1",
+ "description": "Hesap yaratma ekranındaki bir sonraki hesabın varsayılan ismi"
+ },
+ "newContract": {
+ "message": "Yeni Sözleşme"
+ },
+ "newPassword": {
+ "message": "Yeni Parola (min 8 karakter)"
+ },
+ "newRecipient": {
+ "message": "Yeni alıcı"
+ },
+ "newRPC": {
+ "message": "Yeni RPC URL"
+ },
+ "next": {
+ "message": "Sonraki"
+ },
+ "noAddressForName": {
+ "message": "Bu isim için bir adres tanımlanmamış."
+ },
+ "noDeposits": {
+ "message": "Yatırma alınmadı"
+ },
+ "noTransactionHistory": {
+ "message": "İşlem geçmişi yok."
+ },
+ "noTransactions": {
+ "message": "İşlem yok"
+ },
+ "notStarted": {
+ "message": "Başlamadı"
+ },
+ "oldUI": {
+ "message": "Eski UI"
+ },
+ "oldUIMessage": {
+ "message": "Eski UI'a döndünüz. Yeni UI'a üst sağ sekme menüsündeki seçenek ile dönebilirsiniz."
+ },
+ "or": {
+ "message": "veya",
+ "description": "Yeni bir hesap yaratmak veya almak arasındaki seçim"
+ },
+ "passwordCorrect": {
+ "message": "Lütfen parolanın doğru olduğuna emin olun."
+ },
+ "passwordMismatch": {
+ "message": "parolalar eşleşmiyor",
+ "description": "parola yaratma işleminde, iki yeni parola alanı eşleşmiyor."
+ },
+ "passwordShort": {
+ "message": "parola yeterince uzun değil",
+ "description": "parola yaratma işleminde, parola güvenli olacak kadar uzun değil."
+ },
+ "pastePrivateKey": {
+ "message": "Özel anahtar dizinizi buraya yapıştırın:",
+ "description": "Özel anahtardan hesap almak için"
+ },
+ "pasteSeed": {
+ "message": "Kaynak ifadenizi buraya yapıştırın!"
+ },
+ "personalAddressDetected": {
+ "message": "Kişisel adres tespit edilidi. Jeton sözleşme adresini girin."
+ },
+ "pleaseReviewTransaction": {
+ "message": "Lütfen işleminizi gözden geçirin."
+ },
+ "popularTokens": {
+ "message": "Popüler Jetonlar"
+ },
+ "privacyMsg": {
+ "message": "Gizlilik Şartları"
+ },
+ "privateKey": {
+ "message": "Özel Anahtar",
+ "description": "Hesap alırken bu tip bir dosya seçin"
+ },
+ "privateKeyWarning": {
+ "message": "Uyarı: Bu anahtarı kimse ile paylaşmayın. Özel anahtarlarınıza sahip herkes hesaplarınızıdaki tüm varlığınızı çalabilir."
+ },
+ "privateNetwork": {
+ "message": "Özel Ağ"
+ },
+ "qrCode": {
+ "message": "QR Kodunu göster"
+ },
+ "readdToken": {
+ "message": "Gelecekte Bu jetonu hesap seçenekleri menüsünde “Jeton ekle”'ye giderek geri ekleyebilirsiniz."
+ },
+ "readMore": {
+ "message": "Burada daha fazla okuyun."
+ },
+ "readMore2": {
+ "message": "Daha fazla okuyun."
+ },
+ "receive": {
+ "message": "Al"
+ },
+ "recipientAddress": {
+ "message": "Alıcı adresi"
+ },
+ "refundAddress": {
+ "message": "İade adresiniz"
+ },
+ "rejected": {
+ "message": "Rededildi"
+ },
+ "resetAccount": {
+ "message": "Hesabı sıfıla"
+ },
+ "restoreFromSeed": {
+ "message": "Kaynak ifadeden geri getir. Restore from seed phrase"
+ },
+ "restoreVault": {
+ "message": "Kasayı geri getir"
+ },
+ "required": {
+ "message": "Gerekli"
+ },
+ "retryWithMoreGas": {
+ "message": "Daha yüksek bir gas fiyatı ile tekrar dene"
+ },
+ "walletSeed": {
+ "message": "Cüzdan Kaynağı"
+ },
+ "revealSeedWords": {
+ "message": "Kaynak kelimelerini göster"
+ },
+ "revealSeedWordsWarning": {
+ "message": "Açık bir yerde kaynak kelimeliriniz geri getirmeyin! Bu kelimeler tüm hesaplarınızı çalmak için kullanılabilir."
+ },
+ "revert": {
+ "message": "Geri döndür"
+ },
+ "rinkeby": {
+ "message": "Rinkeby Test Ağı"
+ },
+ "ropsten": {
+ "message": "Ropsten Test Ağı"
+ },
+ "currentRpc": {
+ "message": "Geçerli RPC"
+ },
+ "connectingToMainnet": {
+ "message": "Main Ethereum Ağına bağlanıyor"
+ },
+ "connectingToRopsten": {
+ "message": "Ropsten Test Ağına bağlanıyor"
+ },
+ "connectingToKovan": {
+ "message": "Kovan Test Ağına bağlanıyor"
+ },
+ "connectingToRinkeby": {
+ "message": "Rinkeby Test Ağına bağlanıyor"
+ },
+ "connectingToUnknown": {
+ "message": "Bilinmeyen Ağa bağlanıyor"
+ },
+ "sampleAccountName": {
+ "message": "E.g. Yeni hesabım",
+ "description": "Kullanıcının hesabına okunabilir isim ekleme konseptini anlamasına yardımcı olmak."
+ },
+ "save": {
+ "message": "Kaydet"
+ },
+ "reprice_title": {
+ "message": "İşlemi Yeniden Fiyatlandır"
+ },
+ "reprice_subtitle": {
+ "message": "İşlemizi hızlandırmayı denemek için gas fiyatınızı yükseltin."
+ },
+ "saveAsFile": {
+ "message": "Dosya olarak kaydet",
+ "description": "Hesap verme işlemi"
+ },
+ "saveSeedAsFile": {
+ "message": "Kaynak Kelimelerini Dosya olarak Kaydet"
+ },
+ "search": {
+ "message": "Ara"
+ },
+ "secretPhrase": {
+ "message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
+ },
+ "newPassword8Chars": {
+ "message": "Yeni Parola (minumum 8 karakter)"
+ },
+ "seedPhraseReq": {
+ "message": "Kaynak ifadeleri 12 kelimedir."
+ },
+ "select": {
+ "message": "Seç"
+ },
+ "selectCurrency": {
+ "message": "Döviz Seç"
+ },
+ "selectService": {
+ "message": "Servis Seç"
+ },
+ "selectType": {
+ "message": "Tip Seç"
+ },
+ "send": {
+ "message": "Gönder"
+ },
+ "sendETH": {
+ "message": "ETH Gönder"
+ },
+ "sendTokens": {
+ "message": "Jeton Gönder"
+ },
+ "onlySendToEtherAddress": {
+ "message": "Ethereum adresine sadece ETH gönder."
+ },
+ "searchTokens": {
+ "message": "Jeton ara"
+ },
+ "sendTokensAnywhere": {
+ "message": "Ethereum hesabı olan birine Jeton gönder"
+ },
+ "settings": {
+ "message": "Ayarlar"
+ },
+ "info": {
"message": "Bilgi"
- },
- "shapeshiftBuy": {
- "message": "Shapeshift ile satın al"
- },
- "showPrivateKeys": {
- "message": "Özel anahtarları göster"
- },
- "showQRCode": {
- "message": "QR Kodu göster"
- },
- "sign": {
- "message": "İmza"
- },
- "signed": {
- "message": "İmzalandı"
- },
- "signMessage": {
- "message": "Mesajı İmzala"
- },
- "signNotice": {
- "message": "Bu mesajı imzalamanın tehlikeli \nyan etkileri olabilir. Tamamen güvendiğiniz sitelerden \ngelen mesajları hesabınızla imzalayınız.\n Bu tehlikeli metod gelecek versiyonlarda çıkarılacaktır. "
- },
- "sigRequest": {
- "message": "İmza isteği"
- },
- "sigRequested": {
- "message": "İmza isteniyor"
- },
- "spaceBetween": {
- "message": "Kelimeler arası sadece bir boşluk olabilir."
- },
- "status": {
- "message": "Durum"
- },
- "stateLogs": {
- "message": "Durum Kayıtları"
- },
- "stateLogsDescription": {
- "message": "Durum kayıtları açık hesap adresinizi ve gönderilen işlemleri içerir."
- },
- "stateLogError": {
- "message": "Durum kayıtlarını alma hatası"
- },
- "submit": {
- "message": "Gönder"
- },
- "submitted": {
- "message": "Gönderildi"
- },
- "supportCenter": {
- "message": "Destek merkezimizi ziyaret edin"
- },
- "symbolBetweenZeroTen": {
- "message": "Sembol 0 ve 10 karakter aralığında olmalıdır."
- },
- "takesTooLong": {
- "message": "Çok mu uzun sürüyor?"
- },
- "terms": {
- "message": "Kullanım şartları"
- },
- "testFaucet": {
- "message": "Test Musluğu"
- },
- "to": {
- "message": "Kime"
- },
- "toETHviaShapeShift": {
- "message": "ShapeShift üstünden $1'dan ETH'e",
- "description": "system will fill in deposit type in start of message"
- },
- "tokenAddress": {
- "message": "Jeton Adresi"
- },
- "tokenAlreadyAdded": {
- "message": "Jeton çoktan eklenmiş."
- },
- "tokenBalance": {
- "message": "Jeton bakiyeniz:"
- },
- "tokenSelection": {
- "message": "Jeton arayın veya popüler jeton listemizden seçin."
- },
- "tokenSymbol": {
- "message": "Jeton Sembolü"
- },
- "tokenWarning1": {
- "message": "MetaMask hesabınızla aldığınız jetonların kaydını tutun. Başka bir hesapla jetonlar satın aldıysanız, o jetonlar burada gözükmeyecektir."
- },
- "total": {
- "message": "Toplam"
- },
- "transactions": {
- "message": "işlemler"
- },
- "transactionError": {
- "message": "İşlem Hatası. Sözleşme kodundan kural dışı durum fırlatıldı."
- },
- "transactionMemo": {
- "message": "İşlem notu (opsiyonel)"
- },
- "transactionNumber": {
- "message": "İşlem numarası"
- },
- "transfers": {
- "message": "Transferler"
- },
- "troubleTokenBalances": {
- "message": "Jeton bakiyelerinizi yüklerken sorun yaşadık. Buradan izleyebilirsiniz ",
- "description": "Jeton bakiyelerini görmek için bir link (burası) ile takip ediliyor"
- },
- "twelveWords": {
- "message": "MetaMask hesaplarınızı geri getirmenin tek yolu bu 12 kelimedir.\nBu kelimeleri güvenli ve gizli bir yerde saklayın."
- },
- "typePassword": {
- "message": "Parolanızı girin"
- },
- "uiWelcome": {
- "message": "Yeni UI (Beta)'ya hoşgeldiniz"
- },
- "uiWelcomeMessage": {
- "message": "Şu anda yeni MetaMask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
- },
- "unapproved": {
- "message": "Onaylanmadı"
- },
- "unavailable": {
- "message": "Mevcut değil"
- },
- "unknown": {
- "message": "Bilinmeyen"
- },
- "unknownNetwork": {
- "message": "Bilinmeyen özel ağ"
- },
- "unknownNetworkId": {
- "message": "Bilinmeyen ağ IDsi"
- },
- "uriErrorMsg": {
- "message": "URIler için HTTP/HTTPS öneki gerekmektedir."
- },
- "usaOnly": {
- "message": "Sadece ABD",
- "description": "Bu dövizi sadece ABD ikamet edenler kullanabilir"
- },
- "usedByClients": {
- "message": "Farklı istemciler tarafından kullanılmakta"
- },
- "useOldUI": {
- "message": "Eski UI kullan"
- },
- "validFileImport": {
- "message": "Almak için geçerli bir dosya seçmelisiniz"
- },
- "vaultCreated": {
- "message": "Kasa Yaratıldı"
- },
- "viewAccount": {
- "message": "Hesabı İncele"
- },
- "visitWebSite": {
- "message": "Web sitemizi ziyaret edin"
- },
- "warning": {
- "message": "Uyarı"
- },
- "welcomeBeta": {
- "message": "MetaMask Beta'ya Hoşgeldiniz"
- },
- "whatsThis": {
- "message": "Bu nedir?"
- },
- "yourSigRequested": {
- "message": "İmzanız isteniyor"
- },
- "youSign": {
- "message": "İmzalıyorsunuz"
- }
+ },
+ "shapeshiftBuy": {
+ "message": "Shapeshift ile satın al"
+ },
+ "showPrivateKeys": {
+ "message": "Özel anahtarları göster"
+ },
+ "showQRCode": {
+ "message": "QR Kodu göster"
+ },
+ "sign": {
+ "message": "İmza"
+ },
+ "signed": {
+ "message": "İmzalandı"
+ },
+ "signMessage": {
+ "message": "Mesajı İmzala"
+ },
+ "signNotice": {
+ "message": "Bu mesajı imzalamanın tehlikeli \nyan etkileri olabilir. Tamamen güvendiğiniz sitelerden \ngelen mesajları hesabınızla imzalayınız.\n Bu tehlikeli metod gelecek versiyonlarda çıkarılacaktır. "
+ },
+ "sigRequest": {
+ "message": "İmza isteği"
+ },
+ "sigRequested": {
+ "message": "İmza isteniyor"
+ },
+ "spaceBetween": {
+ "message": "Kelimeler arası sadece bir boşluk olabilir."
+ },
+ "status": {
+ "message": "Durum"
+ },
+ "stateLogs": {
+ "message": "Durum Kayıtları"
+ },
+ "stateLogsDescription": {
+ "message": "Durum kayıtları açık hesap adresinizi ve gönderilen işlemleri içerir."
+ },
+ "stateLogError": {
+ "message": "Durum kayıtlarını alma hatası"
+ },
+ "submit": {
+ "message": "Gönder"
+ },
+ "submitted": {
+ "message": "Gönderildi"
+ },
+ "supportCenter": {
+ "message": "Destek merkezimizi ziyaret edin"
+ },
+ "symbolBetweenZeroTen": {
+ "message": "Sembol 0 ve 10 karakter aralığında olmalıdır."
+ },
+ "takesTooLong": {
+ "message": "Çok mu uzun sürüyor?"
+ },
+ "terms": {
+ "message": "Kullanım şartları"
+ },
+ "testFaucet": {
+ "message": "Test Musluğu"
+ },
+ "to": {
+ "message": "Kime"
+ },
+ "toETHviaShapeShift": {
+ "message": "ShapeShift üstünden $1'dan ETH'e",
+ "description": "system will fill in deposit type in start of message"
+ },
+ "tokenAddress": {
+ "message": "Jeton Adresi"
+ },
+ "tokenAlreadyAdded": {
+ "message": "Jeton çoktan eklenmiş."
+ },
+ "tokenBalance": {
+ "message": "Jeton bakiyeniz:"
+ },
+ "tokenSelection": {
+ "message": "Jeton arayın veya popüler jeton listemizden seçin."
+ },
+ "tokenSymbol": {
+ "message": "Jeton Sembolü"
+ },
+ "tokenWarning1": {
+ "message": "MetaMask hesabınızla aldığınız jetonların kaydını tutun. Başka bir hesapla jetonlar satın aldıysanız, o jetonlar burada gözükmeyecektir."
+ },
+ "total": {
+ "message": "Toplam"
+ },
+ "transactions": {
+ "message": "işlemler"
+ },
+ "transactionError": {
+ "message": "İşlem Hatası. Sözleşme kodundan kural dışı durum fırlatıldı."
+ },
+ "transactionMemo": {
+ "message": "İşlem notu (opsiyonel)"
+ },
+ "transactionNumber": {
+ "message": "İşlem numarası"
+ },
+ "transfers": {
+ "message": "Transferler"
+ },
+ "troubleTokenBalances": {
+ "message": "Jeton bakiyelerinizi yüklerken sorun yaşadık. Buradan izleyebilirsiniz ",
+ "description": "Jeton bakiyelerini görmek için bir link (burası) ile takip ediliyor"
+ },
+ "twelveWords": {
+ "message": "MetaMask hesaplarınızı geri getirmenin tek yolu bu 12 kelimedir.\nBu kelimeleri güvenli ve gizli bir yerde saklayın."
+ },
+ "typePassword": {
+ "message": "Parolanızı girin"
+ },
+ "uiWelcome": {
+ "message": "Yeni UI (Beta)'ya hoşgeldiniz"
+ },
+ "uiWelcomeMessage": {
+ "message": "Şu anda yeni MetaMask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
+ },
+ "unapproved": {
+ "message": "Onaylanmadı"
+ },
+ "unavailable": {
+ "message": "Mevcut değil"
+ },
+ "unknown": {
+ "message": "Bilinmeyen"
+ },
+ "unknownNetwork": {
+ "message": "Bilinmeyen özel ağ"
+ },
+ "unknownNetworkId": {
+ "message": "Bilinmeyen ağ IDsi"
+ },
+ "uriErrorMsg": {
+ "message": "URIler için HTTP/HTTPS öneki gerekmektedir."
+ },
+ "usaOnly": {
+ "message": "Sadece ABD",
+ "description": "Bu dövizi sadece ABD ikamet edenler kullanabilir"
+ },
+ "usedByClients": {
+ "message": "Farklı istemciler tarafından kullanılmakta"
+ },
+ "useOldUI": {
+ "message": "Eski UI kullan"
+ },
+ "validFileImport": {
+ "message": "Almak için geçerli bir dosya seçmelisiniz"
+ },
+ "vaultCreated": {
+ "message": "Kasa Yaratıldı"
+ },
+ "viewAccount": {
+ "message": "Hesabı İncele"
+ },
+ "visitWebSite": {
+ "message": "Web sitemizi ziyaret edin"
+ },
+ "warning": {
+ "message": "Uyarı"
+ },
+ "welcomeBeta": {
+ "message": "MetaMask Beta'ya Hoşgeldiniz"
+ },
+ "whatsThis": {
+ "message": "Bu nedir?"
+ },
+ "yourSigRequested": {
+ "message": "İmzanız isteniyor"
+ },
+ "youSign": {
+ "message": "İmzalıyorsunuz"
+ }
}
diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json
index 8ce0671a4..90ac2a55b 100644
--- a/app/_locales/zh_CN/messages.json
+++ b/app/_locales/zh_CN/messages.json
@@ -387,7 +387,7 @@
"message": "导入账户"
},
"importAccountMsg": {
- "message":" Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
+ "message": " Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
},
"importAnAccount": {
"message": "导入一个账户"
@@ -511,7 +511,7 @@
"description": "User is important an account and needs to add a file to continue"
},
"needImportPassword": {
- "message": "必须为已选择的文件输入密码。",
+ "message": "必须为已选择的文件输入密码。",
"description": "Password and file needed to import an account"
},
"negativeETH": {
@@ -561,7 +561,7 @@
"message": "旧版界面"
},
"oldUIMessage": {
- "message": "你已经切换到旧版界面。 你可以通过右上方下拉菜单中的选项切换回新的用户界面。"
+ "message": "你已经切换到旧版界面。 你可以通过右上方下拉菜单中的选项切换回新的用户界面。"
},
"or": {
"message": "或",
@@ -605,7 +605,7 @@
"description": "select this type of file to use to import an account"
},
"privateKeyWarning": {
- "message": "注意:永远不要公开这个私钥。任何拥有你的私钥的人都可以窃取你帐户中的任何资产。"
+ "message": "注意:永远不要公开这个私钥。任何拥有你的私钥的人都可以窃取你帐户中的任何资产。"
},
"privateNetwork": {
"message": "私有网络"
@@ -614,7 +614,7 @@
"message": "显示二维码"
},
"readdToken": {
- "message": "之后你还可以通过帐户选项菜单中的“添加代币”来添加此代币。"
+ "message": "之后你还可以通过帐户选项菜单中的“添加代币”来添加此代币。"
},
"readMore": {
"message": "了解更多。"
@@ -766,7 +766,7 @@
"message": "设置"
},
"info": {
- "message": "信息"
+ "message": "信息"
},
"shapeshiftBuy": {
"message": "使用 Shapeshift 购买"
@@ -888,7 +888,7 @@
"message": "欢迎使用新版界面 (Beta)"
},
"uiWelcomeMessage": {
- "message": "你现在正在使用新的 MetaMask 界面。 尝试发送代币等新功能,有任何问题请告知我们。"
+ "message": "你现在正在使用新的 MetaMask 界面。 尝试发送代币等新功能,有任何问题请告知我们。"
},
"unapproved": {
"message": "未批准"
diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json
index 200c75c3c..f71ce311f 100644
--- a/app/_locales/zh_TW/messages.json
+++ b/app/_locales/zh_TW/messages.json
@@ -372,7 +372,7 @@
"message": "導入帳戶"
},
"importAccountMsg": {
- "message":" 匯入的帳戶與您原有 MetaMask 帳戶的助憶詞並無關聯. 請查看與導入帳戶相關的資料 "
+ "message": " 匯入的帳戶與您原有 MetaMask 帳戶的助憶詞並無關聯. 請查看與導入帳戶相關的資料 "
},
"importAnAccount": {
"message": "導入一個帳戶"
diff --git a/app/images/eth.svg b/app/images/eth.svg
new file mode 100644
index 000000000..6375b790f
--- /dev/null
+++ b/app/images/eth.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 22.1.0, 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 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#38393A;}
+</style>
+<title>deposit-eth</title>
+<desc>Created with Sketch.</desc>
+<g id="deposit-eth" transform="translate(0.000000, 14.000000)">
+ <path id="Shape" class="st0" d="M19.9,16L7.5,8.7L19.9,26L32.3,8.7L19.9,16L19.9,16z M20.1-14L7.7,6.4l12.4,7.3l12.4-7.2L20.1-14z"
+ />
+</g>
+</svg>
diff --git a/app/loading.html b/app/loading.html
index aef5d9607..71403a5ac 100644
--- a/app/loading.html
+++ b/app/loading.html
@@ -1,5 +1,9 @@
-<html>
+<!DOCTYPE html>
+<html lang="en">
<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>MetaMask Loading</title>
<style>
#div-logo {
@@ -31,5 +35,11 @@
<div id="div-logo">
<img id="logo" src="./images/loginglogo.svg">
</div>
+ <script type="text/javascript">
+ // redirect to 404 after one minute
+ setTimeout(() => {
+ location.href = './404.html'
+ }, 60000)
+ </script>
</body>
</html>
diff --git a/app/manifest.json b/app/manifest.json
index 7c554f1ac..aabacd49a 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
- "version": "4.12.0",
+ "version": "4.16.0",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 0343e134c..2a3c5b08b 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -2,6 +2,9 @@
* @file The entry point for the web extension singleton process.
*/
+// this needs to run before anything else
+require('./lib/setupFetchDebugging')()
+
const urlUtil = require('url')
const endOfStream = require('end-of-stream')
const pump = require('pump')
@@ -20,13 +23,13 @@ const createStreamSink = require('./lib/createStreamSink')
const NotificationManager = require('./lib/notification-manager.js')
const MetamaskController = require('./metamask-controller')
const rawFirstTimeState = require('./first-time-state')
-const setupRaven = require('./lib/setupRaven')
+const setupSentry = require('./lib/setupSentry')
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
const EdgeEncryptor = require('./edge-encryptor')
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
const getObjStructure = require('./lib/getObjStructure')
-const ipfsContent = require('./lib/ipfsContent.js')
+const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup')
const {
ENVIRONMENT_TYPE_POPUP,
@@ -47,7 +50,7 @@ global.METAMASK_NOTIFIER = notificationManager
// setup sentry error reporting
const release = platform.getVersion()
-const raven = setupRaven({ release })
+const sentry = setupSentry({ release })
// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
// Internet Explorer 6-11
@@ -55,7 +58,6 @@ const isIE = !!document.documentMode
// Edge 20+
const isEdge = !isIE && !!window.StyleMedia
-let ipfsHandle
let popupIsOpen = false
let notificationIsOpen = false
const openMetamaskTabsIDs = {}
@@ -161,7 +163,6 @@ async function initialize () {
const initLangCode = await getFirstPreferredLangCode()
await setupController(initState, initLangCode)
log.debug('MetaMask initialization complete.')
- ipfsHandle = ipfsContent(initState.NetworkController.provider)
}
//
@@ -194,14 +195,14 @@ async function loadStateFromPersistence () {
// we were able to recover (though it might be old)
versionedData = diskStoreState
const vaultStructure = getObjStructure(versionedData)
- raven.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
+ sentry.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
// "extra" key is required by Sentry
extra: { vaultStructure },
})
} else {
// unable to recover, clear state
versionedData = migrator.generateInitialState(firstTimeState)
- raven.captureMessage('MetaMask - Empty vault found - unable to recover')
+ sentry.captureMessage('MetaMask - Empty vault found - unable to recover')
}
}
@@ -209,7 +210,7 @@ async function loadStateFromPersistence () {
migrator.on('error', (err) => {
// get vault structure without secrets
const vaultStructure = getObjStructure(versionedData)
- raven.captureException(err, {
+ sentry.captureException(err, {
// "extra" key is required by Sentry
extra: { vaultStructure },
})
@@ -266,17 +267,15 @@ function setupController (initState, initLangCode) {
})
global.metamaskController = controller
- controller.networkController.on('networkDidChange', () => {
- ipfsHandle && ipfsHandle.remove()
- ipfsHandle = ipfsContent(controller.networkController.providerStore.getState())
- })
+ const provider = controller.provider
+ setupEnsIpfsResolver({ provider })
// report failed transactions to Sentry
controller.txController.on(`tx:status-update`, (txId, status) => {
if (status !== 'failed') return
const txMeta = controller.txController.txStateManager.getTx(txId)
try {
- reportFailedTxToSentry({ raven, txMeta })
+ reportFailedTxToSentry({ sentry, txMeta })
} catch (e) {
console.error(e)
}
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index d870741d6..33523eb46 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -135,17 +135,22 @@ function doctypeCheck () {
}
/**
- * Checks the current document extension
+ * Returns whether or not the extension (suffix) of the current document is prohibited
*
- * @returns {boolean} {@code true} if the current extension is not prohibited
+ * This checks {@code window.location.pathname} against a set of file extensions
+ * that should not have web3 injected into them. This check is indifferent of query parameters
+ * in the location.
+ *
+ * @returns {boolean} whether or not the extension of the current document is prohibited
*/
function suffixCheck () {
- var prohibitedTypes = ['xml', 'pdf']
- var currentUrl = window.location.href
- var currentRegex
+ const prohibitedTypes = [
+ /\.xml$/,
+ /\.pdf$/,
+ ]
+ const currentUrl = window.location.pathname
for (let i = 0; i < prohibitedTypes.length; i++) {
- currentRegex = new RegExp(`\\.${prohibitedTypes[i]}$`)
- if (currentRegex.test(currentUrl)) {
+ if (prohibitedTypes[i].test(currentUrl)) {
return false
}
}
diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js
index 89c7cc888..e55b09d03 100644
--- a/app/scripts/controllers/blacklist.js
+++ b/app/scripts/controllers/blacklist.js
@@ -83,8 +83,25 @@ class BlacklistController {
*
*/
async updatePhishingList () {
- const response = await fetch('https://api.infura.io/v2/blacklist')
- const phishing = await response.json()
+ // make request
+ let response
+ try {
+ response = await fetch('https://api.infura.io/v2/blacklist')
+ } catch (err) {
+ log.error(new Error(`BlacklistController - failed to fetch blacklist:\n${err.stack}`))
+ return
+ }
+ // parse response
+ let rawResponse
+ let phishing
+ try {
+ const rawResponse = await response.text()
+ phishing = JSON.parse(rawResponse)
+ } catch (err) {
+ log.error(new Error(`BlacklistController - failed to parse blacklist:\n${rawResponse}`))
+ return
+ }
+ // update current blacklist
this.store.updateState({ phishing })
this._setupPhishingDetector(phishing)
return phishing
@@ -97,9 +114,9 @@ class BlacklistController {
*/
scheduleUpdates () {
if (this._phishingUpdateIntervalRef) return
- this.updatePhishingList().catch(log.warn)
+ this.updatePhishingList()
this._phishingUpdateIntervalRef = setInterval(() => {
- this.updatePhishingList().catch(log.warn)
+ this.updatePhishingList()
}, POLLING_INTERVAL)
}
diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js
index d5bc5fe2b..fce65fd9c 100644
--- a/app/scripts/controllers/currency.js
+++ b/app/scripts/controllers/currency.js
@@ -21,6 +21,7 @@ class CurrencyController {
* since midnight of January 1, 1970
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
* Used to clear an existing interval on subsequent calls of that method.
+ * @property {string} nativeCurrency The ticker/symbol of the native chain currency
*
*/
constructor (opts = {}) {
@@ -28,6 +29,7 @@ class CurrencyController {
currentCurrency: 'usd',
conversionRate: 0,
conversionDate: 'N/A',
+ nativeCurrency: 'ETH',
}, opts.initState)
this.store = new ObservableStore(initState)
}
@@ -37,6 +39,29 @@ class CurrencyController {
//
/**
+ * A getter for the nativeCurrency property
+ *
+ * @returns {string} A 2-4 character shorthand that describes the specific currency
+ *
+ */
+ getNativeCurrency () {
+ return this.store.getState().nativeCurrency
+ }
+
+ /**
+ * A setter for the nativeCurrency property
+ *
+ * @param {string} nativeCurrency The new currency to set as the nativeCurrency in the store
+ *
+ */
+ setNativeCurrency (nativeCurrency) {
+ this.store.updateState({
+ nativeCurrency,
+ ticker: nativeCurrency,
+ })
+ }
+
+ /**
* A getter for the currentCurrency property
*
* @returns {string} A 2-4 character shorthand that describes a specific currency, currently selected by the user
@@ -104,17 +129,60 @@ class CurrencyController {
*
*/
async updateConversionRate () {
- let currentCurrency
+ let currentCurrency, nativeCurrency
try {
currentCurrency = this.getCurrentCurrency()
- const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`)
- const parsedResponse = await response.json()
- this.setConversionRate(Number(parsedResponse.bid))
- this.setConversionDate(Number(parsedResponse.timestamp))
+ nativeCurrency = this.getNativeCurrency()
+ // select api
+ let apiUrl
+ if (nativeCurrency === 'ETH') {
+ // ETH
+ apiUrl = `https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`
+ } else {
+ // ETC
+ apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${nativeCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}`
+ }
+ // attempt request
+ let response
+ try {
+ response = await fetch(apiUrl)
+ } catch (err) {
+ log.error(new Error(`CurrencyController - Failed to request currency from Infura:\n${err.stack}`))
+ return
+ }
+ // parse response
+ let rawResponse
+ let parsedResponse
+ try {
+ rawResponse = await response.text()
+ parsedResponse = JSON.parse(rawResponse)
+ } catch (err) {
+ log.error(new Error(`CurrencyController - Failed to parse response "${rawResponse}"`))
+ return
+ }
+ // set conversion rate
+ if (nativeCurrency === 'ETH') {
+ // ETH
+ this.setConversionRate(Number(parsedResponse.bid))
+ this.setConversionDate(Number(parsedResponse.timestamp))
+ } else {
+ // ETC
+ if (parsedResponse[currentCurrency.toUpperCase()]) {
+ this.setConversionRate(Number(parsedResponse[currentCurrency.toUpperCase()]))
+ this.setConversionDate(parseInt((new Date()).getTime() / 1000))
+ } else {
+ this.setConversionRate(0)
+ this.setConversionDate('N/A')
+ }
+ }
} catch (err) {
- log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err)
+ // reset current conversion rate
+ log.warn(`MetaMask - Failed to query currency conversion:`, nativeCurrency, currentCurrency, err)
this.setConversionRate(0)
this.setConversionDate('N/A')
+ // throw error
+ log.error(new Error(`CurrencyController - Failed to query rate for currency "${currentCurrency}":\n${err.stack}`))
+ return
}
}
diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js
index 9e6a45888..319c5bf3e 100644
--- a/app/scripts/controllers/network/createMetamaskMiddleware.js
+++ b/app/scripts/controllers/network/createMetamaskMiddleware.js
@@ -11,6 +11,7 @@ function createMetamaskMiddleware ({
processTransaction,
processEthSignMessage,
processTypedMessage,
+ processTypedMessageV3,
processPersonalMessage,
getPendingNonce,
}) {
@@ -25,6 +26,7 @@ function createMetamaskMiddleware ({
processTransaction,
processEthSignMessage,
processTypedMessage,
+ processTypedMessageV3,
processPersonalMessage,
}),
createPendingNonceMiddleware({ getPendingNonce }),
diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js
index c1667d9a6..c21e9c764 100644
--- a/app/scripts/controllers/network/network.js
+++ b/app/scripts/controllers/network/network.js
@@ -11,6 +11,8 @@ const createInfuraClient = require('./createInfuraClient')
const createJsonRpcClient = require('./createJsonRpcClient')
const createLocalhostClient = require('./createLocalhostClient')
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
+const extend = require('extend')
+const networks = { networkList: {} }
const {
ROPSTEN,
@@ -29,6 +31,10 @@ const defaultProviderConfig = {
type: testMode ? RINKEBY : MAINNET,
}
+const defaultNetworkConfig = {
+ ticker: 'ETH',
+}
+
module.exports = class NetworkController extends EventEmitter {
constructor (opts = {}) {
@@ -39,7 +45,8 @@ module.exports = class NetworkController extends EventEmitter {
// create stores
this.providerStore = new ObservableStore(providerConfig)
this.networkStore = new ObservableStore('loading')
- this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
+ this.networkConfig = new ObservableStore(defaultNetworkConfig)
+ this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
this.on('networkDidChange', this.lookupNetwork)
// provider and block tracker
this._provider = null
@@ -51,8 +58,8 @@ module.exports = class NetworkController extends EventEmitter {
initializeProvider (providerParams) {
this._baseProviderParams = providerParams
- const { type, rpcTarget } = this.providerStore.getState()
- this._configureProvider({ type, rpcTarget })
+ const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
+ this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
this.lookupNetwork()
}
@@ -72,7 +79,20 @@ module.exports = class NetworkController extends EventEmitter {
return this.networkStore.getState()
}
- setNetworkState (network) {
+ getNetworkConfig () {
+ return this.networkConfig.getState()
+ }
+
+ setNetworkState (network, type) {
+ if (network === 'loading') {
+ return this.networkStore.putState(network)
+ }
+
+ // type must be defined
+ if (!type) {
+ return
+ }
+ network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network
return this.networkStore.putState(network)
}
@@ -85,18 +105,32 @@ module.exports = class NetworkController extends EventEmitter {
if (!this._provider) {
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
}
+ var { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider)
- ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
- if (err) return this.setNetworkState('loading')
- log.info('web3.getNetwork returned ' + network)
- this.setNetworkState(network)
+ // first attempt to perform lookup via eth_chainId
+ ethQuery.sendAsync({ method: 'eth_chainId' }, (err, chainIdHex) => {
+ if (err) {
+ // if eth_chainId is not supported, fallback to net_verion
+ ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
+ if (err) return this.setNetworkState('loading')
+ log.info(`net_version returned ${network}`)
+ this.setNetworkState(network, type)
+ })
+ return
+ }
+ const chainId = Number.parseInt(chainIdHex, 16)
+ log.info(`net_version returned ${chainId}`)
+ this.setNetworkState(chainId, type)
})
}
- setRpcTarget (rpcTarget) {
+ setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
const providerConfig = {
type: 'rpc',
rpcTarget,
+ chainId,
+ ticker,
+ nickname,
}
this.providerConfig = providerConfig
}
@@ -132,7 +166,7 @@ module.exports = class NetworkController extends EventEmitter {
}
_configureProvider (opts) {
- const { type, rpcTarget } = opts
+ const { type, rpcTarget, chainId, ticker, nickname } = opts
// infura type-based endpoints
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
if (isInfura) {
@@ -142,7 +176,7 @@ module.exports = class NetworkController extends EventEmitter {
this._configureLocalhostProvider()
// url-based rpc endpoints
} else if (type === 'rpc') {
- this._configureStandardProvider({ rpcUrl: rpcTarget })
+ this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
}
@@ -152,6 +186,11 @@ module.exports = class NetworkController extends EventEmitter {
log.info('NetworkController - configureInfuraProvider', type)
const networkClient = createInfuraClient({ network: type })
this._setNetworkClient(networkClient)
+ // setup networkConfig
+ var settings = {
+ ticker: 'ETH',
+ }
+ this.networkConfig.putState(settings)
}
_configureLocalhostProvider () {
@@ -160,9 +199,22 @@ module.exports = class NetworkController extends EventEmitter {
this._setNetworkClient(networkClient)
}
- _configureStandardProvider ({ rpcUrl }) {
+ _configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) {
log.info('NetworkController - configureStandardProvider', rpcUrl)
const networkClient = createJsonRpcClient({ rpcUrl })
+ // hack to add a 'rpc' network with chainId
+ networks.networkList['rpc'] = {
+ chainId: chainId,
+ rpcUrl,
+ ticker: ticker || 'ETH',
+ nickname,
+ }
+ // setup networkConfig
+ var settings = {
+ network: chainId,
+ }
+ settings = extend(settings, networks.networkList['rpc'])
+ this.networkConfig.putState(settings)
this._setNetworkClient(networkClient)
}
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index fd6a4866d..eaeaee499 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -25,7 +25,7 @@ class PreferencesController {
*/
constructor (opts = {}) {
const initState = extend({
- frequentRpcList: [],
+ frequentRpcListDetail: [],
currentAccountTab: 'history',
accountTokens: {},
assetImages: {},
@@ -38,6 +38,9 @@ class PreferencesController {
lostIdentities: {},
seedWords: null,
forgottenPassword: false,
+ preferences: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ },
}, opts.initState)
this.diagnostics = opts.diagnostics
@@ -101,7 +104,7 @@ class PreferencesController {
* @param {Function} - end
*/
async requestWatchAsset (req, res, next, end) {
- if (req.method === 'metamask_watchAsset') {
+ if (req.method === 'metamask_watchAsset' || req.method === 'wallet_watchAsset') {
const { type, options } = req.params
switch (type) {
case 'ERC20':
@@ -372,22 +375,6 @@ class PreferencesController {
}
/**
- * Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
- *
- * @param {string} _url The the new rpc url to add to the updated list
- * @param {bool} remove Remove selected url
- * @returns {Promise<void>} Promise resolves with undefined
- *
- */
- updateFrequentRpcList (_url, remove = false) {
- return this.addToFrequentRpcList(_url, remove)
- .then((rpcList) => {
- this.store.updateState({ frequentRpcList: rpcList })
- return Promise.resolve()
- })
- }
-
- /**
* Setter for the `currentAccountTab` property
*
* @param {string} currentAccountTab Specifies the new tab to be marked as current
@@ -402,35 +389,53 @@ class PreferencesController {
}
/**
- * Returns an updated rpcList based on the passed url and the current list.
- * The returned list will have a max length of 3. If the _url currently exists it the list, it will be moved to the
- * end of the list. The current list is modified and returned as a promise.
+ * Adds custom RPC url to state.
*
- * @param {string} _url The rpc url to add to the frequentRpcList.
- * @param {bool} remove Remove selected url
- * @returns {Promise<array>} The updated frequentRpcList.
+ * @param {string} url The RPC url to add to frequentRpcList.
+ * @param {number} chainId Optional chainId of the selected network.
+ * @param {string} ticker Optional ticker symbol of the selected network.
+ * @param {string} nickname Optional nickname of the selected network.
+ * @returns {Promise<array>} Promise resolving to updated frequentRpcList.
*
*/
- addToFrequentRpcList (_url, remove = false) {
- const rpcList = this.getFrequentRpcList()
- const index = rpcList.findIndex((element) => { return element === _url })
+ addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '') {
+ const rpcList = this.getFrequentRpcListDetail()
+ const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
- if (!remove && _url !== 'http://localhost:8545') {
- rpcList.push(_url)
+ if (url !== 'http://localhost:8545') {
+ rpcList.push({ rpcUrl: url, chainId, ticker, nickname })
+ }
+ this.store.updateState({ frequentRpcListDetail: rpcList })
+ return Promise.resolve(rpcList)
+ }
+
+ /**
+ * Removes custom RPC url from state.
+ *
+ * @param {string} url The RPC url to remove from frequentRpcList.
+ * @returns {Promise<array>} Promise resolving to updated frequentRpcList.
+ *
+ */
+ removeFromFrequentRpcList (url) {
+ const rpcList = this.getFrequentRpcListDetail()
+ const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
+ if (index !== -1) {
+ rpcList.splice(index, 1)
}
+ this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
}
/**
- * Getter for the `frequentRpcList` property.
+ * Getter for the `frequentRpcListDetail` property.
*
- * @returns {array<string>} An array of one or two rpc urls.
+ * @returns {array<array>} An array of rpc urls.
*
*/
- getFrequentRpcList () {
- return this.store.getState().frequentRpcList
+ getFrequentRpcListDetail () {
+ return this.store.getState().frequentRpcListDetail
}
/**
@@ -463,6 +468,33 @@ class PreferencesController {
getFeatureFlags () {
return this.store.getState().featureFlags
}
+
+ /**
+ * Updates the `preferences` property, which is an object. These are user-controlled features
+ * found in the settings page.
+ * @param {string} preference The preference to enable or disable.
+ * @param {boolean} value Indicates whether or not the preference should be enabled or disabled.
+ * @returns {Promise<object>} Promises a new object; the updated preferences object.
+ */
+ setPreference (preference, value) {
+ const currentPreferences = this.getPreferences()
+ const updatedPreferences = {
+ ...currentPreferences,
+ [preference]: value,
+ }
+
+ this.store.updateState({ preferences: updatedPreferences })
+ return Promise.resolve(updatedPreferences)
+ }
+
+ /**
+ * A getter for the `preferences` property
+ * @returns {object} A key-boolean map of user-selected preferences.
+ */
+ getPreferences () {
+ return this.store.getState().preferences
+ }
+
//
// PRIVATE METHODS
//
diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js
index ebd49f882..9f2290924 100644
--- a/app/scripts/controllers/transactions/index.js
+++ b/app/scripts/controllers/transactions/index.js
@@ -166,6 +166,10 @@ class TransactionController extends EventEmitter {
async addUnapprovedTransaction (txParams) {
// validate
const normalizedTxParams = txUtils.normalizeTxParams(txParams)
+ // Assert the from address is the selected address
+ if (normalizedTxParams.from !== this.getSelectedAddress()) {
+ throw new Error(`Transaction from address isn't valid for this account`)
+ }
txUtils.validateTxParams(normalizedTxParams)
// construct txMeta
let txMeta = this.txStateManager.generateTxMeta({
@@ -362,7 +366,40 @@ class TransactionController extends EventEmitter {
this.txStateManager.setTxStatusSubmitted(txId)
}
- confirmTransaction (txId) {
+ /**
+ * Sets the status of the transaction to confirmed and sets the status of nonce duplicates as
+ * dropped if the txParams have data it will fetch the txReceipt
+ * @param {number} txId - The tx's ID
+ * @returns {Promise<void>}
+ */
+ async confirmTransaction (txId) {
+ // get the txReceipt before marking the transaction confirmed
+ // to ensure the receipt is gotten before the ui revives the tx
+ const txMeta = this.txStateManager.getTx(txId)
+
+ if (!txMeta) {
+ return
+ }
+
+ try {
+ const txReceipt = await this.query.getTransactionReceipt(txMeta.hash)
+
+ // It seems that sometimes the numerical values being returned from
+ // this.query.getTransactionReceipt are BN instances and not strings.
+ const gasUsed = typeof txReceipt.gasUsed !== 'string'
+ ? txReceipt.gasUsed.toString(16)
+ : txReceipt.gasUsed
+
+ txMeta.txReceipt = {
+ ...txReceipt,
+ gasUsed,
+ }
+
+ this.txStateManager.updateTx(txMeta, 'transactions#confirmTransaction - add txReceipt')
+ } catch (err) {
+ log.error(err)
+ }
+
this.txStateManager.setTxStatusConfirmed(txId)
this._markNonceDuplicatesDropped(txId)
}
diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js
index 3dd45507f..def67c2c3 100644
--- a/app/scripts/controllers/transactions/tx-gas-utils.js
+++ b/app/scripts/controllers/transactions/tx-gas-utils.js
@@ -7,6 +7,8 @@ const {
const { addHexPrefix } = require('ethereumjs-util')
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
+import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/constants/error-keys'
+
/**
tx-gas-utils are gas utility methods for Transaction manager
its passed ethquery
@@ -32,6 +34,7 @@ class TxGasUtil {
} catch (err) {
txMeta.simulationFails = {
reason: err.message,
+ errorKey: err.errorKey,
}
return txMeta
}
@@ -56,24 +59,38 @@ class TxGasUtil {
return txParams.gas
}
- // if recipient has no code, gas is 21k max:
const recipient = txParams.to
const hasRecipient = Boolean(recipient)
- let code
- if (recipient) code = await this.query.getCode(recipient)
- if (hasRecipient && (!code || code === '0x')) {
- txParams.gas = SIMPLE_GAS_COST
- txMeta.simpleSend = true // Prevents buffer addition
- return SIMPLE_GAS_COST
+ // see if we can set the gas based on the recipient
+ if (hasRecipient) {
+ const code = await this.query.getCode(recipient)
+ // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0'
+ const codeIsEmpty = !code || code === '0x' || code === '0x0'
+
+ if (codeIsEmpty) {
+ // if there's data in the params, but there's no contract code, it's not a valid transaction
+ if (txParams.data) {
+ const err = new Error('TxGasUtil - Trying to call a function on a non-contract address')
+ // set error key so ui can display localized error message
+ err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY
+ throw err
+ }
+
+ // This is a standard ether simple send, gas requirement is exactly 21k
+ txParams.gas = SIMPLE_GAS_COST
+ // prevents buffer addition
+ txMeta.simpleSend = true
+ return SIMPLE_GAS_COST
+ }
}
- // if not, fall back to block gasLimit
+ // fallback to block gasLimit
const blockGasLimitBN = hexToBn(blockGasLimitHex)
const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
txParams.gas = bnToHex(saferGasLimitBN)
- // run tx
+ // estimate tx gas requirements
return await this.query.estimateGas(txParams)
}
diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js
index daa6cc388..58c48e34e 100644
--- a/app/scripts/controllers/transactions/tx-state-manager.js
+++ b/app/scripts/controllers/transactions/tx-state-manager.js
@@ -400,6 +400,11 @@ class TransactionStateManager extends EventEmitter {
*/
_setTxStatus (txId, status) {
const txMeta = this.getTx(txId)
+
+ if (!txMeta) {
+ return
+ }
+
txMeta.status = status
setTimeout(() => {
try {
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js
index 431702d63..b885a7e05 100644
--- a/app/scripts/inpage.js
+++ b/app/scripts/inpage.js
@@ -27,6 +27,8 @@ var metamaskStream = new LocalMessageDuplexStream({
// compose the inpage provider
var inpageProvider = new MetamaskInpageProvider(metamaskStream)
+// set a high max listener count to avoid unnecesary warnings
+inpageProvider.setMaxListeners(100)
// Augment the provider with its enable method
inpageProvider.enable = function (options = {}) {
diff --git a/app/scripts/lib/contracts/registrar.js b/app/scripts/lib/ens-ipfs/contracts/registrar.js
index 99ca24458..99ca24458 100644
--- a/app/scripts/lib/contracts/registrar.js
+++ b/app/scripts/lib/ens-ipfs/contracts/registrar.js
diff --git a/app/scripts/lib/contracts/resolver.js b/app/scripts/lib/ens-ipfs/contracts/resolver.js
index 1bf3f90ce..1bf3f90ce 100644
--- a/app/scripts/lib/contracts/resolver.js
+++ b/app/scripts/lib/ens-ipfs/contracts/resolver.js
diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js
new file mode 100644
index 000000000..fe2dc1134
--- /dev/null
+++ b/app/scripts/lib/ens-ipfs/resolver.js
@@ -0,0 +1,54 @@
+const namehash = require('eth-ens-namehash')
+const multihash = require('multihashes')
+const Eth = require('ethjs-query')
+const EthContract = require('ethjs-contract')
+const registrarAbi = require('./contracts/registrar')
+const resolverAbi = require('./contracts/resolver')
+
+module.exports = resolveEnsToIpfsContentId
+
+
+async function resolveEnsToIpfsContentId ({ provider, name }) {
+ const eth = new Eth(provider)
+ const hash = namehash.hash(name)
+ const contract = new EthContract(eth)
+ // lookup registrar
+ const chainId = Number.parseInt(await eth.net_version(), 10)
+ const registrarAddress = getRegistrarForChainId(chainId)
+ if (!registrarAddress) {
+ throw new Error(`EnsIpfsResolver - no known ens-ipfs registrar for chainId "${chainId}"`)
+ }
+ const Registrar = contract(registrarAbi).at(registrarAddress)
+ // lookup resolver
+ const resolverLookupResult = await Registrar.resolver(hash)
+ const resolverAddress = resolverLookupResult[0]
+ if (hexValueIsEmpty(resolverAddress)) {
+ throw new Error(`EnsIpfsResolver - no resolver found for name "${name}"`)
+ }
+ const Resolver = contract(resolverAbi).at(resolverAddress)
+ // lookup content id
+ const contentLookupResult = await Resolver.content(hash)
+ const contentHash = contentLookupResult[0]
+ if (hexValueIsEmpty(contentHash)) {
+ throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`)
+ }
+ const nonPrefixedHex = contentHash.slice(2)
+ const buffer = multihash.fromHexString(nonPrefixedHex)
+ const contentId = multihash.toB58String(multihash.encode(buffer, 'sha2-256'))
+ return contentId
+}
+
+function hexValueIsEmpty(value) {
+ return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value)
+}
+
+function getRegistrarForChainId (chainId) {
+ switch (chainId) {
+ // mainnet
+ case 1:
+ return '0x314159265dd8dbb310642f98f50c066173c1259b'
+ // ropsten
+ case 3:
+ return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
+ }
+}
diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js
new file mode 100644
index 000000000..45eb1ce14
--- /dev/null
+++ b/app/scripts/lib/ens-ipfs/setup.js
@@ -0,0 +1,63 @@
+const urlUtil = require('url')
+const extension = require('extensionizer')
+const resolveEnsToIpfsContentId = require('./resolver.js')
+
+const supportedTopLevelDomains = ['eth']
+
+module.exports = setupEnsIpfsResolver
+
+function setupEnsIpfsResolver({ provider }) {
+
+ // install listener
+ const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
+ extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns })
+
+ // return api object
+ return {
+ // uninstall listener
+ remove () {
+ extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail)
+ },
+ }
+
+ async function webRequestDidFail (details) {
+ const { tabId, url } = details
+ // ignore requests that are not associated with tabs
+ if (tabId === -1) return
+ // parse ens name
+ const urlData = urlUtil.parse(url)
+ const { hostname: name, path, search } = urlData
+ const domainParts = name.split('.')
+ const topLevelDomain = domainParts[domainParts.length - 1]
+ // if unsupported TLD, abort
+ if (!supportedTopLevelDomains.includes(topLevelDomain)) return
+ // otherwise attempt resolve
+ attemptResolve({ tabId, name, path, search })
+ }
+
+ async function attemptResolve({ tabId, name, path, search }) {
+ extension.tabs.update(tabId, { url: `loading.html` })
+ try {
+ const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name })
+ let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}`
+ try {
+ // check if ipfs gateway has result
+ const response = await fetch(url, { method: 'HEAD' })
+ // if failure, redirect to 404 page
+ if (response.status !== 200) {
+ extension.tabs.update(tabId, { url: '404.html' })
+ return
+ }
+ // otherwise redirect to the correct page
+ extension.tabs.update(tabId, { url })
+ } catch (err) {
+ console.warn(err)
+ // if HEAD fetch failed, redirect so user can see relevant error page
+ extension.tabs.update(tabId, { url })
+ }
+ } catch (err) {
+ console.warn(err)
+ extension.tabs.update(tabId, { url: `error.html?name=${name}` })
+ }
+ }
+}
diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js
deleted file mode 100644
index 8b08453c4..000000000
--- a/app/scripts/lib/ipfsContent.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const extension = require('extensionizer')
-const resolver = require('./resolver.js')
-
-module.exports = function (provider) {
- function ipfsContent (details) {
- const name = details.url.substring(7, details.url.length - 1)
- let clearTime = null
- if (/^.+\.eth$/.test(name) === false) return
-
- extension.tabs.query({active: true}, tab => {
- extension.tabs.update(tab.id, { url: 'loading.html' })
-
- clearTime = setTimeout(() => {
- return extension.tabs.update(tab.id, { url: '404.html' })
- }, 60000)
-
- resolver.resolve(name, provider).then(ipfsHash => {
- clearTimeout(clearTime)
- let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
- return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => {
- if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' })
- extension.tabs.update(tab.id, { url: url })
- })
- .catch(err => {
- url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
- extension.tabs.update(tab.id, {url: url})
- return err
- })
- })
- .catch(err => {
- clearTimeout(clearTime)
- const url = err === 'unsupport' ? 'unsupport' : 'error'
- extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`})
- })
- })
- return { cancel: true }
- }
-
- extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']})
-
- return {
- remove () {
- extension.webRequest.onErrorOccurred.removeListener(ipfsContent)
- },
- }
-}
diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js
index df5661e59..de4d57145 100644
--- a/app/scripts/lib/reportFailedTxToSentry.js
+++ b/app/scripts/lib/reportFailedTxToSentry.js
@@ -7,10 +7,10 @@ module.exports = reportFailedTxToSentry
// for sending to sentry
//
-function reportFailedTxToSentry ({ raven, txMeta }) {
+function reportFailedTxToSentry ({ sentry, txMeta }) {
const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message)
- raven.captureMessage(errorMessage, {
+ sentry.captureMessage(errorMessage, {
// "extra" key is required by Sentry
- extra: txMeta,
+ extra: { txMeta },
})
}
diff --git a/app/scripts/lib/resolver.js b/app/scripts/lib/resolver.js
deleted file mode 100644
index ff0fed161..000000000
--- a/app/scripts/lib/resolver.js
+++ /dev/null
@@ -1,71 +0,0 @@
-const namehash = require('eth-ens-namehash')
-const multihash = require('multihashes')
-const HttpProvider = require('ethjs-provider-http')
-const Eth = require('ethjs-query')
-const EthContract = require('ethjs-contract')
-const registrarAbi = require('./contracts/registrar')
-const resolverAbi = require('./contracts/resolver')
-
-function ens (name, provider) {
- const eth = new Eth(new HttpProvider(getProvider(provider.type)))
- const hash = namehash.hash(name)
- const contract = new EthContract(eth)
- const Registrar = contract(registrarAbi).at(getRegistrar(provider.type))
- return new Promise((resolve, reject) => {
- if (provider.type === 'mainnet' || provider.type === 'ropsten') {
- Registrar.resolver(hash).then((address) => {
- if (address === '0x0000000000000000000000000000000000000000') {
- reject(null)
- } else {
- const Resolver = contract(resolverAbi).at(address['0'])
- return Resolver.content(hash)
- }
- }).then((contentHash) => {
- if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null)
- if (contentHash.ret !== '0x') {
- const hex = contentHash['0'].substring(2)
- const buf = multihash.fromHexString(hex)
- resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256')))
- } else {
- reject(null)
- }
- })
- } else {
- return reject('unsupport')
- }
- })
-}
-
-function getProvider (type) {
- switch (type) {
- case 'mainnet':
- return 'https://mainnet.infura.io/'
- case 'ropsten':
- return 'https://ropsten.infura.io/'
- default:
- return 'http://localhost:8545/'
- }
-}
-
-function getRegistrar (type) {
- switch (type) {
- case 'mainnet':
- return '0x314159265dd8dbb310642f98f50c066173c1259b'
- case 'ropsten':
- return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
- default:
- return '0x0000000000000000000000000000000000000000'
- }
-}
-
-module.exports.resolve = function (name, provider) {
- const path = name.split('.')
- const topLevelDomain = path[path.length - 1]
- if (topLevelDomain === 'eth' || topLevelDomain === 'test') {
- return ens(name, provider)
- } else {
- return new Promise((resolve, reject) => {
- reject(null)
- })
- }
-}
diff --git a/app/scripts/lib/setupFetchDebugging.js b/app/scripts/lib/setupFetchDebugging.js
new file mode 100644
index 000000000..c1ef22d21
--- /dev/null
+++ b/app/scripts/lib/setupFetchDebugging.js
@@ -0,0 +1,36 @@
+module.exports = setupFetchDebugging
+
+//
+// This is a utility to help resolve cases where `window.fetch` throws a
+// `TypeError: Failed to Fetch` without any stack or context for the request
+// https://github.com/getsentry/sentry-javascript/pull/1293
+//
+
+function setupFetchDebugging() {
+ if (!global.fetch) return
+ const originalFetch = global.fetch
+
+ global.fetch = wrappedFetch
+
+ async function wrappedFetch(...args) {
+ const initialStack = getCurrentStack()
+ try {
+ return await originalFetch.call(window, ...args)
+ } catch (err) {
+ if (!err.stack) {
+ console.warn('FetchDebugger - fetch encountered an Error without a stack', err)
+ console.warn('FetchDebugger - overriding stack to point of original call')
+ err.stack = initialStack
+ }
+ throw err
+ }
+ }
+}
+
+function getCurrentStack() {
+ try {
+ throw new Error('Fake error for generating stack trace')
+ } catch (err) {
+ return err.stack
+ }
+}
diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupSentry.js
index e6e511640..69042bc19 100644
--- a/app/scripts/lib/setupRaven.js
+++ b/app/scripts/lib/setupSentry.js
@@ -1,58 +1,55 @@
-const Raven = require('raven-js')
+const Sentry = require('@sentry/browser')
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
const extractEthjsErrorMessage = require('./extractEthjsErrorMessage')
-const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
-const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
+const SENTRY_DSN_PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
+const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
-module.exports = setupRaven
+module.exports = setupSentry
-// Setup raven / sentry remote error reporting
-function setupRaven (opts) {
- const { release } = opts
- let ravenTarget
+// Setup sentry remote error reporting
+function setupSentry (opts) {
+ const { release, getState } = opts
+ let sentryTarget
// detect brave
const isBrave = Boolean(window.chrome.ipcRenderer)
if (METAMASK_DEBUG) {
- console.log('Setting up Sentry Remote Error Reporting: DEV')
- ravenTarget = DEV
+ console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_DEV')
+ sentryTarget = SENTRY_DSN_DEV
} else {
- console.log('Setting up Sentry Remote Error Reporting: PROD')
- ravenTarget = PROD
+ console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_PROD')
+ sentryTarget = SENTRY_DSN_PROD
}
- const client = Raven.config(ravenTarget, {
+ Sentry.init({
+ dsn: sentryTarget,
+ debug: METAMASK_DEBUG,
release,
- transport: function (opts) {
- opts.data.extra.isBrave = isBrave
- const report = opts.data
+ beforeSend: (report) => rewriteReport(report),
+ })
- try {
- // handle error-like non-error exceptions
- rewriteErrorLikeExceptions(report)
- // simplify certain complex error messages (e.g. Ethjs)
- simplifyErrorMessages(report)
- // modify report urls
- rewriteReportUrls(report)
- } catch (err) {
- console.warn(err)
- }
- // make request normally
- client._makeRequest(opts)
- },
+ Sentry.configureScope(scope => {
+ scope.setExtra('isBrave', isBrave)
})
- client.install()
- return Raven
-}
+ function rewriteReport(report) {
+ try {
+ // simplify certain complex error messages (e.g. Ethjs)
+ simplifyErrorMessages(report)
+ // modify report urls
+ rewriteReportUrls(report)
+ // append app state
+ if (getState) {
+ const appState = getState()
+ report.extra.appState = appState
+ }
+ } catch (err) {
+ console.warn(err)
+ }
+ return report
+ }
-function rewriteErrorLikeExceptions (report) {
- // handle errors that lost their error-ness in serialization (e.g. dnode)
- rewriteErrorMessages(report, (errorMessage) => {
- if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage
- if (!(report.extra && report.extra.__serialized__ && report.extra.__serialized__.message)) return errorMessage
- return `Non-Error Exception: ${report.extra.__serialized__.message}`
- })
+ return Sentry
}
function simplifyErrorMessages (report) {
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 493877345..1f6a8659b 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -129,6 +129,7 @@ module.exports = class MetamaskController extends EventEmitter {
provider: this.provider,
blockTracker: this.blockTracker,
})
+
// start and stop polling for balances based on activeControllerConnections
this.on('controllerConnectionChanged', (activeControllerConnections) => {
if (activeControllerConnections > 0) {
@@ -138,6 +139,11 @@ module.exports = class MetamaskController extends EventEmitter {
}
})
+ // ensure accountTracker updates balances after network change
+ this.networkController.on('networkDidChange', () => {
+ this.accountTracker._updateAccounts()
+ })
+
// key mgmt
const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring]
this.keyringController = new KeyringController({
@@ -191,6 +197,8 @@ module.exports = class MetamaskController extends EventEmitter {
})
this.networkController.on('networkDidChange', () => {
this.balancesController.updateAllBalances()
+ var currentCurrency = this.currencyController.getCurrentCurrency()
+ this.setCurrentCurrency(currentCurrency, function() {})
})
this.balancesController.updateAllBalances()
@@ -269,6 +277,8 @@ module.exports = class MetamaskController extends EventEmitter {
processTransaction: this.newUnapprovedTransaction.bind(this),
// msg signing
processEthSignMessage: this.newUnsignedMessage.bind(this),
+ processTypedMessage: this.newUnsignedTypedMessage.bind(this),
+ processTypedMessageV3: this.newUnsignedTypedMessage.bind(this),
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
getPendingNonce: this.getPendingNonce.bind(this),
}
@@ -387,6 +397,7 @@ module.exports = class MetamaskController extends EventEmitter {
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController),
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
+ setPreference: nodeify(preferencesController.setPreference, preferencesController),
// BlacklistController
whitelistPhishingDomain: this.whitelistPhishingDomain.bind(this),
@@ -971,8 +982,8 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {Object} msgParams - The params passed to eth_signTypedData.
* @param {Function} cb - The callback function, called with the signature.
*/
- newUnsignedTypedMessage (msgParams, req) {
- const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req)
+ newUnsignedTypedMessage (msgParams, req, version) {
+ const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req, version)
this.sendUpdate()
this.opts.showUnconfirmedMessage()
return promise
@@ -1266,10 +1277,6 @@ module.exports = class MetamaskController extends EventEmitter {
engine.push(subscriptionManager.middleware)
// watch asset
engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController))
- // sign typed data middleware
- engine.push(this.createTypedDataMiddleware('eth_signTypedData', 'V1').bind(this))
- engine.push(this.createTypedDataMiddleware('eth_signTypedData_v1', 'V1').bind(this))
- engine.push(this.createTypedDataMiddleware('eth_signTypedData_v3', 'V3', true).bind(this))
// forward to metamask primary provider
engine.push(createProviderMiddleware({ provider }))
@@ -1405,10 +1412,13 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {Function} cb - A callback function returning currency info.
*/
setCurrentCurrency (currencyCode, cb) {
+ const { ticker } = this.networkController.getNetworkConfig()
try {
+ this.currencyController.setNativeCurrency(ticker)
this.currencyController.setCurrentCurrency(currencyCode)
this.currencyController.updateConversionRate()
const data = {
+ nativeCurrency: ticker || 'ETH',
conversionRate: this.currencyController.getConversionRate(),
currentCurrency: this.currencyController.getCurrentCurrency(),
conversionDate: this.currencyController.getConversionDate(),
@@ -1447,11 +1457,14 @@ module.exports = class MetamaskController extends EventEmitter {
/**
* A method for selecting a custom URL for an ethereum RPC provider.
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
+ * @param {number} chainId - The chainId of the selected network.
+ * @param {string} ticker - The ticker symbol of the selected network.
+ * @param {string} nickname - Optional nickname of the selected network.
* @returns {Promise<String>} - The RPC Target URL confirmed.
*/
- async setCustomRpc (rpcTarget) {
- this.networkController.setRpcTarget(rpcTarget)
- await this.preferencesController.updateFrequentRpcList(rpcTarget)
+ async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
+ this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname)
+ await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname)
return rpcTarget
}
@@ -1460,7 +1473,7 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {string} rpcTarget - A RPC URL to delete.
*/
async delCustomRpc (rpcTarget) {
- await this.preferencesController.updateFrequentRpcList(rpcTarget, true)
+ await this.preferencesController.removeFromFrequentRpcList(rpcTarget)
}
/**
@@ -1535,27 +1548,6 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {Function} - next
* @param {Function} - end
*/
- createTypedDataMiddleware (methodName, version, reverse) {
- return async (req, res, next, end) => {
- const { method, params } = req
- if (method === methodName) {
- const promise = this.typedMessageManager.addUnapprovedMessageAsync({
- data: reverse ? params[1] : params[0],
- from: reverse ? params[0] : params[1],
- }, req, version)
- this.sendUpdate()
- this.opts.showUnconfirmedMessage()
- try {
- res.result = await promise
- end()
- } catch (error) {
- end(error)
- }
- } else {
- next()
- }
- }
- }
/**
* Adds a domain to the {@link BlacklistController} whitelist
diff --git a/app/scripts/ui.js b/app/scripts/ui.js
index 98a036338..c4f6615db 100644
--- a/app/scripts/ui.js
+++ b/app/scripts/ui.js
@@ -9,7 +9,7 @@ const extension = require('extensionizer')
const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
-const setupRaven = require('./lib/setupRaven')
+const setupSentry = require('./lib/setupSentry')
const log = require('loglevel')
start().catch(log.error)
@@ -21,7 +21,17 @@ async function start () {
// setup sentry error reporting
const release = global.platform.getVersion()
- setupRaven({ release })
+ setupSentry({ release, getState })
+ // provide app state to append to error logs
+ function getState() {
+ // get app state
+ const state = window.getCleanAppState()
+ // remove unnecessary data
+ delete state.localeMessages
+ delete state.metamask.recentBlocks
+ // return state to be added to request
+ return state
+ }
// inject css
// const css = MetaMaskUiCss()
diff --git a/development/sentry-publish.js b/development/sentry-publish.js
index 7a6d55115..e14f3f176 100644
--- a/development/sentry-publish.js
+++ b/development/sentry-publish.js
@@ -14,21 +14,27 @@ async function start () {
const versionAlreadyExists = await checkIfVersionExists()
// abort if versions exists
if (versionAlreadyExists) {
- console.log(`Version "${VERSION}" already exists on Sentry, aborting sourcemap upload.`)
- return
+ console.log(`Version "${VERSION}" already exists on Sentry, skipping version creation`)
+ } else {
+ // create sentry release
+ console.log(`creating Sentry release for "${VERSION}"...`)
+ await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`)
+ console.log(`removing any existing files from Sentry release "${VERSION}"...`)
+ await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`)
}
- // create sentry release
- console.log(`creating Sentry release for "${VERSION}"...`)
- await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`)
- console.log(`removing any existing files from Sentry release "${VERSION}"...`)
- await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`)
- // upload sentry source and sourcemaps
- console.log(`uploading source files Sentry release "${VERSION}"...`)
- await exec(`for FILEPATH in ./dist/chrome/*.js; do [ -e $FILEPATH ] || continue; export FILE=\`basename $FILEPATH\` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload $FILEPATH metamask/$FILE; done;`)
- console.log(`uploading sourcemaps Sentry release "${VERSION}"...`)
- await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps'`)
- console.log('all done!')
+ // check if version has artifacts or not
+ const versionHasArtifacts = versionAlreadyExists && await checkIfVersionHasArtifacts()
+ if (!versionHasArtifacts) {
+ // upload sentry source and sourcemaps
+ console.log(`uploading source files Sentry release "${VERSION}"...`)
+ await exec(`for FILEPATH in ./dist/chrome/*.js; do [ -e $FILEPATH ] || continue; export FILE=\`basename $FILEPATH\` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload $FILEPATH metamask/$FILE; done;`)
+ console.log(`uploading sourcemaps Sentry release "${VERSION}"...`)
+ await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps'`)
+ console.log('all done!')
+ } else {
+ console.log(`Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`)
+ }
}
async function checkIfAuthWorks () {
@@ -45,6 +51,12 @@ async function checkIfVersionExists () {
return versionAlreadyExists
}
+async function checkIfVersionHasArtifacts () {
+ const artifacts = await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} list`)
+ // When there's no artifacts, we get a response from the shell like this ['', '']
+ return artifacts[0] && artifacts[0].length > 0
+}
+
async function doesNotFail (asyncFn) {
try {
await asyncFn()
diff --git a/development/states/add-token.json b/development/states/add-token.json
index d04b3a3ca..b59e9b757 100644
--- a/development/states/add-token.json
+++ b/development/states/add-token.json
@@ -107,7 +107,10 @@
"maxModeOn": false,
"editingTransactionId": null
},
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json
index 5017a4d57..1ffde3938 100644
--- a/development/states/confirm-sig-requests.json
+++ b/development/states/confirm-sig-requests.json
@@ -150,7 +150,10 @@
"maxModeOn": false,
"editingTransactionId": null
},
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/development/states/currency-localization.json b/development/states/currency-localization.json
index 847ea11a3..ef28891a3 100644
--- a/development/states/currency-localization.json
+++ b/development/states/currency-localization.json
@@ -108,7 +108,10 @@
"maxModeOn": false,
"editingTransactionId": null
},
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/development/states/first-time.json b/development/states/first-time.json
index a31b985a3..ff7078720 100644
--- a/development/states/first-time.json
+++ b/development/states/first-time.json
@@ -37,7 +37,10 @@
"shapeShiftTxList": [],
"lostAccounts": [],
"tokens": [],
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json
index bb4847155..0cd2f23f2 100644
--- a/development/states/send-new-ui.json
+++ b/development/states/send-new-ui.json
@@ -109,7 +109,10 @@
"maxModeOn": false,
"editingTransactionId": null
},
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/development/states/tx-list-items.json b/development/states/tx-list-items.json
index 0d2273cb0..e83179a17 100644
--- a/development/states/tx-list-items.json
+++ b/development/states/tx-list-items.json
@@ -102,7 +102,10 @@
"shapeShiftTxList": [{"depositAddress":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke","depositType":"BTC","key":"shapeshift","response":{"status":"no_deposits","address":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke"},"time":1522377459106}],
"lostAccounts": [],
"send": {},
- "currentLocale": "en"
+ "currentLocale": "en",
+ "preferences": {
+ "useNativeCurrencyAsPrimaryCurrency": true
+ }
},
"appState": {
"menuOpen": false,
diff --git a/gulpfile.js b/gulpfile.js
index 5a468d2f3..0a0e3b3d5 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -462,7 +462,9 @@ function generateBundler (opts, performBundle) {
bundler.transform(envify({
METAMASK_DEBUG: opts.devMode,
NODE_ENV: opts.devMode ? 'development' : 'production',
- }))
+ }), {
+ global: true,
+ })
if (opts.watch) {
bundler = watchify(bundler)
diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css
index a575fe97e..f3df240e7 100644
--- a/mascara/src/app/first-time/index.css
+++ b/mascara/src/app/first-time/index.css
@@ -17,7 +17,7 @@
font-family: Roboto;
}
-@media screen and (min-height: 576px) {
+@media screen and (min-height: 601px) {
.first-time-flow {
height: 100vh;
}
diff --git a/old-ui/app/app.js b/old-ui/app/app.js
index 9be21ebad..f5e03d4f6 100644
--- a/old-ui/app/app.js
+++ b/old-ui/app/app.js
@@ -73,7 +73,7 @@ function mapStateToProps (state) {
forgottenPassword: state.appState.forgottenPassword,
nextUnreadNotice: state.metamask.nextUnreadNotice,
lostAccounts: state.metamask.lostAccounts,
- frequentRpcList: state.metamask.frequentRpcList || [],
+ frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
featureFlags,
suggestedTokens: state.metamask.suggestedTokens,
diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js
index 234c06a01..fa8e499ed 100644
--- a/old-ui/app/components/app-bar.js
+++ b/old-ui/app/components/app-bar.js
@@ -17,7 +17,7 @@ module.exports = class AppBar extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
- frequentRpcList: PropTypes.array.isRequired,
+ frequentRpcListDetail: PropTypes.array.isRequired,
isMascara: PropTypes.bool.isRequired,
isOnboarding: PropTypes.bool.isRequired,
identities: PropTypes.any.isRequired,
@@ -196,7 +196,7 @@ module.exports = class AppBar extends Component {
renderNetworkDropdown () {
const {
dispatch,
- frequentRpcList: rpcList,
+ frequentRpcListDetail: rpcList,
provider,
} = this.props
const {
@@ -321,8 +321,8 @@ module.exports = class AppBar extends Component {
])
}
- renderCustomOption ({ rpcTarget, type }) {
- const {dispatch} = this.props
+ renderCustomOption ({ rpcTarget, type, ticker }) {
+ const {dispatch, network} = this.props
if (type !== 'rpc') {
return null
@@ -340,7 +340,7 @@ module.exports = class AppBar extends Component {
default:
return h(DropdownMenuItem, {
key: rpcTarget,
- onClick: () => dispatch(actions.setRpcTarget(rpcTarget)),
+ onClick: () => dispatch(actions.setRpcTarget(rpcTarget, network, ticker)),
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
}, [
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
@@ -354,7 +354,8 @@ module.exports = class AppBar extends Component {
const {dispatch} = this.props
const reversedRpcList = rpcList.slice().reverse()
- return reversedRpcList.map((rpc) => {
+ return reversedRpcList.map((entry) => {
+ const rpc = entry.rpcUrl
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) {
@@ -363,7 +364,7 @@ module.exports = class AppBar extends Component {
return h(DropdownMenuItem, {
key: `common${rpc}`,
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- onClick: () => dispatch(actions.setRpcTarget(rpc)),
+ onClick: () => dispatch(actions.setRpcTarget(rpc, entry.chainId, entry.ticker)),
}, [
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
rpc,
diff --git a/old-ui/app/components/balance.js b/old-ui/app/components/balance.js
index 57ca84564..8995f961f 100644
--- a/old-ui/app/components/balance.js
+++ b/old-ui/app/components/balance.js
@@ -1,12 +1,18 @@
const Component = require('react').Component
const h = require('react-hyperscript')
+const connect = require('react-redux').connect
const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const generateBalanceObject = require('../util').generateBalanceObject
const Tooltip = require('./tooltip.js')
const FiatValue = require('./fiat-value.js')
-module.exports = EthBalanceComponent
+module.exports = connect(mapStateToProps)(EthBalanceComponent)
+function mapStateToProps (state) {
+ return {
+ ticker: state.metamask.ticker,
+ }
+}
inherits(EthBalanceComponent, Component)
function EthBalanceComponent () {
@@ -16,9 +22,10 @@ function EthBalanceComponent () {
EthBalanceComponent.prototype.render = function () {
var props = this.props
let { value } = props
+ const { ticker } = props
var style = props.style
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
- value = value ? formatBalance(value, 6, needsParse) : '...'
+ value = value ? formatBalance(value, 6, needsParse, ticker) : '...'
var width = props.width
return (
diff --git a/old-ui/app/components/eth-balance.js b/old-ui/app/components/eth-balance.js
index 4f538fd31..4458e6a9a 100644
--- a/old-ui/app/components/eth-balance.js
+++ b/old-ui/app/components/eth-balance.js
@@ -1,12 +1,18 @@
const Component = require('react').Component
const h = require('react-hyperscript')
+const connect = require('react-redux').connect
const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const generateBalanceObject = require('../util').generateBalanceObject
const Tooltip = require('./tooltip.js')
const FiatValue = require('./fiat-value.js')
-module.exports = EthBalanceComponent
+module.exports = connect(mapStateToProps)(EthBalanceComponent)
+function mapStateToProps (state) {
+ return {
+ ticker: state.metamask.ticker,
+ }
+}
inherits(EthBalanceComponent, Component)
function EthBalanceComponent () {
@@ -16,9 +22,9 @@ function EthBalanceComponent () {
EthBalanceComponent.prototype.render = function () {
var props = this.props
let { value } = props
- const { style, width } = props
+ const { ticker, style, width } = props
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
- value = value ? formatBalance(value, 6, needsParse) : '...'
+ value = value ? formatBalance(value, 6, needsParse, ticker) : '...'
return (
diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js
index c8132539c..35e81210e 100644
--- a/old-ui/app/components/pending-tx.js
+++ b/old-ui/app/components/pending-tx.js
@@ -1,4 +1,5 @@
const Component = require('react').Component
+const connect = require('react-redux').connect
const h = require('react-hyperscript')
const inherits = require('util').inherits
const actions = require('../../../ui/app/actions')
@@ -19,7 +20,9 @@ const BNInput = require('./bn-as-decimal-input')
const MIN_GAS_PRICE_BN = new BN('0')
const MIN_GAS_LIMIT_BN = new BN('21000')
-module.exports = PendingTx
+module.exports = connect()(PendingTx)
+
+
inherits(PendingTx, Component)
function PendingTx () {
Component.call(this)
@@ -445,7 +448,8 @@ PendingTx.prototype.onSubmit = function (event) {
const txMeta = this.gatherTxMeta()
const valid = this.checkValidity()
this.setState({ valid, submitting: true })
- if (valid && this.verifyGasParams()) {
+ const validGasParams = this.verifyGasParams()
+ if (valid && validGasParams) {
this.props.sendTransaction(txMeta, event)
} else {
this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
@@ -488,8 +492,12 @@ PendingTx.prototype.verifyGasParams = function () {
)
}
-PendingTx.prototype._notZeroOrEmptyString = function (obj) {
- return obj !== '' && obj !== '0x0'
+PendingTx.prototype._notZeroOrEmptyString = function (value) {
+ // allow undefined values
+ if (value === undefined) return true
+ // Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
+ const valueIsEmpty = !value || value === '0x' || value === '0x0'
+ return !valueIsEmpty
}
PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
diff --git a/old-ui/app/config.js b/old-ui/app/config.js
index 392a6dba7..7a93887a5 100644
--- a/old-ui/app/config.js
+++ b/old-ui/app/config.js
@@ -68,7 +68,7 @@ ConfigScreen.prototype.render = function () {
currentProviderDisplay(metamaskState),
- h('div', { style: {display: 'flex'} }, [
+ h('div', { style: {display: 'block'} }, [
h('input#new_rpc', {
placeholder: 'New RPC URL',
style: {
@@ -81,7 +81,70 @@ ConfigScreen.prototype.render = function () {
if (event.key === 'Enter') {
var element = event.target
var newRpc = element.value
- rpcValidation(newRpc, state)
+ var chainid = document.querySelector('input#chainid')
+ var ticker = document.querySelector('input#ticker')
+ var nickname = document.querySelector('input#nickname')
+ rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
+ }
+ },
+ }),
+ h('br'),
+ h('input#chainid', {
+ placeholder: 'ChainId (optional)',
+ style: {
+ width: 'inherit',
+ flex: '1 0 auto',
+ height: '30px',
+ margin: '8px',
+ },
+ onKeyPress (event) {
+ if (event.key === 'Enter') {
+ var element = document.querySelector('input#new_rpc')
+ var newRpc = element.value
+ var chainid = document.querySelector('input#chainid')
+ var ticker = document.querySelector('input#ticker')
+ var nickname = document.querySelector('input#nickname')
+ rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
+ }
+ },
+ }),
+ h('br'),
+ h('input#ticker', {
+ placeholder: 'Symbol (optional)',
+ style: {
+ width: 'inherit',
+ flex: '1 0 auto',
+ height: '30px',
+ margin: '8px',
+ },
+ onKeyPress (event) {
+ if (event.key === 'Enter') {
+ var element = document.querySelector('input#new_rpc')
+ var newRpc = element.value
+ var chainid = document.querySelector('input#chainid')
+ var ticker = document.querySelector('input#ticker')
+ var nickname = document.querySelector('input#nickname')
+ rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
+ }
+ },
+ }),
+ h('br'),
+ h('input#nickname', {
+ placeholder: 'Nickname (optional)',
+ style: {
+ width: 'inherit',
+ flex: '1 0 auto',
+ height: '30px',
+ margin: '8px',
+ },
+ onKeyPress (event) {
+ if (event.key === 'Enter') {
+ var element = document.querySelector('input#new_rpc')
+ var newRpc = element.value
+ var chainid = document.querySelector('input#chainid')
+ var ticker = document.querySelector('input#ticker')
+ var nickname = document.querySelector('input#nickname')
+ rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
}
},
}),
@@ -93,7 +156,10 @@ ConfigScreen.prototype.render = function () {
event.preventDefault()
var element = document.querySelector('input#new_rpc')
var newRpc = element.value
- rpcValidation(newRpc, state)
+ var chainid = document.querySelector('input#chainid')
+ var ticker = document.querySelector('input#ticker')
+ var nickname = document.querySelector('input#nickname')
+ rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
},
}, 'Save'),
]),
@@ -189,9 +255,9 @@ ConfigScreen.prototype.render = function () {
)
}
-function rpcValidation (newRpc, state) {
+function rpcValidation (newRpc, chainid, ticker = 'ETH', nickname = '', state) {
if (validUrl.isWebUri(newRpc)) {
- state.dispatch(actions.setRpcTarget(newRpc))
+ state.dispatch(actions.setRpcTarget(newRpc, chainid, ticker, nickname))
} else {
var appendedRpc = `http://${newRpc}`
if (validUrl.isWebUri(appendedRpc)) {
diff --git a/old-ui/app/util.js b/old-ui/app/util.js
index 962832ce7..40e79b88c 100644
--- a/old-ui/app/util.js
+++ b/old-ui/app/util.js
@@ -102,7 +102,7 @@ function parseBalance (balance) {
// Takes wei hex, returns an object with three properties.
// Its "formatted" property is what we generally use to render values.
-function formatBalance (balance, decimalsToKeep, needsParse = true) {
+function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') {
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
var beforeDecimal = parsed[0]
var afterDecimal = parsed[1]
@@ -112,14 +112,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) {
if (afterDecimal !== '0') {
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
if (sigFigs) { afterDecimal = sigFigs[0] }
- formatted = '0.' + afterDecimal + ' ETH'
+ formatted = '0.' + afterDecimal + ` ${ticker}`
}
} else {
- formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ' ETH'
+ formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}`
}
} else {
afterDecimal += Array(decimalsToKeep).join('0')
- formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ' ETH'
+ formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}`
}
return formatted
}
diff --git a/package-lock.json b/package-lock.json
index a617d2de4..43a3aac15 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -489,6 +489,16 @@
}
}
},
+ "@sentry/browser": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.2.3.tgz",
+ "integrity": "sha512-XvuIc1aclz4zuP2LamDuSy62/gl1mmNxzF+Ni5L8mcghBDq0urnOdkblVQgzqGoH8mc2QfjEctGa5djWxg3Bpg==",
+ "requires": {
+ "@sentry/core": "4.2.3",
+ "@sentry/types": "4.2.3",
+ "@sentry/utils": "4.2.3"
+ }
+ },
"@sentry/cli": {
"version": "1.30.3",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.30.3.tgz",
@@ -531,6 +541,48 @@
}
}
},
+ "@sentry/core": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.2.3.tgz",
+ "integrity": "sha512-xo5rvksftnaEdnKbdokyfuqgMnuqw1DFp0lDboIFHlEBcQde/AdThEgLujJWmbVNI3Cg7g8/HvP65f7QBjKfOw==",
+ "requires": {
+ "@sentry/hub": "4.2.3",
+ "@sentry/minimal": "4.2.3",
+ "@sentry/types": "4.2.3",
+ "@sentry/utils": "4.2.3"
+ }
+ },
+ "@sentry/hub": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.2.3.tgz",
+ "integrity": "sha512-7Jc/wz3vybYm1RX2wk/4zAQS8fo3uxvXYBkRfpm3OmnGgTlwDEmJwtegeGWFqufxLl85brZ19V1KAdulmO206A==",
+ "requires": {
+ "@sentry/types": "4.2.3",
+ "@sentry/utils": "4.2.3"
+ }
+ },
+ "@sentry/minimal": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.2.3.tgz",
+ "integrity": "sha512-Hus7LUeJDGsYpT2RTe6bUjG7mHG9uQoyDmW6pYUMN2dhD+cP5cPoTIXO4yxokwgAeDa+GH2/UXoASWc4s2eA2w==",
+ "requires": {
+ "@sentry/hub": "4.2.3",
+ "@sentry/types": "4.2.3"
+ }
+ },
+ "@sentry/types": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.2.3.tgz",
+ "integrity": "sha512-Z7laXlLtLSEXcKzgcD2caWPMTM8sAvR86rssYM5uYb3azC5PO0aAvuhjokkdv1+Ke1Bg7lkaNZamiCSyaH/9xg=="
+ },
+ "@sentry/utils": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.2.3.tgz",
+ "integrity": "sha512-D6+M1081wCwGp8adWV3KFOxrxFmVyjMJ45x6/TnYvXdgDyc+t28oil21FHeKhwjld9eMqgQ5Tf1OOvos1MNBQg==",
+ "requires": {
+ "@sentry/types": "4.2.3"
+ }
+ },
"@sinonjs/formatio": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
@@ -1740,7 +1792,7 @@
"dependencies": {
"bignumber.js": {
"version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2",
- "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2"
+ "from": "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2"
},
"chai": {
"version": "3.5.0",
@@ -6131,9 +6183,9 @@
}
},
"clone": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
- "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs="
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
},
"clone-buffer": {
"version": "1.0.0",
@@ -9570,9 +9622,9 @@
}
},
"eth-block-tracker": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.3.tgz",
- "integrity": "sha512-Uy+5hEvOT1/C6N1Lw/uQ10v03ArnNEQEkM0yhJQWwpd8Ymy3sw4jk75SE58s1spfOBBtnr8JaSAFioAFSeg6HA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.1.0.tgz",
+ "integrity": "sha512-991xTy6CzYYbizkHmgRFFI9iGx1OCISve8sSLuOlt7/yD7VFH1Jd8mOmBqxaG5ywGkIXdwAR78nQ2WDReETzBg==",
"requires": {
"eth-json-rpc-infura": "^3.1.2",
"eth-query": "^2.1.0",
@@ -9604,7 +9656,7 @@
},
"eth-json-rpc-middleware": {
"version": "1.6.0",
- "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz",
+ "resolved": "http://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz",
"integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==",
"requires": {
"async": "^2.5.0",
@@ -9643,12 +9695,12 @@
},
"node-fetch": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
+ "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
"integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
},
"whatwg-fetch": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
+ "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
}
}
@@ -9691,12 +9743,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -9771,12 +9824,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -9897,29 +9951,26 @@
}
},
"eth-json-rpc-middleware": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.1.tgz",
- "integrity": "sha512-5mRpjmszVQbKaUk3kiKkP9+hyyD3ZIg3mJ+jiydZ46cfNbrFVzfTDvZKnYLPrQPEi4+CaYqF+7XnIHIGztd9JQ==",
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.6.tgz",
+ "integrity": "sha512-yf17/rAM4ElKMul8oSvuK7JuYIYEFFdy2YGPo2EZbuOEv2Wq1bteMlppgqZ9NYHriXLAOWV+ojY9kWHGbcU4xA==",
"dev": true,
"requires": {
- "async": "^2.5.0",
"btoa": "^1.2.1",
"clone": "^2.1.1",
"eth-query": "^2.1.2",
"eth-sig-util": "^1.4.2",
- "eth-tx-summary": "^3.1.2",
+ "eth-tx-summary": "^3.2.3",
"ethereumjs-block": "^1.6.0",
"ethereumjs-tx": "^1.3.3",
"ethereumjs-util": "^5.1.2",
- "ethereumjs-vm": "^2.1.0",
+ "ethereumjs-vm": "^2.4.0",
"fetch-ponyfill": "^4.0.0",
- "json-rpc-engine": "^3.6.3",
+ "json-rpc-engine": "^3.8.0",
"json-rpc-error": "^2.0.0",
"json-stable-stringify": "^1.0.1",
"pify": "^3.0.0",
- "promise-to-callback": "^1.0.0",
- "safe-event-emitter": "^1.0.1",
- "tape": "^4.6.3"
+ "safe-event-emitter": "^1.0.1"
},
"dependencies": {
"eth-sig-util": {
@@ -9928,12 +9979,12 @@
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"dev": true,
"requires": {
- "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"ethereumjs-util": "^5.1.1"
}
},
"ethereumjs-abi": {
- "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"dev": true,
"requires": {
@@ -9955,6 +10006,31 @@
"safe-buffer": "^5.1.1",
"secp256k1": "^3.0.1"
}
+ },
+ "ethereumjs-vm": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.4.0.tgz",
+ "integrity": "sha512-MJ4lCWa5c6LhahhhvoDKW+YGjK00ZQn0RHHLh4L+WaH1k6Qv7/q3uTluew6sJGNCZdlO0yYMDXYW9qyxLHKlgQ==",
+ "dev": true,
+ "requires": {
+ "async": "^2.1.2",
+ "async-eventemitter": "^0.2.2",
+ "ethereumjs-account": "^2.0.3",
+ "ethereumjs-block": "~1.7.0",
+ "ethereumjs-common": "~0.4.0",
+ "ethereumjs-util": "^5.2.0",
+ "fake-merkle-patricia-tree": "^1.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "merkle-patricia-tree": "^2.1.2",
+ "rustbn.js": "~0.2.0",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "rustbn.js": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz",
+ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==",
+ "dev": true
}
}
},
@@ -10002,12 +10078,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -10068,12 +10145,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -10333,12 +10411,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -10371,15 +10450,15 @@
}
},
"eth-token-tracker": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/eth-token-tracker/-/eth-token-tracker-1.1.4.tgz",
- "integrity": "sha1-Kf8kV9Zr+juO5JDoP/QP0M8s7EE=",
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/eth-token-tracker/-/eth-token-tracker-1.1.5.tgz",
+ "integrity": "sha512-dyNzEt62i5vpbAAHHj6kEVxSHg/WqCr7TBq1Sbs4y0PvsxcvfWLJpEYtJilndg36H7nJHGadgmHqGW5mYbcNfw==",
"requires": {
"deep-equal": "^1.0.1",
"eth-block-tracker": "^1.0.7",
- "ethjs": "^0.2.7",
- "ethjs-contract": "^0.1.9",
- "ethjs-query": "^0.2.6",
+ "ethjs": "^0.3.6",
+ "ethjs-contract": "^0.2.1",
+ "ethjs-query": "^0.3.7",
"human-standard-token-abi": "^1.0.2"
},
"dependencies": {
@@ -10408,81 +10487,58 @@
"ethjs-util": "^0.1.3",
"pify": "^2.3.0",
"tape": "^4.6.3"
- },
- "dependencies": {
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
- }
}
},
"ethjs": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/ethjs/-/ethjs-0.2.9.tgz",
- "integrity": "sha1-yagNR7ydVg9Z53gEnSIlXlgfMSs=",
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/ethjs/-/ethjs-0.3.9.tgz",
+ "integrity": "sha512-gOQzA3tDUjoLpNONSOALJ/rUFtHi5tXl2mholHasF1cvXhoddqi06yU4OJFJu9AGd6n9v9ywzHlYeIKg1t1hdw==",
"requires": {
"bn.js": "4.11.6",
- "ethjs-abi": "0.2.0",
- "ethjs-contract": "0.1.9",
- "ethjs-filter": "0.1.5",
+ "ethjs-abi": "0.2.1",
+ "ethjs-contract": "0.2.2",
+ "ethjs-filter": "0.1.8",
"ethjs-provider-http": "0.1.6",
- "ethjs-query": "0.3.0",
+ "ethjs-query": "0.3.7",
"ethjs-unit": "0.1.6",
"ethjs-util": "0.1.3",
"js-sha3": "0.5.5",
"number-to-bn": "1.7.0"
},
"dependencies": {
- "ethjs-format": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.3.tgz",
- "integrity": "sha1-m9hnyu6CstvtmEYAuzAiDPPLWDA=",
+ "ethjs-contract": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/ethjs-contract/-/ethjs-contract-0.2.2.tgz",
+ "integrity": "sha512-xxPqEjsULQ/QNWuvX6Ako0PGs5RxALA8N/H3+boLvnaXDFZVGpD7H63H1gBCRTZyYqCldPpVlVHuw/rD45vazw==",
"requires": {
- "bn.js": "4.11.6",
- "ethjs-schema": "^0.1.6",
+ "ethjs-abi": "0.2.0",
+ "ethjs-filter": "0.1.8",
"ethjs-util": "0.1.3",
- "is-hex-prefixed": "1.0.0",
- "number-to-bn": "1.7.0",
- "strip-hex-prefix": "1.0.0"
+ "js-sha3": "0.5.5"
+ },
+ "dependencies": {
+ "ethjs-abi": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.0.tgz",
+ "integrity": "sha1-0+LCIQEVIPxJm3FoIDbBT8wvWyU=",
+ "requires": {
+ "bn.js": "4.11.6",
+ "js-sha3": "0.5.5",
+ "number-to-bn": "1.7.0"
+ }
+ }
}
},
"ethjs-query": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.0.tgz",
- "integrity": "sha1-CAmNYQ+BvV+VSnpXq0mJ9+mBX8Q=",
+ "version": "0.3.7",
+ "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.7.tgz",
+ "integrity": "sha512-TZnKUwfkWjy0SowFdPLtmsytCorHi0i4vvkQn7Jg8rZt33cRzKhuzOwKr/G3vdigCc+ePXOhUGMcJSAPlOG44A==",
"requires": {
- "ethjs-format": "0.2.3",
- "ethjs-rpc": "0.1.5"
+ "ethjs-format": "0.2.7",
+ "ethjs-rpc": "0.2.0",
+ "promise-to-callback": "^1.0.0"
}
},
- "ethjs-schema": {
- "version": "0.1.9",
- "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.1.9.tgz",
- "integrity": "sha1-hYwqXacGrgSBK0zosetLSSHjMJI="
- },
- "ethjs-util": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz",
- "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=",
- "requires": {
- "is-hex-prefixed": "1.0.0",
- "strip-hex-prefix": "1.0.0"
- }
- }
- }
- },
- "ethjs-contract": {
- "version": "0.1.9",
- "resolved": "https://registry.npmjs.org/ethjs-contract/-/ethjs-contract-0.1.9.tgz",
- "integrity": "sha1-HCdmiWpW1H7B1tZhgpxJzDilUgo=",
- "requires": {
- "ethjs-abi": "0.2.0",
- "ethjs-filter": "0.1.5",
- "ethjs-util": "0.1.3",
- "js-sha3": "0.5.5"
- },
- "dependencies": {
"ethjs-util": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz",
@@ -10494,43 +10550,39 @@
}
}
},
- "ethjs-format": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.2.tgz",
- "integrity": "sha1-1zs6YFwuElcHn3B3/VRI6ZjOD80=",
+ "ethjs-abi": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz",
+ "integrity": "sha1-4KepOn6BFjqUR3utVu3lJKtt5TM=",
"requires": {
"bn.js": "4.11.6",
- "ethjs-schema": "0.1.5",
- "ethjs-util": "0.1.3",
- "is-hex-prefixed": "1.0.0",
- "number-to-bn": "1.7.0",
- "strip-hex-prefix": "1.0.0"
- },
- "dependencies": {
- "ethjs-util": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz",
- "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=",
- "requires": {
- "is-hex-prefixed": "1.0.0",
- "strip-hex-prefix": "1.0.0"
- }
- }
+ "js-sha3": "0.5.5",
+ "number-to-bn": "1.7.0"
}
},
+ "ethjs-filter": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/ethjs-filter/-/ethjs-filter-0.1.8.tgz",
+ "integrity": "sha512-qTDPskDL2UadHwjvM8A+WG9HwM4/FoSY3p3rMJORkHltYcAuiQZd2otzOYKcL5w2Q3sbAkW/E3yt/FPFL/AVXA=="
+ },
"ethjs-query": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.2.9.tgz",
- "integrity": "sha1-om5rTzhpnpLzSyGE51x4lDKcQvE=",
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.8.tgz",
+ "integrity": "sha512-/J5JydqrOzU8O7VBOwZKUWXxHDGr46VqNjBCJgBVNNda+tv7Xc8Y2uJc6aMHHVbeN3YOQ7YRElgIc0q1CI02lQ==",
"requires": {
- "ethjs-format": "0.2.2",
- "ethjs-rpc": "0.1.5"
+ "babel-runtime": "^6.26.0",
+ "ethjs-format": "0.2.7",
+ "ethjs-rpc": "0.2.0",
+ "promise-to-callback": "^1.0.0"
}
},
- "ethjs-schema": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.1.5.tgz",
- "integrity": "sha1-WXQOOzl3vNu5sRvDBoIB6Kzquw0="
+ "ethjs-rpc": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.2.0.tgz",
+ "integrity": "sha512-RINulkNZTKnj4R/cjYYtYMnFFaBcVALzbtEJEONrrka8IeoarNB9Jbzn+2rT00Cv8y/CxAI+GgY1d0/i2iQeOg==",
+ "requires": {
+ "promise-to-callback": "^1.0.0"
+ }
},
"human-standard-token-abi": {
"version": "1.0.2",
@@ -10541,6 +10593,11 @@
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz",
"integrity": "sha1-uvDA6MVK1ZA0R9+Wreekobynmko="
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
}
}
},
@@ -10561,12 +10618,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -10799,12 +10857,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -10922,6 +10981,12 @@
}
}
},
+ "ethereumjs-common": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-0.4.1.tgz",
+ "integrity": "sha512-ywYGsOeGCsMNWso5Y4GhjWI24FJv9FK7+VyVKiQgXg8ZRDPXJ7F/kJ1CnjtkjTvDF4e0yqU+FWswlqR3bmZQ9Q==",
+ "dev": true
+ },
"ethereumjs-tx": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.3.tgz",
@@ -10954,7 +11019,7 @@
},
"ethereumjs-util": {
"version": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
- "from": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
+ "from": "ethereumjs-util@github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"requires": {
"bn.js": "^4.8.0",
"create-hash": "^1.1.2",
@@ -11902,6 +11967,25 @@
"pend": "~1.2.0"
}
},
+ "fetch-mock": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-6.5.2.tgz",
+ "integrity": "sha512-EIvbpCLBTYyDLu4HJiqD7wC8psDwTUaPaWXNKZbhNO/peUYKiNp5PkZGKRJtnTxaPQu71ivqafvjpM7aL+MofQ==",
+ "dev": true,
+ "requires": {
+ "babel-polyfill": "^6.26.0",
+ "glob-to-regexp": "^0.4.0",
+ "path-to-regexp": "^2.2.1"
+ },
+ "dependencies": {
+ "path-to-regexp": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz",
+ "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==",
+ "dev": true
+ }
+ }
+ },
"fetch-ponyfill": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz",
@@ -12735,25 +12819,21 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
- "resolved": false,
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "bundled": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
- "resolved": false,
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ "bundled": true
},
"aproba": {
"version": "1.2.0",
- "resolved": false,
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "bundled": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
- "resolved": false,
- "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+ "bundled": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
@@ -12762,13 +12842,11 @@
},
"balanced-match": {
"version": "1.0.0",
- "resolved": false,
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ "bundled": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": false,
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "bundled": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -12776,35 +12854,29 @@
},
"chownr": {
"version": "1.0.1",
- "resolved": false,
- "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
+ "bundled": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "resolved": false,
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ "bundled": true
},
"concat-map": {
"version": "0.0.1",
- "resolved": false,
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
- "resolved": false,
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ "bundled": true
},
"core-util-is": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "bundled": true,
"optional": true
},
"debug": {
"version": "2.6.9",
- "resolved": false,
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "bundled": true,
"optional": true,
"requires": {
"ms": "2.0.0"
@@ -12812,26 +12884,22 @@
},
"deep-extend": {
"version": "0.5.1",
- "resolved": false,
- "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
+ "bundled": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
- "resolved": false,
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "bundled": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
- "resolved": false,
- "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "bundled": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
- "resolved": false,
- "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+ "bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -12839,14 +12907,12 @@
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": false,
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "bundled": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
- "resolved": false,
- "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "bundled": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
@@ -12861,8 +12927,7 @@
},
"glob": {
"version": "7.1.2",
- "resolved": false,
- "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "bundled": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -12875,14 +12940,12 @@
},
"has-unicode": {
"version": "2.0.1",
- "resolved": false,
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "bundled": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
- "resolved": false,
- "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
+ "bundled": true,
"optional": true,
"requires": {
"safer-buffer": "^2.1.0"
@@ -12890,8 +12953,7 @@
},
"ignore-walk": {
"version": "3.0.1",
- "resolved": false,
- "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+ "bundled": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
@@ -12899,8 +12961,7 @@
},
"inflight": {
"version": "1.0.6",
- "resolved": false,
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "bundled": true,
"optional": true,
"requires": {
"once": "^1.3.0",
@@ -12909,46 +12970,39 @@
},
"inherits": {
"version": "2.0.3",
- "resolved": false,
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "bundled": true
},
"ini": {
"version": "1.3.5",
- "resolved": false,
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "bundled": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "resolved": false,
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "bundled": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
- "resolved": false,
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "bundled": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
- "resolved": false,
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "bundled": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "resolved": false,
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ "bundled": true
},
"minipass": {
"version": "2.2.4",
- "resolved": false,
- "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
+ "bundled": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -12956,8 +13010,7 @@
},
"minizlib": {
"version": "1.1.0",
- "resolved": false,
- "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
+ "bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -12965,28 +13018,25 @@
},
"mkdirp": {
"version": "0.5.1",
- "resolved": false,
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "bundled": true,
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
- "resolved": false,
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "bundled": true,
"optional": true
},
"nan": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
- "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz",
+ "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==",
"optional": true
},
"needle": {
"version": "2.2.0",
- "resolved": false,
- "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
+ "bundled": true,
"optional": true,
"requires": {
"debug": "^2.1.2",
@@ -12996,8 +13046,7 @@
},
"node-pre-gyp": {
"version": "0.10.0",
- "resolved": false,
- "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
+ "bundled": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
@@ -13014,8 +13063,7 @@
},
"nopt": {
"version": "4.0.1",
- "resolved": false,
- "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "bundled": true,
"optional": true,
"requires": {
"abbrev": "1",
@@ -13024,14 +13072,12 @@
},
"npm-bundled": {
"version": "1.0.3",
- "resolved": false,
- "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
+ "bundled": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
- "resolved": false,
- "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
+ "bundled": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
@@ -13040,8 +13086,7 @@
},
"npmlog": {
"version": "4.1.2",
- "resolved": false,
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "bundled": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
@@ -13052,39 +13097,33 @@
},
"number-is-nan": {
"version": "1.0.1",
- "resolved": false,
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ "bundled": true
},
"object-assign": {
"version": "4.1.1",
- "resolved": false,
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "bundled": true,
"optional": true
},
"once": {
"version": "1.4.0",
- "resolved": false,
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "bundled": true,
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "bundled": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "bundled": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
- "resolved": false,
- "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "bundled": true,
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
@@ -13093,20 +13132,17 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "resolved": false,
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "bundled": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
- "resolved": false,
- "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "bundled": true,
"optional": true
},
"rc": {
"version": "1.2.7",
- "resolved": false,
- "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
+ "bundled": true,
"optional": true,
"requires": {
"deep-extend": "^0.5.1",
@@ -13117,16 +13153,14 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
- "resolved": false,
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "bundled": true,
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.6",
- "resolved": false,
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "bundled": true,
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -13140,8 +13174,7 @@
},
"rimraf": {
"version": "2.6.2",
- "resolved": false,
- "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "bundled": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
@@ -13149,43 +13182,36 @@
},
"safe-buffer": {
"version": "5.1.1",
- "resolved": false,
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ "bundled": true
},
"safer-buffer": {
"version": "2.1.2",
- "resolved": false,
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "bundled": true,
"optional": true
},
"sax": {
"version": "1.2.4",
- "resolved": false,
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "bundled": true,
"optional": true
},
"semver": {
"version": "5.5.0",
- "resolved": false,
- "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+ "bundled": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
- "resolved": false,
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "bundled": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
- "resolved": false,
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "bundled": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "bundled": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -13194,8 +13220,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": false,
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "bundled": true,
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
@@ -13203,22 +13228,19 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": false,
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "bundled": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
- "resolved": false,
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "bundled": true,
"optional": true
},
"tar": {
"version": "4.4.1",
- "resolved": false,
- "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
+ "bundled": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
@@ -13232,14 +13254,12 @@
},
"util-deprecate": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "bundled": true,
"optional": true
},
"wide-align": {
"version": "1.1.2",
- "resolved": false,
- "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+ "bundled": true,
"optional": true,
"requires": {
"string-width": "^1.0.2"
@@ -13247,13 +13267,11 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": false,
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ "bundled": true
},
"yallist": {
"version": "3.0.2",
- "resolved": false,
- "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
+ "bundled": true
}
}
},
@@ -13799,12 +13817,14 @@
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"dev": true,
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
+ "dev": true,
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -14302,15 +14322,361 @@
}
}
},
+ "glob-to-regexp": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.0.tgz",
+ "integrity": "sha512-fyPCII4vn9Gvjq2U/oDAfP433aiE64cyP/CJjRJcpVGjqqNdioUYn9+r0cSzT1XPwmGAHuTT7iv+rQT8u/YHKQ==",
+ "dev": true
+ },
"glob-watcher": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-4.0.0.tgz",
- "integrity": "sha1-nmOo/25h6TLebMLK7OUHGm1zcyk=",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.1.tgz",
+ "integrity": "sha512-fK92r2COMC199WCyGUblrZKhjra3cyVMDiypDdqg1vsSDmexnbYivK1kNR4QItiNXLKmGlqan469ks67RtNa2g==",
"requires": {
"async-done": "^1.2.0",
- "chokidar": "^1.4.3",
+ "chokidar": "^2.0.0",
"just-debounce": "^1.0.0",
"object.defaults": "^1.1.0"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "chokidar": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
+ "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.0",
+ "braces": "^2.3.0",
+ "fsevents": "^1.2.2",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "lodash.debounce": "^4.0.8",
+ "normalize-path": "^2.1.1",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0",
+ "upath": "^1.0.5"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "dependencies": {
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ }
+ }
+ },
+ "upath": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
+ "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw=="
+ }
}
},
"glob2base": {
@@ -14435,10 +14801,10 @@
"dev": true
},
"gulp": {
- "version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776",
- "from": "github:gulpjs/gulp#4.0",
+ "version": "github:gulpjs/gulp#55eb23a268dcc7340bb40808600fd4802848c06f",
+ "from": "github:gulpjs/gulp#v4.0.0",
"requires": {
- "glob-watcher": "^4.0.0",
+ "glob-watcher": "^5.0.0",
"gulp-cli": "^2.0.0",
"undertaker": "^1.0.0",
"vinyl-fs": "^3.0.0"
@@ -21548,9 +21914,9 @@
"dev": true
},
"mute-stdout": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.0.tgz",
- "integrity": "sha1-WzLqB+tDyd7WEwQ0z5JvRrKn/U0="
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+ "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg=="
},
"mute-stream": {
"version": "0.0.7",
@@ -27144,11 +27510,6 @@
"eve-raphael": "0.5.0"
}
},
- "raven-js": {
- "version": "3.24.2",
- "resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.2.tgz",
- "integrity": "sha512-Dy/FHDxuo5pXywVf8Nrs5utB2juMATpkxWGqHjVbpFD3m8CaWYLvkB5SEXjWFUZ5GvUsrBVVQ+Dfcp0x6Z7SOg=="
- },
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
@@ -32841,6 +33202,7 @@
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
"requires": {
"is-typedarray": "^1.0.0"
}
@@ -33524,9 +33886,9 @@
"optional": true
},
"v8flags": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.0.tgz",
- "integrity": "sha512-0m69VIK2dudEf2Ub0xwLQhZkDZu85OmiOpTw+UGDt56ibviYICHziM/3aE+oVg7IjGPp0c83w3eSVqa+lYZ9UQ==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz",
+ "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==",
"requires": {
"homedir-polyfill": "^1.0.1"
}
@@ -33753,9 +34115,12 @@
},
"dependencies": {
"convert-source-map": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
- "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU="
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
}
}
},
@@ -33866,6 +34231,7 @@
"resolved": "https://registry.npmjs.org/web3/-/web3-0.20.3.tgz",
"integrity": "sha1-yqRDc9yIFayHZ73ba6cwc5ZMqos=",
"requires": {
+ "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934",
"crypto-js": "^3.1.4",
"utf8": "^2.1.1",
"xhr2": "*",
@@ -33874,7 +34240,7 @@
"dependencies": {
"bignumber.js": {
"version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934",
- "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934"
+ "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git"
}
}
},
@@ -34272,7 +34638,8 @@
"dev": true,
"requires": {
"underscore": "1.8.3",
- "web3-core-helpers": "1.0.0-beta.34"
+ "web3-core-helpers": "1.0.0-beta.34",
+ "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2"
},
"dependencies": {
"underscore": {
@@ -34282,8 +34649,9 @@
"dev": true
},
"websocket": {
- "version": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c",
- "from": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c",
+ "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2",
+ "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible",
+ "dev": true,
"requires": {
"debug": "^2.2.0",
"nan": "^2.3.3",
@@ -34897,7 +35265,8 @@
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
- "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
+ "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=",
+ "dev": true
},
"yallist": {
"version": "2.1.2",
diff --git a/package.json b/package.json
index adbf46123..1164c6b4c 100644
--- a/package.json
+++ b/package.json
@@ -82,6 +82,7 @@
},
"dependencies": {
"@material-ui/core": "1.0.0",
+ "@sentry/browser": "^4.1.1",
"@zxing/library": "^0.8.0",
"abi-decoder": "^1.0.9",
"asmcrypto.js": "0.22.0",
@@ -97,7 +98,7 @@
"browserify-derequire": "^0.9.4",
"browserify-unibabel": "^3.0.0",
"classnames": "^2.2.5",
- "clone": "^2.1.1",
+ "clone": "^2.1.2",
"copy-to-clipboard": "^3.0.8",
"css-loader": "^0.28.11",
"currency-formatter": "^1.4.2",
@@ -112,7 +113,7 @@
"ensnare": "^1.0.0",
"eslint-plugin-react": "^7.4.0",
"eth-bin-to-ops": "^1.0.1",
- "eth-block-tracker": "^4.0.3",
+ "eth-block-tracker": "^4.1.0",
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
"eth-ens-namehash": "^2.0.8",
"eth-hd-keyring": "^1.2.2",
@@ -124,7 +125,7 @@
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",
"eth-sig-util": "^2.0.2",
- "eth-token-tracker": "^1.1.4",
+ "eth-token-tracker": "^1.1.5",
"eth-trezor-keyring": "^0.1.0",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-tx": "^1.3.0",
@@ -143,7 +144,7 @@
"fast-levenshtein": "^2.0.6",
"file-loader": "^1.1.11",
"fuse.js": "^3.2.0",
- "gulp": "github:gulpjs/gulp#4.0",
+ "gulp": "github:gulpjs/gulp#v4.0.0",
"gulp-autoprefixer": "^5.0.0",
"gulp-debug": "^3.2.0",
"gulp-eslint": "^4.0.0",
@@ -186,7 +187,6 @@
"pumpify": "^1.3.4",
"qrcode-npm": "0.0.3",
"ramda": "^0.24.1",
- "raven-js": "^3.24.2",
"react": "^15.6.2",
"react-addons-css-transition-group": "^15.6.0",
"react-dom": "^15.6.2",
@@ -261,8 +261,9 @@
"eslint-plugin-json": "^1.2.0",
"eslint-plugin-mocha": "^5.0.0",
"eslint-plugin-react": "^7.4.0",
- "eth-json-rpc-middleware": "^3.1.1",
+ "eth-json-rpc-middleware": "^3.1.6",
"eth-keyring-controller": "^3.3.1",
+ "fetch-mock": "^6.5.2",
"file-loader": "^1.1.11",
"fs-extra": "^6.0.1",
"fs-promise": "^2.0.3",
diff --git a/test/data/2-state.json b/test/data/2-state.json
new file mode 100644
index 000000000..d41a403ff
--- /dev/null
+++ b/test/data/2-state.json
@@ -0,0 +1,70 @@
+{ "isInitialized": true,
+ "provider": { "type": "rpc", "rpcTarget": "http://localhost:8545" },
+ "network": "loading",
+ "accounts": {
+ "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
+ "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
+ "balance": "0x0"
+ },
+ "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
+ "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b",
+ "balance": "0x0"
+ }
+ },
+ "currentBlockGasLimit": "",
+ "unapprovedTxs": {},
+ "selectedAddressTxList": [],
+ "computedBalances": {},
+ "unapprovedMsgs": {},
+ "unapprovedMsgCount": 0,
+ "unapprovedPersonalMsgs": {},
+ "unapprovedPersonalMsgCount": 0,
+ "unapprovedTypedMessages": {},
+ "unapprovedTypedMessagesCount": 0,
+ "isUnlocked": true,
+ "keyringTypes": [ "Simple Key Pair", "HD Key Tree" ],
+ "keyrings":[
+ { "type": "HD Key Tree",
+ "accounts": [
+ "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
+ ]
+ },
+ {
+ "type": "Simple Key Pair",
+ "accounts": [
+ "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b"
+ ]
+ }
+ ],
+ "frequentRpcList": [],
+ "currentAccountTab": "history",
+ "tokens": [],
+ "useBlockie": false,
+ "featureFlags": {},
+ "currentLocale": null,
+ "identities": {
+ "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
+ "name": "Account 1",
+ "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
+ },
+ "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
+ "name": "Account 2",
+ "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b"
+ }
+ },
+
+ "lostIdentities": {},
+ "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
+ "recentBlocks": [],
+ "addressBook": [],
+ "currentCurrency": "usd",
+ "conversionRate": 288.45,
+ "conversionDate": 1506444677,
+ "nextUnreadNotice": null,
+ "noActiveNotices": true,
+ "shapeShiftTxList": [],
+ "infuraNetworkStatus": {},
+ "lostAccounts": [],
+ "seedWords": "debris dizzy just program just float decrease vacant alarm reduce speak stadium",
+ "forgottenPassword": null
+} \ No newline at end of file
diff --git a/test/data/mock-state.json b/test/data/mock-state.json
index 7e083c60e..8deff5531 100644
--- a/test/data/mock-state.json
+++ b/test/data/mock-state.json
@@ -111,7 +111,9 @@
"0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796,
"0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049
},
+ "ticker": "ETH",
"currentCurrency": "usd",
+ "nativeCurrency": "ETH",
"conversionRate": 556.12,
"addressBook": [
{
@@ -1248,4 +1250,4 @@
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
}
}
-} \ No newline at end of file
+}
diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js
index 32aaa29a6..d2c3f8958 100644
--- a/test/e2e/beta/from-import-beta-ui.spec.js
+++ b/test/e2e/beta/from-import-beta-ui.spec.js
@@ -286,7 +286,7 @@ describe('Using MetaMask with an existing account', function () {
await delay(regularDelayMs)
const inputAddress = await findElement(driver, By.css('input[placeholder="Recipient Address"]'))
- const inputAmount = await findElement(driver, By.css('.currency-display__input'))
+ const inputAmount = await findElement(driver, By.css('.unit-input__input'))
await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await inputAmount.sendKeys('1')
@@ -319,7 +319,7 @@ describe('Using MetaMask with an existing account', function () {
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
assert.equal(txValues.length, 1)
- assert.equal(await txValues[0].getText(), '-1 ETH')
+ assert.ok(/-1\s*ETH/.test(await txValues[0].getText()))
})
})
diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js
index 8d1ecac0d..eaa7d18cd 100644
--- a/test/e2e/beta/metamask-beta-ui.spec.js
+++ b/test/e2e/beta/metamask-beta-ui.spec.js
@@ -371,7 +371,7 @@ describe('MetaMask', function () {
it('balance renders', async () => {
const balance = await findElement(driver, By.css('.balance-display .token-amount'))
- await driver.wait(until.elementTextMatches(balance, /100.+ETH/))
+ await driver.wait(until.elementTextMatches(balance, /100\s*ETH/))
await delay(regularDelayMs)
})
})
@@ -383,7 +383,7 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
const inputAddress = await findElement(driver, By.css('input[placeholder="Recipient Address"]'))
- const inputAmount = await findElement(driver, By.css('.currency-display__input'))
+ const inputAmount = await findElement(driver, By.css('.unit-input__input'))
await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await inputAmount.sendKeys('1')
@@ -420,7 +420,7 @@ describe('MetaMask', function () {
if (process.env.SELENIUM_BROWSER !== 'firefox') {
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues, /-1\sETH/), 10000)
+ await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000)
}
})
})
@@ -462,7 +462,7 @@ describe('MetaMask', function () {
assert.equal(transactions.length, 2)
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues, /-3\sETH/), 10000)
+ await driver.wait(until.elementTextMatches(txValues, /-3\s*ETH/), 10000)
})
})
@@ -540,7 +540,7 @@ describe('MetaMask', function () {
await findElements(driver, By.css('.transaction-list-item'))
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txListValue, /-4\sETH/), 10000)
+ await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/), 10000)
await txListValue.click()
await delay(regularDelayMs)
@@ -574,7 +574,7 @@ describe('MetaMask', function () {
}, 10000)
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues[0], /-4\sETH/), 10000)
+ await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/), 10000)
// const txAccounts = await findElements(driver, By.css('.tx-list-account'))
// const firstTxAddress = await txAccounts[0].getText()
@@ -606,7 +606,7 @@ describe('MetaMask', function () {
}, 10000)
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues, /-0\sETH/), 10000)
+ await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/), 10000)
await closeAllWindowHandlesExcept(driver, [extension, dapp])
await driver.switchTo().window(extension)
@@ -616,9 +616,9 @@ describe('MetaMask', function () {
const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance'))
await delay(regularDelayMs)
if (process.env.SELENIUM_BROWSER !== 'firefox') {
- await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000)
+ await driver.wait(until.elementTextMatches(balance, /^92.*\s*ETH.*$/), 10000)
const tokenAmount = await balance.getText()
- assert.ok(/^92.*ETH.*$/.test(tokenAmount))
+ assert.ok(/^92.*\s*ETH.*$/.test(tokenAmount))
await delay(regularDelayMs)
}
})
@@ -662,7 +662,7 @@ describe('MetaMask', function () {
})
it('clicks on the Add Token button', async () => {
- const addToken = await driver.findElement(By.css('.wallet-view__add-token-button'))
+ const addToken = await driver.findElement(By.xpath(`//div[contains(text(), 'Add Token')]`))
await addToken.click()
await delay(regularDelayMs)
})
@@ -702,7 +702,7 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
const inputAddress = await findElement(driver, By.css('input[placeholder="Recipient Address"]'))
- const inputAmount = await findElement(driver, By.css('.currency-display__input'))
+ const inputAmount = await findElement(driver, By.css('.unit-input__input'))
await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await inputAmount.sendKeys('50')
@@ -764,7 +764,7 @@ describe('MetaMask', function () {
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
// or possibly until we use latest version of firefox in the tests
if (process.env.SELENIUM_BROWSER !== 'firefox') {
- await driver.wait(until.elementTextMatches(txValues[0], /-50\sTST/), 10000)
+ await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000)
}
driver.wait(async () => {
@@ -798,7 +798,7 @@ describe('MetaMask', function () {
await findElements(driver, By.css('.transaction-list__pending-transactions'))
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/), 10000)
+ await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/), 10000)
await txListValue.click()
await delay(regularDelayMs)
@@ -834,8 +834,8 @@ describe('MetaMask', function () {
await save.click()
await driver.wait(until.stalenessOf(gasModal))
- const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth'))
- assert.equal(await gasFeeInputs[0].getText(), '♦ 0.0006')
+ const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__primary'))
+ assert.equal(await gasFeeInputs[0].getText(), '0.0006')
})
it('submits the transaction', async function () {
@@ -851,7 +851,7 @@ describe('MetaMask', function () {
}, 10000)
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/))
+ await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/))
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Sent\sToken/))
@@ -897,7 +897,7 @@ describe('MetaMask', function () {
const [txListItem] = await findElements(driver, By.css('.transaction-list-item'))
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/))
+ await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/))
await txListItem.click()
await delay(regularDelayMs)
})
@@ -957,8 +957,8 @@ describe('MetaMask', function () {
await save.click()
await driver.wait(until.stalenessOf(gasModal))
- const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth'))
- assert.equal(await gasFeeInputs[0].getText(), '♦ 0.0006')
+ const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__primary'))
+ assert.equal(await gasFeeInputs[0].getText(), '0.0006')
})
it('submits the transaction', async function () {
@@ -974,7 +974,7 @@ describe('MetaMask', function () {
}, 10000)
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
- await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/))
+ await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/))
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/))
})
@@ -1002,7 +1002,7 @@ describe('MetaMask', function () {
describe('Add existing token using search', () => {
it('clicks on the Add Token button', async () => {
- const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
+ const addToken = await findElement(driver, By.xpath(`//div[contains(text(), 'Add Token')]`))
await addToken.click()
await delay(regularDelayMs)
})
@@ -1027,7 +1027,7 @@ describe('MetaMask', function () {
it('renders the balance for the chosen token', async () => {
const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance'))
- await driver.wait(until.elementTextMatches(balance, /0\sBAT/))
+ await driver.wait(until.elementTextMatches(balance, /0\s*BAT/))
await delay(regularDelayMs)
})
})
diff --git a/test/e2e/beta/run-drizzle.sh b/test/e2e/beta/run-drizzle.sh
index 7bfffd7e6..bfb7e6fdb 100755
--- a/test/e2e/beta/run-drizzle.sh
+++ b/test/e2e/beta/run-drizzle.sh
@@ -11,7 +11,7 @@ sleep 5
cd test/e2e/beta/
rm -rf drizzle-test
mkdir drizzle-test && cd drizzle-test
-npm install truffle
+sudo npm install -g truffle
truffle unbox drizzle
echo "Deploying contracts for Drizzle test..."
truffle compile && truffle migrate
diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js
deleted file mode 100644
index bb9d0d10f..000000000
--- a/test/integration/lib/add-token.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const reactTriggerChange = require('react-trigger-change')
-const {
- timeout,
- queryAsync,
- findAsync,
-} = require('../../lib/util')
-
-QUnit.module('Add token flow')
-
-QUnit.test('successful add token flow', (assert) => {
- const done = assert.async()
- runAddTokenFlowTest(assert)
- .then(done)
- .catch(err => {
- assert.notOk(err, `Error was thrown: ${err.stack}`)
- done()
- })
-})
-
-async function runAddTokenFlowTest (assert, done) {
- const selectState = await queryAsync($, 'select')
- selectState.val('add token')
- reactTriggerChange(selectState[0])
-
- // Used to set values on TextField input component
- const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
- window.HTMLInputElement.prototype, 'value'
- ).set
-
- // Check that no tokens have been added
- assert.ok($('.token-list-item').length === 0, 'no tokens added')
-
- // Go to Add Token screen
- let addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button')
- assert.ok(addTokenButton[0], 'add token button present')
- addTokenButton[0].click()
-
- // Verify Add Token screen
- let addTokenWrapper = await queryAsync($, '.page-container')
- assert.ok(addTokenWrapper[0], 'add token wrapper renders')
-
- let addTokenTitle = await queryAsync($, '.page-container__title')
- assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct')
-
- // Cancel Add Token
- const cancelAddTokenButton = await queryAsync($, 'button.btn-default.btn--large.page-container__footer-button')
- assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
- cancelAddTokenButton.click()
-
- assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view')
-
- // Return to Add Token Screen
- addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button')
- assert.ok(addTokenButton[0], 'add token button present')
- addTokenButton[0].click()
-
- // Verify Add Token Screen
- addTokenWrapper = await queryAsync($, '.page-container')
- addTokenTitle = await queryAsync($, '.page-container__title')
- assert.ok(addTokenWrapper[0], 'add token wrapper renders')
- assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct')
-
- // Search for token
- const searchInput = (await findAsync(addTokenWrapper, '#search-tokens'))[0]
- searchInput.focus()
- await timeout(1000)
- nativeInputValueSetter.call(searchInput, 'a')
- searchInput.dispatchEvent(new Event('input', { bubbles: true}))
-
- // Click token to add
- const tokenWrapper = await queryAsync($, 'div.token-list__token')
- assert.ok(tokenWrapper[0], 'token found')
- const tokenImageProp = tokenWrapper.find('.token-list__token-icon').css('background-image')
- const tokenImageUrl = tokenImageProp.slice(5, -2)
- tokenWrapper[0].click()
-
- // Click Next button
- const nextButton = await queryAsync($, 'button.btn-primary.btn--large')
- assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
- nextButton[0].click()
-
- // Confirm Add token
- const confirmAddToken = await queryAsync($, '.confirm-add-token')
- assert.ok(confirmAddToken[0], 'confirm add token rendered')
- assert.ok($('button.btn-primary.btn--large')[0], 'confirm add token button found')
- $('button.btn-primary.btn--large')[0].click()
-
- // Verify added token image
- let heroBalance = await queryAsync($, '.transaction-view-balance__balance-container')
- assert.ok(heroBalance, 'rendered hero balance')
- assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added')
-
- // Return to Add Token Screen
- addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button')
- assert.ok(addTokenButton[0], 'add token button present')
- addTokenButton[0].click()
-
- addTokenWrapper = await queryAsync($, '.page-container')
- const addTokenTabs = await queryAsync($, '.page-container__tab')
- assert.equal(addTokenTabs.length, 2, 'expected number of tabs')
- assert.equal(addTokenTabs[1].textContent, 'Custom Token', 'Custom Token tab present')
- assert.ok(addTokenTabs[1], 'add custom token tab present')
- addTokenTabs[1].click()
- await timeout(1000)
-
- // Input token contract address
- const customInput = (await findAsync(addTokenWrapper, '#custom-address'))[0]
- customInput.focus()
- await timeout(1000)
- nativeInputValueSetter.call(customInput, '0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
- customInput.dispatchEvent(new Event('input', { bubbles: true}))
-
-
- // Click Next button
- // nextButton = await queryAsync($, 'button.btn-primary--lg')
- // assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
- // nextButton[0].click()
-
- // // Verify symbol length error since contract address won't return symbol
- const errorMessage = await queryAsync($, '#custom-symbol-helper-text')
- assert.ok(errorMessage[0], 'error rendered')
-
- $('button.btn-default.btn--large')[0].click()
-
- // await timeout(100000)
-
- // Confirm Add token
- // assert.equal(
- // $('.page-container__subtitle')[0].textContent,
- // 'Would you like to add these tokens?',
- // 'confirm add token rendered'
- // )
- // assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found')
- // $('button.btn-primary--lg')[0].click()
-
- // Verify added token image
- heroBalance = await queryAsync($, '.transaction-view-balance__balance-container')
- assert.ok(heroBalance, 'rendered hero balance')
- assert.ok(heroBalance.find('.identicon')[0], 'token added')
-}
diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js
index 8d5acf5d0..f6b751ba2 100644
--- a/test/integration/lib/currency-localization.js
+++ b/test/integration/lib/currency-localization.js
@@ -25,5 +25,5 @@ async function runCurrencyLocalizationTest (assert, done) {
const txView = await queryAsync($, '.transaction-view')
const heroBalance = await findAsync($(txView), '.transaction-view-balance__balance')
const fiatAmount = await findAsync($(heroBalance), '.transaction-view-balance__secondary-balance')
- assert.equal(fiatAmount[0].textContent, '₱102,707.97 PHP')
+ assert.equal(fiatAmount[0].textContent, '₱102,707.97PHP')
}
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 7f3c114e4..271dd91cf 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -40,7 +40,7 @@ async function customizeGas (assert, price, limit, ethFee, usdFee) {
const sendGasField = await queryAsync($, '.send-v2__gas-fee-display')
assert.equal(
- (await findAsync(sendGasField, '.currency-display__input-wrapper > input')).val(),
+ (await findAsync(sendGasField, '.currency-display-component'))[0].textContent,
ethFee,
'send gas field should show customized gas total'
)
@@ -94,12 +94,12 @@ async function runSendFlowTest (assert, done) {
sendToDropdownList.children()[2].click()
const sendToAccountAddress = sendToFieldInput.val()
- assert.equal(sendToAccountAddress, '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', 'send to dropdown selects the correct address')
+ assert.equal(sendToAccountAddress, '0x2f8D4a878cFA04A6E60D46362f5644DeAb66572D', 'send to dropdown selects the correct address')
const sendAmountField = await queryAsync($, '.send-v2__form-row:eq(2)')
- sendAmountField.find('.currency-display')[0].click()
+ sendAmountField.find('.unit-input')[0].click()
- const sendAmountFieldInput = await findAsync(sendAmountField, '.currency-display__input')
+ const sendAmountFieldInput = await findAsync(sendAmountField, '.unit-input__input')
sendAmountFieldInput.val('5.1')
reactTriggerChange(sendAmountField.find('input')[0])
@@ -112,9 +112,9 @@ async function runSendFlowTest (assert, done) {
errorMessage = $('.send-v2__error')
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
- await customizeGas(assert, 0, 21000, '0', '$0.00 USD')
- await customizeGas(assert, 1, 21000, '0.000021', '$0.03 USD')
- await customizeGas(assert, 500, 60000, '0.03', '$36.03 USD')
+ await customizeGas(assert, 0, 21000, '0ETH', '$0.00USD')
+ await customizeGas(assert, 1, 21000, '0.000021ETH', '$0.03USD')
+ await customizeGas(assert, 500, 60000, '0.03ETH', '$36.03USD')
const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
@@ -130,11 +130,11 @@ async function runSendFlowTest (assert, done) {
const confirmToName = (await queryAsync($, '.sender-to-recipient__name')).last()
assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name')
- const confirmScreenRowFiats = await queryAsync($, '.confirm-detail-row__fiat')
+ const confirmScreenRowFiats = await queryAsync($, '.confirm-detail-row__secondary')
const confirmScreenGas = confirmScreenRowFiats[0]
assert.equal(confirmScreenGas.textContent, '$3.60', 'confirm screen should show correct gas')
const confirmScreenTotal = confirmScreenRowFiats[1]
- assert.equal(confirmScreenTotal.textContent, '$2,405.36', 'confirm screen should show correct total')
+ assert.equal(confirmScreenTotal.textContent, '$2,405.37', 'confirm screen should show correct total')
const confirmScreenBackButton = await queryAsync($, '.confirm-page-container-header__back-button')
confirmScreenBackButton[0].click()
@@ -150,9 +150,9 @@ async function runSendFlowTest (assert, done) {
sendToFieldInputInEdit.val('0xd85a4b6a394794842887b8284293d69163007bbb')
const sendAmountFieldInEdit = await queryAsync($, '.send-v2__form-row:eq(2)')
- sendAmountFieldInEdit.find('.currency-display')[0].click()
+ sendAmountFieldInEdit.find('.unit-input')[0].click()
- const sendAmountFieldInputInEdit = sendAmountFieldInEdit.find('.currency-display__input')
+ const sendAmountFieldInputInEdit = sendAmountFieldInEdit.find('.unit-input__input')
sendAmountFieldInputInEdit.val('1.0')
reactTriggerChange(sendAmountFieldInputInEdit[0])
diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js
index 822311931..7959e6cc1 100644
--- a/test/unit/app/controllers/network-contoller-test.js
+++ b/test/unit/app/controllers/network-contoller-test.js
@@ -47,7 +47,7 @@ describe('# Network Controller', function () {
describe('#setNetworkState', function () {
it('should update the network', function () {
- networkController.setNetworkState(1)
+ networkController.setNetworkState(1, 'rpc')
const networkState = networkController.getNetworkState()
assert.equal(networkState, 1, 'network is 1')
})
diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js
index b5ccf3fb5..c64c47ae9 100644
--- a/test/unit/app/controllers/preferences-controller-test.js
+++ b/test/unit/app/controllers/preferences-controller-test.js
@@ -375,6 +375,11 @@ describe('preferences controller', function () {
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
sandbox.assert.called(stubEnd)
sandbox.assert.notCalled(stubNext)
+ req.method = 'wallet_watchAsset'
+ req.params.type = 'someasset'
+ await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
+ sandbox.assert.calledTwice(stubEnd)
+ sandbox.assert.notCalled(stubNext)
})
it('should through error if method is supported but asset type is not', async function () {
req.method = 'metamask_watchAsset'
@@ -479,5 +484,24 @@ describe('preferences controller', function () {
assert.equal(preferencesController.store.getState().seedWords, 'foo bar baz')
})
})
+
+ describe('on updateFrequentRpcList', function () {
+ it('should add custom RPC url to state', function () {
+ preferencesController.addToFrequentRpcList('rpc_url', 1)
+ preferencesController.addToFrequentRpcList('http://localhost:8545', 1)
+ assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
+ preferencesController.addToFrequentRpcList('rpc_url', 1)
+ assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
+ })
+
+ it('should remove custom RPC url from state', function () {
+ preferencesController.addToFrequentRpcList('rpc_url', 1)
+ assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
+ preferencesController.removeFromFrequentRpcList('other_rpc_url')
+ preferencesController.removeFromFrequentRpcList('http://localhost:8545')
+ preferencesController.removeFromFrequentRpcList('rpc_url')
+ assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [])
+ })
+ })
})
diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js
index 5ac813b49..ea58aa560 100644
--- a/test/unit/app/controllers/transactions/tx-controller-test.js
+++ b/test/unit/app/controllers/transactions/tx-controller-test.js
@@ -158,9 +158,19 @@ describe('Transaction Controller', function () {
})
describe('#addUnapprovedTransaction', function () {
+ const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d'
+
+ let getSelectedAddress
+ beforeEach(function () {
+ getSelectedAddress = sinon.stub(txController, 'getSelectedAddress').returns(selectedAddress)
+ })
+
+ afterEach(function () {
+ getSelectedAddress.restore()
+ })
it('should add an unapproved transaction and return a valid txMeta', function (done) {
- txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' })
+ txController.addUnapprovedTransaction({ from: selectedAddress })
.then((txMeta) => {
assert(('id' in txMeta), 'should have a id')
assert(('time' in txMeta), 'should have a time stamp')
@@ -180,25 +190,37 @@ describe('Transaction Controller', function () {
assert(txMetaFromEmit, 'txMeta is falsey')
done()
})
- txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' })
+ txController.addUnapprovedTransaction({ from: selectedAddress })
.catch(done)
})
it('should fail if recipient is public', function (done) {
txController.networkStore = new ObservableStore(1)
- txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d', to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' })
+ txController.addUnapprovedTransaction({ from: selectedAddress, to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' })
.catch((err) => {
if (err.message === 'Recipient is a public account') done()
else done(err)
})
})
+ it('should fail if the from address isn\'t the selected address', function (done) {
+ txController.addUnapprovedTransaction({from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2'})
+ .then(function () {
+ assert.fail('transaction should not have been added')
+ done()
+ })
+ .catch(function () {
+ assert.ok('pass')
+ done()
+ })
+ })
+
it('should not fail if recipient is public but not on mainnet', function (done) {
txController.once('newUnapprovedTx', (txMetaFromEmit) => {
assert(txMetaFromEmit, 'txMeta is falsey')
done()
})
- txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d', to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' })
+ txController.addUnapprovedTransaction({ from: selectedAddress, to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2' })
.catch(done)
})
})
diff --git a/test/unit/components/balance-component-test.js b/test/unit/components/balance-component-test.js
deleted file mode 100644
index aa9763b72..000000000
--- a/test/unit/components/balance-component-test.js
+++ /dev/null
@@ -1,44 +0,0 @@
-const assert = require('assert')
-const h = require('react-hyperscript')
-const { createMockStore } = require('redux-test-utils')
-const { shallowWithStore } = require('../../lib/render-helpers')
-const BalanceComponent = require('../../../ui/app/components/balance-component')
-const mockState = {
- metamask: {
- accounts: { abc: {} },
- network: 1,
- selectedAddress: 'abc',
- },
-}
-
-describe('BalanceComponent', function () {
- let balanceComponent
- let store
- let component
- beforeEach(function () {
- store = createMockStore(mockState)
- component = shallowWithStore(h(BalanceComponent), store)
- balanceComponent = component.dive()
- })
-
- it('shows token balance and convert to fiat value based on conversion rate', function () {
- const formattedBalance = '1.23 ETH'
-
- const tokenBalance = balanceComponent.instance().getTokenBalance(formattedBalance, false)
- const fiatDisplayNumber = balanceComponent.instance().getFiatDisplayNumber(formattedBalance, 2)
-
- assert.equal('1.23 ETH', tokenBalance)
- assert.equal(2.46, fiatDisplayNumber)
- })
-
- it('shows only the token balance when conversion rate is not available', function () {
- const formattedBalance = '1.23 ETH'
-
- const tokenBalance = balanceComponent.instance().getTokenBalance(formattedBalance, false)
- const fiatDisplayNumber = balanceComponent.instance().getFiatDisplayNumber(formattedBalance, 0)
-
- assert.equal('1.23 ETH', tokenBalance)
- assert.equal('N/A', fiatDisplayNumber)
- })
-
-})
diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js
new file mode 100644
index 000000000..df7d2ee8f
--- /dev/null
+++ b/test/unit/ui/app/actions.spec.js
@@ -0,0 +1,1468 @@
+// Used to inspect long objects
+// util.inspect({JSON}, false, null))
+// const util = require('util')
+const assert = require('assert')
+const sinon = require('sinon')
+const clone = require('clone')
+const nock = require('nock')
+const fetchMock = require('fetch-mock')
+const configureStore = require('redux-mock-store').default
+const thunk = require('redux-thunk').default
+const EthQuery = require('eth-query')
+const Eth = require('ethjs')
+const KeyringController = require('eth-keyring-controller')
+
+const { createTestProviderTools } = require('../../../stub/provider')
+const provider = createTestProviderTools({ scaffold: {}}).provider
+
+const enLocale = require('../../../../app/_locales/en/messages.json')
+const actions = require('../../../../ui/app/actions')
+const MetaMaskController = require('../../../../app/scripts/metamask-controller')
+
+const firstTimeState = require('../../../unit/localhostState')
+const devState = require('../../../data/2-state.json')
+
+const middleware = [thunk]
+const mockStore = configureStore(middleware)
+
+describe('Actions', () => {
+
+ const noop = () => {}
+
+ let background, metamaskController
+
+ const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
+ const password = 'a-fake-password'
+ const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'
+
+ beforeEach(async () => {
+
+
+ metamaskController = new MetaMaskController({
+ provider,
+ keyringController: new KeyringController({}),
+ showUnapprovedTx: noop,
+ showUnconfirmedMessage: noop,
+ encryptor: {
+ encrypt: function (password, object) {
+ this.object = object
+ return Promise.resolve('mock-encrypted')
+ },
+ decrypt: function () {
+ return Promise.resolve(this.object)
+ },
+ },
+ initState: clone(firstTimeState),
+ })
+
+ await metamaskController.createNewVaultAndRestore(password, TEST_SEED)
+
+ await metamaskController.importAccountWithStrategy('Private Key', [ importPrivkey ])
+
+ background = metamaskController.getApi()
+
+ actions._setBackgroundConnection(background)
+
+ global.ethQuery = new EthQuery(provider)
+ })
+
+ describe('#tryUnlockMetamask', () => {
+
+ let submitPasswordSpy, verifySeedPhraseSpy
+
+ afterEach(() => {
+ submitPasswordSpy.restore()
+ verifySeedPhraseSpy.restore()
+ })
+
+ it('', async () => {
+
+ const store = mockStore({})
+
+ submitPasswordSpy = sinon.spy(background, 'submitPassword')
+ verifySeedPhraseSpy = sinon.spy(background, 'verifySeedPhrase')
+
+ return store.dispatch(actions.tryUnlockMetamask())
+ .then(() => {
+ assert(submitPasswordSpy.calledOnce)
+ assert(verifySeedPhraseSpy.calledOnce)
+ })
+ })
+
+ it('errors on submitPassword will fail', () => {
+
+ const store = mockStore({})
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'UNLOCK_IN_PROGRESS' },
+ { type: 'UNLOCK_FAILED', value: 'error in submitPassword' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ ]
+
+
+ submitPasswordSpy = sinon.stub(background, 'submitPassword')
+
+ submitPasswordSpy.callsFake((password, callback) => {
+ callback(new Error('error in submitPassword'))
+ })
+
+ return store.dispatch(actions.tryUnlockMetamask('test'))
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('displays warning error and unlock failed when verifySeed fails', () => {
+ const store = mockStore({})
+ const displayWarningError = [ { type: 'DISPLAY_WARNING', value: 'error' } ]
+ const unlockFailedError = [ { type: 'UNLOCK_FAILED', value: 'error' } ]
+
+ verifySeedPhraseSpy = sinon.stub(background, 'verifySeedPhrase')
+ verifySeedPhraseSpy.callsFake(callback => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.tryUnlockMetamask('test'))
+ .catch(() => {
+ const actions = store.getActions()
+ const warning = actions.filter(action => action.type === 'DISPLAY_WARNING')
+ const unlockFailed = actions.filter(action => action.type === 'UNLOCK_FAILED')
+ assert.deepEqual(warning, displayWarningError)
+ assert.deepEqual(unlockFailed, unlockFailedError)
+ })
+ })
+ })
+
+ describe('#confirmSeedWords', () => {
+
+ let clearSeedWordCacheSpy
+
+ afterEach(() => {
+ clearSeedWordCacheSpy.restore()
+ })
+
+ it('shows account page after clearing seed word cache', () => {
+
+ const store = mockStore({})
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'SHOW_ACCOUNTS_PAGE' },
+ ]
+
+ clearSeedWordCacheSpy = sinon.spy(background, 'clearSeedWordCache')
+
+ return store.dispatch(actions.confirmSeedWords())
+ .then(() => {
+ assert.equal(clearSeedWordCacheSpy.callCount, 1)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('errors in callback will display warning', () => {
+ const store = mockStore({})
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ clearSeedWordCacheSpy = sinon.stub(background, 'clearSeedWordCache')
+
+ clearSeedWordCacheSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.confirmSeedWords())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#createNewVaultAndRestore', () => {
+
+ let createNewVaultAndRestoreSpy, clearSeedWordCacheSpy
+
+ afterEach(() => {
+ createNewVaultAndRestoreSpy.restore()
+ })
+
+ it('clears seed words and restores new vault', () => {
+
+ const store = mockStore({})
+
+ createNewVaultAndRestoreSpy = sinon.spy(background, 'createNewVaultAndRestore')
+ clearSeedWordCacheSpy = sinon.spy(background, 'clearSeedWordCache')
+ return store.dispatch(actions.createNewVaultAndRestore())
+ .then(() => {
+ assert(clearSeedWordCacheSpy.calledOnce)
+ assert(createNewVaultAndRestoreSpy.calledOnce)
+ })
+ })
+
+ it('errors when callback in clearSeedWordCache throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ ]
+
+ clearSeedWordCacheSpy = sinon.stub(background, 'clearSeedWordCache')
+ clearSeedWordCacheSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.createNewVaultAndRestore())
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('errors when callback in createNewVaultAndRestore throws', () => {
+
+ const store = mockStore({})
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ ]
+
+ createNewVaultAndRestoreSpy = sinon.stub(background, 'createNewVaultAndRestore')
+
+ createNewVaultAndRestoreSpy.callsFake((password, seed, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.createNewVaultAndRestore())
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#createNewVaultAndKeychain', () => {
+
+ let createNewVaultAndKeychainSpy, placeSeedWordsSpy
+
+ afterEach(() => {
+ createNewVaultAndKeychainSpy.restore()
+ placeSeedWordsSpy.restore()
+ })
+
+ it('calls createNewVaultAndKeychain and placeSeedWords in background', () => {
+
+ const store = mockStore()
+
+ createNewVaultAndKeychainSpy = sinon.spy(background, 'createNewVaultAndKeychain')
+ placeSeedWordsSpy = sinon.spy(background, 'placeSeedWords')
+
+ return store.dispatch(actions.createNewVaultAndKeychain())
+ .then(() => {
+ assert(createNewVaultAndKeychainSpy.calledOnce)
+ assert(placeSeedWordsSpy.calledOnce)
+ })
+ })
+
+ it('displays error and value when callback errors', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ ]
+
+ createNewVaultAndKeychainSpy = sinon.stub(background, 'createNewVaultAndKeychain')
+ createNewVaultAndKeychainSpy.callsFake((password, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.createNewVaultAndKeychain())
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+
+ })
+
+ it('errors when placeSeedWords throws', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ ]
+
+ placeSeedWordsSpy = sinon.stub(background, 'placeSeedWords')
+ placeSeedWordsSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.createNewVaultAndKeychain())
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#requestRevealSeed', () => {
+
+ let submitPasswordSpy, placeSeedWordsSpy
+
+ afterEach(() => {
+ submitPasswordSpy.restore()
+ })
+
+ it('calls submitPassword and placeSeedWords from background', () => {
+
+ const store = mockStore()
+
+ submitPasswordSpy = sinon.spy(background, 'submitPassword')
+ placeSeedWordsSpy = sinon.spy(background, 'placeSeedWords')
+
+ return store.dispatch(actions.requestRevealSeed())
+ .then(() => {
+ assert(submitPasswordSpy.calledOnce)
+ assert(placeSeedWordsSpy.calledOnce)
+ })
+ })
+
+ it('displays warning error with value when callback errors', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ submitPasswordSpy = sinon.stub(background, 'submitPassword')
+ submitPasswordSpy.callsFake((password, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.requestRevealSeed())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#requestRevealSeedWords', () => {
+ let submitPasswordSpy
+
+ it('calls submitPassword in background', () => {
+ const store = mockStore()
+
+ submitPasswordSpy = sinon.spy(background, 'verifySeedPhrase')
+
+ return store.dispatch(actions.requestRevealSeedWords())
+ .then(() => {
+ assert(submitPasswordSpy.calledOnce)
+ })
+ })
+
+ it('displays warning error message then callback in background errors', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ submitPasswordSpy = sinon.stub(background, 'verifySeedPhrase')
+ submitPasswordSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.requestRevealSeedWords())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+
+ })
+ })
+
+ describe('#requestRevealSeed', () => {
+
+ let submitPasswordSpy, placeSeedWordsSpy
+
+ afterEach(() => {
+ submitPasswordSpy.restore()
+ placeSeedWordsSpy.restore()
+ })
+
+ it('calls submitPassword and placeSeedWords in background', () => {
+
+ const store = mockStore()
+
+ submitPasswordSpy = sinon.spy(background, 'submitPassword')
+ placeSeedWordsSpy = sinon.spy(background, 'placeSeedWords')
+
+ return store.dispatch(actions.requestRevealSeed())
+ .then(() => {
+ assert(submitPasswordSpy.calledOnce)
+ assert(placeSeedWordsSpy.calledOnce)
+ })
+ })
+
+ it('displays warning error message when submitPassword in background errors', () => {
+ submitPasswordSpy = sinon.stub(background, 'submitPassword')
+ submitPasswordSpy.callsFake((password, callback) => {
+ callback(new Error('error'))
+ })
+
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ return store.dispatch(actions.requestRevealSeed())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('errors when placeSeedWords throw', () => {
+ placeSeedWordsSpy = sinon.stub(background, 'placeSeedWords')
+ placeSeedWordsSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ return store.dispatch(actions.requestRevealSeed())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#removeAccount', () => {
+ let removeAccountSpy
+
+ afterEach(() => {
+ removeAccountSpy.restore()
+ })
+
+ it('calls removeAccount in background and expect actions to show account', () => {
+ const store = mockStore(devState)
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'SHOW_ACCOUNTS_PAGE' },
+ ]
+
+ removeAccountSpy = sinon.spy(background, 'removeAccount')
+
+ return store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'))
+ .then(() => {
+ assert(removeAccountSpy.calledOnce)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('displays warning error message when removeAccount callback errors', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+ removeAccountSpy = sinon.stub(background, 'removeAccount')
+ removeAccountSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'))
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+
+ })
+ })
+
+ describe('#addNewKeyring', () => {
+ let addNewKeyringSpy
+
+ beforeEach(() => {
+ addNewKeyringSpy = sinon.stub(background, 'addNewKeyring')
+ })
+
+ afterEach(() => {
+ addNewKeyringSpy.restore()
+ })
+
+ it('', () => {
+ const privateKey = 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3'
+
+ const store = mockStore()
+ store.dispatch(actions.addNewKeyring('Simple Key Pair', [ privateKey ]))
+ assert(addNewKeyringSpy.calledOnce)
+ })
+
+ it('errors then addNewKeyring in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ addNewKeyringSpy.callsFake((type, opts, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.addNewKeyring())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+
+ })
+
+ describe('#resetAccount', () => {
+
+ let resetAccountSpy
+
+ afterEach(() => {
+ resetAccountSpy.restore()
+ })
+
+ it('', () => {
+
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'SHOW_ACCOUNTS_PAGE' },
+ ]
+
+ resetAccountSpy = sinon.spy(background, 'resetAccount')
+
+ return store.dispatch(actions.resetAccount())
+ .then(() => {
+ assert(resetAccountSpy.calledOnce)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ resetAccountSpy = sinon.stub(background, 'resetAccount')
+ resetAccountSpy.callsFake((callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.resetAccount())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#importNewAccount', () => {
+
+ let importAccountWithStrategySpy
+
+ afterEach(() => {
+ importAccountWithStrategySpy.restore()
+ })
+
+ it('calls importAccountWithStrategies in background', () => {
+ const store = mockStore()
+
+ importAccountWithStrategySpy = sinon.spy(background, 'importAccountWithStrategy')
+
+ const importPrivkey = 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3'
+
+ return store.dispatch(actions.importNewAccount('Private Key', [ importPrivkey ]))
+ .then(() => {
+ assert(importAccountWithStrategySpy.calledOnce)
+ })
+ })
+
+ it('displays warning error message when importAccount in background callback errors', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: 'This may take a while, please be patient.' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ importAccountWithStrategySpy = sinon.stub(background, 'importAccountWithStrategy')
+ importAccountWithStrategySpy.callsFake((strategy, args, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.importNewAccount())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#addNewAccount', () => {
+
+ let addNewAccountSpy
+
+ afterEach(() => {
+ addNewAccountSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore({ metamask: devState })
+
+ addNewAccountSpy = sinon.spy(background, 'addNewAccount')
+
+ return store.dispatch(actions.addNewAccount())
+ .then(() => {
+ assert(addNewAccountSpy.calledOnce)
+ })
+ })
+ })
+
+ describe('#setCurrentCurrency', () => {
+
+ let setCurrentCurrencySpy
+
+ beforeEach(() => {
+ setCurrentCurrencySpy = sinon.stub(background, 'setCurrentCurrency')
+ })
+
+ afterEach(() => {
+ setCurrentCurrencySpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.setCurrentCurrency('jpy'))
+ assert(setCurrentCurrencySpy.calledOnce)
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+ setCurrentCurrencySpy.callsFake((currencyCode, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setCurrentCurrency())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#signMsg', () => {
+
+ let signMessageSpy, metamaskMsgs, msgId, messages
+
+ const msgParams = {
+ from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
+ data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0',
+ }
+
+ beforeEach(() => {
+ metamaskController.newUnsignedMessage(msgParams, noop)
+ metamaskMsgs = metamaskController.messageManager.getUnapprovedMsgs()
+ messages = metamaskController.messageManager.messages
+ msgId = Object.keys(metamaskMsgs)[0]
+ messages[0].msgParams.metamaskId = parseInt(msgId)
+ })
+
+ afterEach(() => {
+ signMessageSpy.restore()
+ })
+
+ it('calls signMsg in background', () => {
+ const store = mockStore()
+
+ signMessageSpy = sinon.spy(background, 'signMessage')
+
+ return store.dispatch(actions.signMsg(msgParams))
+ .then(() => {
+ assert(signMessageSpy.calledOnce)
+ })
+
+ })
+
+ it('errors when signMessage in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'UPDATE_METAMASK_STATE', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ signMessageSpy = sinon.stub(background, 'signMessage')
+ signMessageSpy.callsFake((msgData, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.signMsg())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ })
+
+ describe('#signPersonalMsg', () => {
+
+ let signPersonalMessageSpy, metamaskMsgs, msgId, personalMessages
+
+ const msgParams = {
+ from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
+ data: '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0',
+ }
+
+ beforeEach(() => {
+ metamaskController.newUnsignedPersonalMessage(msgParams, noop)
+ metamaskMsgs = metamaskController.personalMessageManager.getUnapprovedMsgs()
+ personalMessages = metamaskController.personalMessageManager.messages
+ msgId = Object.keys(metamaskMsgs)[0]
+ personalMessages[0].msgParams.metamaskId = parseInt(msgId)
+ })
+
+ afterEach(() => {
+ signPersonalMessageSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+
+ signPersonalMessageSpy = sinon.spy(background, 'signPersonalMessage')
+
+ return store.dispatch(actions.signPersonalMsg(msgParams))
+ .then(() => {
+ assert(signPersonalMessageSpy.calledOnce)
+ })
+
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'UPDATE_METAMASK_STATE', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ signPersonalMessageSpy = sinon.stub(background, 'signPersonalMessage')
+ signPersonalMessageSpy.callsFake((msgData, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.signPersonalMsg(msgParams))
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ })
+
+ describe('#signTx', () => {
+
+ let sendTransactionSpy
+
+ beforeEach(() => {
+ global.ethQuery = new EthQuery(provider)
+ sendTransactionSpy = sinon.stub(global.ethQuery, 'sendTransaction')
+ })
+
+ afterEach(() => {
+ sendTransactionSpy.restore()
+ })
+
+ it('calls sendTransaction in global ethQuery', () => {
+ const store = mockStore()
+ store.dispatch(actions.signTx())
+ assert(sendTransactionSpy.calledOnce)
+ })
+
+ it('errors in when sendTransaction throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'SHOW_CONF_TX_PAGE', transForward: true, id: undefined },
+ ]
+ sendTransactionSpy.callsFake((txData, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.signTx())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#signTokenTx', () => {
+
+ let tokenSpy
+
+ beforeEach(() => {
+ global.eth = new Eth(provider)
+ tokenSpy = sinon.spy(global.eth, 'contract')
+ })
+
+ afterEach(() => {
+ tokenSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.signTokenTx())
+ assert(tokenSpy.calledOnce)
+ })
+ })
+
+ describe('#lockMetamask', () => {
+ let backgroundSetLockedSpy
+
+ afterEach(() => {
+ backgroundSetLockedSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+
+ backgroundSetLockedSpy = sinon.spy(background, 'setLocked')
+
+ return store.dispatch(actions.lockMetamask())
+ .then(() => {
+ assert(backgroundSetLockedSpy.calledOnce)
+ })
+ })
+
+ it('returns display warning error with value when setLocked in background callback errors', () => {
+ const store = mockStore()
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'LOCK_METAMASK' },
+ ]
+ backgroundSetLockedSpy = sinon.stub(background, 'setLocked')
+ backgroundSetLockedSpy.callsFake(callback => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.lockMetamask())
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#setSelectedAddress', () => {
+ let setSelectedAddressSpy
+
+ beforeEach(() => {
+ setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress')
+ })
+
+ afterEach(() => {
+ setSelectedAddressSpy.restore()
+ })
+
+ it('calls setSelectedAddress in background', () => {
+ const store = mockStore({ metamask: devState })
+
+ store.dispatch(actions.setSelectedAddress('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
+ assert(setSelectedAddressSpy.calledOnce)
+ })
+
+ it('errors when setSelectedAddress throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ setSelectedAddressSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setSelectedAddress())
+ assert.deepEqual(store.getActions(), expectedActions)
+
+ })
+ })
+
+ describe('#showAccountDetail', () => {
+ let setSelectedAddressSpy
+
+ beforeEach(() => {
+ setSelectedAddressSpy = sinon.stub(background, 'setSelectedAddress')
+ })
+
+ afterEach(() => {
+ setSelectedAddressSpy.restore()
+ })
+
+ it('#showAccountDetail', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.showAccountDetail())
+ assert(setSelectedAddressSpy.calledOnce)
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+ setSelectedAddressSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+
+ store.dispatch(actions.showAccountDetail())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#addToken', () => {
+ let addTokenSpy
+
+ beforeEach(() => {
+ addTokenSpy = sinon.stub(background, 'addToken')
+ })
+
+ afterEach(() => {
+ addTokenSpy.restore()
+ })
+
+ it('calls addToken in background', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.addToken())
+ .then(() => {
+ assert(addTokenSpy.calledOnce)
+ })
+ })
+
+ it('errors when addToken in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'UPDATE_TOKENS', newTokens: undefined },
+ ]
+
+ addTokenSpy.callsFake((address, symbol, decimals, image, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.addToken())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#removeToken', () => {
+
+ let removeTokenSpy
+
+ beforeEach(() => {
+ removeTokenSpy = sinon.stub(background, 'removeToken')
+ })
+
+ afterEach(() => {
+ removeTokenSpy.restore()
+ })
+
+ it('calls removeToken in background', () => {
+ const store = mockStore()
+ store.dispatch(actions.removeToken())
+ .then(() => {
+ assert(removeTokenSpy.calledOnce)
+ })
+ })
+
+ it('errors when removeToken in background fails', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'UPDATE_TOKENS', newTokens: undefined },
+ ]
+
+ removeTokenSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.removeToken())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#markNoticeRead', () => {
+ let markNoticeReadSpy
+ const notice = {
+ id: 0,
+ read: false,
+ date: 'test date',
+ title: 'test title',
+ body: 'test body',
+ }
+
+ beforeEach(() => {
+ markNoticeReadSpy = sinon.stub(background, 'markNoticeRead')
+ })
+
+ afterEach(() => {
+ markNoticeReadSpy.restore()
+ })
+
+ it('calls markNoticeRead in background', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.markNoticeRead(notice))
+ .then(() => {
+ assert(markNoticeReadSpy.calledOnce)
+ })
+
+ })
+
+ it('errors when markNoticeRead in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+ markNoticeReadSpy.callsFake((notice, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.markNoticeRead())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#setProviderType', () => {
+ let setProviderTypeSpy
+
+ beforeEach(() => {
+ setProviderTypeSpy = sinon.stub(background, 'setProviderType')
+ })
+
+ afterEach(() => {
+ setProviderTypeSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.setProviderType())
+ assert(setProviderTypeSpy.calledOnce)
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
+ ]
+
+ setProviderTypeSpy.callsFake((type, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setProviderType())
+ assert(setProviderTypeSpy.calledOnce)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#setRpcTarget', () => {
+ let setRpcTargetSpy
+
+ beforeEach(() => {
+ setRpcTargetSpy = sinon.stub(background, 'setCustomRpc')
+ })
+
+ afterEach(() => {
+ setRpcTargetSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.setRpcTarget('http://localhost:8545'))
+ assert(setRpcTargetSpy.calledOnce)
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
+ ]
+
+ setRpcTargetSpy.callsFake((newRpc, chainId, ticker, nickname, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setRpcTarget())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#addToAddressBook', () => {
+ let addToAddressBookSpy
+
+ beforeEach(() => {
+ addToAddressBookSpy = sinon.stub(background, 'setAddressBook')
+ })
+
+ afterEach(() => {
+ addToAddressBookSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.addToAddressBook('test'))
+ assert(addToAddressBookSpy.calledOnce)
+ })
+ })
+
+ describe('#exportAccount', () => {
+ let submitPasswordSpy, exportAccountSpy
+
+ afterEach(() => {
+ submitPasswordSpy.restore()
+ exportAccountSpy.restore()
+ })
+
+ it('returns expected actions for successful action', () => {
+ const store = mockStore(devState)
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'SHOW_PRIVATE_KEY', value: '7ec73b91bb20f209a7ff2d32f542c3420b4fccf14abcc7840d2eff0ebcb18505' },
+ ]
+
+ submitPasswordSpy = sinon.spy(background, 'submitPassword')
+ exportAccountSpy = sinon.spy(background, 'exportAccount')
+
+ return store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
+ .then((result) => {
+ assert(submitPasswordSpy.calledOnce)
+ assert(exportAccountSpy.calledOnce)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('returns action errors when first func callback errors', () => {
+ const store = mockStore(devState)
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'Incorrect Password.' },
+ ]
+
+ submitPasswordSpy = sinon.stub(background, 'submitPassword')
+ submitPasswordSpy.callsFake((password, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('returns action errors when second func callback errors', () => {
+ const store = mockStore(devState)
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'Had a problem exporting the account.' },
+ ]
+
+ exportAccountSpy = sinon.stub(background, 'exportAccount')
+ exportAccountSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'))
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#setAccountLabel', () => {
+ let setAccountLabelSpy
+
+ beforeEach(() => {
+ setAccountLabelSpy = sinon.stub(background, 'setAccountLabel')
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.setAccountLabel('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', 'test'))
+ assert(setAccountLabelSpy.calledOnce)
+ })
+ })
+
+ describe('#pairUpdate', () => {
+ beforeEach(() => {
+
+ nock('https://shapeshift.io')
+ .defaultReplyHeaders({ 'access-control-allow-origin': '*' })
+ .get('/marketinfo/btc_eth')
+ .reply(200, {pair: 'BTC_ETH', rate: 25.68289016, minerFee: 0.00176, limit: 0.67748474, minimum: 0.00013569, maxLimit: 0.67758573})
+
+ nock('https://shapeshift.io')
+ .defaultReplyHeaders({ 'access-control-allow-origin': '*' })
+ .get('/coins')
+ .reply(200)
+ })
+
+ afterEach(() => {
+ nock.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ // issue with dispatch action in callback not showing
+ const expectedActions = [
+ { type: 'SHOW_SUB_LOADING_INDICATION' },
+ { type: 'HIDE_WARNING' },
+ ]
+
+ store.dispatch(actions.pairUpdate('btc'))
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#setFeatureFlag', () => {
+ let setFeatureFlagSpy
+
+ beforeEach(() => {
+ setFeatureFlagSpy = sinon.stub(background, 'setFeatureFlag')
+ })
+
+ afterEach(() => {
+ setFeatureFlagSpy.restore()
+ })
+
+ it('calls setFeatureFlag in the background', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.setFeatureFlag())
+ assert(setFeatureFlagSpy.calledOnce)
+ })
+
+ it('errors when setFeatureFlag in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ setFeatureFlagSpy.callsFake((feature, activated, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setFeatureFlag())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#updateNetworkNonce', () => {
+ let getTransactionCountSpy
+
+ afterEach(() => {
+ getTransactionCountSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ getTransactionCountSpy = sinon.spy(global.ethQuery, 'getTransactionCount')
+
+ store.dispatch(actions.updateNetworkNonce())
+ .then(() => {
+ assert(getTransactionCountSpy.calledOnce)
+ })
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+
+ getTransactionCountSpy = sinon.stub(global.ethQuery, 'getTransactionCount')
+ getTransactionCountSpy.callsFake((address, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.updateNetworkNonce())
+ .catch(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#setUseBlockie', () => {
+ let setUseBlockieSpy
+
+ beforeEach(() => {
+ setUseBlockieSpy = sinon.stub(background, 'setUseBlockie')
+ })
+
+ afterEach(() => {
+ setUseBlockieSpy.restore()
+ })
+
+ it('calls setUseBlockie in background', () => {
+ const store = mockStore()
+
+ store.dispatch(actions.setUseBlockie())
+ assert(setUseBlockieSpy.calledOnce)
+ })
+
+ it('errors when setUseBlockie in background throws', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ { type: 'SET_USE_BLOCKIE', value: undefined },
+ ]
+
+ setUseBlockieSpy.callsFake((val, callback) => {
+ callback(new Error('error'))
+ })
+
+ store.dispatch(actions.setUseBlockie())
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ describe('#updateCurrentLocale', () => {
+ let setCurrentLocaleSpy
+
+ beforeEach(() => {
+ fetchMock.get('*', enLocale)
+ })
+
+ afterEach(() => {
+ setCurrentLocaleSpy.restore()
+ fetchMock.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ setCurrentLocaleSpy = sinon.spy(background, 'setCurrentLocale')
+
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'SET_CURRENT_LOCALE', value: 'en' },
+ { type: 'SET_LOCALE_MESSAGES', value: enLocale },
+ ]
+
+ return store.dispatch(actions.updateCurrentLocale('en'))
+ .then(() => {
+ assert(setCurrentLocaleSpy.calledOnce)
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+
+ it('', () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: 'SHOW_LOADING_INDICATION', value: undefined },
+ { type: 'HIDE_LOADING_INDICATION' },
+ { type: 'DISPLAY_WARNING', value: 'error' },
+ ]
+ setCurrentLocaleSpy = sinon.stub(background, 'setCurrentLocale')
+ setCurrentLocaleSpy.callsFake((key, callback) => {
+ callback(new Error('error'))
+ })
+
+ return store.dispatch(actions.updateCurrentLocale('en'))
+ .then(() => {
+ assert.deepEqual(store.getActions(), expectedActions)
+ })
+ })
+ })
+
+ describe('#markPasswordForgotten', () => {
+ let markPasswordForgottenSpy
+
+ beforeEach(() => {
+ markPasswordForgottenSpy = sinon.stub(background, 'markPasswordForgotten')
+ })
+
+ afterEach(() => {
+ markPasswordForgottenSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.markPasswordForgotten())
+ assert(markPasswordForgottenSpy.calledOnce)
+ })
+ })
+
+ describe('#unMarkPasswordForgotten', () => {
+ let unMarkPasswordForgottenSpy
+
+ beforeEach(() => {
+ unMarkPasswordForgottenSpy = sinon.stub(background, 'unMarkPasswordForgotten')
+ })
+
+ afterEach(() => {
+ unMarkPasswordForgottenSpy.restore()
+ })
+
+ it('', () => {
+ const store = mockStore()
+ store.dispatch(actions.unMarkPasswordForgotten())
+ assert(unMarkPasswordForgottenSpy.calledOnce)
+ })
+ })
+
+
+})
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 8f6586139..a8b9189e9 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -305,6 +305,12 @@ var actions = {
updateFeatureFlags,
UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS',
+ // Preferences
+ setPreference,
+ updatePreferences,
+ UPDATE_PREFERENCES: 'UPDATE_PREFERENCES',
+ setUseNativeCurrencyAsPrimaryCurrencyPreference,
+
setMouseUserState,
SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE',
@@ -1762,7 +1768,7 @@ function markNoticeRead (notice) {
background.markNoticeRead(notice, (err, notice) => {
dispatch(actions.hideLoadingIndication())
if (err) {
- dispatch(actions.displayWarning(err))
+ dispatch(actions.displayWarning(err.message))
return reject(err)
}
@@ -1852,7 +1858,7 @@ function setProviderType (type) {
background.setProviderType(type, (err, result) => {
if (err) {
log.error(err)
- return dispatch(self.displayWarning('Had a problem changing networks!'))
+ return dispatch(actions.displayWarning('Had a problem changing networks!'))
}
dispatch(actions.updateProviderType(type))
dispatch(actions.setSelectedToken())
@@ -1868,13 +1874,13 @@ function updateProviderType (type) {
}
}
-function setRpcTarget (newRpc) {
+function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname = '') {
return (dispatch) => {
- log.debug(`background.setRpcTarget: ${newRpc}`)
- background.setCustomRpc(newRpc, (err, result) => {
+ log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`)
+ background.setCustomRpc(newRpc, chainId, ticker, nickname, (err, result) => {
if (err) {
log.error(err)
- return dispatch(self.displayWarning('Had a problem changing networks!'))
+ return dispatch(actions.displayWarning('Had a problem changing networks!'))
}
dispatch(actions.setSelectedToken())
})
@@ -2298,6 +2304,36 @@ function updateFeatureFlags (updatedFeatureFlags) {
}
}
+function setPreference (preference, value) {
+ return dispatch => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.setPreference(preference, value, (err, updatedPreferences) => {
+ dispatch(actions.hideLoadingIndication())
+
+ if (err) {
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.updatePreferences(updatedPreferences))
+ resolve(updatedPreferences)
+ })
+ })
+ }
+}
+
+function updatePreferences (value) {
+ return {
+ type: actions.UPDATE_PREFERENCES,
+ value,
+ }
+}
+
+function setUseNativeCurrencyAsPrimaryCurrencyPreference (value) {
+ return setPreference('useNativeCurrencyAsPrimaryCurrency', value)
+}
+
function setNetworkNonce (networkNonce) {
return {
type: actions.SET_NETWORK_NONCE,
@@ -2309,6 +2345,10 @@ function updateNetworkNonce (address) {
return (dispatch) => {
return new Promise((resolve, reject) => {
global.ethQuery.getTransactionCount(address, (err, data) => {
+ if (err) {
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
dispatch(setNetworkNonce(data))
resolve(data)
})
@@ -2396,7 +2436,7 @@ function setUseBlockie (val) {
function updateCurrentLocale (key) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
- fetchLocale(key)
+ return fetchLocale(key)
.then((localeMessages) => {
log.debug(`background.setCurrentLocale`)
background.setCurrentLocale(key, (err) => {
diff --git a/ui/app/app.js b/ui/app/app.js
index aeb3d05ee..b3aff1f39 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -101,7 +101,7 @@ class App extends Component {
network,
isMouseUser,
provider,
- frequentRpcList,
+ frequentRpcListDetail,
currentView,
setMouseUserState,
sidebar,
@@ -147,7 +147,7 @@ class App extends Component {
// network dropdown
h(NetworkDropdown, {
provider,
- frequentRpcList,
+ frequentRpcListDetail,
}, []),
h(AccountMenu),
@@ -230,7 +230,7 @@ App.propTypes = {
alertMessage: PropTypes.string,
network: PropTypes.string,
provider: PropTypes.object,
- frequentRpcList: PropTypes.array,
+ frequentRpcListDetail: PropTypes.array,
currentView: PropTypes.object,
sidebar: PropTypes.object,
alertOpen: PropTypes.bool,
@@ -322,7 +322,7 @@ function mapStateToProps (state) {
forgottenPassword: state.appState.forgottenPassword,
nextUnreadNotice,
lostAccounts,
- frequentRpcList: state.metamask.frequentRpcList || [],
+ frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
currentCurrency: state.metamask.currentCurrency,
isMouseUser: state.appState.isMouseUser,
betaUI: state.metamask.featureFlags.betaUI,
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js
index 043008a36..06376e48b 100644
--- a/ui/app/components/account-dropdowns.js
+++ b/ui/app/components/account-dropdowns.js
@@ -6,10 +6,11 @@ const genAccountLink = require('etherscan-link').createAccountLink
const connect = require('react-redux').connect
const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
-const Identicon = require('./identicon')
const copyToClipboard = require('copy-to-clipboard')
const { checksumAddress } = require('../util')
+import Identicon from './identicon'
+
class AccountDropdowns extends Component {
constructor (props) {
super(props)
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index bcada41e3..94eae8d07 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -7,12 +7,12 @@ const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const actions = require('../../actions')
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
-const Identicon = require('../identicon')
-const { formatBalance } = require('../../util')
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
const Tooltip = require('../tooltip')
-
+import Identicon from '../identicon'
+import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
+import { PRIMARY } from '../../constants/common'
const {
SETTINGS_ROUTE,
@@ -163,7 +163,6 @@ AccountMenu.prototype.renderAccounts = function () {
const isSelected = identity.address === selectedAddress
const balanceValue = accounts[address] ? accounts[address].balance : ''
- const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...'
const simpleAddress = identity.address.substring(2).toLowerCase()
const keyring = keyrings.find((kr) => {
@@ -189,7 +188,11 @@ AccountMenu.prototype.renderAccounts = function () {
h('div.account-menu__account-info', [
h('div.account-menu__name', identity.name || ''),
- h('div.account-menu__balance', formattedBalance),
+ h(UserPreferencedCurrencyDisplay, {
+ className: 'account-menu__balance',
+ value: balanceValue,
+ type: PRIMARY,
+ }),
]),
this.renderKeyringType(keyring),
diff --git a/ui/app/components/account-panel.js b/ui/app/components/account-panel.js
index abaaf8163..a379ed3ac 100644
--- a/ui/app/components/account-panel.js
+++ b/ui/app/components/account-panel.js
@@ -1,7 +1,7 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
-const Identicon = require('./identicon')
+import Identicon from './identicon'
const formatBalance = require('../util').formatBalance
const addressSummary = require('../util').addressSummary
diff --git a/ui/app/components/add-token-button/add-token-button.component.js b/ui/app/components/add-token-button/add-token-button.component.js
new file mode 100644
index 000000000..10887aed8
--- /dev/null
+++ b/ui/app/components/add-token-button/add-token-button.component.js
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types'
+import React, {PureComponent} from 'react'
+
+export default class AddTokenButton extends PureComponent {
+ static contextTypes = {
+ t: PropTypes.func.isRequired,
+ }
+
+ static defaultProps = {
+ onClick: () => {},
+ }
+
+ static propTypes = {
+ onClick: PropTypes.func,
+ }
+
+ render () {
+ const { t } = this.context
+ const { onClick } = this.props
+
+ return (
+ <div className="add-token-button">
+ <h1 className="add-token-button__help-header">{t('missingYourTokens')}</h1>
+ <p className="add-token-button__help-desc">{t('clickToAdd', [t('addToken')])}</p>
+ <div
+ className="add-token-button__button"
+ onClick={onClick}
+ >
+ {t('addToken')}
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/add-token-button/index.js b/ui/app/components/add-token-button/index.js
new file mode 100644
index 000000000..15c4fe6ca
--- /dev/null
+++ b/ui/app/components/add-token-button/index.js
@@ -0,0 +1 @@
+export { default } from './add-token-button.component'
diff --git a/ui/app/components/add-token-button/index.scss b/ui/app/components/add-token-button/index.scss
new file mode 100644
index 000000000..39f404716
--- /dev/null
+++ b/ui/app/components/add-token-button/index.scss
@@ -0,0 +1,26 @@
+.add-token-button {
+ display: flex;
+ flex-direction: column;
+ color: lighten($scorpion, 25%);
+ width: 185px;
+ margin: 36px auto;
+ text-align: center;
+
+ &__help-header {
+ font-weight: bold;
+ font-size: 1rem;
+ }
+
+ &__help-desc {
+ font-size: 0.75rem;
+ margin-top: 1rem;
+ }
+
+ &__button {
+ font-size: 0.75rem;
+ margin: 1rem;
+ text-transform: uppercase;
+ color: $curious-blue;
+ cursor: pointer;
+ }
+}
diff --git a/ui/app/components/app-header/app-header.component.js b/ui/app/components/app-header/app-header.component.js
index b8b002dcc..c82dc1de9 100644
--- a/ui/app/components/app-header/app-header.component.js
+++ b/ui/app/components/app-header/app-header.component.js
@@ -2,13 +2,13 @@ import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { matchPath } from 'react-router-dom'
+import Identicon from '../identicon'
const {
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_POPUP,
} = require('../../../../app/scripts/lib/enums')
const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
-const Identicon = require('../identicon')
const NetworkIndicator = require('../network')
export default class AppHeader extends PureComponent {
diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js
index d63d78c9f..0f8514c81 100644
--- a/ui/app/components/balance-component.js
+++ b/ui/app/components/balance-component.js
@@ -2,12 +2,13 @@ const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const TokenBalance = require('./token-balance')
-const Identicon = require('./identicon')
-import CurrencyDisplay from './currency-display'
-const { getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors')
+import TokenBalance from './token-balance'
+import Identicon from './identicon'
+import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../constants/common'
+const { getNativeCurrency, getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors')
-const { formatBalance, generateBalanceObject } = require('../util')
+const { formatBalance } = require('../util')
module.exports = connect(mapStateToProps)(BalanceComponent)
@@ -20,6 +21,7 @@ function mapStateToProps (state) {
return {
account,
network,
+ nativeCurrency: getNativeCurrency(state),
conversionRate: conversionRateSelector(state),
currentCurrency: getCurrentCurrency(state),
assetImages: getAssetImages(state),
@@ -65,10 +67,10 @@ BalanceComponent.prototype.renderTokenBalance = function () {
BalanceComponent.prototype.renderBalance = function () {
const props = this.props
- const { shorten, account } = props
+ const { account, nativeCurrency } = props
const balanceValue = account && account.balance
const needsParse = 'needsParse' in props ? props.needsParse : true
- const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...'
+ const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse, nativeCurrency) : '...'
const showFiat = 'showFiat' in props ? props.showFiat : true
if (formattedBalance === 'None' || formattedBalance === '...') {
@@ -80,25 +82,21 @@ BalanceComponent.prototype.renderBalance = function () {
}
return h('div.flex-column.balance-display', {}, [
- h('div.token-amount', {
- style: {},
- }, this.getTokenBalance(formattedBalance, shorten)),
+ h(UserPreferencedCurrencyDisplay, {
+ className: 'token-amount',
+ value: balanceValue,
+ type: PRIMARY,
+ ethNumberOfDecimals: 3,
+ }),
- showFiat && h(CurrencyDisplay, {
+ showFiat && h(UserPreferencedCurrencyDisplay, {
value: balanceValue,
+ type: SECONDARY,
+ ethNumberOfDecimals: 3,
}),
])
}
-BalanceComponent.prototype.getTokenBalance = function (formattedBalance, shorten) {
- const balanceObj = generateBalanceObject(formattedBalance, shorten ? 1 : 3)
-
- const balanceValue = shorten ? balanceObj.shortBalance : balanceObj.balance
- const label = balanceObj.label
-
- return `${balanceValue} ${label}`
-}
-
BalanceComponent.prototype.getFiatDisplayNumber = function (formattedBalance, conversionRate) {
if (formattedBalance === 'None') return formattedBalance
if (conversionRate === 0) return 'N/A'
diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js
index f0703dde2..c7262d2a9 100644
--- a/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js
+++ b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js
@@ -1,16 +1,19 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
+import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../../../constants/common'
const ConfirmDetailRow = props => {
const {
label,
- fiatText,
- ethText,
+ primaryText,
+ secondaryText,
onHeaderClick,
- fiatTextColor,
+ primaryValueTextColor,
headerText,
headerTextClassName,
+ value,
} = props
return (
@@ -25,28 +28,57 @@ const ConfirmDetailRow = props => {
>
{ headerText }
</div>
- <div
- className="confirm-detail-row__fiat"
- style={{ color: fiatTextColor }}
- >
- { fiatText }
- </div>
- <div className="confirm-detail-row__eth">
- { ethText }
- </div>
+ {
+ primaryText
+ ? (
+ <div
+ className="confirm-detail-row__primary"
+ style={{ color: primaryValueTextColor }}
+ >
+ { primaryText }
+ </div>
+ ) : (
+ <UserPreferencedCurrencyDisplay
+ className="confirm-detail-row__primary"
+ type={PRIMARY}
+ value={value}
+ showEthLogo
+ ethLogoHeight="18"
+ style={{ color: primaryValueTextColor }}
+ hideLabel
+ />
+ )
+ }
+ {
+ secondaryText
+ ? (
+ <div className="confirm-detail-row__secondary">
+ { secondaryText }
+ </div>
+ ) : (
+ <UserPreferencedCurrencyDisplay
+ className="confirm-detail-row__secondary"
+ type={SECONDARY}
+ value={value}
+ showEthLogo
+ hideLabel
+ />
+ )
+ }
</div>
</div>
)
}
ConfirmDetailRow.propTypes = {
- label: PropTypes.string,
- fiatText: PropTypes.string,
- ethText: PropTypes.string,
- fiatTextColor: PropTypes.string,
- onHeaderClick: PropTypes.func,
headerText: PropTypes.string,
headerTextClassName: PropTypes.string,
+ label: PropTypes.string,
+ onHeaderClick: PropTypes.func,
+ primaryValueTextColor: PropTypes.string,
+ primaryText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ secondaryText: PropTypes.string,
+ value: PropTypes.string,
}
export default ConfirmDetailRow
diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
index dd6f87c17..580a41fde 100644
--- a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
+++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
@@ -18,18 +18,14 @@
min-width: 0;
}
- &__fiat {
+ &__primary {
font-size: 1.5rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ justify-content: flex-end;
}
- &__eth {
+ &__secondary {
color: $oslo-gray;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ justify-content: flex-end;
}
&__header-text {
diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js b/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
index 6f2489071..c8507985d 100644
--- a/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
+++ b/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
@@ -12,17 +12,19 @@ describe('Confirm Detail Row Component', function () {
let wrapper
beforeEach(() => {
- wrapper = shallow(<ConfirmDetailRow
- errorType={'mockErrorType'}
- label={'mockLabel'}
- showError={false}
- fiatText = {'mockFiatText'}
- ethText = {'mockEthText'}
- fiatTextColor= {'mockColor'}
- onHeaderClick= {propsMethodSpies.onHeaderClick}
- headerText = {'mockHeaderText'}
- headerTextClassName = {'mockHeaderClass'}
- />)
+ wrapper = shallow(
+ <ConfirmDetailRow
+ errorType={'mockErrorType'}
+ label={'mockLabel'}
+ showError={false}
+ primaryText = {'mockFiatText'}
+ secondaryText = {'mockEthText'}
+ primaryValueTextColor= {'mockColor'}
+ onHeaderClick= {propsMethodSpies.onHeaderClick}
+ headerText = {'mockHeaderText'}
+ headerTextClassName = {'mockHeaderClass'}
+ />
+ )
})
describe('render', () => {
@@ -38,16 +40,16 @@ describe('Confirm Detail Row Component', function () {
assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__header-text').childAt(0).text(), 'mockHeaderText')
})
- it('should render the fiatText as a child of the confirm-detail-row__fiat', () => {
- assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__fiat').childAt(0).text(), 'mockFiatText')
+ it('should render the primaryText as a child of the confirm-detail-row__primary', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__primary').childAt(0).text(), 'mockFiatText')
})
- it('should render the ethText as a child of the confirm-detail-row__eth', () => {
- assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__eth').childAt(0).text(), 'mockEthText')
+ it('should render the ethText as a child of the confirm-detail-row__secondary', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__secondary').childAt(0).text(), 'mockEthText')
})
- it('should set the fiatTextColor on confirm-detail-row__fiat', () => {
- assert.equal(wrapper.find('.confirm-detail-row__fiat').props().style.color, 'mockColor')
+ it('should set the fiatTextColor on confirm-detail-row__primary', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__primary').props().style.color, 'mockColor')
})
it('should assure the confirm-detail-row__header-text classname is correct', () => {
@@ -58,7 +60,5 @@ describe('Confirm Detail Row Component', function () {
wrapper.find('.confirm-detail-row__header-text').props().onClick()
assert.equal(assert.equal(propsMethodSpies.onHeaderClick.callCount, 1))
})
-
-
})
})
diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js
index 74e95ece6..1dca81560 100644
--- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js
+++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js
@@ -17,9 +17,10 @@ export default class ConfirmPageContainerContent extends Component {
nonce: PropTypes.string,
assetImage: PropTypes.string,
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ subtitleComponent: PropTypes.node,
summaryComponent: PropTypes.node,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- titleComponent: PropTypes.func,
+ titleComponent: PropTypes.node,
warning: PropTypes.string,
}
@@ -54,7 +55,9 @@ export default class ConfirmPageContainerContent extends Component {
errorKey,
errorMessage,
title,
+ titleComponent,
subtitle,
+ subtitleComponent,
hideSubtitle,
identiconAddress,
nonce,
@@ -80,7 +83,9 @@ export default class ConfirmPageContainerContent extends Component {
})}
action={action}
title={title}
+ titleComponent={titleComponent}
subtitle={subtitle}
+ subtitleComponent={subtitleComponent}
hideSubtitle={hideSubtitle}
identiconAddress={identiconAddress}
nonce={nonce}
diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
index 38b158fd3..89ceb015f 100644
--- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
+++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
@@ -4,7 +4,18 @@ import classnames from 'classnames'
import Identicon from '../../../identicon'
const ConfirmPageContainerSummary = props => {
- const { action, title, subtitle, hideSubtitle, className, identiconAddress, nonce, assetImage } = props
+ const {
+ action,
+ title,
+ titleComponent,
+ subtitle,
+ subtitleComponent,
+ hideSubtitle,
+ className,
+ identiconAddress,
+ nonce,
+ assetImage,
+ } = props
return (
<div className={classnames('confirm-page-container-summary', className)}>
@@ -32,12 +43,12 @@ const ConfirmPageContainerSummary = props => {
)
}
<div className="confirm-page-container-summary__title-text">
- { title }
+ { titleComponent || title }
</div>
</div>
{
hideSubtitle || <div className="confirm-page-container-summary__subtitle">
- { subtitle }
+ { subtitleComponent || subtitle }
</div>
}
</div>
@@ -47,7 +58,9 @@ const ConfirmPageContainerSummary = props => {
ConfirmPageContainerSummary.propTypes = {
action: PropTypes.string,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ titleComponent: PropTypes.node,
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ subtitleComponent: PropTypes.node,
hideSubtitle: PropTypes.bool,
className: PropTypes.string,
identiconAddress: PropTypes.string,
diff --git a/ui/app/components/confirm-page-container/confirm-page-container.component.js b/ui/app/components/confirm-page-container/confirm-page-container.component.js
index 36d5a1f58..8b2e47cbb 100644
--- a/ui/app/components/confirm-page-container/confirm-page-container.component.js
+++ b/ui/app/components/confirm-page-container/confirm-page-container.component.js
@@ -16,8 +16,9 @@ export default class ConfirmPageContainer extends Component {
onEdit: PropTypes.func,
showEdit: PropTypes.bool,
subtitle: PropTypes.string,
+ subtitleComponent: PropTypes.node,
title: PropTypes.string,
- titleComponent: PropTypes.func,
+ titleComponent: PropTypes.node,
// Sender to Recipient
fromAddress: PropTypes.string,
fromName: PropTypes.string,
@@ -65,6 +66,7 @@ export default class ConfirmPageContainer extends Component {
title,
titleComponent,
subtitle,
+ subtitleComponent,
hideSubtitle,
summaryComponent,
detailsComponent,
@@ -101,6 +103,7 @@ export default class ConfirmPageContainer extends Component {
title={title}
titleComponent={titleComponent}
subtitle={subtitle}
+ subtitleComponent={subtitleComponent}
hideSubtitle={hideSubtitle}
summaryComponent={summaryComponent}
detailsComponent={detailsComponent}
diff --git a/ui/app/components/currency-display/currency-display.component.js b/ui/app/components/currency-display/currency-display.component.js
index e4eb58a2a..2d7413b57 100644
--- a/ui/app/components/currency-display/currency-display.component.js
+++ b/ui/app/components/currency-display/currency-display.component.js
@@ -1,14 +1,18 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
-import { ETH, GWEI } from '../../constants/common'
+import classnames from 'classnames'
+import { GWEI } from '../../constants/common'
export default class CurrencyDisplay extends PureComponent {
static propTypes = {
className: PropTypes.string,
displayValue: PropTypes.string,
prefix: PropTypes.string,
+ prefixComponent: PropTypes.node,
+ style: PropTypes.object,
+ suffix: PropTypes.string,
// Used in container
- currency: PropTypes.oneOf([ETH]),
+ currency: PropTypes.string,
denomination: PropTypes.oneOf([GWEI]),
value: PropTypes.string,
numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@@ -16,15 +20,25 @@ export default class CurrencyDisplay extends PureComponent {
}
render () {
- const { className, displayValue, prefix } = this.props
+ const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props
const text = `${prefix || ''}${displayValue}`
+ const title = `${text} ${suffix}`
return (
<div
- className={className}
- title={text}
+ className={classnames('currency-display-component', className)}
+ style={style}
+ title={title}
>
- { text }
+ { prefixComponent}
+ <span className="currency-display-component__text">{ text }</span>
+ {
+ suffix && (
+ <span className="currency-display-component__suffix">
+ { suffix }
+ </span>
+ )
+ }
</div>
)
}
diff --git a/ui/app/components/currency-display/currency-display.container.js b/ui/app/components/currency-display/currency-display.container.js
index 6644a1099..6ddf07172 100644
--- a/ui/app/components/currency-display/currency-display.container.js
+++ b/ui/app/components/currency-display/currency-display.container.js
@@ -2,20 +2,41 @@ import { connect } from 'react-redux'
import CurrencyDisplay from './currency-display.component'
import { getValueFromWeiHex, formatCurrency } from '../../helpers/confirm-transaction/util'
-const mapStateToProps = (state, ownProps) => {
- const { value, numberOfDecimals = 2, currency, denomination, hideLabel } = ownProps
- const { metamask: { currentCurrency, conversionRate } } = state
+const mapStateToProps = state => {
+ const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state
+
+ return {
+ currentCurrency,
+ conversionRate,
+ nativeCurrency,
+ }
+}
+
+const mergeProps = (stateProps, dispatchProps, ownProps) => {
+ const { nativeCurrency, currentCurrency, conversionRate, ...restStateProps } = stateProps
+ const {
+ value,
+ numberOfDecimals = 2,
+ currency,
+ denomination,
+ hideLabel,
+ ...restOwnProps
+ } = ownProps
const toCurrency = currency || currentCurrency
const convertedValue = getValueFromWeiHex({
- value, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
+ value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
})
- const formattedValue = formatCurrency(convertedValue, toCurrency)
- const displayValue = hideLabel ? formattedValue : `${formattedValue} ${toCurrency.toUpperCase()}`
+ const displayValue = formatCurrency(convertedValue, toCurrency)
+ const suffix = hideLabel ? undefined : toCurrency.toUpperCase()
return {
+ ...restStateProps,
+ ...dispatchProps,
+ ...restOwnProps,
displayValue,
+ suffix,
}
}
-export default connect(mapStateToProps)(CurrencyDisplay)
+export default connect(mapStateToProps, null, mergeProps)(CurrencyDisplay)
diff --git a/ui/app/components/currency-display/index.scss b/ui/app/components/currency-display/index.scss
new file mode 100644
index 000000000..313c932b8
--- /dev/null
+++ b/ui/app/components/currency-display/index.scss
@@ -0,0 +1,14 @@
+.currency-display-component {
+ display: flex;
+ align-items: center;
+
+ &__text {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &__suffix {
+ padding-left: 4px;
+ }
+}
diff --git a/ui/app/components/currency-display/tests/currency-display.container.test.js b/ui/app/components/currency-display/tests/currency-display.container.test.js
index 5265bbb04..0c886af50 100644
--- a/ui/app/components/currency-display/tests/currency-display.container.test.js
+++ b/ui/app/components/currency-display/tests/currency-display.container.test.js
@@ -1,12 +1,13 @@
import assert from 'assert'
import proxyquire from 'proxyquire'
-let mapStateToProps
+let mapStateToProps, mergeProps
proxyquire('../currency-display.container.js', {
'react-redux': {
- connect: ms => {
+ connect: (ms, md, mp) => {
mapStateToProps = ms
+ mergeProps = mp
return () => ({})
},
},
@@ -19,86 +20,125 @@ describe('CurrencyDisplay container', () => {
metamask: {
conversionRate: 280.45,
currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
},
}
+ assert.deepEqual(mapStateToProps(mockState), {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ })
+ })
+ })
+
+ describe('mergeProps()', () => {
+ it('should return the correct props', () => {
+ const mockStateProps = {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ }
+
const tests = [
{
props: {
value: '0x2386f26fc10000',
numberOfDecimals: 2,
currency: 'usd',
+ nativeCurrency: 'ETH',
},
result: {
- displayValue: '$2.80 USD',
+ displayValue: '$2.80',
+ suffix: 'USD',
+ nativeCurrency: 'ETH',
},
},
{
props: {
value: '0x2386f26fc10000',
+ currency: 'usd',
+ nativeCurrency: 'ETH',
},
result: {
- displayValue: '$2.80 USD',
+ displayValue: '$2.80',
+ suffix: 'USD',
+ nativeCurrency: 'ETH',
},
},
{
props: {
value: '0x1193461d01595930',
currency: 'ETH',
+ nativeCurrency: 'ETH',
numberOfDecimals: 3,
},
result: {
- displayValue: '1.266 ETH',
+ displayValue: '1.266',
+ suffix: 'ETH',
+ nativeCurrency: 'ETH',
},
},
{
props: {
value: '0x1193461d01595930',
currency: 'ETH',
+ nativeCurrency: 'ETH',
numberOfDecimals: 3,
hideLabel: true,
},
result: {
+ nativeCurrency: 'ETH',
displayValue: '1.266',
+ suffix: undefined,
},
},
{
props: {
value: '0x3b9aca00',
currency: 'ETH',
+ nativeCurrency: 'ETH',
denomination: 'GWEI',
hideLabel: true,
},
result: {
+ nativeCurrency: 'ETH',
displayValue: '1',
+ suffix: undefined,
},
},
{
props: {
value: '0x3b9aca00',
currency: 'ETH',
+ nativeCurrency: 'ETH',
denomination: 'WEI',
hideLabel: true,
},
result: {
+ nativeCurrency: 'ETH',
displayValue: '1000000000',
+ suffix: undefined,
},
},
{
props: {
value: '0x3b9aca00',
currency: 'ETH',
+ nativeCurrency: 'ETH',
numberOfDecimals: 100,
hideLabel: true,
},
result: {
+ nativeCurrency: 'ETH',
displayValue: '1e-9',
+ suffix: undefined,
},
},
]
tests.forEach(({ props, result }) => {
- assert.deepEqual(mapStateToProps(mockState, props), result)
+ assert.deepEqual(mergeProps(mockStateProps, {}, { ...props }), result)
})
})
})
diff --git a/ui/app/components/currency-input/currency-input.component.js b/ui/app/components/currency-input/currency-input.component.js
new file mode 100644
index 000000000..0761a75c5
--- /dev/null
+++ b/ui/app/components/currency-input/currency-input.component.js
@@ -0,0 +1,121 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import UnitInput from '../unit-input'
+import CurrencyDisplay from '../currency-display'
+import { getValueFromWeiHex, getWeiHexFromDecimalValue } from '../../helpers/conversions.util'
+import { ETH } from '../../constants/common'
+
+/**
+ * Component that allows user to enter currency values as a number, and props receive a converted
+ * hex value in WEI. props.value, used as a default or forced value, should be a hex value, which
+ * gets converted into a decimal value depending on the currency (ETH or Fiat).
+ */
+export default class CurrencyInput extends PureComponent {
+ static propTypes = {
+ conversionRate: PropTypes.number,
+ currentCurrency: PropTypes.string,
+ nativeCurrency: PropTypes.string,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ suffix: PropTypes.string,
+ useFiat: PropTypes.bool,
+ value: PropTypes.string,
+ }
+
+ constructor (props) {
+ super(props)
+
+ const { value: hexValue } = props
+ const decimalValue = hexValue ? this.getDecimalValue(props) : 0
+
+ this.state = {
+ decimalValue,
+ hexValue,
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ const { value: prevPropsHexValue } = prevProps
+ const { value: propsHexValue } = this.props
+ const { hexValue: stateHexValue } = this.state
+
+ if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) {
+ const decimalValue = this.getDecimalValue(this.props)
+ this.setState({ hexValue: propsHexValue, decimalValue })
+ }
+ }
+
+ getDecimalValue (props) {
+ const { value: hexValue, useFiat, currentCurrency, conversionRate } = props
+ const decimalValueString = useFiat
+ ? getValueFromWeiHex({
+ value: hexValue, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
+ })
+ : getValueFromWeiHex({
+ value: hexValue, toCurrency: ETH, numberOfDecimals: 6,
+ })
+
+ return Number(decimalValueString) || 0
+ }
+
+ handleChange = decimalValue => {
+ const { useFiat, currentCurrency: fromCurrency, conversionRate, onChange } = this.props
+
+ const hexValue = useFiat
+ ? getWeiHexFromDecimalValue({
+ value: decimalValue, fromCurrency, conversionRate, invertConversionRate: true,
+ })
+ : getWeiHexFromDecimalValue({
+ value: decimalValue, fromCurrency: ETH, fromDenomination: ETH, conversionRate,
+ })
+
+ this.setState({ hexValue, decimalValue })
+ onChange(hexValue)
+ }
+
+ handleBlur = () => {
+ this.props.onBlur(this.state.hexValue)
+ }
+
+ renderConversionComponent () {
+ const { useFiat, currentCurrency, nativeCurrency } = this.props
+ const { hexValue } = this.state
+ let currency, numberOfDecimals
+
+ if (useFiat) {
+ // Display ETH
+ currency = nativeCurrency || ETH
+ numberOfDecimals = 6
+ } else {
+ // Display Fiat
+ currency = currentCurrency
+ numberOfDecimals = 2
+ }
+
+ return (
+ <CurrencyDisplay
+ className="currency-input__conversion-component"
+ currency={currency}
+ value={hexValue}
+ numberOfDecimals={numberOfDecimals}
+ />
+ )
+ }
+
+ render () {
+ const { suffix, ...restProps } = this.props
+ const { decimalValue } = this.state
+
+ return (
+ <UnitInput
+ {...restProps}
+ suffix={suffix}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ value={decimalValue}
+ >
+ { this.renderConversionComponent() }
+ </UnitInput>
+ )
+ }
+}
diff --git a/ui/app/components/currency-input/currency-input.container.js b/ui/app/components/currency-input/currency-input.container.js
new file mode 100644
index 000000000..1d1ed7b41
--- /dev/null
+++ b/ui/app/components/currency-input/currency-input.container.js
@@ -0,0 +1,28 @@
+import { connect } from 'react-redux'
+import CurrencyInput from './currency-input.component'
+import { ETH } from '../../constants/common'
+
+const mapStateToProps = state => {
+ const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state
+
+ return {
+ nativeCurrency,
+ currentCurrency,
+ conversionRate,
+ }
+}
+
+const mergeProps = (stateProps, dispatchProps, ownProps) => {
+ const { nativeCurrency, currentCurrency } = stateProps
+ const { useFiat } = ownProps
+ const suffix = useFiat ? currentCurrency.toUpperCase() : nativeCurrency || ETH
+
+ return {
+ ...stateProps,
+ ...dispatchProps,
+ ...ownProps,
+ suffix,
+ }
+}
+
+export default connect(mapStateToProps, null, mergeProps)(CurrencyInput)
diff --git a/ui/app/components/currency-input/index.js b/ui/app/components/currency-input/index.js
new file mode 100644
index 000000000..d8069fb67
--- /dev/null
+++ b/ui/app/components/currency-input/index.js
@@ -0,0 +1 @@
+export { default } from './currency-input.container'
diff --git a/ui/app/components/currency-input/index.scss b/ui/app/components/currency-input/index.scss
new file mode 100644
index 000000000..fcb2db461
--- /dev/null
+++ b/ui/app/components/currency-input/index.scss
@@ -0,0 +1,7 @@
+.currency-input {
+ &__conversion-component {
+ font-size: 12px;
+ line-height: 12px;
+ padding-left: 1px;
+ }
+}
diff --git a/ui/app/components/currency-input/tests/currency-input.component.test.js b/ui/app/components/currency-input/tests/currency-input.component.test.js
new file mode 100644
index 000000000..a33889f94
--- /dev/null
+++ b/ui/app/components/currency-input/tests/currency-input.component.test.js
@@ -0,0 +1,251 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow, mount } from 'enzyme'
+import sinon from 'sinon'
+import { Provider } from 'react-redux'
+import configureMockStore from 'redux-mock-store'
+import CurrencyInput from '../currency-input.component'
+import UnitInput from '../../unit-input'
+import CurrencyDisplay from '../../currency-display'
+
+describe('CurrencyInput Component', () => {
+ describe('rendering', () => {
+ it('should render properly without a suffix', () => {
+ const wrapper = shallow(
+ <CurrencyInput />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(UnitInput).length, 1)
+ })
+
+ it('should render properly with a suffix', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ suffix="ETH"
+ nativeCurrency="ETH"
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
+ assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ })
+
+ it('should render properly with an ETH value', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ value="de0b6b3a7640000"
+ suffix="ETH"
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
+ assert.equal(currencyInputInstance.state.decimalValue, 1)
+ assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
+ assert.equal(wrapper.find('.unit-input__input').props().value, '1')
+ assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD')
+ })
+
+ it('should render properly with a fiat value', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ value="f602f2234d0ea"
+ suffix="USD"
+ useFiat
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
+ assert.equal(currencyInputInstance.state.decimalValue, 1)
+ assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD')
+ assert.equal(wrapper.find('.unit-input__input').props().value, '1')
+ assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH')
+ })
+ })
+
+ describe('handling actions', () => {
+ const handleChangeSpy = sinon.spy()
+ const handleBlurSpy = sinon.spy()
+
+ afterEach(() => {
+ handleChangeSpy.resetHistory()
+ handleBlurSpy.resetHistory()
+ })
+
+ it('should call onChange and onBlur on input changes with the hex value for ETH', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ suffix="ETH"
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+
+ const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
+ assert.equal(currencyInputInstance.state.decimalValue, 0)
+ assert.equal(currencyInputInstance.state.hexValue, undefined)
+ assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD')
+ const input = wrapper.find('input')
+ assert.equal(input.props().value, 0)
+
+ input.simulate('change', { target: { value: 1 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000'))
+ assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD')
+ assert.equal(currencyInputInstance.state.decimalValue, 1)
+ assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
+
+ assert.equal(handleBlurSpy.callCount, 0)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith('de0b6b3a7640000'))
+ })
+
+ it('should call onChange and onBlur on input changes with the hex value for fiat', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ suffix="USD"
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ useFiat
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+
+ const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
+ assert.equal(currencyInputInstance.state.decimalValue, 0)
+ assert.equal(currencyInputInstance.state.hexValue, undefined)
+ assert.equal(wrapper.find('.currency-display-component').text(), '0ETH')
+ const input = wrapper.find('input')
+ assert.equal(input.props().value, 0)
+
+ input.simulate('change', { target: { value: 1 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith('f602f2234d0ea'))
+ assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH')
+ assert.equal(currencyInputInstance.state.decimalValue, 1)
+ assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
+
+ assert.equal(handleBlurSpy.callCount, 0)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith('f602f2234d0ea'))
+ })
+
+ it('should change the state and pass in a new decimalValue when props.value changes', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = shallow(
+ <Provider store={store}>
+ <CurrencyInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ suffix="USD"
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ useFiat
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const currencyInputInstance = wrapper.find(CurrencyInput).dive()
+ assert.equal(currencyInputInstance.state('decimalValue'), 0)
+ assert.equal(currencyInputInstance.state('hexValue'), undefined)
+ assert.equal(currencyInputInstance.find(UnitInput).props().value, 0)
+
+ currencyInputInstance.setProps({ value: '1ec05e43e72400' })
+ currencyInputInstance.update()
+ assert.equal(currencyInputInstance.state('decimalValue'), 2)
+ assert.equal(currencyInputInstance.state('hexValue'), '1ec05e43e72400')
+ assert.equal(currencyInputInstance.find(UnitInput).props().value, 2)
+ })
+ })
+})
diff --git a/ui/app/components/currency-input/tests/currency-input.container.test.js b/ui/app/components/currency-input/tests/currency-input.container.test.js
new file mode 100644
index 000000000..5d72958e6
--- /dev/null
+++ b/ui/app/components/currency-input/tests/currency-input.container.test.js
@@ -0,0 +1,60 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps, mergeProps
+
+proxyquire('../currency-input.container.js', {
+ 'react-redux': {
+ connect: (ms, md, mp) => {
+ mapStateToProps = ms
+ mergeProps = mp
+ return () => ({})
+ },
+ },
+})
+
+describe('CurrencyInput container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props', () => {
+ const mockState = {
+ metamask: {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ })
+ })
+ })
+
+ describe('mergeProps()', () => {
+ it('should return the correct props', () => {
+ const mockStateProps = {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ }
+ const mockDispatchProps = {}
+
+ assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, { useFiat: true }), {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ useFiat: true,
+ suffix: 'USD',
+ })
+
+ assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ suffix: 'ETH',
+ })
+ })
+ })
+})
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index b497f5c09..e6b3e0c0c 100644
--- a/ui/app/components/dropdowns/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -6,7 +6,7 @@ const genAccountLink = require('../../../../lib/account-link.js')
const connect = require('react-redux').connect
const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
-const Identicon = require('../../identicon')
+import Identicon from '../../identicon'
const { checksumAddress } = require('../../../util')
const copyToClipboard = require('copy-to-clipboard')
const { formatBalance } = require('../../../util')
@@ -26,14 +26,14 @@ class AccountDropdowns extends Component {
}
renderAccounts () {
- const { identities, accounts, selected, menuItemStyles, actions, keyrings } = this.props
+ const { identities, accounts, selected, menuItemStyles, actions, keyrings, ticker } = this.props
return Object.keys(identities).map((key, index) => {
const identity = identities[key]
const isSelected = identity.address === selected
const balanceValue = accounts[key].balance
- const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...'
+ const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, true, ticker) : '...'
const simpleAddress = identity.address.substring(2).toLowerCase()
const keyring = keyrings.find((kr) => {
@@ -421,6 +421,7 @@ AccountDropdowns.propTypes = {
network: PropTypes.number,
// actions.showExportPrivateKeyModal: ,
style: PropTypes.object,
+ ticker: PropTypes.string,
enableAccountsSelector: PropTypes.bool,
enableAccountOption: PropTypes.bool,
enableAccountOptions: PropTypes.bool,
@@ -458,6 +459,7 @@ const mapDispatchToProps = (dispatch) => {
function mapStateToProps (state) {
return {
+ ticker: state.metamask.ticker,
keyrings: state.metamask.keyrings,
sidebarOpen: state.appState.sidebar.isOpen,
}
diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js
index b252b25d9..d4cc695a6 100644
--- a/ui/app/components/dropdowns/network-dropdown.js
+++ b/ui/app/components/dropdowns/network-dropdown.js
@@ -24,8 +24,9 @@ const notToggleElementClassnames = [
function mapStateToProps (state) {
return {
provider: state.metamask.provider,
- frequentRpcList: state.metamask.frequentRpcList || [],
+ frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
networkDropdownOpen: state.appState.networkDropdownOpen,
+ network: state.metamask.network,
}
}
@@ -40,8 +41,8 @@ function mapDispatchToProps (dispatch) {
setDefaultRpcTarget: type => {
dispatch(actions.setDefaultRpcTarget(type))
},
- setRpcTarget: (target) => {
- dispatch(actions.setRpcTarget(target))
+ setRpcTarget: (target, network, ticker, nickname) => {
+ dispatch(actions.setRpcTarget(target, network, ticker, nickname))
},
delRpcTarget: (target) => {
dispatch(actions.delRpcTarget(target))
@@ -71,7 +72,7 @@ module.exports = compose(
NetworkDropdown.prototype.render = function () {
const props = this.props
const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
- const rpcList = props.frequentRpcList
+ const rpcListDetail = props.frequentRpcListDetail
const isOpen = this.props.networkDropdownOpen
const dropdownMenuItemStyle = {
fontSize: '16px',
@@ -225,7 +226,7 @@ NetworkDropdown.prototype.render = function () {
),
this.renderCustomOption(props.provider),
- this.renderCommonRpc(rpcList, props.provider),
+ this.renderCommonRpc(rpcListDetail, props.provider),
h(
DropdownMenuItem,
@@ -267,28 +268,33 @@ NetworkDropdown.prototype.getNetworkName = function () {
} else if (providerName === 'rinkeby') {
name = this.context.t('rinkeby')
} else {
- name = this.context.t('unknownNetwork')
+ name = provider.nickname || this.context.t('unknownNetwork')
}
return name
}
-NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
+NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) {
const props = this.props
- const reversedRpcList = rpcList.slice().reverse()
+ const reversedRpcListDetail = rpcListDetail.slice().reverse()
+ const network = props.network
- return reversedRpcList.map((rpc) => {
+ return reversedRpcListDetail.map((entry) => {
+ const rpc = entry.rpcUrl
+ const ticker = entry.ticker || 'ETH'
+ const nickname = entry.nickname || ''
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
if ((rpc === 'http://localhost:8545') || currentRpcTarget) {
return null
} else {
+ const chainId = entry.chainId || network
return h(
DropdownMenuItem,
{
key: `common${rpc}`,
closeMenu: () => this.props.hideNetworkDropdown(),
- onClick: () => props.setRpcTarget(rpc),
+ onClick: () => props.setRpcTarget(rpc, chainId, ticker, nickname),
style: {
fontSize: '16px',
lineHeight: '20px',
@@ -302,7 +308,7 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
style: {
color: currentRpcTarget ? '#ffffff' : '#9b9b9b',
},
- }, rpc),
+ }, nickname || rpc),
h('i.fa.fa-times.delete',
{
onClick: (e) => {
@@ -317,8 +323,9 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
}
NetworkDropdown.prototype.renderCustomOption = function (provider) {
- const { rpcTarget, type } = provider
+ const { rpcTarget, type, ticker, nickname } = provider
const props = this.props
+ const network = props.network
if (type !== 'rpc') return null
@@ -332,7 +339,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) {
DropdownMenuItem,
{
key: rpcTarget,
- onClick: () => props.setRpcTarget(rpcTarget),
+ onClick: () => props.setRpcTarget(rpcTarget, network, ticker, nickname),
closeMenu: () => this.props.hideNetworkDropdown(),
style: {
fontSize: '16px',
@@ -347,7 +354,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) {
style: {
color: '#ffffff',
},
- }, rpcTarget),
+ }, nickname || rpcTarget),
]
)
}
diff --git a/ui/app/components/dropdowns/tests/network-dropdown.test.js b/ui/app/components/dropdowns/tests/network-dropdown.test.js
index 699b54605..88ad56851 100644
--- a/ui/app/components/dropdowns/tests/network-dropdown.test.js
+++ b/ui/app/components/dropdowns/tests/network-dropdown.test.js
@@ -45,8 +45,8 @@ describe('Network Dropdown', () => {
provider: {
'type': 'test',
},
- frequentRpcList: [
- 'http://localhost:7545',
+ frequentRpcListDetail: [
+ { rpcUrl: 'http://localhost:7545' },
],
},
appState: {
diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js
index c3d084bdc..2f6395a2d 100644
--- a/ui/app/components/eth-balance.js
+++ b/ui/app/components/eth-balance.js
@@ -1,5 +1,6 @@
const { Component } = require('react')
const h = require('react-hyperscript')
+const connect = require('react-redux').connect
const { inherits } = require('util')
const {
formatBalance,
@@ -8,7 +9,12 @@ const {
const Tooltip = require('./tooltip.js')
const FiatValue = require('./fiat-value.js')
-module.exports = EthBalanceComponent
+module.exports = connect(mapStateToProps)(EthBalanceComponent)
+function mapStateToProps (state) {
+ return {
+ ticker: state.metamask.ticker,
+ }
+}
inherits(EthBalanceComponent, Component)
function EthBalanceComponent () {
@@ -17,9 +23,9 @@ function EthBalanceComponent () {
EthBalanceComponent.prototype.render = function () {
const props = this.props
- const { value, style, width, needsParse = true } = props
+ const { ticker, value, style, width, needsParse = true } = props
- const formattedValue = value ? formatBalance(value, 6, needsParse) : '...'
+ const formattedValue = value ? formatBalance(value, 6, needsParse, ticker) : '...'
return (
diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js
deleted file mode 100644
index 7bd921892..000000000
--- a/ui/app/components/identicon.js
+++ /dev/null
@@ -1,124 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-const isNode = require('detect-node')
-const findDOMNode = require('react-dom').findDOMNode
-const jazzicon = require('jazzicon')
-const iconFactoryGen = require('../../lib/icon-factory')
-const iconFactory = iconFactoryGen(jazzicon)
-const { toDataUrl } = require('../../lib/blockies')
-
-module.exports = connect(mapStateToProps)(IdenticonComponent)
-
-inherits(IdenticonComponent, Component)
-function IdenticonComponent () {
- Component.call(this)
-
- this.defaultDiameter = 46
-}
-
-function mapStateToProps (state) {
- return {
- useBlockie: state.metamask.useBlockie,
- }
-}
-
-IdenticonComponent.prototype.render = function () {
- var props = this.props
- const { className = '', address, image } = props
- var diameter = props.diameter || this.defaultDiameter
- const style = {
- height: diameter,
- width: diameter,
- borderRadius: diameter / 2,
- }
- if (image) {
- return h('img', {
- className: `${className} identicon`,
- src: image,
- style: {
- ...style,
- },
- })
- } else if (address) {
- return h('div', {
- className: `${className} identicon`,
- key: 'identicon-' + address,
- style: {
- display: 'flex',
- flexShrink: 0,
- alignItems: 'center',
- justifyContent: 'center',
- ...style,
- overflow: 'hidden',
- },
- })
- } else {
- return h('img.balance-icon', {
- className,
- src: './images/eth_logo.svg',
- style: {
- ...style,
- },
- })
- }
-}
-
-IdenticonComponent.prototype.componentDidMount = function () {
- var props = this.props
- const { address, useBlockie } = props
-
- if (!address) return
-
- if (!isNode) {
- // eslint-disable-next-line react/no-find-dom-node
- var container = findDOMNode(this)
-
- const diameter = props.diameter || this.defaultDiameter
-
- if (useBlockie) {
- _generateBlockie(container, address, diameter)
- } else {
- _generateJazzicon(container, address, diameter)
- }
- }
-}
-
-IdenticonComponent.prototype.componentDidUpdate = function () {
- var props = this.props
- const { address, useBlockie } = props
-
- if (!address) return
-
- if (!isNode) {
- // eslint-disable-next-line react/no-find-dom-node
- var container = findDOMNode(this)
-
- var children = container.children
- for (var i = 0; i < children.length; i++) {
- container.removeChild(children[i])
- }
-
- const diameter = props.diameter || this.defaultDiameter
-
- if (useBlockie) {
- _generateBlockie(container, address, diameter)
- } else {
- _generateJazzicon(container, address, diameter)
- }
- }
-}
-
-function _generateBlockie (container, address, diameter) {
- const img = new Image()
- img.src = toDataUrl(address)
- img.height = diameter
- img.width = diameter
- container.appendChild(img)
-}
-
-function _generateJazzicon (container, address, diameter) {
- const img = iconFactory.iconForAddress(address, diameter)
- container.appendChild(img)
-}
diff --git a/ui/app/components/identicon/identicon.component.js b/ui/app/components/identicon/identicon.component.js
new file mode 100644
index 000000000..b892e5ae5
--- /dev/null
+++ b/ui/app/components/identicon/identicon.component.js
@@ -0,0 +1,99 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import classnames from 'classnames'
+import { toDataUrl } from '../../../lib/blockies'
+import contractMap from 'eth-contract-metadata'
+import { checksumAddress } from '../../../app/util'
+import Jazzicon from '../jazzicon'
+
+const getStyles = diameter => (
+ {
+ height: diameter,
+ width: diameter,
+ borderRadius: diameter / 2,
+ }
+)
+
+export default class Identicon extends PureComponent {
+ static propTypes = {
+ address: PropTypes.string,
+ className: PropTypes.string,
+ diameter: PropTypes.number,
+ image: PropTypes.string,
+ useBlockie: PropTypes.bool,
+ }
+
+ static defaultProps = {
+ diameter: 46,
+ }
+
+ renderImage () {
+ const { className, diameter, image } = this.props
+
+ return (
+ <img
+ className={classnames('identicon', className)}
+ src={image}
+ style={getStyles(diameter)}
+ />
+ )
+ }
+
+ renderJazzicon () {
+ const { address, className, diameter } = this.props
+
+ return (
+ <Jazzicon
+ address={address}
+ diameter={diameter}
+ className={classnames('identicon', className)}
+ style={getStyles(diameter)}
+ />
+ )
+ }
+
+ renderBlockie () {
+ const { address, className, diameter } = this.props
+
+ return (
+ <div
+ className={classnames('identicon', className)}
+ style={getStyles(diameter)}
+ >
+ <img
+ src={toDataUrl(address)}
+ height={diameter}
+ width={diameter}
+ />
+ </div>
+ )
+ }
+
+ render () {
+ const { className, address, image, diameter, useBlockie } = this.props
+
+ if (image) {
+ return this.renderImage()
+ }
+
+ if (address) {
+ const checksummedAddress = checksumAddress(address)
+
+ if (contractMap[checksummedAddress] && contractMap[checksummedAddress].logo) {
+ return this.renderJazzicon()
+ }
+
+ return useBlockie
+ ? this.renderBlockie()
+ : this.renderJazzicon()
+ }
+
+ return (
+ <img
+ className={classnames('balance-icon', className)}
+ src="./images/eth_logo.svg"
+ style={getStyles(diameter)}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/identicon/identicon.container.js b/ui/app/components/identicon/identicon.container.js
new file mode 100644
index 000000000..bc49bc18e
--- /dev/null
+++ b/ui/app/components/identicon/identicon.container.js
@@ -0,0 +1,12 @@
+import { connect } from 'react-redux'
+import Identicon from './identicon.component'
+
+const mapStateToProps = state => {
+ const { metamask: { useBlockie } } = state
+
+ return {
+ useBlockie,
+ }
+}
+
+export default connect(mapStateToProps)(Identicon)
diff --git a/ui/app/components/identicon/index.js b/ui/app/components/identicon/index.js
new file mode 100644
index 000000000..799c886f2
--- /dev/null
+++ b/ui/app/components/identicon/index.js
@@ -0,0 +1 @@
+export { default } from './identicon.container'
diff --git a/ui/app/components/identicon/index.scss b/ui/app/components/identicon/index.scss
new file mode 100644
index 000000000..657afc48f
--- /dev/null
+++ b/ui/app/components/identicon/index.scss
@@ -0,0 +1,7 @@
+.identicon {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+}
diff --git a/test/unit/ui/app/components/identicon.spec.js b/ui/app/components/identicon/tests/identicon.component.test.js
index a2f8d8246..2944818f5 100644
--- a/test/unit/ui/app/components/identicon.spec.js
+++ b/ui/app/components/identicon/tests/identicon.component.test.js
@@ -3,11 +3,9 @@ import assert from 'assert'
import thunk from 'redux-thunk'
import configureMockStore from 'redux-mock-store'
import { mount } from 'enzyme'
+import Identicon from '../identicon.component'
-import IdenticonComponent from '../../../../../ui/app/components/identicon'
-
-describe('Identicon Component', () => {
-
+describe('Identicon', () => {
const state = {
metamask: {
useBlockie: false,
@@ -19,18 +17,35 @@ describe('Identicon Component', () => {
const store = mockStore(state)
it('renders default eth_logo identicon with no props', () => {
- const wrapper = mount(<IdenticonComponent store={store}/>)
+ const wrapper = mount(
+ <Identicon store={store}/>
+ )
+
assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg')
})
it('renders custom image and add className props', () => {
- const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />)
- assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon')
+ const wrapper = mount(
+ <Identicon
+ store={store}
+ className="test-image"
+ image="test-image"
+ />
+ )
+
+ assert.equal(wrapper.find('img.test-image').prop('className'), 'identicon test-image')
assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image')
})
it('renders div with address prop', () => {
- const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />)
- assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon')
+ const wrapper = mount(
+ <Identicon
+ store={store}
+ className="test-address"
+ address="0xTest"
+ />
+ )
+
+ assert.equal(wrapper.find('div.test-address').prop('className'), 'identicon test-address')
})
})
diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss
index 21b65bf55..72de6cb93 100644
--- a/ui/app/components/index.scss
+++ b/ui/app/components/index.scss
@@ -1,15 +1,23 @@
@import './app-header/index';
+@import './add-token-button/index';
+
@import './button-group/index';
@import './card/index';
@import './confirm-page-container/index';
+@import './currency-input/index';
+
+@import './currency-display/index';
+
@import './error-message/index';
@import './export-text-container/index';
+@import './identicon/index';
+
@import './info-box/index';
@import './menu-bar/index';
@@ -49,3 +57,5 @@
@import './app-header/index';
@import './sidebars/index';
+
+@import './unit-input/index';
diff --git a/ui/app/components/jazzicon/index.js b/ui/app/components/jazzicon/index.js
new file mode 100644
index 000000000..bea900ab9
--- /dev/null
+++ b/ui/app/components/jazzicon/index.js
@@ -0,0 +1 @@
+export { default } from './jazzicon.component'
diff --git a/ui/app/components/jazzicon/jazzicon.component.js b/ui/app/components/jazzicon/jazzicon.component.js
new file mode 100644
index 000000000..fcb1c59b1
--- /dev/null
+++ b/ui/app/components/jazzicon/jazzicon.component.js
@@ -0,0 +1,69 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import isNode from 'detect-node'
+import { findDOMNode } from 'react-dom'
+import jazzicon from 'jazzicon'
+import iconFactoryGenerator from '../../../lib/icon-factory'
+const iconFactory = iconFactoryGenerator(jazzicon)
+
+/**
+ * Wrapper around the jazzicon library to return a React component, as the library returns an
+ * HTMLDivElement which needs to be appended.
+ */
+export default class Jazzicon extends PureComponent {
+ static propTypes = {
+ address: PropTypes.string.isRequired,
+ className: PropTypes.string,
+ diameter: PropTypes.number,
+ style: PropTypes.object,
+ }
+
+ static defaultProps = {
+ diameter: 46,
+ }
+
+ componentDidMount () {
+ if (!isNode) {
+ this.appendJazzicon()
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ const { address: prevAddress } = prevProps
+ const { address } = this.props
+
+ if (!isNode && address !== prevAddress) {
+ this.removeExistingChildren()
+ this.appendJazzicon()
+ }
+ }
+
+ removeExistingChildren () {
+ // eslint-disable-next-line react/no-find-dom-node
+ const container = findDOMNode(this)
+ const { children } = container
+
+ for (let i = 0; i < children.length; i++) {
+ container.removeChild(children[i])
+ }
+ }
+
+ appendJazzicon () {
+ // eslint-disable-next-line react/no-find-dom-node
+ const container = findDOMNode(this)
+ const { address, diameter } = this.props
+ const image = iconFactory.iconForAddress(address, diameter)
+ container.appendChild(image)
+ }
+
+ render () {
+ const { className, style } = this.props
+
+ return (
+ <div
+ className={className}
+ style={style}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js
index aa0593df8..2a6c655e1 100644
--- a/ui/app/components/modals/account-modal-container.js
+++ b/ui/app/components/modals/account-modal-container.js
@@ -5,7 +5,7 @@ const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
const { getSelectedIdentity } = require('../../selectors')
-const Identicon = require('../identicon')
+import Identicon from '../identicon'
function mapStateToProps (state, ownProps) {
return {
diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js
index b082db1d0..b973f221c 100644
--- a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js
+++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
-import CurrencyDisplay from '../../../currency-display'
-import { ETH } from '../../../../constants/common'
+import UserPreferencedCurrencyDisplay from '../../../user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../../../../constants/common'
export default class CancelTransaction extends PureComponent {
static propTypes = {
@@ -13,15 +13,15 @@ export default class CancelTransaction extends PureComponent {
return (
<div className="cancel-transaction-gas-fee">
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="cancel-transaction-gas-fee__eth"
- currency={ETH}
value={value}
- numberOfDecimals={6}
+ type={PRIMARY}
/>
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="cancel-transaction-gas-fee__fiat"
value={value}
+ type={SECONDARY}
/>
</div>
)
diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js
index 994c2a577..014815503 100644
--- a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js
+++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js
@@ -2,7 +2,7 @@ import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import CancelTransactionGasFee from '../cancel-transaction-gas-fee.component'
-import CurrencyDisplay from '../../../../currency-display'
+import UserPreferencedCurrencyDisplay from '../../../../user-preferenced-currency-display'
describe('CancelTransactionGasFee Component', () => {
it('should render', () => {
@@ -13,12 +13,11 @@ describe('CancelTransactionGasFee Component', () => {
)
assert.ok(wrapper)
- assert.equal(wrapper.find(CurrencyDisplay).length, 2)
- const ethDisplay = wrapper.find(CurrencyDisplay).at(0)
- const fiatDisplay = wrapper.find(CurrencyDisplay).at(1)
+ assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 2)
+ const ethDisplay = wrapper.find(UserPreferencedCurrencyDisplay).at(0)
+ const fiatDisplay = wrapper.find(UserPreferencedCurrencyDisplay).at(1)
assert.equal(ethDisplay.props().value, '0x3b9aca00')
- assert.equal(ethDisplay.props().currency, 'ETH')
assert.equal(ethDisplay.props().className, 'cancel-transaction-gas-fee__eth')
assert.equal(fiatDisplay.props().value, '0x3b9aca00')
diff --git a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js
index eff94a54a..195c55421 100644
--- a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js
+++ b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js
@@ -78,7 +78,7 @@ export default class ConfirmRemoveAccount extends Component {
<a
className="confirm-remove-account__link"
rel="noopener noreferrer"
- target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-">
+ target="_blank" href="https://metamask.zendesk.com/hc/en-us/articles/360015289932">
{ t('learnMore') }
</a>
</div>
diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js
index fb38516d3..43f3009a5 100644
--- a/ui/app/components/modals/hide-token-confirmation-modal.js
+++ b/ui/app/components/modals/hide-token-confirmation-modal.js
@@ -4,7 +4,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
-const Identicon = require('../identicon')
+import Identicon from '../identicon'
function mapStateToProps (state) {
return {
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 15ca9deaa..338229a28 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -27,7 +27,6 @@ import TransactionConfirmed from './transaction-confirmed'
import ConfirmCustomizeGasModal from './customize-gas'
import CancelTransaction from './cancel-transaction'
import WelcomeBeta from './welcome-beta'
-import TransactionDetails from './transaction-details'
import RejectTransactions from './reject-transactions'
const modalContainerBaseStyle = {
@@ -366,19 +365,6 @@ const MODALS = {
},
},
- TRANSACTION_DETAILS: {
- contents: h(TransactionDetails),
- mobileModalStyle: {
- ...modalContainerMobileStyle,
- },
- laptopModalStyle: {
- ...modalContainerLaptopStyle,
- },
- contentStyle: {
- borderRadius: '8px',
- },
- },
-
REJECT_TRANSACTIONS: {
contents: h(RejectTransactions),
mobileModalStyle: {
diff --git a/ui/app/components/modals/transaction-details/index.js b/ui/app/components/modals/transaction-details/index.js
deleted file mode 100644
index 1fc42c662..000000000
--- a/ui/app/components/modals/transaction-details/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './transaction-details.container'
diff --git a/ui/app/components/modals/transaction-details/transaction-details.component.js b/ui/app/components/modals/transaction-details/transaction-details.component.js
deleted file mode 100644
index f2fec3409..000000000
--- a/ui/app/components/modals/transaction-details/transaction-details.component.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React, { PureComponent } from 'react'
-import PropTypes from 'prop-types'
-import Modal from '../../modal'
-import TransactionListItemDetails from '../../transaction-list-item-details'
-import { hexToDecimal } from '../../../helpers/conversions.util'
-
-export default class TransactionConfirmed extends PureComponent {
- static contextTypes = {
- t: PropTypes.func,
- }
-
- static propTypes = {
- hideModal: PropTypes.func,
- transaction: PropTypes.object,
- onRetry: PropTypes.func,
- showRetry: PropTypes.bool,
- onCancel: PropTypes.func,
- showCancel: PropTypes.bool,
- }
-
- handleSubmit = () => {
- this.props.hideModal()
- }
-
- handleRetry = () => {
- const { onRetry, hideModal } = this.props
-
- Promise.resolve(onRetry()).then(() => hideModal())
- }
-
- render () {
- const { t } = this.context
- const { transaction, showRetry, onCancel, showCancel } = this.props
- const { txParams: { nonce } = {} } = transaction
- const decimalNonce = nonce && hexToDecimal(nonce)
-
- return (
- <Modal
- onSubmit={this.handleSubmit}
- onClose={this.handleSubmit}
- submitText={t('ok')}
- headerText={t('transactionWithNonce', [`#${decimalNonce}`])}
- >
- <TransactionListItemDetails
- transaction={transaction}
- onRetry={this.handleRetry}
- showRetry={showRetry}
- onCancel={() => onCancel()}
- showCancel={showCancel}
- />
- </Modal>
- )
- }
-}
diff --git a/ui/app/components/modals/transaction-details/transaction-details.container.js b/ui/app/components/modals/transaction-details/transaction-details.container.js
deleted file mode 100644
index f212920bb..000000000
--- a/ui/app/components/modals/transaction-details/transaction-details.container.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import TransactionDetails from './transaction-details.component'
-import withModalProps from '../../../higher-order-components/with-modal-props'
-
-export default withModalProps(TransactionDetails)
diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js
index 38626af20..82f9ff9c3 100644
--- a/ui/app/components/network-display/network-display.component.js
+++ b/ui/app/components/network-display/network-display.component.js
@@ -41,7 +41,7 @@ export default class NetworkDisplay extends Component {
}
render () {
- const { network, provider: { type } } = this.props
+ const { network, provider: { type, nickname } } = this.props
const networkClass = networkToClassHash[network]
return (
@@ -61,7 +61,7 @@ export default class NetworkDisplay extends Component {
/>
}
<div className="network-display__name">
- { this.context.t(type) }
+ { type === 'rpc' && nickname ? nickname : this.context.t(type) }
</div>
</div>
)
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 83297c4f2..611aadb7b 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -23,9 +23,10 @@ Network.prototype.render = function () {
const props = this.props
const context = this.context
const networkNumber = props.network
- let providerName
+ let providerName, providerNick
try {
providerName = props.provider.type
+ providerNick = props.provider.nickname || ''
} catch (e) {
providerName = null
}
@@ -131,7 +132,7 @@ Network.prototype.render = function () {
},
}),
- h('.network-name', context.t('privateNetwork')),
+ h('.network-name', providerNick || context.t('privateNetwork')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
}
diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
index 1611f817b..20f550927 100644
--- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
+++ b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
@@ -15,7 +15,7 @@ export default class TokenListPlaceholder extends Component {
</div>
<a
className="token-list-placeholder__link"
- href="https://consensys.zendesk.com/hc/en-us/articles/360004135092"
+ href="https://metamask.zendesk.com/hc/en-us/articles/360015489031"
target="_blank"
rel="noopener noreferrer"
>
diff --git a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
index acaed383a..7f1fb4e49 100644
--- a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
+++ b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
@@ -1,12 +1,15 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ConfirmTransactionBase from '../confirm-transaction-base'
+import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
import {
formatCurrency,
convertTokenToFiat,
addFiat,
roundExponential,
} from '../../../helpers/confirm-transaction/util'
+import { getWeiHexFromDecimalValue } from '../../../helpers/conversions.util'
+import { ETH, PRIMARY } from '../../../constants/common'
export default class ConfirmTokenTransactionBase extends Component {
static contextTypes = {
@@ -36,19 +39,48 @@ export default class ConfirmTokenTransactionBase extends Component {
})
}
- getSubtitle () {
- const { currentCurrency, contractExchangeRate } = this.props
+ renderSubtitleComponent () {
+ const { contractExchangeRate, tokenAmount } = this.props
- if (typeof contractExchangeRate === 'undefined') {
- return this.context.t('noConversionRateAvailable')
- } else {
- const fiatTransactionAmount = this.getFiatTransactionAmount()
- const roundedFiatTransactionAmount = roundExponential(fiatTransactionAmount)
- return formatCurrency(roundedFiatTransactionAmount, currentCurrency)
- }
+ const decimalEthValue = (tokenAmount * contractExchangeRate) || 0
+ const hexWeiValue = getWeiHexFromDecimalValue({
+ value: decimalEthValue,
+ fromCurrency: ETH,
+ fromDenomination: ETH,
+ })
+
+ return typeof contractExchangeRate === 'undefined'
+ ? (
+ <span>
+ { this.context.t('noConversionRateAvailable') }
+ </span>
+ ) : (
+ <UserPreferencedCurrencyDisplay
+ value={hexWeiValue}
+ type={PRIMARY}
+ showEthLogo
+ hideLabel
+ />
+ )
+ }
+
+ renderPrimaryTotalTextOverride () {
+ const { tokenAmount, tokenSymbol, ethTransactionTotal } = this.props
+ const tokensText = `${tokenAmount} ${tokenSymbol}`
+
+ return (
+ <div>
+ <span>{ `${tokensText} + ` }</span>
+ <img
+ src="/images/eth.svg"
+ height="18"
+ />
+ <span>{ ethTransactionTotal }</span>
+ </div>
+ )
}
- getFiatTotalTextOverride () {
+ getSecondaryTotalTextOverride () {
const { fiatTransactionTotal, currentCurrency, contractExchangeRate } = this.props
if (typeof contractExchangeRate === 'undefined') {
@@ -67,7 +99,6 @@ export default class ConfirmTokenTransactionBase extends Component {
tokenAddress,
tokenSymbol,
tokenAmount,
- ethTransactionTotal,
...restProps
} = this.props
@@ -78,9 +109,9 @@ export default class ConfirmTokenTransactionBase extends Component {
toAddress={toAddress}
identiconAddress={tokenAddress}
title={tokensText}
- subtitle={this.getSubtitle()}
- ethTotalTextOverride={`${tokensText} + \u2666 ${ethTransactionTotal}`}
- fiatTotalTextOverride={this.getFiatTotalTextOverride()}
+ subtitleComponent={this.renderSubtitleComponent()}
+ primaryTotalTextOverride={this.renderPrimaryTotalTextOverride()}
+ secondaryTotalTextOverride={this.getSecondaryTotalTextOverride()}
{...restProps}
/>
)
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
index 707dad62d..7d01aaffb 100644
--- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
@@ -1,7 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ConfirmPageContainer, { ConfirmDetailRow } from '../../confirm-page-container'
-import { formatCurrency } from '../../../helpers/confirm-transaction/util'
import { isBalanceSufficient } from '../../send/send.utils'
import { DEFAULT_ROUTE } from '../../../routes'
import {
@@ -9,6 +8,8 @@ import {
TRANSACTION_ERROR_KEY,
} from '../../../constants/error-keys'
import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions'
+import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../../../constants/common'
export default class ConfirmTransactionBase extends Component {
static contextTypes = {
@@ -36,7 +37,9 @@ export default class ConfirmTransactionBase extends Component {
fiatTransactionTotal: PropTypes.string,
fromAddress: PropTypes.string,
fromName: PropTypes.string,
- hexGasTotal: PropTypes.string,
+ hexTransactionAmount: PropTypes.string,
+ hexTransactionFee: PropTypes.string,
+ hexTransactionTotal: PropTypes.string,
isTxReprice: PropTypes.bool,
methodData: PropTypes.object,
nonce: PropTypes.string,
@@ -59,8 +62,8 @@ export default class ConfirmTransactionBase extends Component {
detailsComponent: PropTypes.node,
errorKey: PropTypes.string,
errorMessage: PropTypes.string,
- ethTotalTextOverride: PropTypes.string,
- fiatTotalTextOverride: PropTypes.string,
+ primaryTotalTextOverride: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ secondaryTotalTextOverride: PropTypes.string,
hideData: PropTypes.bool,
hideDetails: PropTypes.bool,
hideSubtitle: PropTypes.bool,
@@ -70,8 +73,10 @@ export default class ConfirmTransactionBase extends Component {
onEditGas: PropTypes.func,
onSubmit: PropTypes.func,
subtitle: PropTypes.string,
+ subtitleComponent: PropTypes.node,
summaryComponent: PropTypes.node,
title: PropTypes.string,
+ titleComponent: PropTypes.node,
valid: PropTypes.bool,
warning: PropTypes.string,
}
@@ -105,7 +110,7 @@ export default class ConfirmTransactionBase extends Component {
const {
balance,
conversionRate,
- hexGasTotal,
+ hexTransactionFee,
txData: {
simulationFails,
txParams: {
@@ -116,7 +121,7 @@ export default class ConfirmTransactionBase extends Component {
const insufficientBalance = balance && !isBalanceSufficient({
amount,
- gasTotal: hexGasTotal || '0x0',
+ gasTotal: hexTransactionFee || '0x0',
balance,
conversionRate,
})
@@ -131,7 +136,7 @@ export default class ConfirmTransactionBase extends Component {
if (simulationFails) {
return {
valid: true,
- errorKey: TRANSACTION_ERROR_KEY,
+ errorKey: simulationFails.errorKey ? simulationFails.errorKey : TRANSACTION_ERROR_KEY,
}
}
@@ -153,13 +158,10 @@ export default class ConfirmTransactionBase extends Component {
renderDetails () {
const {
detailsComponent,
- fiatTransactionFee,
- ethTransactionFee,
- currentCurrency,
- fiatTransactionTotal,
- ethTransactionTotal,
- fiatTotalTextOverride,
- ethTotalTextOverride,
+ primaryTotalTextOverride,
+ secondaryTotalTextOverride,
+ hexTransactionFee,
+ hexTransactionTotal,
hideDetails,
} = this.props
@@ -167,16 +169,13 @@ export default class ConfirmTransactionBase extends Component {
return null
}
- const formattedCurrency = formatCurrency(fiatTransactionTotal, currentCurrency)
-
return (
detailsComponent || (
<div className="confirm-page-container-content__details">
<div className="confirm-page-container-content__gas-fee">
<ConfirmDetailRow
label="Gas Fee"
- fiatText={formatCurrency(fiatTransactionFee, currentCurrency)}
- ethText={`\u2666 ${ethTransactionFee}`}
+ value={hexTransactionFee}
headerText="Edit"
headerTextClassName="confirm-detail-row__header-text--edit"
onHeaderClick={() => this.handleEditGas()}
@@ -185,11 +184,12 @@ export default class ConfirmTransactionBase extends Component {
<div>
<ConfirmDetailRow
label="Total"
- fiatText={fiatTotalTextOverride || formattedCurrency}
- ethText={ethTotalTextOverride || `\u2666 ${ethTransactionTotal}`}
+ value={hexTransactionTotal}
+ primaryText={primaryTotalTextOverride}
+ secondaryText={secondaryTotalTextOverride}
headerText="Amount + Gas Fee"
headerTextClassName="confirm-detail-row__header-text--total"
- fiatTextColor="#2f9ae0"
+ primaryValueTextColor="#2f9ae0"
/>
</div>
</div>
@@ -311,6 +311,43 @@ export default class ConfirmTransactionBase extends Component {
}
}
+ renderTitleComponent () {
+ const { title, titleComponent, hexTransactionAmount } = this.props
+
+ // Title string passed in by props takes priority
+ if (title) {
+ return null
+ }
+
+ return titleComponent || (
+ <UserPreferencedCurrencyDisplay
+ value={hexTransactionAmount}
+ type={PRIMARY}
+ showEthLogo
+ ethLogoHeight="26"
+ hideLabel
+ />
+ )
+ }
+
+ renderSubtitleComponent () {
+ const { subtitle, subtitleComponent, hexTransactionAmount } = this.props
+
+ // Subtitle string passed in by props takes priority
+ if (subtitle) {
+ return null
+ }
+
+ return subtitleComponent || (
+ <UserPreferencedCurrencyDisplay
+ value={hexTransactionAmount}
+ type={SECONDARY}
+ showEthLogo
+ hideLabel
+ />
+ )
+ }
+
render () {
const {
isTxReprice,
@@ -319,12 +356,9 @@ export default class ConfirmTransactionBase extends Component {
toName,
toAddress,
methodData,
- ethTransactionAmount,
- fiatTransactionAmount,
valid: propsValid = true,
errorMessage,
errorKey: propsErrorKey,
- currentCurrency,
action,
title,
subtitle,
@@ -341,7 +375,6 @@ export default class ConfirmTransactionBase extends Component {
const { submitting, submitError } = this.state
const { name } = methodData
- const fiatConvertedAmount = formatCurrency(fiatTransactionAmount, currentCurrency)
const { valid, errorKey } = this.getErrorKey()
return (
@@ -352,8 +385,10 @@ export default class ConfirmTransactionBase extends Component {
toAddress={toAddress}
showEdit={onEdit && !isTxReprice}
action={action || name || this.context.t('unknownFunction')}
- title={title || `${fiatConvertedAmount} ${currentCurrency.toUpperCase()}`}
- subtitle={subtitle || `\u2666 ${ethTransactionAmount}`}
+ title={title}
+ titleComponent={this.renderTitleComponent()}
+ subtitle={subtitle}
+ subtitleComponent={this.renderSubtitleComponent()}
hideSubtitle={hideSubtitle}
summaryComponent={summaryComponent}
detailsComponent={this.renderDetails()}
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
index b34067686..c366d5137 100644
--- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -36,7 +36,9 @@ const mapStateToProps = (state, props) => {
fiatTransactionAmount,
fiatTransactionFee,
fiatTransactionTotal,
- hexGasTotal,
+ hexTransactionAmount,
+ hexTransactionFee,
+ hexTransactionTotal,
tokenData,
methodData,
txData,
@@ -87,7 +89,9 @@ const mapStateToProps = (state, props) => {
fiatTransactionAmount,
fiatTransactionFee,
fiatTransactionTotal,
- hexGasTotal,
+ hexTransactionAmount,
+ hexTransactionFee,
+ hexTransactionTotal,
txData,
tokenData,
methodData,
diff --git a/ui/app/components/pages/create-account/import-account/index.js b/ui/app/components/pages/create-account/import-account/index.js
index e2e973af9..48d8f8838 100644
--- a/ui/app/components/pages/create-account/import-account/index.js
+++ b/ui/app/components/pages/create-account/import-account/index.js
@@ -46,7 +46,7 @@ AccountImportSubview.prototype.render = function () {
},
onClick: () => {
global.platform.openWindow({
- url: 'https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI',
+ url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289932',
})
},
}, this.context.t('here')),
diff --git a/ui/app/components/pages/settings/settings-tab/index.scss b/ui/app/components/pages/settings/settings-tab/index.scss
index 76a0cec6f..ef32b0e4c 100644
--- a/ui/app/components/pages/settings/settings-tab/index.scss
+++ b/ui/app/components/pages/settings/settings-tab/index.scss
@@ -5,12 +5,9 @@
color: $crimson;
}
- &__rpc-save-button {
- align-self: flex-end;
- padding: 5px;
- text-transform: uppercase;
- color: $dusty-gray;
- cursor: pointer;
+ &__advanced-link {
+ color: $curious-blue;
+ padding-left: 5px;
}
&__rpc-save-button {
@@ -19,6 +16,9 @@
text-transform: uppercase;
color: $dusty-gray;
cursor: pointer;
+ width: 25%;
+ min-width: 80px;
+ height: 33px;
}
&__button--red {
@@ -48,4 +48,22 @@
border-color: $ecstasy;
}
}
+
+ &__radio-buttons {
+ display: flex;
+ align-items: center;
+ }
+
+ &__radio-button {
+ display: flex;
+ align-items: center;
+
+ &:not(:last-child) {
+ margin-right: 16px;
+ }
+ }
+
+ &__radio-label {
+ padding-left: 4px;
+ }
}
diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js
index 9da624f56..cd81491a8 100644
--- a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js
+++ b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js
@@ -55,10 +55,17 @@ export default class SettingsTab extends PureComponent {
sendHexData: PropTypes.bool,
currentCurrency: PropTypes.string,
conversionDate: PropTypes.number,
+ nativeCurrency: PropTypes.string,
+ useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
+ setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func,
}
state = {
newRpc: '',
+ chainId: '',
+ showOptions: false,
+ ticker: '',
+ nickname: '',
}
renderCurrentConversion () {
@@ -119,37 +126,98 @@ export default class SettingsTab extends PureComponent {
renderNewRpcUrl () {
const { t } = this.context
- const { newRpc } = this.state
+ const { newRpc, chainId, ticker, nickname } = this.state
return (
<div className="settings-page__content-row">
<div className="settings-page__content-item">
- <span>{ t('newRPC') }</span>
+ <span>{ t('newNetwork') }</span>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<TextField
type="text"
id="new-rpc"
- placeholder={t('newRPC')}
+ placeholder={t('rpcURL')}
value={newRpc}
onChange={e => this.setState({ newRpc: e.target.value })}
onKeyPress={e => {
if (e.key === 'Enter') {
- this.validateRpc(newRpc)
+ this.validateRpc(newRpc, chainId, ticker, nickname)
}
}}
fullWidth
- margin="none"
+ margin="dense"
/>
- <div
- className="settings-tab__rpc-save-button"
- onClick={e => {
- e.preventDefault()
- this.validateRpc(newRpc)
+ <TextField
+ type="text"
+ id="chainid"
+ placeholder={t('optionalChainId')}
+ value={chainId}
+ onChange={e => this.setState({ chainId: e.target.value })}
+ onKeyPress={e => {
+ if (e.key === 'Enter') {
+ this.validateRpc(newRpc, chainId, ticker, nickname)
+ }
}}
- >
- { t('save') }
+ style={{
+ display: this.state.showOptions ? null : 'none',
+ }}
+ fullWidth
+ margin="dense"
+ />
+ <TextField
+ type="text"
+ id="ticker"
+ placeholder={t('optionalSymbol')}
+ value={ticker}
+ onChange={e => this.setState({ ticker: e.target.value })}
+ onKeyPress={e => {
+ if (e.key === 'Enter') {
+ this.validateRpc(newRpc, chainId, ticker, nickname)
+ }
+ }}
+ style={{
+ display: this.state.showOptions ? null : 'none',
+ }}
+ fullWidth
+ margin="dense"
+ />
+ <TextField
+ type="text"
+ id="nickname"
+ placeholder={t('optionalNickname')}
+ value={nickname}
+ onChange={e => this.setState({ nickname: e.target.value })}
+ onKeyPress={e => {
+ if (e.key === 'Enter') {
+ this.validateRpc(newRpc, chainId, ticker, nickname)
+ }
+ }}
+ style={{
+ display: this.state.showOptions ? null : 'none',
+ }}
+ fullWidth
+ margin="dense"
+ />
+ <div className="flex-row flex-align-center space-between">
+ <span className="settings-tab__advanced-link"
+ onClick={e => {
+ e.preventDefault()
+ this.setState({ showOptions: !this.state.showOptions })
+ }}
+ >
+ { t(this.state.showOptions ? 'hideAdvancedOptions' : 'showAdvancedOptions') }
+ </span>
+ <button
+ className="button btn-primary settings-tab__rpc-save-button"
+ onClick={e => {
+ e.preventDefault()
+ this.validateRpc(newRpc, chainId, ticker, nickname)
+ }}
+ >
+ { t('save') }
+ </button>
</div>
</div>
</div>
@@ -157,11 +225,11 @@ export default class SettingsTab extends PureComponent {
)
}
- validateRpc (newRpc) {
+ validateRpc (newRpc, chainId, ticker = 'ETH', nickname) {
const { setRpcTarget, displayWarning } = this.props
if (validUrl.isWebUri(newRpc)) {
- setRpcTarget(newRpc)
+ setRpcTarget(newRpc, chainId, ticker, nickname)
} else {
const appendedRpc = `http://${newRpc}`
@@ -339,6 +407,60 @@ export default class SettingsTab extends PureComponent {
)
}
+ renderUsePrimaryCurrencyOptions () {
+ const { t } = this.context
+ const {
+ nativeCurrency,
+ setUseNativeCurrencyAsPrimaryCurrencyPreference,
+ useNativeCurrencyAsPrimaryCurrency,
+ } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('primaryCurrencySetting') }</span>
+ <div className="settings-page__content-description">
+ { t('primaryCurrencySettingDescription') }
+ </div>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <div className="settings-tab__radio-buttons">
+ <div className="settings-tab__radio-button">
+ <input
+ type="radio"
+ id="native-primary-currency"
+ onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(true)}
+ checked={Boolean(useNativeCurrencyAsPrimaryCurrency)}
+ />
+ <label
+ htmlFor="native-primary-currency"
+ className="settings-tab__radio-label"
+ >
+ { nativeCurrency }
+ </label>
+ </div>
+ <div className="settings-tab__radio-button">
+ <input
+ type="radio"
+ id="fiat-primary-currency"
+ onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(false)}
+ checked={!useNativeCurrencyAsPrimaryCurrency}
+ />
+ <label
+ htmlFor="fiat-primary-currency"
+ className="settings-tab__radio-label"
+ >
+ { t('fiat') }
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
render () {
const { warning, isMascara } = this.props
@@ -346,6 +468,7 @@ export default class SettingsTab extends PureComponent {
<div className="settings-page__content">
{ warning && <div className="settings-tab__error">{ warning }</div> }
{ this.renderCurrentConversion() }
+ { this.renderUsePrimaryCurrencyOptions() }
{ this.renderCurrentLocale() }
{ this.renderNewRpcUrl() }
{ this.renderStateLogs() }
diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js
index 665b56f5c..f4110207e 100644
--- a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js
+++ b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js
@@ -11,19 +11,23 @@ import {
updateCurrentLocale,
setFeatureFlag,
showModal,
+ setUseNativeCurrencyAsPrimaryCurrencyPreference,
} from '../../../../actions'
+import { preferencesSelector } from '../../../../selectors'
const mapStateToProps = state => {
const { appState: { warning }, metamask } = state
const {
currentCurrency,
conversionDate,
+ nativeCurrency,
useBlockie,
featureFlags: { sendHexData } = {},
provider = {},
isMascara,
currentLocale,
} = metamask
+ const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state)
return {
warning,
@@ -31,16 +35,18 @@ const mapStateToProps = state => {
currentLocale,
currentCurrency,
conversionDate,
+ nativeCurrency,
useBlockie,
sendHexData,
provider,
+ useNativeCurrencyAsPrimaryCurrency,
}
}
const mapDispatchToProps = dispatch => {
return {
setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)),
- setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)),
+ setRpcTarget: (newRpc, chainId, ticker, nickname) => dispatch(setRpcTarget(newRpc, chainId, ticker, nickname)),
displayWarning: warning => dispatch(displayWarning(warning)),
revealSeedConfirmation: () => dispatch(revealSeedConfirmation()),
setUseBlockie: value => dispatch(setUseBlockie(value)),
@@ -50,6 +56,9 @@ const mapDispatchToProps = dispatch => {
},
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
+ setUseNativeCurrencyAsPrimaryCurrencyPreference: value => {
+ return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value))
+ },
}
}
diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js
index 3b2c62f49..d3242ddf5 100644
--- a/ui/app/components/qr-code.js
+++ b/ui/app/components/qr-code.js
@@ -26,7 +26,7 @@ function QrCodeView () {
QrCodeView.prototype.render = function () {
const props = this.props
const { message, data } = props.Qr
- const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${data}`
+ const address = `${isHexPrefixed(data) ? 'ethereum:' : ''}${checksumAddress(data)}`
const qrImage = qrCode(4, 'M')
qrImage.addData(address)
qrImage.make()
diff --git a/ui/app/components/send/account-list-item/account-list-item.component.js b/ui/app/components/send/account-list-item/account-list-item.component.js
index 9f4a96e61..14bb7471f 100644
--- a/ui/app/components/send/account-list-item/account-list-item.component.js
+++ b/ui/app/components/send/account-list-item/account-list-item.component.js
@@ -2,7 +2,8 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { checksumAddress } from '../../../util'
import Identicon from '../../identicon'
-import CurrencyDisplay from '../currency-display'
+import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../../../constants/common'
export default class AccountListItem extends Component {
@@ -25,8 +26,6 @@ export default class AccountListItem extends Component {
const {
account,
className,
- conversionRate,
- currentCurrency,
displayAddress = false,
displayBalance = true,
handleClick,
@@ -57,16 +56,20 @@ export default class AccountListItem extends Component {
{ checksumAddress(address) }
</div>}
- {displayBalance && <CurrencyDisplay
- className="account-list-item__account-balances"
- conversionRate={conversionRate}
- convertedBalanceClassName="account-list-item__account-secondary-balance"
- convertedCurrency={currentCurrency}
- primaryBalanceClassName="account-list-item__account-primary-balance"
- primaryCurrency="ETH"
- readOnly={true}
- value={balance}
- />}
+ {
+ displayBalance && (
+ <div className="account-list-item__account-balances">
+ <UserPreferencedCurrencyDisplay
+ type={PRIMARY}
+ value={balance}
+ />
+ <UserPreferencedCurrencyDisplay
+ type={SECONDARY}
+ value={balance}
+ />
+ </div>
+ )
+ }
</div>)
}
diff --git a/ui/app/components/send/account-list-item/account-list-item.container.js b/ui/app/components/send/account-list-item/account-list-item.container.js
index 4b4519288..f8e73d923 100644
--- a/ui/app/components/send/account-list-item/account-list-item.container.js
+++ b/ui/app/components/send/account-list-item/account-list-item.container.js
@@ -2,6 +2,7 @@ import { connect } from 'react-redux'
import {
getConversionRate,
getCurrentCurrency,
+ getNativeCurrency,
} from '../send.selectors.js'
import AccountListItem from './account-list-item.component'
@@ -11,5 +12,6 @@ function mapStateToProps (state) {
return {
conversionRate: getConversionRate(state),
currentCurrency: getCurrentCurrency(state),
+ nativeCurrency: getNativeCurrency(state),
}
}
diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js
index ef152d2e7..6ffc0b1c6 100644
--- a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js
+++ b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js
@@ -4,7 +4,7 @@ import { shallow } from 'enzyme'
import sinon from 'sinon'
import proxyquire from 'proxyquire'
import Identicon from '../../../identicon'
-import CurrencyDisplay from '../../currency-display'
+import UserPreferencedCurrencyDisplay from '../../../user-preferenced-currency-display'
const utilsMethodStubs = {
checksumAddress: sinon.stub().returns('mockCheckSumAddress'),
@@ -28,6 +28,7 @@ describe('AccountListItem Component', function () {
className={'mockClassName'}
conversionRate={4}
currentCurrency={'mockCurrentyCurrency'}
+ nativeCurrency={'ETH'}
displayAddress={false}
displayBalance={false}
handleClick={propsMethodSpies.handleClick}
@@ -114,17 +115,11 @@ describe('AccountListItem Component', function () {
it('should render a CurrencyDisplay with the correct props if displayBalance is true', () => {
wrapper.setProps({ displayBalance: true })
- assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 2)
assert.deepEqual(
- wrapper.find(CurrencyDisplay).props(),
+ wrapper.find(UserPreferencedCurrencyDisplay).at(0).props(),
{
- className: 'account-list-item__account-balances',
- conversionRate: 4,
- convertedBalanceClassName: 'account-list-item__account-secondary-balance',
- convertedCurrency: 'mockCurrentyCurrency',
- primaryBalanceClassName: 'account-list-item__account-primary-balance',
- primaryCurrency: 'ETH',
- readOnly: true,
+ type: 'PRIMARY',
value: 'mockBalance',
}
)
@@ -132,7 +127,7 @@ describe('AccountListItem Component', function () {
it('should not render a CurrencyDisplay if displayBalance is false', () => {
wrapper.setProps({ displayBalance: false })
- assert.equal(wrapper.find(CurrencyDisplay).length, 0)
+ assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 0)
})
})
})
diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js
index af0859117..7c2f5fcb2 100644
--- a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js
+++ b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js
@@ -13,6 +13,7 @@ proxyquire('../account-list-item.container.js', {
'../send.selectors.js': {
getConversionRate: (s) => `mockConversionRate:${s}`,
getCurrentCurrency: (s) => `mockCurrentCurrency:${s}`,
+ getNativeCurrency: (s) => `mockNativeCurrency:${s}`,
},
})
@@ -24,6 +25,7 @@ describe('account-list-item container', () => {
assert.deepEqual(mapStateToProps('mockState'), {
conversionRate: 'mockConversionRate:mockState',
currentCurrency: 'mockCurrentCurrency:mockState',
+ nativeCurrency: 'mockNativeCurrency:mockState',
})
})
diff --git a/ui/app/components/send/currency-display/currency-display.js b/ui/app/components/send/currency-display/currency-display.js
deleted file mode 100644
index 2b8eaa41f..000000000
--- a/ui/app/components/send/currency-display/currency-display.js
+++ /dev/null
@@ -1,186 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const { conversionUtil, multiplyCurrencies } = require('../../../conversion-util')
-const { removeLeadingZeroes } = require('../send.utils')
-const currencyFormatter = require('currency-formatter')
-const currencies = require('currency-formatter/currencies')
-const ethUtil = require('ethereumjs-util')
-const PropTypes = require('prop-types')
-
-CurrencyDisplay.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = CurrencyDisplay
-
-inherits(CurrencyDisplay, Component)
-function CurrencyDisplay () {
- Component.call(this)
-}
-
-function toHexWei (value) {
- return conversionUtil(value, {
- fromNumericBase: 'dec',
- toNumericBase: 'hex',
- toDenomination: 'WEI',
- })
-}
-
-CurrencyDisplay.prototype.componentWillMount = function () {
- this.setState({
- valueToRender: this.getValueToRender(this.props),
- })
-}
-
-CurrencyDisplay.prototype.componentWillReceiveProps = function (nextProps) {
- const currentValueToRender = this.getValueToRender(this.props)
- const newValueToRender = this.getValueToRender(nextProps)
- if (currentValueToRender !== newValueToRender) {
- this.setState({
- valueToRender: newValueToRender,
- })
- }
-}
-
-CurrencyDisplay.prototype.getAmount = function (value) {
- const { selectedToken } = this.props
- const { decimals } = selectedToken || {}
- const multiplier = Math.pow(10, Number(decimals || 0))
-
- const sendAmount = multiplyCurrencies(value || '0', multiplier, {toNumericBase: 'hex'})
-
- return selectedToken
- ? sendAmount
- : toHexWei(value)
-}
-
-CurrencyDisplay.prototype.getValueToRender = function ({ selectedToken, conversionRate, value, readOnly }) {
- if (value === '0x0') return readOnly ? '0' : ''
- const { decimals, symbol } = selectedToken || {}
- const multiplier = Math.pow(10, Number(decimals || 0))
-
- return selectedToken
- ? conversionUtil(ethUtil.addHexPrefix(value), {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- toCurrency: symbol,
- conversionRate: multiplier,
- invertConversionRate: true,
- })
- : conversionUtil(ethUtil.addHexPrefix(value), {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- numberOfDecimals: 9,
- conversionRate,
- })
-}
-
-CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValue) {
- const { primaryCurrency, convertedCurrency, conversionRate } = this.props
-
- if (conversionRate === 0 || conversionRate === null || conversionRate === undefined) {
- if (nonFormattedValue !== 0) {
- return null
- }
- }
-
- let convertedValue = conversionUtil(nonFormattedValue, {
- fromNumericBase: 'dec',
- fromCurrency: primaryCurrency,
- toCurrency: convertedCurrency,
- numberOfDecimals: 2,
- conversionRate,
- })
-
- convertedValue = Number(convertedValue).toFixed(2)
- const upperCaseCurrencyCode = convertedCurrency.toUpperCase()
- return currencies.find(currency => currency.code === upperCaseCurrencyCode)
- ? currencyFormatter.format(Number(convertedValue), {
- code: upperCaseCurrencyCode,
- })
- : convertedValue
- }
-
-CurrencyDisplay.prototype.handleChange = function (newVal) {
- this.setState({ valueToRender: removeLeadingZeroes(newVal) })
- this.props.onChange(this.getAmount(newVal))
-}
-
-CurrencyDisplay.prototype.getInputWidth = function (valueToRender, readOnly) {
- const valueString = String(valueToRender)
- const valueLength = valueString.length || 1
- const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0
- return (valueLength + decimalPointDeficit + 0.75) + 'ch'
-}
-
-CurrencyDisplay.prototype.onlyRenderConversions = function (convertedValueToRender) {
- const {
- convertedBalanceClassName = 'currency-display__converted-value',
- convertedCurrency,
- } = this.props
- return h('div', {
- className: convertedBalanceClassName,
- }, convertedValueToRender == null
- ? this.context.t('noConversionRateAvailable')
- : `${convertedValueToRender} ${convertedCurrency.toUpperCase()}`
-)
- }
-
-CurrencyDisplay.prototype.render = function () {
- const {
- className = 'currency-display',
- primaryBalanceClassName = 'currency-display__input',
- primaryCurrency,
- readOnly = false,
- inError = false,
- onBlur,
- step,
- } = this.props
- const { valueToRender } = this.state
-
- const convertedValueToRender = this.getConvertedValueToRender(valueToRender)
-
- return h('div', {
- className,
- style: {
- borderColor: inError ? 'red' : null,
- },
- onClick: () => {
- this.currencyInput && this.currencyInput.focus()
- },
- }, [
-
- h('div.currency-display__primary-row', [
-
- h('div.currency-display__input-wrapper', [
-
- h('input', {
- className: primaryBalanceClassName,
- value: `${valueToRender}`,
- placeholder: '0',
- type: 'number',
- readOnly,
- ...(!readOnly ? {
- onChange: e => this.handleChange(e.target.value),
- onBlur: () => onBlur(this.getAmount(valueToRender)),
- } : {}),
- ref: input => { this.currencyInput = input },
- style: {
- width: this.getInputWidth(valueToRender, readOnly),
- },
- min: 0,
- step,
- }),
-
- h('span.currency-display__currency-symbol', primaryCurrency),
-
- ]),
-
- ]), this.onlyRenderConversions(convertedValueToRender),
-
- ])
-
-}
-
diff --git a/ui/app/components/send/currency-display/index.js b/ui/app/components/send/currency-display/index.js
deleted file mode 100644
index 5dc269c5a..000000000
--- a/ui/app/components/send/currency-display/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './currency-display.js'
diff --git a/ui/app/components/send/currency-display/tests/currency-display.test.js b/ui/app/components/send/currency-display/tests/currency-display.test.js
deleted file mode 100644
index c9560b81c..000000000
--- a/ui/app/components/send/currency-display/tests/currency-display.test.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import React from 'react'
-import assert from 'assert'
-import sinon from 'sinon'
-import { shallow, mount } from 'enzyme'
-import CurrencyDisplay from '../currency-display'
-
-describe('', () => {
-
- const token = {
- address: '0xTest',
- symbol: 'TST',
- decimals: '13',
- }
-
- it('retuns ETH value for wei value', () => {
- const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}})
-
- const value = wrapper.instance().getValueToRender({
- // 1000000000000000000
- value: 'DE0B6B3A7640000',
- })
-
- assert.equal(value, 1)
- })
-
- it('returns value of token based on token decimals', () => {
- const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}})
-
- const value = wrapper.instance().getValueToRender({
- selectedToken: token,
- // 1000000000000000000
- value: 'DE0B6B3A7640000',
- })
-
- assert.equal(value, 100000)
- })
-
- it('returns hex value with decimal adjustment', () => {
-
- const wrapper = mount(
- <CurrencyDisplay
- selectedToken={token}
- />, {context: {t: str => str + '_t'}})
-
- const value = wrapper.instance().getAmount(1)
- // 10000000000000
- assert.equal(value, '9184e72a000')
- })
-
- it('#getConvertedValueToRender converts input value based on conversionRate', () => {
-
- const wrapper = mount(
- <CurrencyDisplay
- primaryCurrency={'usd'}
- convertedCurrency={'ja'}
- conversionRate={2}
- />, {context: {t: str => str + '_t'}})
-
- const value = wrapper.instance().getConvertedValueToRender(32)
-
- assert.equal(value, 64)
- })
-
- it('#onlyRenderConversions renders single element for converted currency and value', () => {
- const wrapper = mount(
- <CurrencyDisplay
- convertedCurrency={'test'}
- />, {context: {t: str => str + '_t'}})
-
- const value = wrapper.instance().onlyRenderConversions(10)
- assert.equal(value.props.className, 'currency-display__converted-value')
- assert.equal(value.props.children, '10 TEST')
- })
-
- it('simulates change value in input', () => {
- const handleChangeSpy = sinon.spy()
-
- const wrapper = shallow(
- <CurrencyDisplay
- onChange={handleChangeSpy}
- />, {context: {t: str => str + '_t'}})
-
- const input = wrapper.find('input')
- input.simulate('focus')
- input.simulate('change', { target: { value: '100' } })
-
- assert.equal(wrapper.state().valueToRender, '100')
- assert.equal(wrapper.find('input').prop('value'), '100')
- })
-
-})
diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js
index 4d0d36ab4..ceb620941 100644
--- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js
@@ -34,21 +34,27 @@ export default class AmountMaxButton extends Component {
})
}
+ onMaxClick = (event) => {
+ const { setMaxModeTo } = this.props
+
+ event.preventDefault()
+ setMaxModeTo(true)
+ this.setMaxAmount()
+ }
+
render () {
- const { setMaxModeTo, maxModeOn } = this.props
-
- return (
- <div
- className="send-v2__amount-max"
- onClick={(event) => {
- event.preventDefault()
- setMaxModeTo(true)
- this.setMaxAmount()
- }}
- >
- {!maxModeOn ? this.context.t('max') : ''}
- </div>
- )
+ return this.props.maxModeOn
+ ? null
+ : (
+ <div>
+ <span
+ className="send-v2__amount-max"
+ onClick={this.onMaxClick}
+ >
+ {this.context.t('max')}
+ </span>
+ </div>
+ )
}
}
diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js
index 86a05ff21..b04d3897f 100644
--- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js
@@ -56,9 +56,8 @@ describe('AmountMaxButton Component', function () {
})
describe('render', () => {
- it('should render a div with a send-v2__amount-max class', () => {
- assert.equal(wrapper.find('.send-v2__amount-max').length, 1)
- assert(wrapper.find('.send-v2__amount-max').is('div'))
+ it('should render an element with a send-v2__amount-max class', () => {
+ assert(wrapper.exists('.send-v2__amount-max'))
})
it('should call setMaxModeTo and setMaxAmount when the send-v2__amount-max div is clicked', () => {
@@ -77,9 +76,9 @@ describe('AmountMaxButton Component', function () {
)
})
- it('should not render text when maxModeOn is true', () => {
+ it('should not render anything when maxModeOn is true', () => {
wrapper.setProps({ maxModeOn: true })
- assert.equal(wrapper.find('.send-v2__amount-max').text(), '')
+ assert.ok(!wrapper.exists('.send-v2__amount-max'))
})
it('should render the expected text when maxModeOn is false', () => {
diff --git a/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js b/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js
index c548a5695..0268376bf 100644
--- a/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js
+++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js
@@ -2,7 +2,8 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import SendRowWrapper from '../send-row-wrapper/'
import AmountMaxButton from './amount-max-button/'
-import CurrencyDisplay from '../../currency-display'
+import UserPreferencedCurrencyInput from '../../../user-preferenced-currency-input'
+import UserPreferencedTokenInput from '../../../user-preferenced-token-input'
export default class SendAmountRow extends Component {
@@ -84,16 +85,25 @@ export default class SendAmountRow extends Component {
}
}
+ renderInput () {
+ const { amount, inError, selectedToken } = this.props
+ const Component = selectedToken ? UserPreferencedTokenInput : UserPreferencedCurrencyInput
+
+ return (
+ <Component
+ onChange={newAmount => this.validateAmount(newAmount)}
+ onBlur={newAmount => {
+ this.updateGas(newAmount)
+ this.updateAmount(newAmount)
+ }}
+ error={inError}
+ value={amount}
+ />
+ )
+ }
+
render () {
- const {
- amount,
- amountConversionRate,
- convertedCurrency,
- gasTotal,
- inError,
- primaryCurrency,
- selectedToken,
- } = this.props
+ const { gasTotal, inError } = this.props
return (
<SendRowWrapper
@@ -102,20 +112,7 @@ export default class SendAmountRow extends Component {
errorType={'amount'}
>
{!inError && gasTotal && <AmountMaxButton />}
- <CurrencyDisplay
- conversionRate={amountConversionRate}
- convertedCurrency={convertedCurrency}
- onBlur={newAmount => {
- this.updateGas(newAmount)
- this.updateAmount(newAmount)
- }}
- onChange={newAmount => this.validateAmount(newAmount)}
- inError={inError}
- primaryCurrency={primaryCurrency || 'ETH'}
- selectedToken={selectedToken}
- value={amount}
- step="any"
- />
+ { this.renderInput() }
</SendRowWrapper>
)
}
diff --git a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js
index 8425e076e..56e80cb83 100644
--- a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js
@@ -6,7 +6,7 @@ import SendAmountRow from '../send-amount-row.component.js'
import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component'
import AmountMaxButton from '../amount-max-button/amount-max-button.container'
-import CurrencyDisplay from '../../../currency-display'
+import UserPreferencedTokenInput from '../../../../user-preferenced-token-input'
const propsMethodSpies = {
setMaxModeTo: sinon.spy(),
@@ -150,26 +150,18 @@ describe('SendAmountRow Component', function () {
assert(wrapper.find(SendRowWrapper).childAt(0).is(AmountMaxButton))
})
- it('should render a CurrencyDisplay as the second child of the SendRowWrapper', () => {
- assert(wrapper.find(SendRowWrapper).childAt(1).is(CurrencyDisplay))
+ it('should render a UserPreferencedTokenInput as the second child of the SendRowWrapper', () => {
+ assert(wrapper.find(SendRowWrapper).childAt(1).is(UserPreferencedTokenInput))
})
- it('should render the CurrencyDisplay with the correct props', () => {
+ it('should render the UserPreferencedTokenInput with the correct props', () => {
const {
- conversionRate,
- convertedCurrency,
onBlur,
onChange,
- inError,
- primaryCurrency,
- selectedToken,
+ error,
value,
} = wrapper.find(SendRowWrapper).childAt(1).props()
- assert.equal(conversionRate, 'mockAmountConversionRate')
- assert.equal(convertedCurrency, 'mockConvertedCurrency')
- assert.equal(inError, false)
- assert.equal(primaryCurrency, 'mockPrimaryCurrency')
- assert.deepEqual(selectedToken, { address: 'mockTokenAddress' })
+ assert.equal(error, false)
assert.equal(value, 'mockAmount')
assert.equal(SendAmountRow.prototype.updateGas.callCount, 0)
assert.equal(SendAmountRow.prototype.updateAmount.callCount, 0)
@@ -192,11 +184,5 @@ describe('SendAmountRow Component', function () {
['mockNewAmount']
)
})
-
- it('should pass the default primaryCurrency to the CurrencyDisplay if primaryCurrency is falsy', () => {
- wrapper.setProps({ primaryCurrency: null })
- const { primaryCurrency } = wrapper.find(SendRowWrapper).childAt(1).props()
- assert.equal(primaryCurrency, 'ETH')
- })
})
})
diff --git a/ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js
index bb9a94428..9bbb67506 100644
--- a/ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js
+++ b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
-import CurrencyDisplay from '../../../../send/currency-display'
-
+import UserPreferencedCurrencyDisplay from '../../../../user-preferenced-currency-display'
+import { PRIMARY, SECONDARY } from '../../../../../constants/common'
export default class GasFeeDisplay extends Component {
@@ -19,27 +19,24 @@ export default class GasFeeDisplay extends Component {
};
render () {
- const {
- conversionRate,
- gasTotal,
- onClick,
- primaryCurrency = 'ETH',
- convertedCurrency,
- gasLoadingError,
- } = this.props
+ const { gasTotal, onClick, gasLoadingError } = this.props
return (
<div className="send-v2__gas-fee-display">
{gasTotal
- ? <CurrencyDisplay
- primaryCurrency={primaryCurrency}
- convertedCurrency={convertedCurrency}
- value={gasTotal}
- conversionRate={conversionRate}
- gasLoadingError={gasLoadingError}
- convertedPrefix={'$'}
- readOnly
- />
+ ? (
+ <div className="currency-display">
+ <UserPreferencedCurrencyDisplay
+ value={gasTotal}
+ type={PRIMARY}
+ />
+ <UserPreferencedCurrencyDisplay
+ className="currency-display__converted-value"
+ value={gasTotal}
+ type={SECONDARY}
+ />
+ </div>
+ )
: gasLoadingError
? <div className="currency-display.currency-display--message">
{this.context.t('setGasPrice')}
diff --git a/ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js
index 7cbe8d0df..9ff01493a 100644
--- a/ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js
+++ b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js
@@ -2,7 +2,7 @@ import React from 'react'
import assert from 'assert'
import {shallow} from 'enzyme'
import GasFeeDisplay from '../gas-fee-display.component'
-import CurrencyDisplay from '../../../../../send/currency-display'
+import UserPreferencedCurrencyDisplay from '../../../../../user-preferenced-currency-display'
import sinon from 'sinon'
@@ -29,17 +29,15 @@ describe('SendGasRow Component', function () {
describe('render', () => {
it('should render a CurrencyDisplay component', () => {
- assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 2)
})
it('should render the CurrencyDisplay with the correct props', () => {
const {
- conversionRate,
- convertedCurrency,
+ type,
value,
- } = wrapper.find(CurrencyDisplay).props()
- assert.equal(conversionRate, 20)
- assert.equal(convertedCurrency, 'mockConvertedCurrency')
+ } = wrapper.find(UserPreferencedCurrencyDisplay).at(0).props()
+ assert.equal(type, 'PRIMARY')
assert.equal(value, 'mockGasTotal')
})
diff --git a/ui/app/components/send/send.selectors.js b/ui/app/components/send/send.selectors.js
index 22e379693..eb22a08b7 100644
--- a/ui/app/components/send/send.selectors.js
+++ b/ui/app/components/send/send.selectors.js
@@ -19,6 +19,7 @@ const selectors = {
getCurrentNetwork,
getCurrentViewContext,
getForceGasMin,
+ getNativeCurrency,
getGasLimit,
getGasPrice,
getGasPriceFromRecentBlocks,
@@ -111,6 +112,10 @@ function getCurrentCurrency (state) {
return state.metamask.currentCurrency
}
+function getNativeCurrency (state) {
+ return state.metamask.nativeCurrency
+}
+
function getCurrentNetwork (state) {
return state.metamask.network
}
diff --git a/ui/app/components/send/send.utils.js b/ui/app/components/send/send.utils.js
index a18a9e4b3..eb1667c63 100644
--- a/ui/app/components/send/send.utils.js
+++ b/ui/app/components/send/send.utils.js
@@ -215,7 +215,9 @@ async function estimateGas ({
// if recipient has no code, gas is 21k max:
if (!selectedToken && !data) {
const code = Boolean(to) && await global.eth.getCode(to)
- if (!code || code === '0x') {
+ // Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
+ const codeIsEmpty = !code || code === '0x' || code === '0x0'
+ if (codeIsEmpty) {
return SIMPLE_GAS_COST
}
} else if (selectedToken && !to) {
diff --git a/ui/app/components/send/tests/send-selectors-test-data.js b/ui/app/components/send/tests/send-selectors-test-data.js
index 8b939dadb..30a2666cf 100644
--- a/ui/app/components/send/tests/send-selectors-test-data.js
+++ b/ui/app/components/send/tests/send-selectors-test-data.js
@@ -26,6 +26,7 @@ module.exports = {
'currentCurrency': 'USD',
'conversionRate': 1200.88200327,
'conversionDate': 1489013762,
+ 'nativeCurrency': 'ETH',
'noActiveNotices': true,
'frequentRpcList': [],
'network': '3',
diff --git a/ui/app/components/send/tests/send-selectors.test.js b/ui/app/components/send/tests/send-selectors.test.js
index 1a47cd209..e7e901f0d 100644
--- a/ui/app/components/send/tests/send-selectors.test.js
+++ b/ui/app/components/send/tests/send-selectors.test.js
@@ -12,6 +12,7 @@ const {
getCurrentCurrency,
getCurrentNetwork,
getCurrentViewContext,
+ getNativeCurrency,
getForceGasMin,
getGasLimit,
getGasPrice,
@@ -178,6 +179,15 @@ describe('send selectors', () => {
})
})
+ describe('getNativeCurrency()', () => {
+ it('should return the ticker symbol of the selected network', () => {
+ assert.equal(
+ getNativeCurrency(mockState),
+ 'ETH'
+ )
+ })
+ })
+
describe('getCurrentNetwork()', () => {
it('should return the id of the currently selected network', () => {
assert.equal(
diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js
index 49ebf49d9..39d15dfa7 100644
--- a/ui/app/components/send/to-autocomplete/to-autocomplete.js
+++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js
@@ -5,6 +5,7 @@ const inherits = require('util').inherits
const AccountListItem = require('../account-list-item/account-list-item.component').default
const connect = require('react-redux').connect
const Tooltip = require('../../tooltip')
+const checksumAddress = require('../../../util').checksumAddress
ToAutoComplete.contextTypes = {
t: PropTypes.func,
@@ -48,7 +49,7 @@ ToAutoComplete.prototype.renderDropdown = function () {
account,
className: 'account-list-item__dropdown',
handleClick: () => {
- onChange(account.address)
+ onChange(checksumAddress(account.address))
closeDropdown()
},
icon: this.getListItemIcon(account.address, to),
diff --git a/ui/app/components/sender-to-recipient/sender-to-recipient.component.js b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
index 61f77224d..e71bd7406 100644
--- a/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
+++ b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js
@@ -5,6 +5,7 @@ import Identicon from '../identicon'
import Tooltip from '../tooltip-v2'
import copyToClipboard from 'copy-to-clipboard'
import { DEFAULT_VARIANT, CARDS_VARIANT } from './sender-to-recipient.constants'
+import { checksumAddress } from '../../util'
const variantHash = {
[DEFAULT_VARIANT]: 'sender-to-recipient--default',
@@ -40,7 +41,7 @@ export default class SenderToRecipient extends PureComponent {
return !this.props.addressOnly && (
<div className="sender-to-recipient__sender-icon">
<Identicon
- address={this.props.senderAddress}
+ address={checksumAddress(this.props.senderAddress)}
diameter={24}
/>
</div>
@@ -50,6 +51,7 @@ export default class SenderToRecipient extends PureComponent {
renderSenderAddress () {
const { t } = this.context
const { senderName, senderAddress, addressOnly } = this.props
+ const checksummedSenderAddress = checksumAddress(senderAddress)
return (
<Tooltip
@@ -60,7 +62,7 @@ export default class SenderToRecipient extends PureComponent {
onHidden={() => this.setState({ senderAddressCopied: false })}
>
<div className="sender-to-recipient__name">
- { addressOnly ? `${t('from')}: ${senderAddress}` : senderName }
+ { addressOnly ? `${t('from')}: ${checksummedSenderAddress}` : senderName }
</div>
</Tooltip>
)
@@ -68,11 +70,12 @@ export default class SenderToRecipient extends PureComponent {
renderRecipientIdenticon () {
const { recipientAddress, assetImage } = this.props
+ const checksummedRecipientAddress = checksumAddress(recipientAddress)
return !this.props.addressOnly && (
<div className="sender-to-recipient__sender-icon">
<Identicon
- address={recipientAddress}
+ address={checksummedRecipientAddress}
diameter={24}
image={assetImage}
/>
@@ -83,13 +86,14 @@ export default class SenderToRecipient extends PureComponent {
renderRecipientWithAddress () {
const { t } = this.context
const { recipientName, recipientAddress, addressOnly } = this.props
+ const checksummedRecipientAddress = checksumAddress(recipientAddress)
return (
<div
className="sender-to-recipient__party sender-to-recipient__party--recipient sender-to-recipient__party--recipient-with-address"
onClick={() => {
this.setState({ recipientAddressCopied: true })
- copyToClipboard(recipientAddress)
+ copyToClipboard(checksummedRecipientAddress)
}}
>
{ this.renderRecipientIdenticon() }
@@ -103,7 +107,7 @@ export default class SenderToRecipient extends PureComponent {
<div className="sender-to-recipient__name">
{
addressOnly
- ? `${t('to')}: ${recipientAddress}`
+ ? `${t('to')}: ${checksummedRecipientAddress}`
: (recipientName || this.context.t('newContract'))
}
</div>
@@ -147,6 +151,7 @@ export default class SenderToRecipient extends PureComponent {
render () {
const { senderAddress, recipientAddress, variant } = this.props
+ const checksummedSenderAddress = checksumAddress(senderAddress)
return (
<div className={classnames(variantHash[variant])}>
@@ -154,7 +159,7 @@ export default class SenderToRecipient extends PureComponent {
className={classnames('sender-to-recipient__party sender-to-recipient__party--sender')}
onClick={() => {
this.setState({ senderAddressCopied: true })
- copyToClipboard(senderAddress)
+ copyToClipboard(checksummedSenderAddress)
}}
>
{ this.renderSenderIdenticon() }
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index b87bf959e..0461b615a 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -52,12 +52,12 @@ ShiftListItem.prototype.render = function () {
},
}, [
h('img', {
- src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ src: 'https://shapeshift.io/logo.png',
style: {
height: '35px',
width: '132px',
position: 'absolute',
- clip: 'rect(0px,23px,34px,0px)',
+ clip: 'rect(0px,30px,34px,0px)',
},
}),
]),
@@ -132,7 +132,6 @@ ShiftListItem.prototype.renderInfo = function () {
case 'no_deposits':
return h('.flex-column', {
style: {
- width: '200px',
overflow: 'hidden',
},
}, [
diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js
index 5b0c7684a..85af3b00b 100644
--- a/ui/app/components/signature-request.js
+++ b/ui/app/components/signature-request.js
@@ -2,7 +2,7 @@ const Component = require('react').Component
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const Identicon = require('./identicon')
+import Identicon from './identicon'
const connect = require('react-redux').connect
const ethUtil = require('ethereumjs-util')
const classnames = require('classnames')
@@ -204,7 +204,7 @@ SignatureRequest.prototype.renderBody = function () {
h('span.request-signature__help-link', {
onClick: () => {
global.platform.openWindow({
- url: 'https://consensys.zendesk.com/hc/en-us/articles/360004427792',
+ url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751',
})
},
}, this.context.t('learnMore'))]
diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js
index 477d97597..75ba347fa 100644
--- a/ui/app/components/token-cell.js
+++ b/ui/app/components/token-cell.js
@@ -2,7 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
-const Identicon = require('./identicon')
+import Identicon from './identicon'
const prefixForNetwork = require('../../lib/etherscan-prefix-for-network')
const selectors = require('../selectors')
const actions = require('../actions')
diff --git a/ui/app/components/token-input/index.js b/ui/app/components/token-input/index.js
new file mode 100644
index 000000000..22c06111e
--- /dev/null
+++ b/ui/app/components/token-input/index.js
@@ -0,0 +1 @@
+export { default } from './token-input.container'
diff --git a/ui/app/components/token-input/tests/token-input.component.test.js b/ui/app/components/token-input/tests/token-input.component.test.js
new file mode 100644
index 000000000..2dacb9bc4
--- /dev/null
+++ b/ui/app/components/token-input/tests/token-input.component.test.js
@@ -0,0 +1,308 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import assert from 'assert'
+import { shallow, mount } from 'enzyme'
+import sinon from 'sinon'
+import { Provider } from 'react-redux'
+import configureMockStore from 'redux-mock-store'
+import TokenInput from '../token-input.component'
+import UnitInput from '../../unit-input'
+import CurrencyDisplay from '../../currency-display'
+
+describe('TokenInput Component', () => {
+ const t = key => `translate ${key}`
+
+ describe('rendering', () => {
+ it('should render properly without a token', () => {
+ const wrapper = shallow(
+ <TokenInput />,
+ { context: { t } }
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(UnitInput).length, 1)
+ })
+
+ it('should render properly with a token', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ />
+ </Provider>,
+ { context: { t },
+ childContextTypes: {
+ t: PropTypes.func,
+ },
+ },
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
+ assert.equal(wrapper.find('.currency-input__conversion-component').length, 1)
+ assert.equal(wrapper.find('.currency-input__conversion-component').text(), 'translate noConversionRateAvailable')
+ })
+
+ it('should render properly with a token and selectedTokenExchangeRate', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ />
+ </Provider>,
+ { context: { t },
+ childContextTypes: {
+ t: PropTypes.func,
+ },
+ },
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
+ assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ })
+
+ it('should render properly with a token value for ETH', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ value="2710"
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
+ assert.equal(tokenInputInstance.state.decimalValue, 1)
+ assert.equal(tokenInputInstance.state.hexValue, '2710')
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
+ assert.equal(wrapper.find('.unit-input__input').props().value, '1')
+ assert.equal(wrapper.find('.currency-display-component').text(), '2ETH')
+ })
+
+ it('should render properly with a token value for fiat', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ value="2710"
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ showFiat
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
+ assert.equal(tokenInputInstance.state.decimalValue, 1)
+ assert.equal(tokenInputInstance.state.hexValue, '2710')
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
+ assert.equal(wrapper.find('.unit-input__input').props().value, '1')
+ assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD')
+ })
+ })
+
+ describe('handling actions', () => {
+ const handleChangeSpy = sinon.spy()
+ const handleBlurSpy = sinon.spy()
+
+ afterEach(() => {
+ handleChangeSpy.resetHistory()
+ handleBlurSpy.resetHistory()
+ })
+
+ it('should call onChange and onBlur on input changes with the hex value for ETH', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+
+ const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
+ assert.equal(tokenInputInstance.state.decimalValue, 0)
+ assert.equal(tokenInputInstance.state.hexValue, undefined)
+ assert.equal(wrapper.find('.currency-display-component').text(), '0ETH')
+ const input = wrapper.find('input')
+ assert.equal(input.props().value, 0)
+
+ input.simulate('change', { target: { value: 1 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith('2710'))
+ assert.equal(wrapper.find('.currency-display-component').text(), '2ETH')
+ assert.equal(tokenInputInstance.state.decimalValue, 1)
+ assert.equal(tokenInputInstance.state.hexValue, '2710')
+
+ assert.equal(handleBlurSpy.callCount, 0)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith('2710'))
+ })
+
+ it('should call onChange and onBlur on input changes with the hex value for fiat', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = mount(
+ <Provider store={store}>
+ <TokenInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ showFiat
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+
+ const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
+ assert.equal(tokenInputInstance.state.decimalValue, 0)
+ assert.equal(tokenInputInstance.state.hexValue, undefined)
+ assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD')
+ const input = wrapper.find('input')
+ assert.equal(input.props().value, 0)
+
+ input.simulate('change', { target: { value: 1 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith('2710'))
+ assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD')
+ assert.equal(tokenInputInstance.state.decimalValue, 1)
+ assert.equal(tokenInputInstance.state.hexValue, '2710')
+
+ assert.equal(handleBlurSpy.callCount, 0)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith('2710'))
+ })
+
+ it('should change the state and pass in a new decimalValue when props.value changes', () => {
+ const mockStore = {
+ metamask: {
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = shallow(
+ <Provider store={store}>
+ <TokenInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ selectedToken={{
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ }}
+ suffix="ABC"
+ selectedTokenExchangeRate={2}
+ showFiat
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ const tokenInputInstance = wrapper.find(TokenInput).dive()
+ assert.equal(tokenInputInstance.state('decimalValue'), 0)
+ assert.equal(tokenInputInstance.state('hexValue'), undefined)
+ assert.equal(tokenInputInstance.find(UnitInput).props().value, 0)
+
+ tokenInputInstance.setProps({ value: '2710' })
+ tokenInputInstance.update()
+ assert.equal(tokenInputInstance.state('decimalValue'), 1)
+ assert.equal(tokenInputInstance.state('hexValue'), '2710')
+ assert.equal(tokenInputInstance.find(UnitInput).props().value, 1)
+ })
+ })
+})
diff --git a/ui/app/components/token-input/tests/token-input.container.test.js b/ui/app/components/token-input/tests/token-input.container.test.js
new file mode 100644
index 000000000..d73bc9a94
--- /dev/null
+++ b/ui/app/components/token-input/tests/token-input.container.test.js
@@ -0,0 +1,129 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps, mergeProps
+
+proxyquire('../token-input.container.js', {
+ 'react-redux': {
+ connect: (ms, md, mp) => {
+ mapStateToProps = ms
+ mergeProps = mp
+ return () => ({})
+ },
+ },
+})
+
+describe('TokenInput container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props when send is empty', () => {
+ const mockState = {
+ metamask: {
+ currentCurrency: 'usd',
+ tokens: [
+ {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ ],
+ selectedTokenAddress: '0x1',
+ contractExchangeRates: {},
+ send: {},
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ currentCurrency: 'usd',
+ selectedToken: {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ selectedTokenExchangeRate: 0,
+ })
+ })
+
+ it('should return the correct props when selectedTokenAddress is not found and send is populated', () => {
+ const mockState = {
+ metamask: {
+ currentCurrency: 'usd',
+ tokens: [
+ {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ ],
+ selectedTokenAddress: '0x2',
+ contractExchangeRates: {},
+ send: {
+ token: { address: 'test' },
+ },
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ currentCurrency: 'usd',
+ selectedToken: {
+ address: 'test',
+ },
+ selectedTokenExchangeRate: 0,
+ })
+ })
+
+ it('should return the correct props when contractExchangeRates is populated', () => {
+ const mockState = {
+ metamask: {
+ currentCurrency: 'usd',
+ tokens: [
+ {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ ],
+ selectedTokenAddress: '0x1',
+ contractExchangeRates: {
+ '0x1': 5,
+ },
+ send: {},
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ currentCurrency: 'usd',
+ selectedToken: {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ selectedTokenExchangeRate: 5,
+ })
+ })
+ })
+
+ describe('mergeProps()', () => {
+ it('should return the correct props', () => {
+ const mockStateProps = {
+ currentCurrency: 'usd',
+ selectedToken: {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ selectedTokenExchangeRate: 5,
+ }
+
+ assert.deepEqual(mergeProps(mockStateProps, {}, {}), {
+ currentCurrency: 'usd',
+ selectedToken: {
+ address: '0x1',
+ decimals: '4',
+ symbol: 'ABC',
+ },
+ selectedTokenExchangeRate: 5,
+ suffix: 'ABC',
+ })
+ })
+ })
+})
diff --git a/ui/app/components/token-input/token-input.component.js b/ui/app/components/token-input/token-input.component.js
new file mode 100644
index 000000000..d1388945b
--- /dev/null
+++ b/ui/app/components/token-input/token-input.component.js
@@ -0,0 +1,136 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import UnitInput from '../unit-input'
+import CurrencyDisplay from '../currency-display'
+import { getWeiHexFromDecimalValue } from '../../helpers/conversions.util'
+import ethUtil from 'ethereumjs-util'
+import { conversionUtil, multiplyCurrencies } from '../../conversion-util'
+import { ETH } from '../../constants/common'
+
+/**
+ * Component that allows user to enter token values as a number, and props receive a converted
+ * hex value. props.value, used as a default or forced value, should be a hex value, which
+ * gets converted into a decimal value.
+ */
+export default class TokenInput extends PureComponent {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ currentCurrency: PropTypes.string,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ value: PropTypes.string,
+ suffix: PropTypes.string,
+ showFiat: PropTypes.bool,
+ selectedToken: PropTypes.object,
+ selectedTokenExchangeRate: PropTypes.number,
+ }
+
+ constructor (props) {
+ super(props)
+
+ const { value: hexValue } = props
+ const decimalValue = hexValue ? this.getDecimalValue(props) : 0
+
+ this.state = {
+ decimalValue,
+ hexValue,
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ const { value: prevPropsHexValue } = prevProps
+ const { value: propsHexValue } = this.props
+ const { hexValue: stateHexValue } = this.state
+
+ if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) {
+ const decimalValue = this.getDecimalValue(this.props)
+ this.setState({ hexValue: propsHexValue, decimalValue })
+ }
+ }
+
+ getDecimalValue (props) {
+ const { value: hexValue, selectedToken: { decimals, symbol } = {} } = props
+
+ const multiplier = Math.pow(10, Number(decimals || 0))
+ const decimalValueString = conversionUtil(ethUtil.addHexPrefix(hexValue), {
+ fromNumericBase: 'hex',
+ toNumericBase: 'dec',
+ toCurrency: symbol,
+ conversionRate: multiplier,
+ invertConversionRate: true,
+ })
+
+ return Number(decimalValueString) || 0
+ }
+
+ handleChange = decimalValue => {
+ const { selectedToken: { decimals } = {}, onChange } = this.props
+
+ const multiplier = Math.pow(10, Number(decimals || 0))
+ const hexValue = multiplyCurrencies(decimalValue || 0, multiplier, { toNumericBase: 'hex' })
+
+ this.setState({ hexValue, decimalValue })
+ onChange(hexValue)
+ }
+
+ handleBlur = () => {
+ this.props.onBlur(this.state.hexValue)
+ }
+
+ renderConversionComponent () {
+ const { selectedTokenExchangeRate, showFiat, currentCurrency } = this.props
+ const { decimalValue } = this.state
+ let currency, numberOfDecimals
+
+ if (showFiat) {
+ // Display Fiat
+ currency = currentCurrency
+ numberOfDecimals = 2
+ } else {
+ // Display ETH
+ currency = ETH
+ numberOfDecimals = 6
+ }
+
+ const decimalEthValue = (decimalValue * selectedTokenExchangeRate) || 0
+ const hexWeiValue = getWeiHexFromDecimalValue({
+ value: decimalEthValue,
+ fromCurrency: ETH,
+ fromDenomination: ETH,
+ })
+
+ return selectedTokenExchangeRate
+ ? (
+ <CurrencyDisplay
+ className="currency-input__conversion-component"
+ currency={currency}
+ value={hexWeiValue}
+ numberOfDecimals={numberOfDecimals}
+ />
+ ) : (
+ <div className="currency-input__conversion-component">
+ { this.context.t('noConversionRateAvailable') }
+ </div>
+ )
+ }
+
+ render () {
+ const { suffix, ...restProps } = this.props
+ const { decimalValue } = this.state
+
+ return (
+ <UnitInput
+ {...restProps}
+ suffix={suffix}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ value={decimalValue}
+ >
+ { this.renderConversionComponent() }
+ </UnitInput>
+ )
+ }
+}
diff --git a/ui/app/components/token-input/token-input.container.js b/ui/app/components/token-input/token-input.container.js
new file mode 100644
index 000000000..ec233b1b8
--- /dev/null
+++ b/ui/app/components/token-input/token-input.container.js
@@ -0,0 +1,27 @@
+import { connect } from 'react-redux'
+import TokenInput from './token-input.component'
+import { getSelectedToken, getSelectedTokenExchangeRate } from '../../selectors'
+
+const mapStateToProps = state => {
+ const { metamask: { currentCurrency } } = state
+
+ return {
+ currentCurrency,
+ selectedToken: getSelectedToken(state),
+ selectedTokenExchangeRate: getSelectedTokenExchangeRate(state),
+ }
+}
+
+const mergeProps = (stateProps, dispatchProps, ownProps) => {
+ const { selectedToken } = stateProps
+ const suffix = selectedToken && selectedToken.symbol
+
+ return {
+ ...stateProps,
+ ...dispatchProps,
+ ...ownProps,
+ suffix,
+ }
+}
+
+export default connect(mapStateToProps, null, mergeProps)(TokenInput)
diff --git a/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js b/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js
index 85d56a6a2..a7c35f51e 100644
--- a/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js
+++ b/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js
@@ -18,10 +18,11 @@ describe('TransactionActivityLog container', () => {
const mockState = {
metamask: {
conversionRate: 280.45,
+ nativeCurrency: 'ETH',
},
}
- assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45 })
+ assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45, nativeCurrency: 'ETH' })
})
})
})
diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js
index c4cf57d14..58d932a0f 100644
--- a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js
+++ b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js
@@ -4,7 +4,6 @@ import classnames from 'classnames'
import { getActivities } from './transaction-activity-log.util'
import Card from '../card'
import { getEthConversionFromWeiHex, getValueFromWeiHex } from '../../helpers/conversions.util'
-import { ETH } from '../../constants/common'
import { formatDate } from '../../util'
export default class TransactionActivityLog extends PureComponent {
@@ -16,6 +15,7 @@ export default class TransactionActivityLog extends PureComponent {
transaction: PropTypes.object,
className: PropTypes.string,
conversionRate: PropTypes.number,
+ nativeCurrency: PropTypes.string,
}
state = {
@@ -27,10 +27,14 @@ export default class TransactionActivityLog extends PureComponent {
}
componentDidUpdate (prevProps) {
- const { transaction: { history: prevHistory = [] } = {} } = prevProps
- const { transaction: { history = [] } = {} } = this.props
+ const {
+ transaction: { history: prevHistory = [], txReceipt: { status: prevStatus } = {} } = {},
+ } = prevProps
+ const {
+ transaction: { history = [], txReceipt: { status } = {} } = {},
+ } = this.props
- if (prevHistory.length !== history.length) {
+ if (prevHistory.length !== history.length || prevStatus !== status) {
this.setActivites()
}
}
@@ -41,16 +45,17 @@ export default class TransactionActivityLog extends PureComponent {
}
renderActivity (activity, index) {
- const { conversionRate } = this.props
+ const { conversionRate, nativeCurrency } = this.props
const { eventKey, value, timestamp } = activity
const ethValue = index === 0
? `${getValueFromWeiHex({
value,
- toCurrency: ETH,
+ fromCurrency: nativeCurrency,
+ toCurrency: nativeCurrency,
conversionRate,
numberOfDecimals: 6,
- })} ${ETH}`
- : getEthConversionFromWeiHex({ value, toCurrency: ETH, conversionRate })
+ })} ${nativeCurrency}`
+ : getEthConversionFromWeiHex({ value, fromCurrency: nativeCurrency, conversionRate })
const formattedTimestamp = formatDate(timestamp)
const activityText = this.context.t(eventKey, [ethValue, formattedTimestamp])
diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.container.js b/ui/app/components/transaction-activity-log/transaction-activity-log.container.js
index 4c8b6d971..622f77df1 100644
--- a/ui/app/components/transaction-activity-log/transaction-activity-log.container.js
+++ b/ui/app/components/transaction-activity-log/transaction-activity-log.container.js
@@ -1,10 +1,11 @@
import { connect } from 'react-redux'
import TransactionActivityLog from './transaction-activity-log.component'
-import { conversionRateSelector } from '../../selectors'
+import { conversionRateSelector, getNativeCurrency } from '../../selectors'
const mapStateToProps = state => {
return {
conversionRate: conversionRateSelector(state),
+ nativeCurrency: getNativeCurrency(state),
}
}
diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
index 32834ff47..16597ae1a 100644
--- a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
+++ b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
@@ -18,6 +18,7 @@ const TRANSACTION_SUBMITTED_EVENT = 'transactionSubmitted'
const TRANSACTION_CONFIRMED_EVENT = 'transactionConfirmed'
const TRANSACTION_DROPPED_EVENT = 'transactionDropped'
const TRANSACTION_UPDATED_EVENT = 'transactionUpdated'
+const TRANSACTION_ERRORED_EVENT = 'transactionErrored'
const eventPathsHash = {
[STATUS_PATH]: true,
@@ -39,18 +40,22 @@ function eventCreator (eventKey, timestamp, value) {
}
export function getActivities (transaction) {
- const { history = [] } = transaction
+ const { history = [], txReceipt: { status } = {} } = transaction
- return history.reduce((acc, base) => {
+ const historyActivities = history.reduce((acc, base) => {
// First history item should be transaction creation
if (!Array.isArray(base) && base.status === UNAPPROVED_STATUS && base.txParams) {
const { time, txParams: { value } = {} } = base
return acc.concat(eventCreator(TRANSACTION_CREATED_EVENT, time, value))
+ // An entry in the history may be an array of more sub-entries.
} else if (Array.isArray(base)) {
const events = []
base.forEach(entry => {
- const { op, path, value, timestamp } = entry
+ const { op, path, value, timestamp: entryTimestamp } = entry
+ // Not all sub-entries in a history entry have a timestamp. If the sub-entry does not have a
+ // timestamp, the first sub-entry in a history entry should.
+ const timestamp = entryTimestamp || base[0] && base[0].timestamp
if (path in eventPathsHash && op === REPLACE_OP) {
switch (path) {
@@ -79,4 +84,10 @@ export function getActivities (transaction) {
return acc
}, [])
+
+ // If txReceipt.status is '0x0', that means that an on-chain error occured for the transaction,
+ // so we add an error entry to the Activity Log.
+ return status === '0x0'
+ ? historyActivities.concat(eventCreator(TRANSACTION_ERRORED_EVENT))
+ : historyActivities
}
diff --git a/ui/app/components/transaction-breakdown/index.js b/ui/app/components/transaction-breakdown/index.js
index c887f504f..4a5b52663 100644
--- a/ui/app/components/transaction-breakdown/index.js
+++ b/ui/app/components/transaction-breakdown/index.js
@@ -1 +1 @@
-export { default } from './transaction-breakdown.component'
+export { default } from './transaction-breakdown.container'
diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown.component.js b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js
index bb6075e9f..3a7647873 100644
--- a/ui/app/components/transaction-breakdown/transaction-breakdown.component.js
+++ b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js
@@ -4,8 +4,9 @@ import classnames from 'classnames'
import TransactionBreakdownRow from './transaction-breakdown-row'
import Card from '../card'
import CurrencyDisplay from '../currency-display'
+import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
import HexToDecimal from '../hex-to-decimal'
-import { ETH, GWEI } from '../../constants/common'
+import { GWEI, PRIMARY, SECONDARY } from '../../constants/common'
import { getHexGasTotal } from '../../helpers/confirm-transaction/util'
import { sumHexes } from '../../helpers/transactions.util'
@@ -17,6 +18,7 @@ export default class TransactionBreakdown extends PureComponent {
static propTypes = {
transaction: PropTypes.object,
className: PropTypes.string,
+ nativeCurrency: PropTypes.string.isRequired,
}
static defaultProps = {
@@ -25,9 +27,12 @@ export default class TransactionBreakdown extends PureComponent {
render () {
const { t } = this.context
- const { transaction, className } = this.props
- const { txParams: { gas, gasPrice, value } = {} } = transaction
- const hexGasTotal = getHexGasTotal({ gasLimit: gas, gasPrice })
+ const { transaction, className, nativeCurrency } = this.props
+ const { txParams: { gas, gasPrice, value } = {}, txReceipt: { gasUsed } = {} } = transaction
+
+ const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas
+
+ const hexGasTotal = getHexGasTotal({ gasLimit, gasPrice })
const totalInHex = sumHexes(hexGasTotal, value)
return (
@@ -37,9 +42,9 @@ export default class TransactionBreakdown extends PureComponent {
className="transaction-breakdown__card"
>
<TransactionBreakdownRow title={t('amount')}>
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-breakdown__value"
- currency={ETH}
+ type={PRIMARY}
value={value}
/>
</TransactionBreakdownRow>
@@ -52,10 +57,23 @@ export default class TransactionBreakdown extends PureComponent {
value={gas}
/>
</TransactionBreakdownRow>
+ {
+ typeof gasUsed === 'string' && (
+ <TransactionBreakdownRow
+ title={`${t('gasUsed')} (${t('units')})`}
+ className="transaction-breakdown__row-title"
+ >
+ <HexToDecimal
+ className="transaction-breakdown__value"
+ value={gasUsed}
+ />
+ </TransactionBreakdownRow>
+ )
+ }
<TransactionBreakdownRow title={t('gasPrice')}>
<CurrencyDisplay
className="transaction-breakdown__value"
- currency={ETH}
+ currency={nativeCurrency}
denomination={GWEI}
value={gasPrice}
hideLabel
@@ -63,14 +81,14 @@ export default class TransactionBreakdown extends PureComponent {
</TransactionBreakdownRow>
<TransactionBreakdownRow title={t('total')}>
<div>
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-breakdown__value transaction-breakdown__value--eth-total"
- currency={ETH}
+ type={PRIMARY}
value={totalInHex}
- numberOfDecimals={6}
/>
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-breakdown__value"
+ type={SECONDARY}
value={totalInHex}
/>
</div>
diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown.container.js b/ui/app/components/transaction-breakdown/transaction-breakdown.container.js
new file mode 100644
index 000000000..ed2708e03
--- /dev/null
+++ b/ui/app/components/transaction-breakdown/transaction-breakdown.container.js
@@ -0,0 +1,11 @@
+import { connect } from 'react-redux'
+import TransactionBreakdown from './transaction-breakdown.component'
+import { getNativeCurrency } from '../../selectors'
+
+const mapStateToProps = (state) => {
+ return {
+ nativeCurrency: getNativeCurrency(state),
+ }
+}
+
+export default connect(mapStateToProps)(TransactionBreakdown)
diff --git a/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js
index 13cb51349..a4f28fd63 100644
--- a/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js
+++ b/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js
@@ -5,6 +5,7 @@ import { CARDS_VARIANT } from '../sender-to-recipient/sender-to-recipient.consta
import TransactionActivityLog from '../transaction-activity-log'
import TransactionBreakdown from '../transaction-breakdown'
import Button from '../button'
+import Tooltip from '../tooltip'
import prefixForNetwork from '../../../lib/etherscan-prefix-for-network'
export default class TransactionListItemDetails extends PureComponent {
@@ -75,13 +76,15 @@ export default class TransactionListItemDetails extends PureComponent {
</Button>
)
}
- <Button
- type="raised"
- onClick={this.handleEtherscanClick}
- className="transaction-list-item-details__header-button"
- >
- <img src="/images/arrow-popout.svg" />
- </Button>
+ <Tooltip title={t('viewOnEtherscan')}>
+ <Button
+ type="raised"
+ onClick={this.handleEtherscanClick}
+ className="transaction-list-item-details__header-button"
+ >
+ <img src="/images/arrow-popout.svg" />
+ </Button>
+ </Tooltip>
</div>
</div>
<div className="transaction-list-item-details__sender-to-recipient-container">
diff --git a/ui/app/components/transaction-list-item/index.scss b/ui/app/components/transaction-list-item/index.scss
index 9d694546b..ac0e7beeb 100644
--- a/ui/app/components/transaction-list-item/index.scss
+++ b/ui/app/components/transaction-list-item/index.scss
@@ -85,6 +85,7 @@
text-align: end;
grid-area: primary-amount;
align-self: end;
+ justify-self: end;
@media screen and (max-width: $break-small) {
padding-bottom: 2px;
@@ -97,6 +98,7 @@
color: #5e6064;
grid-area: secondary-amount;
align-self: start;
+ justify-self: end;
}
}
diff --git a/ui/app/components/transaction-list-item/transaction-list-item.component.js b/ui/app/components/transaction-list-item/transaction-list-item.component.js
index c1c69f59b..696634fe0 100644
--- a/ui/app/components/transaction-list-item/transaction-list-item.component.js
+++ b/ui/app/components/transaction-list-item/transaction-list-item.component.js
@@ -4,13 +4,13 @@ import classnames from 'classnames'
import Identicon from '../identicon'
import TransactionStatus from '../transaction-status'
import TransactionAction from '../transaction-action'
-import CurrencyDisplay from '../currency-display'
+import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
import TokenCurrencyDisplay from '../token-currency-display'
import TransactionListItemDetails from '../transaction-list-item-details'
import { CONFIRM_TRANSACTION_ROUTE } from '../../routes'
import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions'
-import { ETH } from '../../constants/common'
-import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../app/scripts/lib/enums'
+import { PRIMARY, SECONDARY } from '../../constants/common'
+import { getStatusKey } from '../../helpers/transactions.util'
export default class TransactionListItem extends PureComponent {
static propTypes = {
@@ -23,7 +23,6 @@ export default class TransactionListItem extends PureComponent {
showCancelModal: PropTypes.func,
showCancel: PropTypes.bool,
showRetry: PropTypes.bool,
- showTransactionDetailsModal: PropTypes.func,
token: PropTypes.object,
tokenData: PropTypes.object,
transaction: PropTypes.object,
@@ -38,31 +37,16 @@ export default class TransactionListItem extends PureComponent {
const {
transaction,
history,
- showTransactionDetailsModal,
- methodData,
- showCancel,
- showRetry,
} = this.props
const { id, status } = transaction
const { showTransactionDetails } = this.state
- const windowType = window.METAMASK_UI_TYPE
if (status === UNAPPROVED_STATUS) {
history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`)
return
}
- if (windowType === ENVIRONMENT_TYPE_FULLSCREEN) {
- this.setState({ showTransactionDetails: !showTransactionDetails })
- } else {
- showTransactionDetailsModal({
- transaction,
- onRetry: this.handleRetry,
- showRetry: showRetry && methodData.done,
- onCancel: this.handleCancel,
- showCancel,
- })
- }
+ this.setState({ showTransactionDetails: !showTransactionDetails })
}
handleCancel = () => {
@@ -102,12 +86,11 @@ export default class TransactionListItem extends PureComponent {
prefix="-"
/>
) : (
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-list-item__amount transaction-list-item__amount--primary"
value={value}
+ type={PRIMARY}
prefix="-"
- numberOfDecimals={2}
- currency={ETH}
/>
)
}
@@ -118,10 +101,11 @@ export default class TransactionListItem extends PureComponent {
return token
? null
: (
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-list-item__amount transaction-list-item__amount--secondary"
- prefix="-"
value={value}
+ prefix="-"
+ type={SECONDARY}
/>
)
}
@@ -167,7 +151,7 @@ export default class TransactionListItem extends PureComponent {
</div>
<TransactionStatus
className="transaction-list-item__status"
- statusKey={transaction.status}
+ statusKey={getStatusKey(transaction)}
title={(
(transaction.err && transaction.err.rpc)
? transaction.err.rpc.message
diff --git a/ui/app/components/transaction-list-item/transaction-list-item.container.js b/ui/app/components/transaction-list-item/transaction-list-item.container.js
index 72f5f5d61..62ed7a73f 100644
--- a/ui/app/components/transaction-list-item/transaction-list-item.container.js
+++ b/ui/app/components/transaction-list-item/transaction-list-item.container.js
@@ -28,16 +28,6 @@ const mapDispatchToProps = dispatch => {
showCancelModal: (transactionId, originalGasPrice) => {
return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice }))
},
- showTransactionDetailsModal: ({ transaction, onRetry, showRetry, onCancel, showCancel }) => {
- return dispatch(showModal({
- name: 'TRANSACTION_DETAILS',
- transaction,
- onRetry,
- showRetry,
- onCancel,
- showCancel,
- }))
- },
}
}
diff --git a/ui/app/components/transaction-list/index.scss b/ui/app/components/transaction-list/index.scss
index 777f701f9..ba7ffd87b 100644
--- a/ui/app/components/transaction-list/index.scss
+++ b/ui/app/components/transaction-list/index.scss
@@ -2,9 +2,7 @@
display: flex;
flex-direction: column;
flex: 1;
- overflow-y: hidden;
margin-top: 8px;
- border-top: 1px solid $geyser;
&__completed-transactions {
display: flex;
@@ -26,7 +24,6 @@
&__transactions {
flex: 1;
- overflow-y: auto;
}
&__pending-transactions {
diff --git a/ui/app/components/transaction-status/index.scss b/ui/app/components/transaction-status/index.scss
index 35be550f7..26a1f5d38 100644
--- a/ui/app/components/transaction-status/index.scss
+++ b/ui/app/components/transaction-status/index.scss
@@ -25,4 +25,9 @@
background-color: #FFF2DB;
color: #CA810A;
}
-} \ No newline at end of file
+
+ &--failed {
+ background: lighten($monzo, 56%);
+ color: $monzo;
+ }
+}
diff --git a/ui/app/components/transaction-view-balance/index.scss b/ui/app/components/transaction-view-balance/index.scss
index 12045ab6d..659f896ff 100644
--- a/ui/app/components/transaction-view-balance/index.scss
+++ b/ui/app/components/transaction-view-balance/index.scss
@@ -4,11 +4,13 @@
align-items: center;
flex: 1;
height: 54px;
+ min-width: 0;
&__balance {
- margin-left: 12px;
+ margin: 0 12px;
display: flex;
flex-direction: column;
+ min-width: 0;
@media screen and (max-width: $break-small) {
align-items: center;
@@ -21,7 +23,8 @@
font-size: 1.5rem;
@media screen and (max-width: $break-small) {
- margin-bottom: 12px;
+ margin: 12px 0;
+ margin-left: 0;
font-size: 1.75rem;
}
}
@@ -30,7 +33,6 @@
font-size: 1.5rem;
@media screen and (max-width: $break-small) {
- margin-bottom: 12px;
font-size: 1.75rem;
}
}
@@ -45,6 +47,7 @@
display: flex;
flex-direction: row;
align-items: center;
+ min-width: 0;
@media screen and (max-width: $break-small) {
flex-direction: column;
diff --git a/ui/app/components/transaction-view-balance/tests/token-view-balance.component.test.js b/ui/app/components/transaction-view-balance/tests/token-view-balance.component.test.js
index bb95cb27e..513a8aac9 100644
--- a/ui/app/components/transaction-view-balance/tests/token-view-balance.component.test.js
+++ b/ui/app/components/transaction-view-balance/tests/token-view-balance.component.test.js
@@ -3,7 +3,7 @@ import assert from 'assert'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import TokenBalance from '../../token-balance'
-import CurrencyDisplay from '../../currency-display'
+import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
import { SEND_ROUTE } from '../../../routes'
import TransactionViewBalance from '../transaction-view-balance.component'
@@ -35,7 +35,7 @@ describe('TransactionViewBalance Component', () => {
assert.equal(wrapper.find('.transaction-view-balance').length, 1)
assert.equal(wrapper.find('.transaction-view-balance__button').length, 2)
- assert.equal(wrapper.find(CurrencyDisplay).length, 2)
+ assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 2)
const buttons = wrapper.find('.transaction-view-balance__buttons')
assert.equal(propsMethodSpies.showDepositModal.callCount, 0)
diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js
index 1b7a29c87..273845c47 100644
--- a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js
+++ b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js
@@ -3,9 +3,9 @@ import PropTypes from 'prop-types'
import Button from '../button'
import Identicon from '../identicon'
import TokenBalance from '../token-balance'
-import CurrencyDisplay from '../currency-display'
+import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
import { SEND_ROUTE } from '../../routes'
-import { ETH } from '../../constants/common'
+import { PRIMARY, SECONDARY } from '../../constants/common'
export default class TransactionViewBalance extends PureComponent {
static contextTypes = {
@@ -33,15 +33,17 @@ export default class TransactionViewBalance extends PureComponent {
/>
) : (
<div className="transaction-view-balance__balance">
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-view-balance__primary-balance"
value={balance}
- currency={ETH}
- numberOfDecimals={3}
+ type={PRIMARY}
+ ethNumberOfDecimals={3}
/>
- <CurrencyDisplay
+ <UserPreferencedCurrencyDisplay
className="transaction-view-balance__secondary-balance"
value={balance}
+ type={SECONDARY}
+ ethNumberOfDecimals={3}
/>
</div>
)
diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js
index 30c5cab16..cb8078ec1 100644
--- a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js
+++ b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js
@@ -2,7 +2,7 @@ import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import { compose } from 'recompose'
import TransactionViewBalance from './transaction-view-balance.component'
-import { getSelectedToken, getSelectedAddress, getSelectedTokenAssetImage } from '../../selectors'
+import { getSelectedToken, getSelectedAddress, getNativeCurrency, getSelectedTokenAssetImage } from '../../selectors'
import { showModal } from '../../actions'
const mapStateToProps = state => {
@@ -15,6 +15,7 @@ const mapStateToProps = state => {
selectedToken: getSelectedToken(state),
network,
balance,
+ nativeCurrency: getNativeCurrency(state),
assetImage: getSelectedTokenAssetImage(state),
}
}
diff --git a/ui/app/components/transaction-view/index.scss b/ui/app/components/transaction-view/index.scss
index af9771ce0..13187f0e5 100644
--- a/ui/app/components/transaction-view/index.scss
+++ b/ui/app/components/transaction-view/index.scss
@@ -4,6 +4,7 @@
min-width: 0;
display: flex;
flex-direction: column;
+ overflow-y: auto;
&__balance-wrapper {
@media screen and (max-width: $break-small) {
diff --git a/ui/app/components/unit-input/index.js b/ui/app/components/unit-input/index.js
new file mode 100644
index 000000000..7c33c9e5c
--- /dev/null
+++ b/ui/app/components/unit-input/index.js
@@ -0,0 +1 @@
+export { default } from './unit-input.component'
diff --git a/ui/app/components/unit-input/index.scss b/ui/app/components/unit-input/index.scss
new file mode 100644
index 000000000..28c5bf6f0
--- /dev/null
+++ b/ui/app/components/unit-input/index.scss
@@ -0,0 +1,44 @@
+.unit-input {
+ min-height: 54px;
+ border: 1px solid #dedede;
+ border-radius: 4px;
+ background-color: #fff;
+ color: #4d4d4d;
+ font-size: 1rem;
+ padding: 8px 10px;
+ position: relative;
+
+ input[type="number"] {
+ -moz-appearance: textfield;
+ }
+
+ input[type="number"]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ display: none;
+ }
+
+ input[type="number"]:hover::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ display: none;
+ }
+
+ &__input {
+ color: #4d4d4d;
+ font-size: 1rem;
+ font-family: Roboto;
+ border: none;
+ outline: 0 !important;
+ max-width: 22ch;
+ }
+
+ &__input-container {
+ display: flex;
+ align-items: center;
+ }
+
+ &--error {
+ border-color: $red;
+ }
+}
diff --git a/ui/app/components/unit-input/tests/unit-input.component.test.js b/ui/app/components/unit-input/tests/unit-input.component.test.js
new file mode 100644
index 000000000..97d987bc7
--- /dev/null
+++ b/ui/app/components/unit-input/tests/unit-input.component.test.js
@@ -0,0 +1,146 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow, mount } from 'enzyme'
+import sinon from 'sinon'
+import UnitInput from '../unit-input.component'
+
+describe('UnitInput Component', () => {
+ describe('rendering', () => {
+ it('should render properly without a suffix', () => {
+ const wrapper = shallow(
+ <UnitInput />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input__suffix').length, 0)
+ })
+
+ it('should render properly with a suffix', () => {
+ const wrapper = shallow(
+ <UnitInput
+ suffix="ETH"
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input__suffix').length, 1)
+ assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
+ })
+
+ it('should render properly with a child omponent', () => {
+ const wrapper = shallow(
+ <UnitInput>
+ <div className="testing">
+ TESTCOMPONENT
+ </div>
+ </UnitInput>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.testing').length, 1)
+ assert.equal(wrapper.find('.testing').text(), 'TESTCOMPONENT')
+ })
+
+ it('should render with an error class when props.error === true', () => {
+ const wrapper = shallow(
+ <UnitInput
+ error
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find('.unit-input--error').length, 1)
+ })
+ })
+
+ describe('handling actions', () => {
+ const handleChangeSpy = sinon.spy()
+ const handleBlurSpy = sinon.spy()
+
+ afterEach(() => {
+ handleChangeSpy.resetHistory()
+ handleBlurSpy.resetHistory()
+ })
+
+ it('should focus the input on component click', () => {
+ const wrapper = mount(
+ <UnitInput />
+ )
+
+ assert.ok(wrapper)
+ const handleFocusSpy = sinon.spy(wrapper.instance(), 'handleFocus')
+ wrapper.instance().forceUpdate()
+ wrapper.update()
+ assert.equal(handleFocusSpy.callCount, 0)
+ wrapper.find('.unit-input').simulate('click')
+ assert.equal(handleFocusSpy.callCount, 1)
+ })
+
+ it('should call onChange on input changes with the value', () => {
+ const wrapper = mount(
+ <UnitInput
+ onChange={handleChangeSpy}
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ const input = wrapper.find('input')
+ input.simulate('change', { target: { value: 123 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith(123))
+ assert.equal(wrapper.state('value'), 123)
+ })
+
+ it('should call onBlur on blur with the value', () => {
+ const wrapper = mount(
+ <UnitInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+ const input = wrapper.find('input')
+ input.simulate('change', { target: { value: 123 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith(123))
+ assert.equal(wrapper.state('value'), 123)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith(123))
+ })
+
+ it('should set the component state value with props.value', () => {
+ const wrapper = mount(
+ <UnitInput
+ value={123}
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.state('value'), 123)
+ })
+
+ it('should update the component state value with props.value', () => {
+ const wrapper = mount(
+ <UnitInput
+ onChange={handleChangeSpy}
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ const input = wrapper.find('input')
+ input.simulate('change', { target: { value: 123 } })
+ assert.equal(wrapper.state('value'), 123)
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith(123))
+ wrapper.setProps({ value: 456 })
+ assert.equal(wrapper.state('value'), 456)
+ assert.equal(handleChangeSpy.callCount, 1)
+ })
+ })
+})
diff --git a/ui/app/components/unit-input/unit-input.component.js b/ui/app/components/unit-input/unit-input.component.js
new file mode 100644
index 000000000..f1ebf4d77
--- /dev/null
+++ b/ui/app/components/unit-input/unit-input.component.js
@@ -0,0 +1,104 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import classnames from 'classnames'
+import { removeLeadingZeroes } from '../send/send.utils'
+
+/**
+ * Component that attaches a suffix or unit of measurement trailing user input, ex. 'ETH'. Also
+ * allows rendering a child component underneath the input to, for example, display conversions of
+ * the shown suffix.
+ */
+export default class UnitInput extends PureComponent {
+ static propTypes = {
+ children: PropTypes.node,
+ error: PropTypes.bool,
+ onBlur: PropTypes.func,
+ onChange: PropTypes.func,
+ placeholder: PropTypes.string,
+ suffix: PropTypes.string,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ }
+
+ static defaultProps = {
+ placeholder: '0',
+ }
+
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ value: props.value || '',
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ const { value: prevPropsValue } = prevProps
+ const { value: propsValue } = this.props
+ const { value: stateValue } = this.state
+
+ if (prevPropsValue !== propsValue && propsValue !== stateValue) {
+ this.setState({ value: propsValue })
+ }
+ }
+
+ handleFocus = () => {
+ this.unitInput.focus()
+ }
+
+ handleChange = event => {
+ const { value: userInput } = event.target
+ let value = userInput
+
+ if (userInput.length && userInput.length > 1) {
+ value = removeLeadingZeroes(userInput)
+ }
+
+ this.setState({ value })
+ this.props.onChange(value)
+ }
+
+ handleBlur = event => {
+ const { onBlur } = this.props
+ typeof onBlur === 'function' && onBlur(this.state.value)
+ }
+
+ getInputWidth (value) {
+ const valueString = String(value)
+ const valueLength = valueString.length || 1
+ const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0
+ return (valueLength + decimalPointDeficit + 0.75) + 'ch'
+ }
+
+ render () {
+ const { error, placeholder, suffix, children } = this.props
+ const { value } = this.state
+
+ return (
+ <div
+ className={classnames('unit-input', { 'unit-input--error': error })}
+ onClick={this.handleFocus}
+ >
+ <div className="unit-input__input-container">
+ <input
+ type="number"
+ className="unit-input__input"
+ value={value}
+ placeholder={placeholder}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ style={{ width: this.getInputWidth(value) }}
+ ref={ref => { this.unitInput = ref }}
+ />
+ {
+ suffix && (
+ <div className="unit-input__suffix">
+ { suffix }
+ </div>
+ )
+ }
+ </div>
+ { children }
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/user-preferenced-currency-display/index.js b/ui/app/components/user-preferenced-currency-display/index.js
new file mode 100644
index 000000000..0deddaecf
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-display/index.js
@@ -0,0 +1 @@
+export { default } from './user-preferenced-currency-display.container'
diff --git a/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js
new file mode 100644
index 000000000..ead584c26
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js
@@ -0,0 +1,34 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display.component'
+import CurrencyDisplay from '../../currency-display'
+
+describe('UserPreferencedCurrencyDisplay Component', () => {
+ describe('rendering', () => {
+ it('should render properly', () => {
+ const wrapper = shallow(
+ <UserPreferencedCurrencyDisplay />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ })
+
+ it('should pass all props to the CurrencyDisplay child component', () => {
+ const wrapper = shallow(
+ <UserPreferencedCurrencyDisplay
+ prop1={true}
+ prop2="test"
+ prop3={1}
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(CurrencyDisplay).length, 1)
+ assert.equal(wrapper.find(CurrencyDisplay).props().prop1, true)
+ assert.equal(wrapper.find(CurrencyDisplay).props().prop2, 'test')
+ assert.equal(wrapper.find(CurrencyDisplay).props().prop3, 1)
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js
new file mode 100644
index 000000000..ba1c23d83
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js
@@ -0,0 +1,115 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps, mergeProps
+
+proxyquire('../user-preferenced-currency-display.container.js', {
+ 'react-redux': {
+ connect: (ms, md, mp) => {
+ mapStateToProps = ms
+ mergeProps = mp
+ return () => ({})
+ },
+ },
+})
+
+describe('UserPreferencedCurrencyDisplay container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props', () => {
+ const mockState = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ preferences: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ },
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ nativeCurrency: 'ETH',
+ useNativeCurrencyAsPrimaryCurrency: true,
+ })
+ })
+ })
+
+ describe('mergeProps()', () => {
+ it('should return the correct props', () => {
+ const mockDispatchProps = {}
+
+ const tests = [
+ {
+ stateProps: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ nativeCurrency: 'ETH',
+ },
+ ownProps: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: 'ETH',
+ nativeCurrency: 'ETH',
+ numberOfDecimals: 6,
+ prefix: undefined,
+ },
+ },
+ {
+ stateProps: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ },
+ ownProps: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: undefined,
+ nativeCurrency: 'ETH',
+ numberOfDecimals: 2,
+ prefix: undefined,
+ },
+ },
+ {
+ stateProps: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ nativeCurrency: 'ETH',
+ },
+ ownProps: {
+ type: 'SECONDARY',
+ fiatNumberOfDecimals: 4,
+ fiatPrefix: '-',
+ },
+ result: {
+ nativeCurrency: 'ETH',
+ currency: undefined,
+ numberOfDecimals: 4,
+ prefix: '-',
+ },
+ },
+ {
+ stateProps: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ },
+ ownProps: {
+ type: 'SECONDARY',
+ fiatNumberOfDecimals: 4,
+ numberOfDecimals: 3,
+ fiatPrefix: 'a',
+ prefix: 'b',
+ },
+ result: {
+ currency: 'ETH',
+ nativeCurrency: 'ETH',
+ numberOfDecimals: 3,
+ prefix: 'b',
+ },
+ },
+ ]
+
+ tests.forEach(({ stateProps, ownProps, result }) => {
+ assert.deepEqual(mergeProps({ ...stateProps }, mockDispatchProps, { ...ownProps }), {
+ ...result,
+ })
+ })
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js
new file mode 100644
index 000000000..f2a834ea7
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js
@@ -0,0 +1,46 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { PRIMARY, SECONDARY, ETH } from '../../constants/common'
+import CurrencyDisplay from '../currency-display'
+
+export default class UserPreferencedCurrencyDisplay extends PureComponent {
+ static propTypes = {
+ className: PropTypes.string,
+ prefix: PropTypes.string,
+ value: PropTypes.string,
+ numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ hideLabel: PropTypes.bool,
+ style: PropTypes.object,
+ showEthLogo: PropTypes.bool,
+ ethLogoHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ // Used in container
+ type: PropTypes.oneOf([PRIMARY, SECONDARY]),
+ ethNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fiatNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ ethPrefix: PropTypes.string,
+ fiatPrefix: PropTypes.string,
+ // From container
+ currency: PropTypes.string,
+ nativeCurrency: PropTypes.string,
+ }
+
+ renderEthLogo () {
+ const { currency, showEthLogo, ethLogoHeight = 12 } = this.props
+
+ return currency === ETH && showEthLogo && (
+ <img
+ src="/images/eth.svg"
+ height={ethLogoHeight}
+ />
+ )
+ }
+
+ render () {
+ return (
+ <CurrencyDisplay
+ {...this.props}
+ prefixComponent={this.renderEthLogo()}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js
new file mode 100644
index 000000000..7999301ad
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js
@@ -0,0 +1,54 @@
+import { connect } from 'react-redux'
+import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display.component'
+import { preferencesSelector } from '../../selectors'
+import { ETH, PRIMARY, SECONDARY } from '../../constants/common'
+
+const mapStateToProps = (state, ownProps) => {
+ const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state)
+
+ return {
+ useNativeCurrencyAsPrimaryCurrency,
+ nativeCurrency: state.metamask.nativeCurrency,
+ }
+}
+
+const mergeProps = (stateProps, dispatchProps, ownProps) => {
+ const { useNativeCurrencyAsPrimaryCurrency, nativeCurrency, ...restStateProps } = stateProps
+ const {
+ type,
+ numberOfDecimals: propsNumberOfDecimals,
+ ethNumberOfDecimals,
+ fiatNumberOfDecimals,
+ ethPrefix,
+ fiatPrefix,
+ prefix: propsPrefix,
+ ...restOwnProps
+ } = ownProps
+
+ let currency, numberOfDecimals, prefix
+
+ if (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency ||
+ type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency) {
+ // Display ETH
+ currency = nativeCurrency || ETH
+ numberOfDecimals = propsNumberOfDecimals || ethNumberOfDecimals || 6
+ prefix = propsPrefix || ethPrefix
+ } else if (type === SECONDARY && useNativeCurrencyAsPrimaryCurrency ||
+ type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency) {
+ // Display Fiat
+ numberOfDecimals = propsNumberOfDecimals || fiatNumberOfDecimals || 2
+ prefix = propsPrefix || fiatPrefix
+ }
+
+ return {
+ ...restStateProps,
+ ...dispatchProps,
+ ...restOwnProps,
+ nativeCurrency,
+ currency,
+ numberOfDecimals,
+ prefix,
+ }
+}
+
+export default connect(mapStateToProps, null, mergeProps)(UserPreferencedCurrencyDisplay)
diff --git a/ui/app/components/user-preferenced-currency-input/index.js b/ui/app/components/user-preferenced-currency-input/index.js
new file mode 100644
index 000000000..4dc70db3d
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-input/index.js
@@ -0,0 +1 @@
+export { default } from './user-preferenced-currency-input.container'
diff --git a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js
new file mode 100644
index 000000000..710b5d519
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js
@@ -0,0 +1,32 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import UserPreferencedCurrencyInput from '../user-preferenced-currency-input.component'
+import CurrencyInput from '../../currency-input'
+
+describe('UserPreferencedCurrencyInput Component', () => {
+ describe('rendering', () => {
+ it('should render properly', () => {
+ const wrapper = shallow(
+ <UserPreferencedCurrencyInput />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(CurrencyInput).length, 1)
+ })
+
+ it('should render useFiat for CurrencyInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => {
+ const wrapper = shallow(
+ <UserPreferencedCurrencyInput
+ useNativeCurrencyAsPrimaryCurrency
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(CurrencyInput).length, 1)
+ assert.equal(wrapper.find(CurrencyInput).props().useFiat, false)
+ wrapper.setProps({ useNativeCurrencyAsPrimaryCurrency: false })
+ assert.equal(wrapper.find(CurrencyInput).props().useFiat, true)
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js
new file mode 100644
index 000000000..959726443
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js
@@ -0,0 +1,31 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps
+
+proxyquire('../user-preferenced-currency-input.container.js', {
+ 'react-redux': {
+ connect: ms => {
+ mapStateToProps = ms
+ return () => ({})
+ },
+ },
+})
+
+describe('UserPreferencedCurrencyInput container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props', () => {
+ const mockState = {
+ metamask: {
+ preferences: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ },
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ })
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js
new file mode 100644
index 000000000..463e66b80
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js
@@ -0,0 +1,20 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import CurrencyInput from '../currency-input'
+
+export default class UserPreferencedCurrencyInput extends PureComponent {
+ static propTypes = {
+ useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
+ }
+
+ render () {
+ const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props
+
+ return (
+ <CurrencyInput
+ {...restProps}
+ useFiat={!useNativeCurrencyAsPrimaryCurrency}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js
new file mode 100644
index 000000000..0b88eb5a7
--- /dev/null
+++ b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js
@@ -0,0 +1,13 @@
+import { connect } from 'react-redux'
+import UserPreferencedCurrencyInput from './user-preferenced-currency-input.component'
+import { preferencesSelector } from '../../selectors'
+
+const mapStateToProps = state => {
+ const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state)
+
+ return {
+ useNativeCurrencyAsPrimaryCurrency,
+ }
+}
+
+export default connect(mapStateToProps)(UserPreferencedCurrencyInput)
diff --git a/ui/app/components/user-preferenced-token-input/index.js b/ui/app/components/user-preferenced-token-input/index.js
new file mode 100644
index 000000000..54167e633
--- /dev/null
+++ b/ui/app/components/user-preferenced-token-input/index.js
@@ -0,0 +1 @@
+export { default } from './user-preferenced-token-input.container'
diff --git a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js
new file mode 100644
index 000000000..d85bddeeb
--- /dev/null
+++ b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js
@@ -0,0 +1,32 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import UserPreferencedTokenInput from '../user-preferenced-token-input.component'
+import TokenInput from '../../token-input'
+
+describe('UserPreferencedCurrencyInput Component', () => {
+ describe('rendering', () => {
+ it('should render properly', () => {
+ const wrapper = shallow(
+ <UserPreferencedTokenInput />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(TokenInput).length, 1)
+ })
+
+ it('should render showFiat for TokenInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => {
+ const wrapper = shallow(
+ <UserPreferencedTokenInput
+ useNativeCurrencyAsPrimaryCurrency
+ />
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.find(TokenInput).length, 1)
+ assert.equal(wrapper.find(TokenInput).props().showFiat, false)
+ wrapper.setProps({ useNativeCurrencyAsPrimaryCurrency: false })
+ assert.equal(wrapper.find(TokenInput).props().showFiat, true)
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js
new file mode 100644
index 000000000..2f89fba90
--- /dev/null
+++ b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js
@@ -0,0 +1,31 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps
+
+proxyquire('../user-preferenced-token-input.container.js', {
+ 'react-redux': {
+ connect: ms => {
+ mapStateToProps = ms
+ return () => ({})
+ },
+ },
+})
+
+describe('UserPreferencedTokenInput container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props', () => {
+ const mockState = {
+ metamask: {
+ preferences: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ },
+ },
+ }
+
+ assert.deepEqual(mapStateToProps(mockState), {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ })
+ })
+ })
+})
diff --git a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js
new file mode 100644
index 000000000..8f14231ac
--- /dev/null
+++ b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js
@@ -0,0 +1,20 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import TokenInput from '../token-input'
+
+export default class UserPreferencedTokenInput extends PureComponent {
+ static propTypes = {
+ useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
+ }
+
+ render () {
+ const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props
+
+ return (
+ <TokenInput
+ {...restProps}
+ showFiat={!useNativeCurrencyAsPrimaryCurrency}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js
new file mode 100644
index 000000000..3305d4e29
--- /dev/null
+++ b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js
@@ -0,0 +1,13 @@
+import { connect } from 'react-redux'
+import UserPreferencedTokenInput from './user-preferenced-token-input.component'
+import { preferencesSelector } from '../../selectors'
+
+const mapStateToProps = state => {
+ const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state)
+
+ return {
+ useNativeCurrencyAsPrimaryCurrency,
+ }
+}
+
+export default connect(mapStateToProps)(UserPreferencedTokenInput)
diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js
index 064a6ab55..e050e0ee6 100644
--- a/ui/app/components/wallet-view.js
+++ b/ui/app/components/wallet-view.js
@@ -7,7 +7,7 @@ const { compose } = require('recompose')
const inherits = require('util').inherits
const classnames = require('classnames')
const { checksumAddress } = require('../util')
-const Identicon = require('./identicon')
+import Identicon from './identicon'
// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
const Tooltip = require('./tooltip-v2.js').default
const copyToClipboard = require('copy-to-clipboard')
@@ -17,7 +17,7 @@ const TokenList = require('./token-list')
const selectors = require('../selectors')
const { ADD_TOKEN_ROUTE } = require('../routes')
-import Button from './button'
+import AddTokenButton from './add-token-button'
module.exports = compose(
withRouter,
@@ -100,19 +100,33 @@ WalletView.prototype.renderWalletBalance = function () {
])
}
+WalletView.prototype.renderAddToken = function () {
+ const {
+ sidebarOpen,
+ hideSidebar,
+ history,
+ } = this.props
+
+ return h(AddTokenButton, {
+ onClick () {
+ history.push(ADD_TOKEN_ROUTE)
+ if (sidebarOpen) {
+ hideSidebar()
+ }
+ },
+ })
+}
+
WalletView.prototype.render = function () {
const {
responsiveDisplayClassname,
selectedAddress,
keyrings,
showAccountDetailModal,
- sidebarOpen,
hideSidebar,
- history,
identities,
} = this.props
// temporary logs + fake extra wallets
- // console.log('walletview, selectedAccount:', selectedAccount)
const checksummedAddress = checksumAddress(selectedAddress)
@@ -201,14 +215,7 @@ WalletView.prototype.render = function () {
h(TokenList),
- h(Button, {
- type: 'primary',
- className: 'wallet-view__add-token-button',
- onClick: () => {
- history.push(ADD_TOKEN_ROUTE)
- sidebarOpen && hideSidebar()
- },
- }, this.context.t('addToken')),
+ this.renderAddToken(),
])
}
diff --git a/ui/app/constants/common.js b/ui/app/constants/common.js
index a20f6cc02..4ff4dc837 100644
--- a/ui/app/constants/common.js
+++ b/ui/app/constants/common.js
@@ -1,3 +1,6 @@
export const ETH = 'ETH'
export const GWEI = 'GWEI'
export const WEI = 'WEI'
+
+export const PRIMARY = 'PRIMARY'
+export const SECONDARY = 'SECONDARY'
diff --git a/ui/app/constants/error-keys.js b/ui/app/constants/error-keys.js
index f70ed3b19..704064c96 100644
--- a/ui/app/constants/error-keys.js
+++ b/ui/app/constants/error-keys.js
@@ -1,3 +1,4 @@
export const INSUFFICIENT_FUNDS_ERROR_KEY = 'insufficientFunds'
export const GAS_LIMIT_TOO_LOW_ERROR_KEY = 'gasLimitTooLow'
export const TRANSACTION_ERROR_KEY = 'transactionError'
+export const TRANSACTION_NO_CONTRACT_ERROR_KEY = 'transactionErrorNoContract'
diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss
index 655188a3e..5826a8b49 100644
--- a/ui/app/css/itcss/components/buttons.scss
+++ b/ui/app/css/itcss/components/buttons.scss
@@ -3,7 +3,7 @@
*/
.button {
- height: 44px;
+ min-height: 44px;
background: $white;
display: flex;
justify-content: center;
@@ -82,12 +82,13 @@
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08);
padding: 6px;
height: initial;
+ min-height: initial;
width: initial;
min-width: initial;
}
.btn--large {
- height: 54px;
+ min-height: 54px;
}
.btn-green {
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
index 8e963d495..233e781ef 100644
--- a/ui/app/css/itcss/components/newui-sections.scss
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -120,18 +120,6 @@ $wallet-view-bg: $alabaster;
}
}
}
-
- &__add-token-button {
- flex: 0 0 auto;
- margin: 36px auto;
- background: none;
- transition: border-color .3s ease;
- width: 150px;
-
- &:hover {
- border-color: $curious-blue;
- }
- }
}
@media screen and (min-width: 576px) {
diff --git a/ui/app/css/itcss/components/request-signature.scss b/ui/app/css/itcss/components/request-signature.scss
index 445b9ebf5..6c950d846 100644
--- a/ui/app/css/itcss/components/request-signature.scss
+++ b/ui/app/css/itcss/components/request-signature.scss
@@ -19,7 +19,7 @@
}
@media screen and (min-width: $break-large) {
- max-height: 620px;
+ height: 620px;
}
}
diff --git a/ui/app/css/itcss/components/wallet-balance.scss b/ui/app/css/itcss/components/wallet-balance.scss
index 293771550..3c3349ae0 100644
--- a/ui/app/css/itcss/components/wallet-balance.scss
+++ b/ui/app/css/itcss/components/wallet-balance.scss
@@ -29,7 +29,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
align-items: center;
margin: 20px 24px;
flex-direction: row;
- flex-grow: 3;
+ min-width: 0;
@media #{$wallet-balance-breakpoint-range} {
margin: 10% 4%;
@@ -38,8 +38,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
.balance-display {
margin-left: 15px;
- justify-content: flex-start;
- align-items: flex-start;
+ min-width: 0;
.token-amount {
font-size: 1.5rem;
diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js
index 30c32f2bf..275eb1551 100644
--- a/ui/app/ducks/confirm-transaction.duck.js
+++ b/ui/app/ducks/confirm-transaction.duck.js
@@ -2,6 +2,7 @@ import {
conversionRateSelector,
currentCurrencySelector,
unconfirmedTransactionsHashSelector,
+ getNativeCurrency,
} from '../selectors/confirm-transaction'
import {
@@ -14,7 +15,13 @@ import {
hexGreaterThan,
} from '../helpers/confirm-transaction/util'
-import { getTokenData, getMethodData, isSmartContractAddress } from '../helpers/transactions.util'
+import {
+ getTokenData,
+ getMethodData,
+ isSmartContractAddress,
+ sumHexes,
+} from '../helpers/transactions.util'
+
import { getSymbolAndDecimals } from '../token-util'
import { conversionUtil } from '../conversion-util'
@@ -31,7 +38,6 @@ const CLEAR_CONFIRM_TRANSACTION = createActionType('CLEAR_CONFIRM_TRANSACTION')
const UPDATE_TRANSACTION_AMOUNTS = createActionType('UPDATE_TRANSACTION_AMOUNTS')
const UPDATE_TRANSACTION_FEES = createActionType('UPDATE_TRANSACTION_FEES')
const UPDATE_TRANSACTION_TOTALS = createActionType('UPDATE_TRANSACTION_TOTALS')
-const UPDATE_HEX_GAS_TOTAL = createActionType('UPDATE_HEX_GAS_TOTAL')
const UPDATE_TOKEN_PROPS = createActionType('UPDATE_TOKEN_PROPS')
const UPDATE_NONCE = createActionType('UPDATE_NONCE')
const UPDATE_TO_SMART_CONTRACT = createActionType('UPDATE_TO_SMART_CONTRACT')
@@ -53,7 +59,9 @@ const initState = {
ethTransactionAmount: '',
ethTransactionFee: '',
ethTransactionTotal: '',
- hexGasTotal: '',
+ hexTransactionAmount: '',
+ hexTransactionFee: '',
+ hexTransactionTotal: '',
nonce: '',
toSmartContract: false,
fetchingData: false,
@@ -99,30 +107,28 @@ export default function reducer ({ confirmTransaction: confirmState = initState
methodData: {},
}
case UPDATE_TRANSACTION_AMOUNTS:
- const { fiatTransactionAmount, ethTransactionAmount } = action.payload
+ const { fiatTransactionAmount, ethTransactionAmount, hexTransactionAmount } = action.payload
return {
...confirmState,
fiatTransactionAmount: fiatTransactionAmount || confirmState.fiatTransactionAmount,
ethTransactionAmount: ethTransactionAmount || confirmState.ethTransactionAmount,
+ hexTransactionAmount: hexTransactionAmount || confirmState.hexTransactionAmount,
}
case UPDATE_TRANSACTION_FEES:
- const { fiatTransactionFee, ethTransactionFee } = action.payload
+ const { fiatTransactionFee, ethTransactionFee, hexTransactionFee } = action.payload
return {
...confirmState,
fiatTransactionFee: fiatTransactionFee || confirmState.fiatTransactionFee,
ethTransactionFee: ethTransactionFee || confirmState.ethTransactionFee,
+ hexTransactionFee: hexTransactionFee || confirmState.hexTransactionFee,
}
case UPDATE_TRANSACTION_TOTALS:
- const { fiatTransactionTotal, ethTransactionTotal } = action.payload
+ const { fiatTransactionTotal, ethTransactionTotal, hexTransactionTotal } = action.payload
return {
...confirmState,
fiatTransactionTotal: fiatTransactionTotal || confirmState.fiatTransactionTotal,
ethTransactionTotal: ethTransactionTotal || confirmState.ethTransactionTotal,
- }
- case UPDATE_HEX_GAS_TOTAL:
- return {
- ...confirmState,
- hexGasTotal: action.payload,
+ hexTransactionTotal: hexTransactionTotal || confirmState.hexTransactionTotal,
}
case UPDATE_TOKEN_PROPS:
const { tokenSymbol = '', tokenDecimals = '' } = action.payload
@@ -222,13 +228,6 @@ export function updateTransactionTotals (totals) {
}
}
-export function updateHexGasTotal (hexGasTotal) {
- return {
- type: UPDATE_HEX_GAS_TOTAL,
- payload: hexGasTotal,
- }
-}
-
export function updateTokenProps (tokenProps) {
return {
type: UPDATE_TOKEN_PROPS,
@@ -294,43 +293,53 @@ export function updateTxDataAndCalculate (txData) {
const state = getState()
const currentCurrency = currentCurrencySelector(state)
const conversionRate = conversionRateSelector(state)
+ const nativeCurrency = getNativeCurrency(state)
dispatch(updateTxData(txData))
- const { txParams: { value, gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData
+ const { txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData
const fiatTransactionAmount = getValueFromWeiHex({
- value, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
+ value, fromCurrency: nativeCurrency, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
})
const ethTransactionAmount = getValueFromWeiHex({
- value, toCurrency: 'ETH', conversionRate, numberOfDecimals: 6,
+ value, fromCurrency: nativeCurrency, toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6,
})
- dispatch(updateTransactionAmounts({ fiatTransactionAmount, ethTransactionAmount }))
-
- const hexGasTotal = getHexGasTotal({ gasLimit, gasPrice })
+ dispatch(updateTransactionAmounts({
+ fiatTransactionAmount,
+ ethTransactionAmount,
+ hexTransactionAmount: value,
+ }))
- dispatch(updateHexGasTotal(hexGasTotal))
+ const hexTransactionFee = getHexGasTotal({ gasLimit, gasPrice })
const fiatTransactionFee = getTransactionFee({
- value: hexGasTotal,
+ value: hexTransactionFee,
+ fromCurrency: nativeCurrency,
toCurrency: currentCurrency,
numberOfDecimals: 2,
conversionRate,
})
const ethTransactionFee = getTransactionFee({
- value: hexGasTotal,
- toCurrency: 'ETH',
+ value: hexTransactionFee,
+ fromCurrency: nativeCurrency,
+ toCurrency: nativeCurrency,
numberOfDecimals: 6,
conversionRate,
})
- dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee }))
+ dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee, hexTransactionFee }))
const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount)
const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount)
+ const hexTransactionTotal = sumHexes(value, hexTransactionFee)
- dispatch(updateTransactionTotals({ fiatTransactionTotal, ethTransactionTotal }))
+ dispatch(updateTransactionTotals({
+ fiatTransactionTotal,
+ ethTransactionTotal,
+ hexTransactionTotal,
+ }))
}
}
diff --git a/ui/app/ducks/tests/confirm-transaction.duck.test.js b/ui/app/ducks/tests/confirm-transaction.duck.test.js
index 1bab0add0..eceacd0bd 100644
--- a/ui/app/ducks/tests/confirm-transaction.duck.test.js
+++ b/ui/app/ducks/tests/confirm-transaction.duck.test.js
@@ -19,7 +19,9 @@ const initialState = {
ethTransactionAmount: '',
ethTransactionFee: '',
ethTransactionTotal: '',
- hexGasTotal: '',
+ hexTransactionAmount: '',
+ hexTransactionFee: '',
+ hexTransactionTotal: '',
nonce: '',
toSmartContract: false,
fetchingData: false,
@@ -34,7 +36,6 @@ const CLEAR_METHOD_DATA = 'metamask/confirm-transaction/CLEAR_METHOD_DATA'
const UPDATE_TRANSACTION_AMOUNTS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS'
const UPDATE_TRANSACTION_FEES = 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES'
const UPDATE_TRANSACTION_TOTALS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS'
-const UPDATE_HEX_GAS_TOTAL = 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL'
const UPDATE_TOKEN_PROPS = 'metamask/confirm-transaction/UPDATE_TOKEN_PROPS'
const UPDATE_NONCE = 'metamask/confirm-transaction/UPDATE_NONCE'
const UPDATE_TO_SMART_CONTRACT = 'metamask/confirm-transaction/UPDATE_TO_SMART_CONTRACT'
@@ -65,7 +66,9 @@ describe('Confirm Transaction Duck', () => {
ethTransactionAmount: '1',
ethTransactionFee: '0.000021',
ethTransactionTotal: '469.27',
- hexGasTotal: '0x1319718a5000',
+ hexTransactionAmount: '',
+ hexTransactionFee: '0x1319718a5000',
+ hexTransactionTotal: '',
nonce: '0x0',
toSmartContract: false,
fetchingData: false,
@@ -186,12 +189,14 @@ describe('Confirm Transaction Duck', () => {
payload: {
fiatTransactionAmount: '123.45',
ethTransactionAmount: '.5',
+ hexTransactionAmount: '0x1',
},
}),
{
...mockState.confirmTransaction,
fiatTransactionAmount: '123.45',
ethTransactionAmount: '.5',
+ hexTransactionAmount: '0x1',
}
)
})
@@ -203,12 +208,14 @@ describe('Confirm Transaction Duck', () => {
payload: {
fiatTransactionFee: '123.45',
ethTransactionFee: '.5',
+ hexTransactionFee: '0x1',
},
}),
{
...mockState.confirmTransaction,
fiatTransactionFee: '123.45',
ethTransactionFee: '.5',
+ hexTransactionFee: '0x1',
}
)
})
@@ -220,25 +227,14 @@ describe('Confirm Transaction Duck', () => {
payload: {
fiatTransactionTotal: '123.45',
ethTransactionTotal: '.5',
+ hexTransactionTotal: '0x1',
},
}),
{
...mockState.confirmTransaction,
fiatTransactionTotal: '123.45',
ethTransactionTotal: '.5',
- }
- )
- })
-
- it('should update hexGasTotal when receiving an UPDATE_HEX_GAS_TOTAL action', () => {
- assert.deepEqual(
- ConfirmTransactionReducer(mockState, {
- type: UPDATE_HEX_GAS_TOTAL,
- payload: '0x0',
- }),
- {
- ...mockState.confirmTransaction,
- hexGasTotal: '0x0',
+ hexTransactionTotal: '0x1',
}
)
})
@@ -435,19 +431,6 @@ describe('Confirm Transaction Duck', () => {
)
})
- it('should create an action to update hexGasTotal', () => {
- const hexGasTotal = '0x0'
- const expectedAction = {
- type: UPDATE_HEX_GAS_TOTAL,
- payload: hexGasTotal,
- }
-
- assert.deepEqual(
- actions.updateHexGasTotal(hexGasTotal),
- expectedAction
- )
- })
-
it('should create an action to update tokenProps', () => {
const tokenProps = {
tokenDecimals: '1',
@@ -568,7 +551,6 @@ describe('Confirm Transaction Duck', () => {
const expectedActions = [
'metamask/confirm-transaction/UPDATE_TX_DATA',
'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS',
- 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL',
'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES',
'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS',
]
@@ -637,7 +619,6 @@ describe('Confirm Transaction Duck', () => {
const expectedActions = [
'metamask/confirm-transaction/UPDATE_TX_DATA',
'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS',
- 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL',
'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES',
'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS',
]
@@ -687,7 +668,6 @@ describe('Confirm Transaction Duck', () => {
const expectedActions = [
'metamask/confirm-transaction/UPDATE_TX_DATA',
'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS',
- 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL',
'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES',
'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS',
]
diff --git a/ui/app/helpers/confirm-transaction/util.js b/ui/app/helpers/confirm-transaction/util.js
index bcac22500..eb334a4b8 100644
--- a/ui/app/helpers/confirm-transaction/util.js
+++ b/ui/app/helpers/confirm-transaction/util.js
@@ -55,6 +55,7 @@ export function addFiat (...args) {
export function getValueFromWeiHex ({
value,
+ fromCurrency = 'ETH',
toCurrency,
conversionRate,
numberOfDecimals,
@@ -63,7 +64,7 @@ export function getValueFromWeiHex ({
return conversionUtil(value, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
- fromCurrency: 'ETH',
+ fromCurrency,
toCurrency,
numberOfDecimals,
fromDenomination: 'WEI',
@@ -74,6 +75,7 @@ export function getValueFromWeiHex ({
export function getTransactionFee ({
value,
+ fromCurrency = 'ETH',
toCurrency,
conversionRate,
numberOfDecimals,
@@ -82,7 +84,7 @@ export function getTransactionFee ({
fromNumericBase: 'BN',
toNumericBase: 'dec',
fromDenomination: 'WEI',
- fromCurrency: 'ETH',
+ fromCurrency,
toCurrency,
numberOfDecimals,
conversionRate,
@@ -99,6 +101,7 @@ export function formatCurrency (value, currencyCode) {
export function convertTokenToFiat ({
value,
+ fromCurrency = 'ETH',
toCurrency,
conversionRate,
contractExchangeRate,
@@ -108,6 +111,7 @@ export function convertTokenToFiat ({
return conversionUtil(value, {
fromNumericBase: 'dec',
toNumericBase: 'dec',
+ fromCurrency,
toCurrency,
numberOfDecimals: 2,
conversionRate: totalExchangeRate,
diff --git a/ui/app/helpers/conversions.util.js b/ui/app/helpers/conversions.util.js
index 20ef9e35b..cb5e1b90b 100644
--- a/ui/app/helpers/conversions.util.js
+++ b/ui/app/helpers/conversions.util.js
@@ -20,8 +20,8 @@ export function decimalToHex (decimal) {
})
}
-export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDecimals = 6 }) {
- const denominations = [ETH, GWEI, WEI]
+export function getEthConversionFromWeiHex ({ value, fromCurrency = ETH, conversionRate, numberOfDecimals = 6 }) {
+ const denominations = [fromCurrency, GWEI, WEI]
let nonZeroDenomination
@@ -29,7 +29,8 @@ export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDec
const convertedValue = getValueFromWeiHex({
value,
conversionRate,
- toCurrency: ETH,
+ fromCurrency,
+ toCurrency: fromCurrency,
numberOfDecimals,
toDenomination: denominations[i],
})
@@ -45,6 +46,7 @@ export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDec
export function getValueFromWeiHex ({
value,
+ fromCurrency = ETH,
toCurrency,
conversionRate,
numberOfDecimals,
@@ -53,7 +55,7 @@ export function getValueFromWeiHex ({
return conversionUtil(value, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
- fromCurrency: ETH,
+ fromCurrency,
toCurrency,
numberOfDecimals,
fromDenomination: WEI,
@@ -61,3 +63,22 @@ export function getValueFromWeiHex ({
conversionRate,
})
}
+
+export function getWeiHexFromDecimalValue ({
+ value,
+ fromCurrency,
+ conversionRate,
+ fromDenomination,
+ invertConversionRate,
+}) {
+ return conversionUtil(value, {
+ fromNumericBase: 'dec',
+ toNumericBase: 'hex',
+ toCurrency: ETH,
+ fromCurrency,
+ conversionRate,
+ invertConversionRate,
+ fromDenomination,
+ toDenomination: WEI,
+ })
+}
diff --git a/ui/app/helpers/tests/transactions.util.test.js b/ui/app/helpers/tests/transactions.util.test.js
index 103a84a8c..838522e35 100644
--- a/ui/app/helpers/tests/transactions.util.test.js
+++ b/ui/app/helpers/tests/transactions.util.test.js
@@ -19,4 +19,39 @@ describe('Transactions utils', () => {
assert.doesNotThrow(() => utils.getTokenData())
})
})
+
+ describe('getStatusKey', () => {
+ it('should return the correct status', () => {
+ const tests = [
+ {
+ transaction: {
+ status: 'confirmed',
+ txReceipt: {
+ status: '0x0',
+ },
+ },
+ expected: 'failed',
+ },
+ {
+ transaction: {
+ status: 'confirmed',
+ txReceipt: {
+ status: '0x1',
+ },
+ },
+ expected: 'confirmed',
+ },
+ {
+ transaction: {
+ status: 'pending',
+ },
+ expected: 'pending',
+ },
+ ]
+
+ tests.forEach(({ transaction, expected }) => {
+ assert.equal(utils.getStatusKey(transaction), expected)
+ })
+ })
+ })
})
diff --git a/ui/app/helpers/transactions.util.js b/ui/app/helpers/transactions.util.js
index f7d249e63..2f4b1d095 100644
--- a/ui/app/helpers/transactions.util.js
+++ b/ui/app/helpers/transactions.util.js
@@ -27,10 +27,21 @@ export function getTokenData (data = '') {
const registry = new MethodRegistry({ provider: global.ethereumProvider })
+/**
+ * Attempts to return the method data from the MethodRegistry library, if the method exists in the
+ * registry. Otherwise, returns an empty object.
+ * @param {string} data - The hex data (@code txParams.data) of a transaction
+ * @returns {Object}
+ */
export async function getMethodData (data = '') {
const prefixedData = ethUtil.addHexPrefix(data)
const fourBytePrefix = prefixedData.slice(0, 10)
const sig = await registry.lookup(fourBytePrefix)
+
+ if (!sig) {
+ return {}
+ }
+
const parsedResult = registry.parse(sig)
return {
@@ -114,7 +125,9 @@ export function getLatestSubmittedTxWithNonce (transactions = [], nonce = '0x0')
export async function isSmartContractAddress (address) {
const code = await global.eth.getCode(address)
- return code && code !== '0x'
+ // Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
+ const codeIsEmpty = !code || code === '0x' || code === '0x0'
+ return !codeIsEmpty
}
export function sumHexes (...args) {
@@ -126,3 +139,21 @@ export function sumHexes (...args) {
return ethUtil.addHexPrefix(total)
}
+
+/**
+ * Returns a status key for a transaction. Requires parsing the txMeta.txReceipt on top of
+ * txMeta.status because txMeta.status does not reflect on-chain errors.
+ * @param {Object} transaction - The txMeta object of a transaction.
+ * @param {Object} transaction.txReceipt - The transaction receipt.
+ * @returns {string}
+ */
+export function getStatusKey (transaction) {
+ const { txReceipt: { status } = {} } = transaction
+
+ // There was an on-chain failure
+ if (status === '0x0') {
+ return 'failed'
+ }
+
+ return transaction.status
+}
diff --git a/ui/app/reducers.js b/ui/app/reducers.js
index 80e76d570..e1a982f93 100644
--- a/ui/app/reducers.js
+++ b/ui/app/reducers.js
@@ -1,3 +1,4 @@
+const clone = require('clone')
const extend = require('xtend')
const copyToClipboard = require('copy-to-clipboard')
@@ -52,19 +53,24 @@ function rootReducer (state, action) {
return state
}
+window.getCleanAppState = function () {
+ const state = clone(window.METAMASK_CACHED_LOG_STATE)
+ // append additional information
+ state.version = global.platform.getVersion()
+ state.browser = window.navigator.userAgent
+ // ensure seedWords are not included
+ if (state.metamask) delete state.metamask.seedWords
+ if (state.appState.currentView) delete state.appState.currentView.seedWords
+ return state
+}
+
window.logStateString = function (cb) {
- const state = window.METAMASK_CACHED_LOG_STATE
- const version = global.platform.getVersion()
- const browser = window.navigator.userAgent
- return global.platform.getPlatformInfo((err, platform) => {
- if (err) {
- return cb(err)
- }
- state.version = version
+ const state = window.getCleanAppState()
+ global.platform.getPlatformInfo((err, platform) => {
+ if (err) return cb(err)
state.platform = platform
- state.browser = browser
const stateString = JSON.stringify(state, removeSeedWords, 2)
- return cb(null, stateString)
+ cb(null, stateString)
})
}
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index de19def6d..982b26868 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -51,6 +51,9 @@ function reduceMetamask (state, action) {
isRevealingSeedWords: false,
welcomeScreenSeen: false,
currentLocale: '',
+ preferences: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ },
}, state.metamask)
switch (action.type) {
@@ -367,6 +370,12 @@ function reduceMetamask (state, action) {
})
}
+ case actions.UPDATE_PREFERENCES: {
+ return extend(metamaskState, {
+ preferences: { ...action.payload },
+ })
+ }
+
default:
return metamaskState
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
index fb4517628..7209f19d1 100644
--- a/ui/app/selectors.js
+++ b/ui/app/selectors.js
@@ -26,6 +26,7 @@ const selectors = {
getAddressBook,
getSendFrom,
getCurrentCurrency,
+ getNativeCurrency,
getSendAmount,
getSelectedTokenToFiatRate,
getSelectedTokenContract,
@@ -33,6 +34,7 @@ const selectors = {
getSendMaxModeState,
getCurrentViewContext,
getTotalUnapprovedCount,
+ preferencesSelector,
}
module.exports = selectors
@@ -142,6 +144,10 @@ function getCurrentCurrency (state) {
return state.metamask.currentCurrency
}
+function getNativeCurrency (state) {
+ return state.metamask.nativeCurrency
+}
+
function getSelectedTokenToFiatRate (state) {
const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state)
const conversionRate = conversionRateSelector(state)
@@ -195,3 +201,7 @@ function getTotalUnapprovedCount ({ metamask }) {
return Object.keys(unapprovedTxs).length + unapprovedMsgCount + unapprovedPersonalMsgCount +
unapprovedTypedMessagesCount
}
+
+function preferencesSelector ({ metamask }) {
+ return metamask.preferences
+}
diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js
index 86b10bac3..90924c036 100644
--- a/ui/app/selectors/confirm-transaction.js
+++ b/ui/app/selectors/confirm-transaction.js
@@ -93,6 +93,7 @@ export const unconfirmedTransactionsCountSelector = createSelector(
export const currentCurrencySelector = state => state.metamask.currentCurrency
export const conversionRateSelector = state => state.metamask.conversionRate
+export const getNativeCurrency = state => state.metamask.nativeCurrency
const txDataSelector = state => state.confirmTransaction.txData
const tokenDataSelector = state => state.confirmTransaction.tokenData
diff --git a/ui/app/util.js b/ui/app/util.js
index 37c0fb698..b19a028cc 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -128,7 +128,7 @@ function parseBalance (balance) {
// Takes wei hex, returns an object with three properties.
// Its "formatted" property is what we generally use to render values.
-function formatBalance (balance, decimalsToKeep, needsParse = true) {
+function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') {
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
var beforeDecimal = parsed[0]
var afterDecimal = parsed[1]
@@ -138,14 +138,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) {
if (afterDecimal !== '0') {
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
if (sigFigs) { afterDecimal = sigFigs[0] }
- formatted = '0.' + afterDecimal + ' ETH'
+ formatted = '0.' + afterDecimal + ` ${ticker}`
}
} else {
- formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ' ETH'
+ formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}`
}
} else {
afterDecimal += Array(decimalsToKeep).join('0')
- formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ' ETH'
+ formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}`
}
return formatted
}
diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js
index c6a7d0bf1..db07049e1 100644
--- a/ui/i18n-helper.js
+++ b/ui/i18n-helper.js
@@ -13,7 +13,7 @@ const getMessage = (locale, key, substitutions) => {
return null
}
if (!locale[key]) {
- log.error(`Translator - Unable to find value for key "${key}"`)
+ log.warn(`Translator - Unable to find value for key "${key}"`)
return null
}
const entry = locale[key]