aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorAkihiro <an0326ja@gmail.com>2018-07-21 09:47:14 +0800
committerAkihiro <an0326ja@gmail.com>2018-07-21 09:47:14 +0800
commit8c77e998e0491dfb48c91d2938644c9f855a2532 (patch)
treef3e54e635c92d54111ac2ddfc3e780ccdcdaf968 /ui
parent9dd637569d5c820d07ff15a8039f5ce5590f41dd (diff)
parente094d4ad1fb84a9bc663c328d0650bd9d8bf8716 (diff)
downloadtangerine-wallet-browser-8c77e998e0491dfb48c91d2938644c9f855a2532.tar.gz
tangerine-wallet-browser-8c77e998e0491dfb48c91d2938644c9f855a2532.tar.zst
tangerine-wallet-browser-8c77e998e0491dfb48c91d2938644c9f855a2532.zip
Merge remote-tracking branch 'upstream/develop' into develop
Diffstat (limited to 'ui')
-rw-r--r--ui/app/actions.js136
-rw-r--r--ui/app/app.js22
-rw-r--r--ui/app/components/account-menu/index.js69
-rw-r--r--ui/app/components/alert/index.js22
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js18
-rw-r--r--ui/app/components/customize-gas-modal/index.js6
-rw-r--r--ui/app/components/dropdowns/account-dropdown-mini.js2
-rw-r--r--ui/app/components/ens-input.js2
-rw-r--r--ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js93
-rw-r--r--ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js20
-rw-r--r--ui/app/components/modals/confirm-remove-account/index.js2
-rw-r--r--ui/app/components/modals/customize-gas/customize-gas.component.js2
-rw-r--r--ui/app/components/modals/index.scss52
-rw-r--r--ui/app/components/modals/modal.js14
-rw-r--r--ui/app/components/network-display/index.scss6
-rw-r--r--ui/app/components/pages/confirm-approve/confirm-approve.component.js19
-rw-r--r--ui/app/components/pages/confirm-approve/confirm-approve.container.js19
-rw-r--r--ui/app/components/pages/confirm-send-token/confirm-send-token.component.js20
-rw-r--r--ui/app/components/pages/confirm-send-token/confirm-send-token.container.js26
-rw-r--r--ui/app/components/pages/confirm-send-token/index.scss19
-rw-r--r--ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js85
-rw-r--r--ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js34
-rw-r--r--ui/app/components/pages/confirm-token-transaction-base/index.js2
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js42
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js18
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js20
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js1
-rw-r--r--ui/app/components/pages/confirm-transaction/confirm-transaction.component.js7
-rw-r--r--ui/app/components/pages/create-account/connect-hardware/account-list.js143
-rw-r--r--ui/app/components/pages/create-account/connect-hardware/connect-screen.js149
-rw-r--r--ui/app/components/pages/create-account/connect-hardware/index.js234
-rw-r--r--ui/app/components/pages/create-account/index.js25
-rw-r--r--ui/app/components/pages/create-account/new-account.js2
-rw-r--r--ui/app/components/pages/index.scss2
-rw-r--r--ui/app/components/pending-tx/confirm-deploy-contract.js358
-rw-r--r--ui/app/components/pending-tx/confirm-send-ether.js692
-rw-r--r--ui/app/components/pending-tx/confirm-send-token.js696
-rw-r--r--ui/app/components/pending-tx/index.js165
-rw-r--r--ui/app/components/selected-account/selected-account.component.js11
-rw-r--r--ui/app/components/send/README.md (renamed from ui/app/components/send_/README.md)0
-rw-r--r--ui/app/components/send/account-list-item/account-list-item-README.md (renamed from ui/app/components/send_/account-list-item/account-list-item-README.md)0
-rw-r--r--ui/app/components/send/account-list-item/account-list-item.component.js (renamed from ui/app/components/send_/account-list-item/account-list-item.component.js)2
-rw-r--r--ui/app/components/send/account-list-item/account-list-item.container.js (renamed from ui/app/components/send_/account-list-item/account-list-item.container.js)0
-rw-r--r--ui/app/components/send/account-list-item/account-list-item.scss (renamed from ui/app/components/send_/account-list-item/account-list-item.scss)0
-rw-r--r--ui/app/components/send/account-list-item/index.js (renamed from ui/app/components/send_/account-list-item/index.js)0
-rw-r--r--ui/app/components/send/account-list-item/tests/account-list-item-component.test.js (renamed from ui/app/components/send_/account-list-item/tests/account-list-item-component.test.js)2
-rw-r--r--ui/app/components/send/account-list-item/tests/account-list-item-container.test.js (renamed from ui/app/components/send_/account-list-item/tests/account-list-item-container.test.js)0
-rw-r--r--ui/app/components/send/currency-display/currency-display.js (renamed from ui/app/components/send/currency-display.js)43
-rw-r--r--ui/app/components/send/currency-display/index.js1
-rw-r--r--ui/app/components/send/index.js (renamed from ui/app/components/send_/index.js)0
-rw-r--r--ui/app/components/send/send-content/index.js (renamed from ui/app/components/send_/send-content/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/README.md (renamed from ui/app/components/send_/send-content/send-amount-row/README.md)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/index.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/index.js (renamed from ui/app/components/send_/send-content/send-amount-row/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js (renamed from ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js)2
-rw-r--r--ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js (renamed from ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/send-amount-row.scss (renamed from ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/send-amount-row.selectors.js (renamed from ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js)2
-rw-r--r--ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-container.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-selectors.test.js (renamed from ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-content-README.md (renamed from ui/app/components/send_/send-content/send-content-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-content.component.js (renamed from ui/app/components/send_/send-content/send-content.component.js)2
-rw-r--r--ui/app/components/send/send-content/send-content.scss (renamed from ui/app/components/send_/send-content/send-content.scss)0
-rw-r--r--ui/app/components/send/send-content/send-dropdown-list/index.js (renamed from ui/app/components/send_/send-content/send-dropdown-list/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-dropdown-list/send-dropdown-list.component.js (renamed from ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js (renamed from ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown-README.md (renamed from ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js (renamed from ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.scss (renamed from ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/from-dropdown/index.js (renamed from ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js (renamed from ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/index.js (renamed from ui/app/components/send_/send-content/send-from-row/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/send-from-row-README.md (renamed from ui/app/components/send_/send-content/send-from-row/send-from-row-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/send-from-row.component.js (renamed from ui/app/components/send_/send-content/send-from-row/send-from-row.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/send-from-row.container.js (renamed from ui/app/components/send_/send-content/send-from-row/send-from-row.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/send-from-row.selectors.js (renamed from ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/tests/send-from-row-component.test.js (renamed from ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/tests/send-from-row-container.test.js (renamed from ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-from-row/tests/send-from-row-selectors.test.js (renamed from ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/README.md (renamed from ui/app/components/send_/send-content/send-gas-row/README.md)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js (renamed from ui/app/components/send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/gas-fee-display/index.js (renamed from ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js (renamed from ui/app/components/send_/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/index.js (renamed from ui/app/components/send_/send-content/send-gas-row/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js (renamed from ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js (renamed from ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/send-gas-row.scss (renamed from ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/send-gas-row.selectors.js (renamed from ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-component.test.js (renamed from ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-container.test.js (renamed from ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-selectors.test.js (renamed from ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-hex-data-row/index.js1
-rw-r--r--ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js40
-rw-r--r--ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.container.js21
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/index.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/index.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper-README.md (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.scss (renamed from ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss)0
-rw-r--r--ui/app/components/send/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js (renamed from ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/index.js (renamed from ui/app/components/send_/send-content/send-to-row/index.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row-README.md (renamed from ui/app/components/send_/send-content/send-to-row/send-to-row-README.md)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.component.js (renamed from ui/app/components/send_/send-content/send-to-row/send-to-row.component.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.container.js (renamed from ui/app/components/send_/send-content/send-to-row/send-to-row.container.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js (renamed from ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.utils.js (renamed from ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js (renamed from ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js (renamed from ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/tests/send-to-row-selectors.test.js (renamed from ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js (renamed from ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js)0
-rw-r--r--ui/app/components/send/send-content/tests/send-content-component.test.js (renamed from ui/app/components/send_/send-content/tests/send-content-component.test.js)0
-rw-r--r--ui/app/components/send/send-footer/README.md (renamed from ui/app/components/send_/send-footer/README.md)0
-rw-r--r--ui/app/components/send/send-footer/index.js (renamed from ui/app/components/send_/send-footer/index.js)0
-rw-r--r--ui/app/components/send/send-footer/send-footer.component.js (renamed from ui/app/components/send_/send-footer/send-footer.component.js)5
-rw-r--r--ui/app/components/send/send-footer/send-footer.container.js (renamed from ui/app/components/send_/send-footer/send-footer.container.js)7
-rw-r--r--ui/app/components/send/send-footer/send-footer.scss (renamed from ui/app/components/send_/send-footer/send-footer.scss)0
-rw-r--r--ui/app/components/send/send-footer/send-footer.selectors.js (renamed from ui/app/components/send_/send-footer/send-footer.selectors.js)0
-rw-r--r--ui/app/components/send/send-footer/send-footer.utils.js (renamed from ui/app/components/send_/send-footer/send-footer.utils.js)38
-rw-r--r--ui/app/components/send/send-footer/tests/send-footer-component.test.js (renamed from ui/app/components/send_/send-footer/tests/send-footer-component.test.js)2
-rw-r--r--ui/app/components/send/send-footer/tests/send-footer-container.test.js (renamed from ui/app/components/send_/send-footer/tests/send-footer-container.test.js)5
-rw-r--r--ui/app/components/send/send-footer/tests/send-footer-selectors.test.js (renamed from ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js)0
-rw-r--r--ui/app/components/send/send-footer/tests/send-footer-utils.test.js (renamed from ui/app/components/send_/send-footer/tests/send-footer-utils.test.js)24
-rw-r--r--ui/app/components/send/send-header/README.md (renamed from ui/app/components/send_/send-header/README.md)0
-rw-r--r--ui/app/components/send/send-header/index.js (renamed from ui/app/components/send_/send-header/index.js)0
-rw-r--r--ui/app/components/send/send-header/send-header.component.js (renamed from ui/app/components/send_/send-header/send-header.component.js)0
-rw-r--r--ui/app/components/send/send-header/send-header.container.js (renamed from ui/app/components/send_/send-header/send-header.container.js)0
-rw-r--r--ui/app/components/send/send-header/send-header.selectors.js (renamed from ui/app/components/send_/send-header/send-header.selectors.js)0
-rw-r--r--ui/app/components/send/send-header/tests/send-header-component.test.js (renamed from ui/app/components/send_/send-header/tests/send-header-component.test.js)0
-rw-r--r--ui/app/components/send/send-header/tests/send-header-container.test.js (renamed from ui/app/components/send_/send-header/tests/send-header-container.test.js)0
-rw-r--r--ui/app/components/send/send-header/tests/send-header-selectors.test.js (renamed from ui/app/components/send_/send-header/tests/send-header-selectors.test.js)0
-rw-r--r--ui/app/components/send/send.component.js (renamed from ui/app/components/send_/send.component.js)0
-rw-r--r--ui/app/components/send/send.constants.js (renamed from ui/app/components/send_/send.constants.js)0
-rw-r--r--ui/app/components/send/send.container.js (renamed from ui/app/components/send_/send.container.js)0
-rw-r--r--ui/app/components/send/send.scss (renamed from ui/app/components/send_/send.scss)0
-rw-r--r--ui/app/components/send/send.selectors.js (renamed from ui/app/components/send_/send.selectors.js)5
-rw-r--r--ui/app/components/send/send.utils.js (renamed from ui/app/components/send_/send.utils.js)0
-rw-r--r--ui/app/components/send/tests/send-component.test.js (renamed from ui/app/components/send_/tests/send-component.test.js)0
-rw-r--r--ui/app/components/send/tests/send-container.test.js (renamed from ui/app/components/send_/tests/send-container.test.js)0
-rw-r--r--ui/app/components/send/tests/send-selectors-test-data.js (renamed from ui/app/components/send_/tests/send-selectors-test-data.js)0
-rw-r--r--ui/app/components/send/tests/send-selectors.test.js (renamed from ui/app/components/send_/tests/send-selectors.test.js)0
-rw-r--r--ui/app/components/send/tests/send-utils.test.js (renamed from ui/app/components/send_/tests/send-utils.test.js)26
-rw-r--r--ui/app/components/send/to-autocomplete.component.js2
-rw-r--r--ui/app/components/send/to-autocomplete/index.js1
-rw-r--r--ui/app/components/send/to-autocomplete/to-autocomplete.js120
-rw-r--r--ui/app/components/send_/send.utils.test.js30
-rw-r--r--ui/app/components/tx-list-item.js24
-rw-r--r--ui/app/components/wallet-view.js2
-rw-r--r--ui/app/conf-tx.js136
-rw-r--r--ui/app/css/itcss/components/account-menu.scss18
-rw-r--r--ui/app/css/itcss/components/alert.scss57
-rw-r--r--ui/app/css/itcss/components/index.scss2
-rw-r--r--ui/app/css/itcss/components/new-account.scss297
-rw-r--r--ui/app/css/itcss/components/send.scss4
-rw-r--r--ui/app/css/itcss/components/transaction-list.scss10
-rw-r--r--ui/app/helpers/confirm-transaction/util.js17
-rw-r--r--ui/app/reducers/app.js15
-rw-r--r--ui/app/reducers/metamask.js8
-rw-r--r--ui/app/routes.js4
-rw-r--r--ui/app/selectors/confirm-transaction.js99
-rw-r--r--ui/app/util.js9
175 files changed, 2058 insertions, 2280 deletions
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 1fb49c920..6c947fc35 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -6,7 +6,7 @@ const {
calcGasTotal,
calcTokenBalance,
estimateGas,
-} = require('./components/send_/send.utils')
+} = require('./components/send/send.utils')
const ethUtil = require('ethereumjs-util')
const { fetchLocale } = require('../i18n-helper')
const log = require('loglevel')
@@ -26,6 +26,11 @@ var actions = {
SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE',
showSidebar: showSidebar,
hideSidebar: hideSidebar,
+ // sidebar state
+ ALERT_OPEN: 'UI_ALERT_OPEN',
+ ALERT_CLOSE: 'UI_ALERT_CLOSE',
+ showAlert: showAlert,
+ hideAlert: hideAlert,
// network dropdown open
NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN',
NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE',
@@ -78,9 +83,14 @@ var actions = {
addNewKeyring,
importNewAccount,
addNewAccount,
+ connectHardware,
+ checkHardwareStatus,
+ forgetDevice,
+ unlockTrezorAccount,
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
navigateToNewAccountScreen,
resetAccount,
+ removeAccount,
showNewVaultSeed: showNewVaultSeed,
showInfoPage: showInfoPage,
CLOSE_WELCOME_SCREEN: 'CLOSE_WELCOME_SCREEN',
@@ -164,6 +174,7 @@ var actions = {
UPDATE_GAS_PRICE: 'UPDATE_GAS_PRICE',
UPDATE_GAS_TOTAL: 'UPDATE_GAS_TOTAL',
UPDATE_SEND_FROM: 'UPDATE_SEND_FROM',
+ UPDATE_SEND_HEX_DATA: 'UPDATE_SEND_HEX_DATA',
UPDATE_SEND_TOKEN_BALANCE: 'UPDATE_SEND_TOKEN_BALANCE',
UPDATE_SEND_TO: 'UPDATE_SEND_TO',
UPDATE_SEND_AMOUNT: 'UPDATE_SEND_AMOUNT',
@@ -183,6 +194,7 @@ var actions = {
setSendTokenBalance,
updateSendTokenBalance,
updateSendFrom,
+ updateSendHexData,
updateSendTo,
updateSendAmount,
updateSendMemo,
@@ -533,6 +545,26 @@ function resetAccount () {
}
}
+function removeAccount (address) {
+ return dispatch => {
+ dispatch(actions.showLoadingIndication())
+
+ return new Promise((resolve, reject) => {
+ background.removeAccount(address, (err, account) => {
+ dispatch(actions.hideLoadingIndication())
+ if (err) {
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ log.info('Account removed: ' + account)
+ dispatch(actions.showAccountsPage())
+ resolve()
+ })
+ })
+ }
+}
+
function addNewKeyring (type, opts) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@@ -599,6 +631,88 @@ function addNewAccount () {
}
}
+function checkHardwareStatus (deviceName) {
+ log.debug(`background.checkHardwareStatus`, deviceName)
+ return (dispatch, getState) => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.checkHardwareStatus(deviceName, (err, unlocked) => {
+ if (err) {
+ log.error(err)
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.hideLoadingIndication())
+
+ forceUpdateMetamaskState(dispatch)
+ return resolve(unlocked)
+ })
+ })
+ }
+}
+
+function forgetDevice (deviceName) {
+ log.debug(`background.forgetDevice`, deviceName)
+ return (dispatch, getState) => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.forgetDevice(deviceName, (err, response) => {
+ if (err) {
+ log.error(err)
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.hideLoadingIndication())
+
+ forceUpdateMetamaskState(dispatch)
+ return resolve()
+ })
+ })
+ }
+}
+
+function connectHardware (deviceName, page) {
+ log.debug(`background.connectHardware`, deviceName, page)
+ return (dispatch, getState) => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.connectHardware(deviceName, page, (err, accounts) => {
+ if (err) {
+ log.error(err)
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.hideLoadingIndication())
+
+ forceUpdateMetamaskState(dispatch)
+ return resolve(accounts)
+ })
+ })
+ }
+}
+
+function unlockTrezorAccount (index) {
+ log.debug(`background.unlockTrezorAccount`, index)
+ return (dispatch, getState) => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.unlockTrezorAccount(index, (err, accounts) => {
+ if (err) {
+ log.error(err)
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.hideLoadingIndication())
+ return resolve()
+ })
+ })
+ }
+}
+
function showInfoPage () {
return {
type: actions.SHOW_INFO_PAGE,
@@ -838,6 +952,13 @@ function updateSendFrom (from) {
}
}
+function updateSendHexData (value) {
+ return {
+ type: actions.UPDATE_SEND_HEX_DATA,
+ value,
+ }
+}
+
function updateSendTo (to, nickname = '') {
return {
type: actions.UPDATE_SEND_TO,
@@ -1617,6 +1738,19 @@ function hideSidebar () {
}
}
+function showAlert (msg) {
+ return {
+ type: actions.ALERT_OPEN,
+ value: msg,
+ }
+}
+
+function hideAlert () {
+ return {
+ type: actions.ALERT_CLOSE,
+ }
+}
+
function showLoadingIndication (message) {
return {
diff --git a/ui/app/app.js b/ui/app/app.js
index 74d360d3c..dbb6146d1 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -11,7 +11,7 @@ const log = require('loglevel')
// init
const InitializeScreen = require('../../mascara/src/app/first-time').default
// accounts
-const SendTransactionScreen = require('./components/send_/send.container')
+const SendTransactionScreen = require('./components/send/send.container')
const ConfirmTransaction = require('./components/pages/confirm-transaction')
// slideout menu
@@ -36,6 +36,8 @@ const AccountMenu = require('./components/account-menu')
// Global Modals
const Modal = require('./components/modals/index').Modal
+// Global Alert
+const Alert = require('./components/alert')
const AppHeader = require('./components/app-header')
@@ -93,6 +95,7 @@ class App extends Component {
render () {
const {
isLoading,
+ alertMessage,
loadingMessage,
network,
isMouseUser,
@@ -126,6 +129,9 @@ class App extends Component {
// global modal
h(Modal, {}, []),
+ // global alert
+ h(Alert, {visible: this.props.alertOpen, msg: alertMessage}),
+
h(AppHeader),
// sidebar
@@ -149,14 +155,6 @@ class App extends Component {
)
}
- renderGlobalModal () {
- return h(Modal, {
- ref: 'modalRef',
- }, [
- // h(BuyOptions, {}, []),
- ])
- }
-
renderSidebar () {
return h('div', [
h('style', `
@@ -265,11 +263,13 @@ App.propTypes = {
setCurrentCurrencyToUSD: PropTypes.func,
isLoading: PropTypes.bool,
loadingMessage: PropTypes.string,
+ alertMessage: PropTypes.string,
network: PropTypes.string,
provider: PropTypes.object,
frequentRpcList: PropTypes.array,
currentView: PropTypes.object,
sidebarOpen: PropTypes.bool,
+ alertOpen: PropTypes.bool,
hideSidebar: PropTypes.func,
isMascara: PropTypes.bool,
isOnboarding: PropTypes.bool,
@@ -305,6 +305,8 @@ function mapStateToProps (state) {
const {
networkDropdownOpen,
sidebarOpen,
+ alertOpen,
+ alertMessage,
isLoading,
loadingMessage,
} = appState
@@ -330,6 +332,8 @@ function mapStateToProps (state) {
// state from plugin
networkDropdownOpen,
sidebarOpen,
+ alertOpen,
+ alertMessage,
isLoading,
loadingMessage,
noActiveNotices,
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index f34631ca8..9c063d31e 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -9,11 +9,17 @@ 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')
+
+
const {
SETTINGS_ROUTE,
INFO_ROUTE,
NEW_ACCOUNT_ROUTE,
IMPORT_ACCOUNT_ROUTE,
+ CONNECT_HARDWARE_ROUTE,
DEFAULT_ROUTE,
} = require('../../routes')
@@ -63,6 +69,9 @@ function mapDispatchToProps (dispatch) {
dispatch(actions.hideSidebar())
dispatch(actions.toggleAccountMenu())
},
+ showRemoveAccountConfirmationModal: (identity) => {
+ return dispatch(actions.showModal({ name: 'CONFIRM_REMOVE_ACCOUNT', identity }))
+ },
}
}
@@ -106,6 +115,18 @@ AccountMenu.prototype.render = function () {
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
text: this.context.t('importAccount'),
}),
+ h(Item, {
+ onClick: () => {
+ toggleAccountMenu()
+ if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
+ global.platform.openExtensionInBrowser(CONNECT_HARDWARE_ROUTE)
+ } else {
+ history.push(CONNECT_HARDWARE_ROUTE)
+ }
+ },
+ icon: h('img.account-menu__item-icon', { src: 'images/connect-icon.svg' }),
+ text: this.context.t('connectHardwareWallet'),
+ }),
h(Divider),
h(Item, {
onClick: () => {
@@ -136,7 +157,8 @@ AccountMenu.prototype.renderAccounts = function () {
} = this.props
const accountOrder = keyrings.reduce((list, keyring) => list.concat(keyring.accounts), [])
- return accountOrder.map((address) => {
+ return accountOrder.filter(address => !!identities[address]).map((address) => {
+
const identity = identities[address]
const isSelected = identity.address === selectedAddress
@@ -170,16 +192,53 @@ AccountMenu.prototype.renderAccounts = function () {
h('div.account-menu__balance', formattedBalance),
]),
- this.indicateIfLoose(keyring),
+ this.renderKeyringType(keyring),
+ this.renderRemoveAccount(keyring, identity),
],
)
})
}
-AccountMenu.prototype.indicateIfLoose = function (keyring) {
+AccountMenu.prototype.renderRemoveAccount = function (keyring, identity) {
+ // Any account that's not from the HD wallet Keyring can be removed
+ const type = keyring.type
+ const isRemovable = type !== 'HD Key Tree'
+ if (isRemovable) {
+ return h(Tooltip, {
+ title: this.context.t('removeAccount'),
+ position: 'bottom',
+ }, [
+ h('a.remove-account-icon', {
+ onClick: (e) => this.removeAccount(e, identity),
+ }, ''),
+ ])
+ }
+ return null
+}
+
+AccountMenu.prototype.removeAccount = function (e, identity) {
+ e.preventDefault()
+ e.stopPropagation()
+ const { showRemoveAccountConfirmationModal } = this.props
+ showRemoveAccountConfirmationModal(identity)
+}
+
+AccountMenu.prototype.renderKeyringType = function (keyring) {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
- const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label.allcaps', this.context.t('imported')) : null
+ let label
+ switch (type) {
+ case 'Trezor Hardware':
+ label = this.context.t('hardware')
+ break
+ case 'Simple Key Pair':
+ label = this.context.t('imported')
+ break
+ default:
+ label = ''
+ }
+
+ return label !== '' ? h('.keyring-label.allcaps', label) : null
+
} catch (e) { return }
}
diff --git a/ui/app/components/alert/index.js b/ui/app/components/alert/index.js
new file mode 100644
index 000000000..fc39d41e2
--- /dev/null
+++ b/ui/app/components/alert/index.js
@@ -0,0 +1,22 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+
+class Alert extends Component {
+
+ render () {
+ const className = `.global-alert${this.props.visible ? '.visible' : '.hidden'}`
+ return (
+ h(`div${className}`, {},
+ h('a.msg', {}, this.props.msg)
+ )
+ )
+ }
+}
+
+Alert.propTypes = {
+ visible: PropTypes.bool.isRequired,
+ msg: PropTypes.string,
+}
+module.exports = Alert
+
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 631cf5803..f0703dde2 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
@@ -5,10 +5,10 @@ import classnames from 'classnames'
const ConfirmDetailRow = props => {
const {
label,
- fiatFee,
- ethFee,
+ fiatText,
+ ethText,
onHeaderClick,
- fiatFeeColor,
+ fiatTextColor,
headerText,
headerTextClassName,
} = props
@@ -27,12 +27,12 @@ const ConfirmDetailRow = props => {
</div>
<div
className="confirm-detail-row__fiat"
- style={{ color: fiatFeeColor }}
+ style={{ color: fiatTextColor }}
>
- { fiatFee }
+ { fiatText }
</div>
<div className="confirm-detail-row__eth">
- { `\u2666 ${ethFee}` }
+ { ethText }
</div>
</div>
</div>
@@ -41,9 +41,9 @@ const ConfirmDetailRow = props => {
ConfirmDetailRow.propTypes = {
label: PropTypes.string,
- fiatFee: PropTypes.string,
- ethFee: PropTypes.string,
- fiatFeeColor: PropTypes.string,
+ fiatText: PropTypes.string,
+ ethText: PropTypes.string,
+ fiatTextColor: PropTypes.string,
onHeaderClick: PropTypes.func,
headerText: PropTypes.string,
headerTextClassName: PropTypes.string,
diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js
index cefa428b9..c255fd64d 100644
--- a/ui/app/components/customize-gas-modal/index.js
+++ b/ui/app/components/customize-gas-modal/index.js
@@ -16,11 +16,11 @@ const {
MIN_GAS_PRICE_DEC,
MIN_GAS_LIMIT_DEC,
MIN_GAS_PRICE_GWEI,
-} = require('../send_/send.constants')
+} = require('../send/send.constants')
const {
isBalanceSufficient,
-} = require('../send_/send.utils')
+} = require('../send/send.utils')
const {
conversionUtil,
@@ -45,7 +45,7 @@ const {
const {
getGasPrice,
getGasLimit,
-} = require('../send_/send.selectors')
+} = require('../send/send.selectors')
function mapStateToProps (state) {
const selectedToken = getSelectedToken(state)
diff --git a/ui/app/components/dropdowns/account-dropdown-mini.js b/ui/app/components/dropdowns/account-dropdown-mini.js
index a7a908d3b..261eb0aa2 100644
--- a/ui/app/components/dropdowns/account-dropdown-mini.js
+++ b/ui/app/components/dropdowns/account-dropdown-mini.js
@@ -1,7 +1,7 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const AccountListItem = require('../send_/account-list-item/account-list-item.component').default
+const AccountListItem = require('../send/account-list-item/account-list-item.component').default
module.exports = AccountDropdownMini
diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js
index adbf2dba8..b9f99b3d1 100644
--- a/ui/app/components/ens-input.js
+++ b/ui/app/components/ens-input.js
@@ -10,7 +10,7 @@ const networkMap = require('ethjs-ens/lib/network-map.json')
const ensRE = /.+\..+$/
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
const connect = require('react-redux').connect
-const ToAutoComplete = require('./send/to-autocomplete.component').default
+const ToAutoComplete = require('./send/to-autocomplete').default
const log = require('loglevel')
const { isValidENSAddress } = require('../util')
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
new file mode 100644
index 000000000..5a9f0f289
--- /dev/null
+++ b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js
@@ -0,0 +1,93 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Button from '../../button'
+import { addressSummary } from '../../../util'
+import Identicon from '../../identicon'
+import genAccountLink from '../../../../lib/account-link'
+
+class ConfirmRemoveAccount extends Component {
+ static propTypes = {
+ hideModal: PropTypes.func.isRequired,
+ removeAccount: PropTypes.func.isRequired,
+ identity: PropTypes.object.isRequired,
+ network: PropTypes.string.isRequired,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ handleRemove () {
+ this.props.removeAccount(this.props.identity.address)
+ .then(() => this.props.hideModal())
+ }
+
+ renderSelectedAccount () {
+ const { identity } = this.props
+ return (
+ <div className="modal-container__account">
+ <div className="modal-container__account__identicon">
+ <Identicon
+ address={identity.address}
+ diameter={32}
+ />
+ </div>
+ <div className="modal-container__account__name">
+ <span className="modal-container__account__label">Name</span>
+ <span className="account_value">{identity.name}</span>
+ </div>
+ <div className="modal-container__account__address">
+ <span className="modal-container__account__label">Public Address</span>
+ <span className="account_value">{ addressSummary(identity.address, 4, 4) }</span>
+ </div>
+ <div className="modal-container__account__link">
+ <a
+ className=""
+ href={genAccountLink(identity.address, this.props.network)}
+ target={'_blank'}
+ title={this.context.t('etherscanView')}
+ >
+ <img src="images/popout.svg" />
+ </a>
+ </div>
+ </div>
+ )
+ }
+
+ render () {
+ const { t } = this.context
+
+ return (
+ <div className="modal-container">
+ <div className="modal-container__content">
+ <div className="modal-container__title">
+ { `${t('removeAccount')}` }?
+ </div>
+ { this.renderSelectedAccount() }
+ <div className="modal-container__description">
+ { t('removeAccountDescription') }
+ <a className="modal-container__link" rel="noopener noreferrer" target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-">{ t('learnMore') }</a>
+ </div>
+ </div>
+ <div className="modal-container__footer">
+ <Button
+ type="default"
+ className="modal-container__footer-button"
+ onClick={() => this.props.hideModal()}
+ >
+ { t('nevermind') }
+ </Button>
+ <Button
+ type="secondary"
+ className="modal-container__footer-button"
+ onClick={() => this.handleRemove()}
+ >
+ { t('remove') }
+ </Button>
+ </div>
+ </div>
+ )
+ }
+}
+
+export default ConfirmRemoveAccount
diff --git a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js
new file mode 100644
index 000000000..4b194c995
--- /dev/null
+++ b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js
@@ -0,0 +1,20 @@
+import { connect } from 'react-redux'
+import ConfirmRemoveAccount from './confirm-remove-account.component'
+
+const { hideModal, removeAccount } = require('../../../actions')
+
+const mapStateToProps = state => {
+ return {
+ identity: state.appState.modal.modalState.props.identity,
+ network: state.metamask.network,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ hideModal: () => dispatch(hideModal()),
+ removeAccount: (address) => dispatch(removeAccount(address)),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ConfirmRemoveAccount)
diff --git a/ui/app/components/modals/confirm-remove-account/index.js b/ui/app/components/modals/confirm-remove-account/index.js
new file mode 100644
index 000000000..9763fbe05
--- /dev/null
+++ b/ui/app/components/modals/confirm-remove-account/index.js
@@ -0,0 +1,2 @@
+import ConfirmRemoveAccount from './confirm-remove-account.container'
+module.exports = ConfirmRemoveAccount
diff --git a/ui/app/components/modals/customize-gas/customize-gas.component.js b/ui/app/components/modals/customize-gas/customize-gas.component.js
index d17c290b6..0337c5413 100644
--- a/ui/app/components/modals/customize-gas/customize-gas.component.js
+++ b/ui/app/components/modals/customize-gas/customize-gas.component.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import GasModalCard from '../../customize-gas-modal/gas-modal-card'
-import { MIN_GAS_PRICE_GWEI } from '../../send_/send.constants'
+import { MIN_GAS_PRICE_GWEI } from '../../send/send.constants'
import {
getDecimalGasLimit,
diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss
index 160911c10..e198cca44 100644
--- a/ui/app/components/modals/index.scss
+++ b/ui/app/components/modals/index.scss
@@ -20,6 +20,58 @@
font-size: .875rem;
}
+ &__account {
+ border: 1px solid #b7b7b7;
+ border-radius: 4px;
+ padding: 10px;
+ display: flex;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ width: 100%;
+
+ &__identicon {
+ margin-right: 10px;
+ }
+
+ &__name,
+ &__address {
+ margin-right: 10px;
+ font-size: 14px;
+ }
+
+ &__name {
+ width: 100px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &__label {
+ font-size: 11px;
+ display: block;
+ color: #9b9b9b;
+ }
+
+ &__link {
+ margin-top: 14px;
+
+ img {
+ width: 15px;
+ height: 15px;
+ }
+ }
+
+ @media screen and (max-width: 575px) {
+ &__name {
+ width: 90px;
+ }
+ }
+ }
+
+ &__link {
+ color: #2f9ae0;
+ }
+
&__content {
overflow-y: auto;
flex: 1;
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 973438b6b..f59825ed1 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -20,6 +20,7 @@ const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
const CustomizeGasModal = require('../customize-gas-modal')
const NotifcationModal = require('./notification-modal')
const ConfirmResetAccount = require('./confirm-reset-account')
+const ConfirmRemoveAccount = require('./confirm-remove-account')
const TransactionConfirmed = require('./transaction-confirmed')
const WelcomeBeta = require('./welcome-beta')
const Notification = require('./notification')
@@ -243,6 +244,19 @@ const MODALS = {
},
},
+ CONFIRM_REMOVE_ACCOUNT: {
+ contents: h(ConfirmRemoveAccount),
+ mobileModalStyle: {
+ ...modalContainerMobileStyle,
+ },
+ laptopModalStyle: {
+ ...modalContainerLaptopStyle,
+ },
+ contentStyle: {
+ borderRadius: '8px',
+ },
+ },
+
NEW_ACCOUNT: {
contents: [
h(NewAccountModal, {}, []),
diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss
index e82d0e70c..2085cff67 100644
--- a/ui/app/components/network-display/index.scss
+++ b/ui/app/components/network-display/index.scss
@@ -9,7 +9,7 @@
height: 25px;
&--mainnet {
- background-color: lighten($blue-lagoon, 45%);
+ background-color: lighten($blue-lagoon, 68%);
}
&--ropsten {
@@ -17,11 +17,11 @@
}
&--kovan {
- background-color: lighten($purple, 45%);
+ background-color: lighten($purple, 65%);
}
&--rinkeby {
- background-color: lighten($tulip-tree, 45%);
+ background-color: lighten($tulip-tree, 35%);
}
}
diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.component.js b/ui/app/components/pages/confirm-approve/confirm-approve.component.js
index d775b0362..b71eaa1d4 100644
--- a/ui/app/components/pages/confirm-approve/confirm-approve.component.js
+++ b/ui/app/components/pages/confirm-approve/confirm-approve.component.js
@@ -1,29 +1,20 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import ConfirmTransactionBase from '../confirm-transaction-base'
+import ConfirmTokenTransactionBase from '../confirm-token-transaction-base'
export default class ConfirmApprove extends Component {
- static contextTypes = {
- t: PropTypes.func,
- }
-
static propTypes = {
- tokenAddress: PropTypes.string,
- toAddress: PropTypes.string,
- tokenAmount: PropTypes.string,
+ tokenAmount: PropTypes.number,
tokenSymbol: PropTypes.string,
}
render () {
- const { toAddress, tokenAddress, tokenAmount, tokenSymbol } = this.props
+ const { tokenAmount, tokenSymbol } = this.props
return (
- <ConfirmTransactionBase
- toAddress={toAddress}
- identiconAddress={tokenAddress}
- title={`${tokenAmount} ${tokenSymbol}`}
+ <ConfirmTokenTransactionBase
+ tokenAmount={tokenAmount}
warning={`By approving this action, you grant permission for this contract to spend up to ${tokenAmount} of your ${tokenSymbol}.`}
- hideSubtitle
/>
)
}
diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.container.js b/ui/app/components/pages/confirm-approve/confirm-approve.container.js
index 040e499ae..4ef9f4ced 100644
--- a/ui/app/components/pages/confirm-approve/confirm-approve.container.js
+++ b/ui/app/components/pages/confirm-approve/confirm-approve.container.js
@@ -1,25 +1,12 @@
import { connect } from 'react-redux'
import ConfirmApprove from './confirm-approve.component'
+import { approveTokenAmountAndToAddressSelector } from '../../../selectors/confirm-transaction'
const mapStateToProps = state => {
- const { confirmTransaction } = state
- const {
- tokenData = {},
- txData: { txParams: { to: tokenAddress } = {} } = {},
- tokenProps: { tokenSymbol } = {},
- } = confirmTransaction
- const { params = [] } = tokenData
-
- let toAddress = ''
- let tokenAmount = ''
-
- if (params && params.length === 2) {
- [{ value: toAddress }, { value: tokenAmount }] = params
- }
+ const { confirmTransaction: { tokenProps: { tokenSymbol } = {} } } = state
+ const { tokenAmount } = approveTokenAmountAndToAddressSelector(state)
return {
- toAddress,
- tokenAddress,
tokenAmount,
tokenSymbol,
}
diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js
index 46ad9ccab..cb39e3d7b 100644
--- a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js
+++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js
@@ -1,20 +1,13 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import ConfirmTransactionBase from '../confirm-transaction-base'
+import ConfirmTokenTransactionBase from '../confirm-token-transaction-base'
import { SEND_ROUTE } from '../../../routes'
export default class ConfirmSendToken extends Component {
- static contextTypes = {
- t: PropTypes.func,
- }
-
static propTypes = {
history: PropTypes.object,
- tokenAddress: PropTypes.string,
- toAddress: PropTypes.string,
- numberOfTokens: PropTypes.number,
- tokenSymbol: PropTypes.string,
editTransaction: PropTypes.func,
+ tokenAmount: PropTypes.number,
}
handleEdit (confirmTransactionData) {
@@ -24,15 +17,12 @@ export default class ConfirmSendToken extends Component {
}
render () {
- const { toAddress, tokenAddress, tokenSymbol, numberOfTokens } = this.props
+ const { tokenAmount } = this.props
return (
- <ConfirmTransactionBase
- toAddress={toAddress}
- identiconAddress={tokenAddress}
- title={`${numberOfTokens} ${tokenSymbol}`}
+ <ConfirmTokenTransactionBase
onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)}
- hideSubtitle
+ tokenAmount={tokenAmount}
/>
)
}
diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js
index 2d7efeed6..d60911e59 100644
--- a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js
+++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js
@@ -2,36 +2,16 @@ import { connect } from 'react-redux'
import { compose } from 'recompose'
import { withRouter } from 'react-router-dom'
import ConfirmSendToken from './confirm-send-token.component'
-import { calcTokenAmount } from '../../../token-util'
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck'
import { setSelectedToken, updateSend, showSendTokenPage } from '../../../actions'
import { conversionUtil } from '../../../conversion-util'
+import { sendTokenTokenAmountAndToAddressSelector } from '../../../selectors/confirm-transaction'
const mapStateToProps = state => {
- const { confirmTransaction } = state
- const {
- tokenData = {},
- tokenProps: { tokenSymbol, tokenDecimals } = {},
- txData: { txParams: { to: tokenAddress } = {} } = {},
- } = confirmTransaction
- const { params = [] } = tokenData
-
- let toAddress = ''
- let tokenAmount = ''
-
- if (params && params.length === 2) {
- [{ value: toAddress }, { value: tokenAmount }] = params
- }
-
- const numberOfTokens = tokenAmount && tokenDecimals
- ? calcTokenAmount(tokenAmount, tokenDecimals)
- : 0
+ const { tokenAmount } = sendTokenTokenAmountAndToAddressSelector(state)
return {
- toAddress,
- tokenAddress,
- tokenSymbol,
- numberOfTokens,
+ tokenAmount,
}
}
diff --git a/ui/app/components/pages/confirm-send-token/index.scss b/ui/app/components/pages/confirm-send-token/index.scss
deleted file mode 100644
index 0476749f6..000000000
--- a/ui/app/components/pages/confirm-send-token/index.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-.confirm-send-token {
- &__title {
- padding: 4px 0;
- display: flex;
- align-items: center;
- }
-
- &__identicon {
- flex: 0 0 auto;
- }
-
- &__title-text {
- font-size: 2.25rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- padding-left: 8px;
- }
-}
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
new file mode 100644
index 000000000..365ae216e
--- /dev/null
+++ b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
@@ -0,0 +1,85 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+import {
+ formatCurrency,
+ convertTokenToFiat,
+ addFiat,
+} from '../../../helpers/confirm-transaction/util'
+
+export default class ConfirmTokenTransactionBase extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ tokenAddress: PropTypes.string,
+ toAddress: PropTypes.string,
+ tokenAmount: PropTypes.number,
+ tokenSymbol: PropTypes.string,
+ fiatTransactionTotal: PropTypes.string,
+ ethTransactionTotal: PropTypes.string,
+ contractExchangeRate: PropTypes.number,
+ conversionRate: PropTypes.number,
+ currentCurrency: PropTypes.string,
+ }
+
+ getFiatTransactionAmount () {
+ const { tokenAmount, currentCurrency, conversionRate, contractExchangeRate } = this.props
+
+ return convertTokenToFiat({
+ value: tokenAmount,
+ toCurrency: currentCurrency,
+ conversionRate,
+ contractExchangeRate,
+ })
+ }
+
+ getSubtitle () {
+ const { currentCurrency, contractExchangeRate } = this.props
+
+ if (typeof contractExchangeRate === 'undefined') {
+ return this.context.t('noConversionRateAvailable')
+ } else {
+ const fiatTransactionAmount = this.getFiatTransactionAmount()
+ return formatCurrency(fiatTransactionAmount, currentCurrency)
+ }
+ }
+
+ getFiatTotalTextOverride () {
+ const { fiatTransactionTotal, currentCurrency, contractExchangeRate } = this.props
+
+ if (typeof contractExchangeRate === 'undefined') {
+ return formatCurrency(fiatTransactionTotal, currentCurrency)
+ } else {
+ const fiatTransactionAmount = this.getFiatTransactionAmount()
+ const fiatTotal = addFiat(fiatTransactionAmount, fiatTransactionTotal)
+ return formatCurrency(fiatTotal, currentCurrency)
+ }
+ }
+
+ render () {
+ const {
+ toAddress,
+ tokenAddress,
+ tokenSymbol,
+ tokenAmount,
+ ethTransactionTotal,
+ ...restProps
+ } = this.props
+
+ const tokensText = `${tokenAmount} ${tokenSymbol}`
+
+ return (
+ <ConfirmTransactionBase
+ toAddress={toAddress}
+ identiconAddress={tokenAddress}
+ title={tokensText}
+ subtitle={this.getSubtitle()}
+ ethTotalTextOverride={`${tokensText} + \u2666 ${ethTransactionTotal}`}
+ fiatTotalTextOverride={this.getFiatTotalTextOverride()}
+ {...restProps}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
new file mode 100644
index 000000000..be38acdb0
--- /dev/null
+++ b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
@@ -0,0 +1,34 @@
+import { connect } from 'react-redux'
+import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component'
+import {
+ tokenAmountAndToAddressSelector,
+ contractExchangeRateSelector,
+} from '../../../selectors/confirm-transaction'
+
+const mapStateToProps = (state, ownProps) => {
+ const { tokenAmount: ownTokenAmount } = ownProps
+ const { confirmTransaction, metamask: { currentCurrency, conversionRate } } = state
+ const {
+ txData: { txParams: { to: tokenAddress } = {} } = {},
+ tokenProps: { tokenSymbol } = {},
+ fiatTransactionTotal,
+ ethTransactionTotal,
+ } = confirmTransaction
+
+ const { tokenAmount, toAddress } = tokenAmountAndToAddressSelector(state)
+ const contractExchangeRate = contractExchangeRateSelector(state)
+
+ return {
+ toAddress,
+ tokenAddress,
+ tokenAmount: typeof ownTokenAmount !== 'undefined' ? ownTokenAmount : tokenAmount,
+ tokenSymbol,
+ currentCurrency,
+ conversionRate,
+ contractExchangeRate,
+ fiatTransactionTotal,
+ ethTransactionTotal,
+ }
+}
+
+export default connect(mapStateToProps)(ConfirmTokenTransactionBase)
diff --git a/ui/app/components/pages/confirm-token-transaction-base/index.js b/ui/app/components/pages/confirm-token-transaction-base/index.js
new file mode 100644
index 000000000..e15c5d56b
--- /dev/null
+++ b/ui/app/components/pages/confirm-token-transaction-base/index.js
@@ -0,0 +1,2 @@
+export { default } from './confirm-token-transaction-base.container'
+export { default as ConfirmTokenTransactionBase } from './confirm-token-transaction-base.component'
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 842b34d2e..e1bf2210f 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
@@ -2,7 +2,7 @@ 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 { isBalanceSufficient } from '../../send/send.utils'
import { DEFAULT_ROUTE } from '../../../routes'
import {
INSUFFICIENT_FUNDS_ERROR_KEY,
@@ -54,6 +54,8 @@ export default class ConfirmTransactionBase extends Component {
detailsComponent: PropTypes.node,
errorKey: PropTypes.string,
errorMessage: PropTypes.string,
+ ethTotalTextOverride: PropTypes.string,
+ fiatTotalTextOverride: PropTypes.string,
hideData: PropTypes.bool,
hideDetails: PropTypes.bool,
hideSubtitle: PropTypes.bool,
@@ -146,6 +148,8 @@ export default class ConfirmTransactionBase extends Component {
currentCurrency,
fiatTransactionTotal,
ethTransactionTotal,
+ fiatTotalTextOverride,
+ ethTotalTextOverride,
hideDetails,
} = this.props
@@ -153,14 +157,16 @@ 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"
- fiatFee={formatCurrency(fiatTransactionFee, currentCurrency)}
- ethFee={ethTransactionFee}
+ fiatText={formatCurrency(fiatTransactionFee, currentCurrency)}
+ ethText={`\u2666 ${ethTransactionFee}`}
headerText="Edit"
headerTextClassName="confirm-detail-row__header-text--edit"
onHeaderClick={() => this.handleEditGas()}
@@ -169,11 +175,11 @@ export default class ConfirmTransactionBase extends Component {
<div>
<ConfirmDetailRow
label="Total"
- fiatFee={formatCurrency(fiatTransactionTotal, currentCurrency)}
- ethFee={ethTransactionTotal}
+ fiatText={fiatTotalTextOverride || formattedCurrency}
+ ethText={ethTotalTextOverride || `\u2666 ${ethTransactionTotal}`}
headerText="Amount + Gas Fee"
headerTextClassName="confirm-detail-row__header-text--total"
- fiatFeeColor="#2f9ae0"
+ fiatTextColor="#2f9ae0"
/>
</div>
</div>
@@ -206,17 +212,21 @@ export default class ConfirmTransactionBase extends Component {
<div className="confirm-page-container-content__data-box-label">
{`${t('functionType')}:`}
<span className="confirm-page-container-content__function-type">
- { name }
+ { name || t('notFound') }
</span>
</div>
- <div className="confirm-page-container-content__data-box">
- <div className="confirm-page-container-content__data-field-label">
- { `${t('parameters')}:` }
- </div>
- <div>
- <pre>{ JSON.stringify(params, null, 2) }</pre>
- </div>
- </div>
+ {
+ params && (
+ <div className="confirm-page-container-content__data-box">
+ <div className="confirm-page-container-content__data-field-label">
+ { `${t('parameters')}:` }
+ </div>
+ <div>
+ <pre>{ JSON.stringify(params, null, 2) }</pre>
+ </div>
+ </div>
+ )
+ }
<div className="confirm-page-container-content__data-box-label">
{`${t('hexData')}:`}
</div>
@@ -297,7 +307,7 @@ export default class ConfirmTransactionBase extends Component {
toName={toName}
toAddress={toAddress}
showEdit={onEdit && !isTxReprice}
- action={action || name}
+ action={action || name || this.context.t('unknownFunction')}
title={title || `${fiatConvertedAmount} ${currentCurrency.toUpperCase()}`}
subtitle={subtitle || `\u2666 ${ethTransactionAmount}`}
hideSubtitle={hideSubtitle}
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 31108bbd0..0c0deff18 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
@@ -2,6 +2,7 @@ import { connect } from 'react-redux'
import { compose } from 'recompose'
import { withRouter } from 'react-router-dom'
import R from 'ramda'
+import contractMap from 'eth-contract-metadata'
import ConfirmTransactionBase from './confirm-transaction-base.component'
import {
clearConfirmTransaction,
@@ -13,9 +14,17 @@ import {
GAS_LIMIT_TOO_LOW_ERROR_KEY,
} from '../../../constants/error-keys'
import { getHexGasTotal } from '../../../helpers/confirm-transaction/util'
-import { isBalanceSufficient } from '../../send_/send.utils'
+import { isBalanceSufficient } from '../../send/send.utils'
import { conversionGreaterThan } from '../../../conversion-util'
-import { MIN_GAS_LIMIT_DEC } from '../../send_/send.constants'
+import { MIN_GAS_LIMIT_DEC } from '../../send/send.constants'
+import { addressSlicer } from '../../../util'
+
+const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
+ return {
+ ...acc,
+ [base.toLowerCase()]: contractMap[base],
+ }
+}, {})
const mapStateToProps = (state, props) => {
const { toAddress: propsToAddress } = props
@@ -48,7 +57,10 @@ const mapStateToProps = (state, props) => {
const { balance } = accounts[selectedAddress]
const { name: fromName } = identities[selectedAddress]
const toAddress = propsToAddress || txParamsToAddress
- const toName = identities[toAddress] && identities[toAddress].name
+ const toName = identities[toAddress]
+ ? identities[toAddress].name
+ : casedContractMap[toAddress] ? casedContractMap[toAddress].name : addressSlicer(toAddress)
+
const isTxReprice = Boolean(lastGasPrice)
const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList)
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
index 25259b98c..0280f73c6 100644
--- a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
@@ -8,11 +8,16 @@ import {
CONFIRM_SEND_ETHER_PATH,
CONFIRM_SEND_TOKEN_PATH,
CONFIRM_APPROVE_PATH,
+ CONFIRM_TRANSFER_FROM_PATH,
CONFIRM_TOKEN_METHOD_PATH,
SIGNATURE_REQUEST_PATH,
} from '../../../routes'
import { isConfirmDeployContract } from './confirm-transaction-switch.util'
-import { TOKEN_METHOD_TRANSFER, TOKEN_METHOD_APPROVE } from './confirm-transaction-switch.constants'
+import {
+ TOKEN_METHOD_TRANSFER,
+ TOKEN_METHOD_APPROVE,
+ TOKEN_METHOD_TRANSFER_FROM,
+} from './confirm-transaction-switch.constants'
export default class ConfirmTransactionSwitch extends Component {
static propTypes = {
@@ -27,8 +32,7 @@ export default class ConfirmTransactionSwitch extends Component {
methodData: { name },
fetchingMethodData,
} = this.props
- const { id } = txData
-
+ const { id, txParams: { data } = {} } = txData
if (isConfirmDeployContract(txData)) {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_DEPLOY_CONTRACT_PATH}`
@@ -39,10 +43,10 @@ export default class ConfirmTransactionSwitch extends Component {
return <Loading />
}
- if (name) {
- const methodName = name.toLowerCase()
+ if (data) {
+ const methodName = name && name.toLowerCase()
- switch (methodName.toLowerCase()) {
+ switch (methodName) {
case TOKEN_METHOD_TRANSFER: {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SEND_TOKEN_PATH}`
return <Redirect to={{ pathname }} />
@@ -51,6 +55,10 @@ export default class ConfirmTransactionSwitch extends Component {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_APPROVE_PATH}`
return <Redirect to={{ pathname }} />
}
+ case TOKEN_METHOD_TRANSFER_FROM: {
+ const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TRANSFER_FROM_PATH}`
+ return <Redirect to={{ pathname }} />
+ }
default: {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TOKEN_METHOD_PATH}`
return <Redirect to={{ pathname }} />
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js
index 622d2a37a..9db4a2f96 100644
--- a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js
@@ -1,2 +1,3 @@
export const TOKEN_METHOD_TRANSFER = 'transfer'
export const TOKEN_METHOD_APPROVE = 'approve'
+export const TOKEN_METHOD_TRANSFER_FROM = 'transferfrom'
diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js
index 874a89fd2..3ac656d73 100644
--- a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js
+++ b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js
@@ -8,6 +8,7 @@ import ConfirmSendEther from '../confirm-send-ether'
import ConfirmSendToken from '../confirm-send-token'
import ConfirmDeployContract from '../confirm-deploy-contract'
import ConfirmApprove from '../confirm-approve'
+import ConfirmTokenTransactionBase from '../confirm-token-transaction-base'
import ConfTx from '../../../conf-tx'
import {
DEFAULT_ROUTE,
@@ -16,6 +17,7 @@ import {
CONFIRM_SEND_ETHER_PATH,
CONFIRM_SEND_TOKEN_PATH,
CONFIRM_APPROVE_PATH,
+ CONFIRM_TRANSFER_FROM_PATH,
CONFIRM_TOKEN_METHOD_PATH,
SIGNATURE_REQUEST_PATH,
} from '../../../routes'
@@ -139,6 +141,11 @@ export default class ConfirmTransaction extends Component {
/>
<Route
exact
+ path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_TRANSFER_FROM_PATH}`}
+ component={ConfirmTokenTransactionBase}
+ />
+ <Route
+ exact
path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${SIGNATURE_REQUEST_PATH}`}
component={ConfTx}
/>
diff --git a/ui/app/components/pages/create-account/connect-hardware/account-list.js b/ui/app/components/pages/create-account/connect-hardware/account-list.js
new file mode 100644
index 000000000..c722d1f55
--- /dev/null
+++ b/ui/app/components/pages/create-account/connect-hardware/account-list.js
@@ -0,0 +1,143 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const genAccountLink = require('../../../../../lib/account-link.js')
+
+class AccountList extends Component {
+ constructor (props, context) {
+ super(props)
+ }
+
+ renderHeader () {
+ return (
+ h('div.hw-connect', [
+ h('h3.hw-connect__title', {}, this.context.t('selectAnAccount')),
+ h('p.hw-connect__msg', {}, this.context.t('selectAnAccountHelp')),
+ ])
+ )
+ }
+
+ renderAccounts () {
+ return h('div.hw-account-list', [
+ this.props.accounts.map((a, i) => {
+
+ return h('div.hw-account-list__item', { key: a.address }, [
+ h('div.hw-account-list__item__radio', [
+ h('input', {
+ type: 'radio',
+ name: 'selectedAccount',
+ id: `address-${i}`,
+ value: a.index,
+ onChange: (e) => this.props.onAccountChange(e.target.value),
+ checked: this.props.selectedAccount === a.index.toString(),
+ }),
+ h(
+ 'label.hw-account-list__item__label',
+ {
+ htmlFor: `address-${i}`,
+ },
+ [
+ h('span.hw-account-list__item__index', a.index + 1),
+ `${a.address.slice(0, 4)}...${a.address.slice(-4)}`,
+ h('span.hw-account-list__item__balance', `${a.balance}`),
+ ]),
+ ]),
+ h(
+ 'a.hw-account-list__item__link',
+ {
+ href: genAccountLink(a.address, this.props.network),
+ target: '_blank',
+ title: this.context.t('etherscanView'),
+ },
+ h('img', { src: 'images/popout.svg' })
+ ),
+ ])
+ }),
+ ])
+ }
+
+ renderPagination () {
+ return h('div.hw-list-pagination', [
+ h(
+ 'button.hw-list-pagination__button',
+ {
+ onClick: () => this.props.getPage(-1),
+ },
+ `< ${this.context.t('prev')}`
+ ),
+
+ h(
+ 'button.hw-list-pagination__button',
+ {
+ onClick: () => this.props.getPage(1),
+ },
+ `${this.context.t('next')} >`
+ ),
+ ])
+ }
+
+ renderButtons () {
+ const disabled = this.props.selectedAccount === null
+ const buttonProps = {}
+ if (disabled) {
+ buttonProps.disabled = true
+ }
+
+ return h('div.new-account-connect-form__buttons', {}, [
+ h(
+ 'button.btn-default.btn--large.new-account-connect-form__button',
+ {
+ onClick: this.props.onCancel.bind(this),
+ },
+ [this.context.t('cancel')]
+ ),
+
+ h(
+ `button.btn-primary.btn--large.new-account-connect-form__button.unlock ${disabled ? '.btn-primary--disabled' : ''}`,
+ {
+ onClick: this.props.onUnlockAccount.bind(this),
+ ...buttonProps,
+ },
+ [this.context.t('unlock')]
+ ),
+ ])
+ }
+
+ renderForgetDevice () {
+ return h('div.hw-forget-device-container', {}, [
+ h('a', {
+ onClick: this.props.onForgetDevice.bind(this),
+ }, this.context.t('forgetDevice')),
+ ])
+ }
+
+ render () {
+ return h('div.new-account-connect-form.account-list', {}, [
+ this.renderHeader(),
+ this.renderAccounts(),
+ this.renderPagination(),
+ this.renderButtons(),
+ this.renderForgetDevice(),
+ ])
+ }
+
+}
+
+
+AccountList.propTypes = {
+ accounts: PropTypes.array.isRequired,
+ onAccountChange: PropTypes.func.isRequired,
+ onForgetDevice: PropTypes.func.isRequired,
+ getPage: PropTypes.func.isRequired,
+ network: PropTypes.string,
+ selectedAccount: PropTypes.string,
+ history: PropTypes.object,
+ onUnlockAccount: PropTypes.func,
+ onCancel: PropTypes.func,
+}
+
+AccountList.contextTypes = {
+ t: PropTypes.func,
+}
+
+module.exports = AccountList
diff --git a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js
new file mode 100644
index 000000000..cb2b86595
--- /dev/null
+++ b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js
@@ -0,0 +1,149 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+
+class ConnectScreen extends Component {
+ constructor (props, context) {
+ super(props)
+ }
+
+ renderUnsupportedBrowser () {
+ return (
+ h('div.new-account-connect-form.unsupported-browser', {}, [
+ h('div.hw-connect', [
+ h('h3.hw-connect__title', {}, this.context.t('browserNotSupported')),
+ h('p.hw-connect__msg', {}, this.context.t('chromeRequiredForTrezor')),
+ ]),
+ h(
+ 'button.btn-primary.btn--large',
+ {
+ onClick: () => global.platform.openWindow({
+ url: 'https://google.com/chrome',
+ }),
+ },
+ this.context.t('downloadGoogleChrome')
+ ),
+ ])
+ )
+ }
+
+ renderHeader () {
+ return (
+ h('div.hw-connect__header', {}, [
+ h('h3.hw-connect__header__title', {}, this.context.t(`hardwareSupport`)),
+ h('p.hw-connect__header__msg', {}, this.context.t(`hardwareSupportMsg`)),
+ ])
+ )
+ }
+
+ renderTrezorAffiliateLink () {
+ return h('div.hw-connect__get-trezor', {}, [
+ h('p.hw-connect__get-trezor__msg', {}, this.context.t(`dontHaveATrezorWallet`)),
+ h('a.hw-connect__get-trezor__link', {
+ href: 'https://shop.trezor.io/?a=metamask',
+ target: '_blank',
+ }, this.context.t('orderOneHere')),
+ ])
+ }
+
+ renderConnectToTrezorButton () {
+ return h(
+ 'button.btn-primary.btn--large',
+ { onClick: this.props.connectToTrezor.bind(this) },
+ this.props.btnText
+ )
+ }
+
+ scrollToTutorial = (e) => {
+ if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'})
+ }
+
+ renderLearnMore () {
+ return (
+ h('p.hw-connect__learn-more', {
+ onClick: this.scrollToTutorial,
+ }, [
+ this.context.t('learnMore'),
+ h('img.hw-connect__learn-more__arrow', { src: 'images/caret-right.svg'}),
+ ])
+ )
+ }
+
+ renderTutorialSteps () {
+ const steps = [
+ {
+ asset: 'hardware-wallet-step-1',
+ dimensions: {width: '225px', height: '75px'},
+ },
+ {
+ asset: 'hardware-wallet-step-2',
+ dimensions: {width: '300px', height: '100px'},
+ },
+ {
+ asset: 'hardware-wallet-step-3',
+ dimensions: {width: '120px', height: '90px'},
+ },
+ ]
+
+ return h('.hw-tutorial', {
+ ref: node => { this.referenceNode = node },
+ },
+ steps.map((step, i) => (
+ h('div.hw-connect', {}, [
+ h('h3.hw-connect__title', {}, this.context.t(`step${i + 1}HardwareWallet`)),
+ h('p.hw-connect__msg', {}, this.context.t(`step${i + 1}HardwareWalletMsg`)),
+ h('img.hw-connect__step-asset', { src: `images/${step.asset}.svg`, ...step.dimensions }),
+ ])
+ ))
+ )
+ }
+
+ renderFooter () {
+ return (
+ h('div.hw-connect__footer', {}, [
+ h('h3.hw-connect__footer__title', {}, this.context.t(`readyToConnect`)),
+ this.renderConnectToTrezorButton(),
+ h('p.hw-connect__footer__msg', {}, [
+ this.context.t(`havingTroubleConnecting`),
+ h('a.hw-connect__footer__link', {
+ href: 'https://support.metamask.io/',
+ target: '_blank',
+ }, this.context.t('getHelp')),
+ ]),
+ ])
+ )
+ }
+
+ renderConnectScreen () {
+ return (
+ h('div.new-account-connect-form', {}, [
+ this.renderHeader(),
+ this.renderTrezorAffiliateLink(),
+ this.renderConnectToTrezorButton(),
+ this.renderLearnMore(),
+ this.renderTutorialSteps(),
+ this.renderFooter(),
+ ])
+ )
+ }
+
+ render () {
+ if (this.props.browserSupported) {
+ return this.renderConnectScreen()
+ }
+ return this.renderUnsupportedBrowser()
+ }
+}
+
+ConnectScreen.propTypes = {
+ connectToTrezor: PropTypes.func.isRequired,
+ btnText: PropTypes.string.isRequired,
+ browserSupported: PropTypes.bool.isRequired,
+}
+
+ConnectScreen.contextTypes = {
+ t: PropTypes.func,
+}
+
+module.exports = ConnectScreen
+
diff --git a/ui/app/components/pages/create-account/connect-hardware/index.js b/ui/app/components/pages/create-account/connect-hardware/index.js
new file mode 100644
index 000000000..cc3761c04
--- /dev/null
+++ b/ui/app/components/pages/create-account/connect-hardware/index.js
@@ -0,0 +1,234 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const connect = require('react-redux').connect
+const actions = require('../../../../actions')
+const ConnectScreen = require('./connect-screen')
+const AccountList = require('./account-list')
+const { DEFAULT_ROUTE } = require('../../../../routes')
+const { formatBalance } = require('../../../../util')
+
+class ConnectHardwareForm extends Component {
+ constructor (props, context) {
+ super(props)
+ this.state = {
+ error: null,
+ btnText: context.t('connectToTrezor'),
+ selectedAccount: null,
+ accounts: [],
+ browserSupported: true,
+ }
+ }
+
+ componentWillReceiveProps (nextProps) {
+ const { accounts } = nextProps
+ const newAccounts = this.state.accounts.map(a => {
+ const normalizedAddress = a.address.toLowerCase()
+ const balanceValue = accounts[normalizedAddress] && accounts[normalizedAddress].balance || null
+ a.balance = balanceValue ? formatBalance(balanceValue, 6) : '...'
+ return a
+ })
+ this.setState({accounts: newAccounts})
+ }
+
+
+ async componentDidMount () {
+ const unlocked = await this.props.checkHardwareStatus('trezor')
+ if (unlocked) {
+ this.getPage(0)
+ }
+ }
+
+ connectToTrezor = () => {
+ if (this.state.accounts.length) {
+ return null
+ }
+ this.setState({ btnText: this.context.t('connecting')})
+ this.getPage(0)
+ }
+
+ onAccountChange = (account) => {
+ this.setState({selectedAccount: account.toString(), error: null})
+ }
+
+ showTemporaryAlert () {
+ this.props.showAlert(this.context.t('hardwareWalletConnected'))
+ // Autohide the alert after 5 seconds
+ setTimeout(_ => {
+ this.props.hideAlert()
+ }, 5000)
+ }
+
+ getPage = (page) => {
+ this.props
+ .connectHardware('trezor', page)
+ .then(accounts => {
+ if (accounts.length) {
+
+ // If we just loaded the accounts for the first time
+ // show the global alert
+ if (this.state.accounts.length === 0) {
+ this.showTemporaryAlert()
+ }
+
+ const newState = {}
+ // Default to the first account
+ if (this.state.selectedAccount === null) {
+ accounts.forEach((a, i) => {
+ if (a.address.toLowerCase() === this.props.address) {
+ newState.selectedAccount = a.index.toString()
+ }
+ })
+ // If the page doesn't contain the selected account, let's deselect it
+ } else if (!accounts.filter(a => a.index.toString() === this.state.selectedAccount).length) {
+ newState.selectedAccount = null
+ }
+
+
+ // Map accounts with balances
+ newState.accounts = accounts.map(account => {
+ const normalizedAddress = account.address.toLowerCase()
+ const balanceValue = this.props.accounts[normalizedAddress] && this.props.accounts[normalizedAddress].balance || null
+ account.balance = balanceValue ? formatBalance(balanceValue, 6) : '...'
+ return account
+ })
+
+ this.setState(newState)
+ }
+ })
+ .catch(e => {
+ if (e === 'Window blocked') {
+ this.setState({ browserSupported: false })
+ }
+ this.setState({ btnText: this.context.t('connectToTrezor') })
+ })
+ }
+
+ onForgetDevice = () => {
+ this.props.forgetDevice('trezor')
+ .then(_ => {
+ this.setState({
+ error: null,
+ btnText: this.context.t('connectToTrezor'),
+ selectedAccount: null,
+ accounts: [],
+ })
+ }).catch(e => {
+ this.setState({ error: e.toString() })
+ })
+ }
+
+ onUnlockAccount = () => {
+
+ if (this.state.selectedAccount === null) {
+ this.setState({ error: this.context.t('accountSelectionRequired') })
+ }
+
+ this.props.unlockTrezorAccount(this.state.selectedAccount)
+ .then(_ => {
+ this.props.history.push(DEFAULT_ROUTE)
+ }).catch(e => {
+ this.setState({ error: e.toString() })
+ })
+ }
+
+ onCancel = () => {
+ this.props.history.push(DEFAULT_ROUTE)
+ }
+
+ renderError () {
+ return this.state.error
+ ? h('span.error', { style: { marginBottom: 40 } }, this.state.error)
+ : null
+ }
+
+ renderContent () {
+ if (!this.state.accounts.length) {
+ return h(ConnectScreen, {
+ connectToTrezor: this.connectToTrezor,
+ btnText: this.state.btnText,
+ browserSupported: this.state.browserSupported,
+ })
+ }
+
+ return h(AccountList, {
+ accounts: this.state.accounts,
+ selectedAccount: this.state.selectedAccount,
+ onAccountChange: this.onAccountChange,
+ network: this.props.network,
+ getPage: this.getPage,
+ history: this.props.history,
+ onUnlockAccount: this.onUnlockAccount,
+ onForgetDevice: this.onForgetDevice,
+ onCancel: this.onCancel,
+ })
+ }
+
+ render () {
+ return h('div', [
+ this.renderError(),
+ this.renderContent(),
+ ])
+ }
+}
+
+ConnectHardwareForm.propTypes = {
+ hideModal: PropTypes.func,
+ showImportPage: PropTypes.func,
+ showConnectPage: PropTypes.func,
+ connectHardware: PropTypes.func,
+ checkHardwareStatus: PropTypes.func,
+ forgetDevice: PropTypes.func,
+ showAlert: PropTypes.func,
+ hideAlert: PropTypes.func,
+ unlockTrezorAccount: PropTypes.func,
+ numberOfExistingAccounts: PropTypes.number,
+ history: PropTypes.object,
+ t: PropTypes.func,
+ network: PropTypes.string,
+ accounts: PropTypes.object,
+ address: PropTypes.string,
+}
+
+const mapStateToProps = state => {
+ const {
+ metamask: { network, selectedAddress, identities = {}, accounts = [] },
+ } = state
+ const numberOfExistingAccounts = Object.keys(identities).length
+
+ return {
+ network,
+ accounts,
+ address: selectedAddress,
+ numberOfExistingAccounts,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ connectHardware: (deviceName, page) => {
+ return dispatch(actions.connectHardware(deviceName, page))
+ },
+ checkHardwareStatus: (deviceName) => {
+ return dispatch(actions.checkHardwareStatus(deviceName))
+ },
+ forgetDevice: (deviceName) => {
+ return dispatch(actions.forgetDevice(deviceName))
+ },
+ unlockTrezorAccount: index => {
+ return dispatch(actions.unlockTrezorAccount(index))
+ },
+ showImportPage: () => dispatch(actions.showImportPage()),
+ showConnectPage: () => dispatch(actions.showConnectPage()),
+ showAlert: (msg) => dispatch(actions.showAlert(msg)),
+ hideAlert: () => dispatch(actions.hideAlert()),
+ }
+}
+
+ConnectHardwareForm.contextTypes = {
+ t: PropTypes.func,
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(
+ ConnectHardwareForm
+)
diff --git a/ui/app/components/pages/create-account/index.js b/ui/app/components/pages/create-account/index.js
index 5681e43a9..d3de1ea01 100644
--- a/ui/app/components/pages/create-account/index.js
+++ b/ui/app/components/pages/create-account/index.js
@@ -8,7 +8,12 @@ const { getCurrentViewContext } = require('../../../selectors')
const classnames = require('classnames')
const NewAccountCreateForm = require('./new-account')
const NewAccountImportForm = require('./import-account')
-const { NEW_ACCOUNT_ROUTE, IMPORT_ACCOUNT_ROUTE } = require('../../../routes')
+const ConnectHardwareForm = require('./connect-hardware')
+const {
+ NEW_ACCOUNT_ROUTE,
+ IMPORT_ACCOUNT_ROUTE,
+ CONNECT_HARDWARE_ROUTE,
+} = require('../../../routes')
class CreateAccountPage extends Component {
renderTabs () {
@@ -36,6 +41,19 @@ class CreateAccountPage extends Component {
}, [
this.context.t('import'),
]),
+ h(
+ 'div.new-account__tabs__tab',
+ {
+ className: classnames('new-account__tabs__tab', {
+ 'new-account__tabs__selected': matchPath(location.pathname, {
+ path: CONNECT_HARDWARE_ROUTE,
+ exact: true,
+ }),
+ }),
+ onClick: () => history.push(CONNECT_HARDWARE_ROUTE),
+ },
+ this.context.t('connect')
+ ),
])
}
@@ -57,6 +75,11 @@ class CreateAccountPage extends Component {
path: IMPORT_ACCOUNT_ROUTE,
component: NewAccountImportForm,
}),
+ h(Route, {
+ exact: true,
+ path: CONNECT_HARDWARE_ROUTE,
+ component: ConnectHardwareForm,
+ }),
]),
]),
])
diff --git a/ui/app/components/pages/create-account/new-account.js b/ui/app/components/pages/create-account/new-account.js
index 9c94990e0..402b8f03b 100644
--- a/ui/app/components/pages/create-account/new-account.js
+++ b/ui/app/components/pages/create-account/new-account.js
@@ -62,6 +62,7 @@ class NewAccountCreateForm extends Component {
NewAccountCreateForm.propTypes = {
hideModal: PropTypes.func,
showImportPage: PropTypes.func,
+ showConnectPage: PropTypes.func,
createAccount: PropTypes.func,
numberOfExistingAccounts: PropTypes.number,
history: PropTypes.object,
@@ -92,6 +93,7 @@ const mapDispatchToProps = dispatch => {
})
},
showImportPage: () => dispatch(actions.showImportPage()),
+ showConnectPage: () => dispatch(actions.showConnectPage()),
}
}
diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss
index 8b333b6a8..b15c59863 100644
--- a/ui/app/components/pages/index.scss
+++ b/ui/app/components/pages/index.scss
@@ -3,5 +3,3 @@
@import './add-token/index';
@import './confirm-add-token/index';
-
-@import './confirm-send-token/index';
diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js
deleted file mode 100644
index af3a14f57..000000000
--- a/ui/app/components/pending-tx/confirm-deploy-contract.js
+++ /dev/null
@@ -1,358 +0,0 @@
-const { Component } = require('react')
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const PropTypes = require('prop-types')
-const actions = require('../../actions')
-const clone = require('clone')
-const ethUtil = require('ethereumjs-util')
-const BN = ethUtil.BN
-const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
-const { conversionUtil } = require('../../conversion-util')
-const SenderToRecipient = require('../sender-to-recipient')
-const NetworkDisplay = require('../network-display')
-
-const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
-
-class ConfirmDeployContract extends Component {
- constructor (props) {
- super(props)
-
- this.state = {
- valid: false,
- submitting: false,
- }
- }
-
- onSubmit (event) {
- event.preventDefault()
- const txMeta = this.gatherTxMeta()
- const valid = this.checkValidity()
- this.setState({ valid, submitting: true })
-
- if (valid && this.verifyGasParams()) {
- this.props.sendTransaction(txMeta, event)
- } else {
- this.props.displayWarning(this.context.t('invalidGasParams'))
- this.setState({ submitting: false })
- }
- }
-
- cancel (event, txMeta) {
- event.preventDefault()
- this.props.cancelTransaction(txMeta)
- }
-
- checkValidity () {
- const form = this.getFormEl()
- const valid = form.checkValidity()
- return valid
- }
-
- getFormEl () {
- const form = document.querySelector('form#pending-tx-form')
- // Stub out form for unit tests:
- if (!form) {
- return { checkValidity () { return true } }
- }
- return form
- }
-
- // After a customizable state value has been updated,
- gatherTxMeta () {
- const props = this.props
- const state = this.state
- const txData = clone(state.txData) || clone(props.txData)
-
- // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
- return txData
- }
-
- verifyGasParams () {
- // We call this in case the gas has not been modified at all
- if (!this.state) { return true }
- return (
- this._notZeroOrEmptyString(this.state.gas) &&
- this._notZeroOrEmptyString(this.state.gasPrice)
- )
- }
-
- _notZeroOrEmptyString (obj) {
- return obj !== '' && obj !== '0x0'
- }
-
- bnMultiplyByFraction (targetBN, numerator, denominator) {
- const numBN = new BN(numerator)
- const denomBN = new BN(denominator)
- return targetBN.mul(numBN).div(denomBN)
- }
-
- getData () {
- const { identities } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- return {
- from: {
- address: txParams.from,
- name: identities[txParams.from].name,
- },
- memo: txParams.memo || '',
- }
- }
-
- getAmount () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- const FIAT = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- fromDenomination: 'WEI',
- conversionRate,
- })
- const ETH = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- fromDenomination: 'WEI',
- conversionRate,
- numberOfDecimals: 6,
- })
-
- return {
- fiat: Number(FIAT),
- token: Number(ETH),
- }
-
- }
-
- getGasFee () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- // Gas
- const gas = txParams.gas
- const gasBn = hexToBn(gas)
-
- // Gas Price
- const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
- const gasPriceBn = hexToBn(gasPrice)
-
- const txFeeBn = gasBn.mul(gasPriceBn)
-
- const FIAT = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- conversionRate,
- })
- const ETH = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- numberOfDecimals: 6,
- conversionRate,
- })
-
- return {
- fiat: Number(FIAT),
- eth: Number(ETH),
- }
- }
-
- renderGasFee () {
- const { currentCurrency } = this.props
- const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
-
- return (
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`),
-
- h(
- 'div.confirm-screen-row-detail',
- `${ethGas} ETH`
- ),
- ]),
- ])
- )
- }
-
- renderHeroAmount () {
- const { currentCurrency } = this.props
- const { fiat: fiatAmount } = this.getAmount()
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
- const { memo = '' } = txParams
-
- return (
- h('div.confirm-send-token__hero-amount-wrapper', [
- h('h3.flex-center.confirm-screen-send-amount', `${fiatAmount}`),
- h('h3.flex-center.confirm-screen-send-amount-currency', currentCurrency.toUpperCase()),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', memo),
- ]),
- ])
- )
- }
-
- renderTotalPlusGas () {
- const { currentCurrency } = this.props
- const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
- const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
-
- return (
- h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
- h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
- h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
- ]),
-
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${fiatAmount + fiatGas} ${currentCurrency.toUpperCase()}`),
- h('div.confirm-screen-row-detail', `${tokenAmount + ethGas} ETH`),
- ]),
- ])
- )
- }
-
- render () {
- const { backToAccountDetail, selectedAddress } = this.props
- const txMeta = this.gatherTxMeta()
-
- const {
- from: {
- address: fromAddress,
- name: fromName,
- },
- } = this.getData()
-
- this.inputs = []
-
- return (
- h('.page-container', [
- h('.page-container__header', [
- h('.page-container__header-row', [
- h('span.page-container__back-button', {
- onClick: () => backToAccountDetail(selectedAddress),
- }, this.context.t('back')),
- window.METAMASK_UI_TYPE === 'notification' && h(NetworkDisplay),
- ]),
- h('.page-container__title', this.context.t('confirmContract')),
- h('.page-container__subtitle', this.context.t('pleaseReviewTransaction')),
- ]),
- // Main Send token Card
- h('.page-container__content', [
-
- h(SenderToRecipient, {
- senderName: fromName,
- senderAddress: fromAddress,
- }),
-
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're deploying a new contract.`,
- // ]),
-
- this.renderHeroAmount(),
-
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
- ]),
- ]),
-
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', this.context.t('newContract')),
- ]),
- ]),
-
- this.renderGasFee(),
-
- this.renderTotalPlusGas(),
-
- ]),
- ]),
-
- h('form#pending-tx-form', {
- onSubmit: event => this.onSubmit(event),
- }, [
- h('.page-container__footer', [
- // Cancel Button
- h('button.btn-cancel.page-container__footer-button.allcaps', {
- onClick: event => this.cancel(event, txMeta),
- }, this.context.t('cancel')),
-
- // Accept Button
- h('button.btn-confirm.page-container__footer-button.allcaps', {
- onClick: event => this.onSubmit(event),
- }, this.context.t('confirm')),
- ]),
- ]),
- ])
- )
- }
-}
-
-ConfirmDeployContract.propTypes = {
- sendTransaction: PropTypes.func,
- cancelTransaction: PropTypes.func,
- backToAccountDetail: PropTypes.func,
- displayWarning: PropTypes.func,
- identities: PropTypes.object,
- conversionRate: PropTypes.number,
- currentCurrency: PropTypes.string,
- selectedAddress: PropTypes.string,
- t: PropTypes.func,
-}
-
-const mapStateToProps = state => {
- const {
- conversionRate,
- identities,
- currentCurrency,
- } = state.metamask
- const accounts = state.metamask.accounts
- const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
- return {
- currentCurrency,
- conversionRate,
- identities,
- selectedAddress,
- }
-}
-
-const mapDispatchToProps = dispatch => {
- return {
- backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
- cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
- displayWarning: warning => actions.displayWarning(warning),
- }
-}
-
-ConfirmDeployContract.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)
diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js
deleted file mode 100644
index 22b2670d8..000000000
--- a/ui/app/components/pending-tx/confirm-send-ether.js
+++ /dev/null
@@ -1,692 +0,0 @@
-const Component = require('react').Component
-const { withRouter } = require('react-router-dom')
-const { compose } = require('recompose')
-const PropTypes = require('prop-types')
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const actions = require('../../actions')
-const clone = require('clone')
-const ethUtil = require('ethereumjs-util')
-const BN = ethUtil.BN
-const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
-const classnames = require('classnames')
-const {
- conversionUtil,
- addCurrencies,
- multiplyCurrencies,
-} = require('../../conversion-util')
-const {
- calcGasTotal,
- isBalanceSufficient,
-} = require('../send_/send.utils')
-const GasFeeDisplay = require('../send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component').default
-const SenderToRecipient = require('../sender-to-recipient')
-const NetworkDisplay = require('../network-display')
-const currencyFormatter = require('currency-formatter')
-const currencies = require('currency-formatter/currencies')
-
-const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
-const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes')
-const {
- ENVIRONMENT_TYPE_POPUP,
- ENVIRONMENT_TYPE_NOTIFICATION,
-} = require('../../../../app/scripts/lib/enums')
-
-import {
- updateSendErrors,
-} from '../../ducks/send.duck'
-
-ConfirmSendEther.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = compose(
- withRouter,
- connect(mapStateToProps, mapDispatchToProps)
-)(ConfirmSendEther)
-
-
-function mapStateToProps (state) {
- const {
- conversionRate,
- identities,
- currentCurrency,
- send,
- } = state.metamask
- const accounts = state.metamask.accounts
- const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
- const { balance } = accounts[selectedAddress]
- return {
- conversionRate,
- identities,
- selectedAddress,
- currentCurrency,
- send,
- balance,
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- clearSend: () => dispatch(actions.clearSend()),
- editTransaction: txMeta => {
- const { id, txParams } = txMeta
- const {
- gas: gasLimit,
- gasPrice,
- to,
- value: amount,
- } = txParams
-
- dispatch(actions.updateSend({
- gasLimit,
- gasPrice,
- gasTotal: null,
- to,
- amount,
- errors: { to: null, amount: null },
- editingTransactionId: id,
- }))
- },
- cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
- showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
- const { id, txParams, lastGasPrice } = txMeta
- const { gas: txGasLimit, gasPrice: txGasPrice } = txParams
-
- let forceGasMin
- if (lastGasPrice) {
- forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
- multiplicandBase: 16,
- multiplierBase: 10,
- toNumericBase: 'hex',
- fromDenomination: 'WEI',
- }))
- }
-
- dispatch(actions.updateSend({
- gasLimit: sendGasLimit || txGasLimit,
- gasPrice: sendGasPrice || txGasPrice,
- editingTransactionId: id,
- gasTotal: sendGasTotal,
- forceGasMin,
- }))
- dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
- },
- updateSendErrors: error => dispatch(updateSendErrors(error)),
- }
-}
-
-inherits(ConfirmSendEther, Component)
-function ConfirmSendEther () {
- Component.call(this)
- this.state = {}
- this.onSubmit = this.onSubmit.bind(this)
-}
-
-ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) {
- const {
- balance: oldBalance,
- conversionRate: oldConversionRate,
- } = prevProps
- const {
- updateSendErrors,
- balance,
- conversionRate,
- send: {
- errors: {
- simulationFails,
- },
- },
- } = this.props
- const txMeta = this.gatherTxMeta()
-
- const shouldUpdateBalanceSendErrors = balance && [
- balance !== oldBalance,
- conversionRate !== oldConversionRate,
- ].some(x => Boolean(x))
-
- if (shouldUpdateBalanceSendErrors) {
- const balanceIsSufficient = this.isBalanceSufficient(txMeta)
- updateSendErrors({
- insufficientFunds: balanceIsSufficient ? false : 'insufficientFunds',
- })
- }
-
- const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails)
-
- if (shouldUpdateSimulationSendError) {
- updateSendErrors({
- simulationFails: !txMeta.simulationFails ? false : 'transactionError',
- })
- }
-}
-
-ConfirmSendEther.prototype.componentWillMount = function () {
- this.updateComponentSendErrors({})
-}
-
-ConfirmSendEther.prototype.componentDidUpdate = function (prevProps) {
- this.updateComponentSendErrors(prevProps)
-}
-
-ConfirmSendEther.prototype.getAmount = function () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- const FIAT = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- fromDenomination: 'WEI',
- conversionRate,
- })
- const ETH = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- fromDenomination: 'WEI',
- conversionRate,
- numberOfDecimals: 6,
- })
-
- return {
- FIAT,
- ETH,
- }
-
-}
-
-ConfirmSendEther.prototype.getGasFee = function () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- // Gas
- const gas = txParams.gas
- const gasBn = hexToBn(gas)
-
- // From latest master
-// const gasLimit = new BN(parseInt(blockGasLimit))
-// const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20)
-// const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20)
-// const safeGasLimit = safeGasLimitBN.toString(10)
-
- // Gas Price
- const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
- const gasPriceBn = hexToBn(gasPrice)
-
- const txFeeBn = gasBn.mul(gasPriceBn)
-
- const FIAT = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- conversionRate,
- })
- const ETH = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- numberOfDecimals: 6,
- conversionRate,
- })
-
- return {
- FIAT,
- ETH,
- gasFeeInHex: txFeeBn.toString(16),
- }
-}
-
-ConfirmSendEther.prototype.getData = function () {
- const { identities } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
- const account = identities ? identities[txParams.from] || {} : {}
- const { FIAT: gasFeeInFIAT, ETH: gasFeeInETH, gasFeeInHex } = this.getGasFee()
- const { FIAT: amountInFIAT, ETH: amountInETH } = this.getAmount()
-
- const totalInFIAT = addCurrencies(gasFeeInFIAT, amountInFIAT, {
- toNumericBase: 'dec',
- numberOfDecimals: 2,
- })
- const totalInETH = addCurrencies(gasFeeInETH, amountInETH, {
- toNumericBase: 'dec',
- numberOfDecimals: 6,
- })
-
- return {
- from: {
- address: txParams.from,
- name: account.name,
- },
- to: {
- address: txParams.to,
- name: identities[txParams.to] ? identities[txParams.to].name : this.context.t('newRecipient'),
- },
- memo: txParams.memo || '',
- gasFeeInFIAT,
- gasFeeInETH,
- amountInFIAT,
- amountInETH,
- totalInFIAT,
- totalInETH,
- gasFeeInHex,
- }
-}
-
-ConfirmSendEther.prototype.convertToRenderableCurrency = function (value, currencyCode) {
- const upperCaseCurrencyCode = currencyCode.toUpperCase()
-
- return currencies.find(currency => currency.code === upperCaseCurrencyCode)
- ? currencyFormatter.format(Number(value), {
- code: upperCaseCurrencyCode,
- })
- : value
-}
-
-ConfirmSendEther.prototype.editTransaction = function () {
- const { editTransaction, history } = this.props
- const txMeta = this.gatherTxMeta()
- editTransaction(txMeta)
- history.push(SEND_ROUTE)
-}
-
-ConfirmSendEther.prototype.renderHeaderRow = function (isTxReprice) {
- const windowType = window.METAMASK_UI_TYPE
- const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION &&
- windowType !== ENVIRONMENT_TYPE_POPUP
-
- if (isTxReprice && isFullScreen) {
- return null
- }
-
- return (
- h('.page-container__header-row', [
- h('span.page-container__back-button', {
- onClick: () => this.editTransaction(),
- style: {
- visibility: isTxReprice ? 'hidden' : 'initial',
- },
- }, 'Edit'),
- !isFullScreen && h(NetworkDisplay),
- ])
- )
-}
-
-ConfirmSendEther.prototype.renderHeader = function (isTxReprice) {
- const title = isTxReprice ? this.context.t('speedUpTitle') : this.context.t('confirm')
- const subtitle = isTxReprice
- ? this.context.t('speedUpSubtitle')
- : this.context.t('pleaseReviewTransaction')
-
- return (
- h('.page-container__header', [
- this.renderHeaderRow(isTxReprice),
- h('.page-container__title', title),
- h('.page-container__subtitle', subtitle),
- ])
- )
-}
-
-ConfirmSendEther.prototype.render = function () {
- const {
- currentCurrency,
- clearSend,
- conversionRate,
- currentCurrency: convertedCurrency,
- showCustomizeGasModal,
- send: {
- gasTotal,
- gasLimit: sendGasLimit,
- gasPrice: sendGasPrice,
- errors,
- },
- } = this.props
- const txMeta = this.gatherTxMeta()
- const isTxReprice = Boolean(txMeta.lastGasPrice)
- const txParams = txMeta.txParams || {}
-
- const {
- from: {
- address: fromAddress,
- name: fromName,
- },
- to: {
- address: toAddress,
- name: toName,
- },
- memo,
- gasFeeInHex,
- amountInFIAT,
- totalInFIAT,
- totalInETH,
- } = this.getData()
-
- const convertedAmountInFiat = this.convertToRenderableCurrency(amountInFIAT, currentCurrency)
- const convertedTotalInFiat = this.convertToRenderableCurrency(totalInFIAT, currentCurrency)
-
- // This is from the latest master
- // It handles some of the errors that we are not currently handling
- // Leaving as comments fo reference
-
- // const balanceBn = hexToBn(balance)
- // const insufficientBalance = balanceBn.lt(maxCost)
- // const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting
- // const showRejectAll = props.unconfTxListLength > 1
-// const dangerousGasLimit = gasBn.gte(saferGasLimitBN)
-// const gasLimitSpecified = txMeta.gasLimitSpecified
-
- this.inputs = []
-
- return (
- // Main Send token Card
- h('.page-container', [
- this.renderHeader(isTxReprice),
- h('.page-container__content', [
- h(SenderToRecipient, {
- senderName: fromName,
- senderAddress: fromAddress,
- recipientName: toName,
- recipientAddress: txParams.to,
- }),
-
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
- // ]),
-
- h('h3.flex-center.confirm-screen-send-amount', [`${convertedAmountInFiat}`]),
- h('h3.flex-center.confirm-screen-send-amount-currency', [ currentCurrency.toUpperCase() ]),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', [ memo ? `"${memo}"` : '' ]),
- ]),
-
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
- ]),
- ]),
-
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', toName),
- h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
- ]),
- ]),
-
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]),
- h('div.confirm-screen-section-column', [
- h(GasFeeDisplay, {
- gasTotal: gasTotal || gasFeeInHex,
- conversionRate,
- convertedCurrency,
- onClick: () => showCustomizeGasModal(txMeta, sendGasLimit, sendGasPrice, gasTotal),
- }),
- ]),
- ]),
-
- h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
- h('div', {
- className: classnames({
- 'confirm-screen-section-column--with-error': errors['insufficientFunds'],
- 'confirm-screen-section-column': !errors['insufficientFunds'],
- }),
- }, [
- h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
- h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
- ]),
-
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${convertedTotalInFiat} ${currentCurrency.toUpperCase()}`),
- h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
- ]),
-
- this.renderErrorMessage('insufficientFunds'),
- ]),
- ]),
-
-// These are latest errors handling from master
-// Leaving as comments as reference when we start implementing error handling
-// h('style', `
-// .conf-buttons button {
-// margin-left: 10px;
-// text-transform: uppercase;
-// }
-// `),
-
-// txMeta.simulationFails ?
-// h('.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Transaction Error. Exception thrown in contract code.')
-// : null,
-
-// !isValidAddress ?
-// h('.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.')
-// : null,
-
-// insufficientBalance ?
-// h('span.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Insufficient balance for transaction')
-// : null,
-
-// // send + cancel
-// h('.flex-row.flex-space-around.conf-buttons', {
-// style: {
-// display: 'flex',
-// justifyContent: 'flex-end',
-// margin: '14px 25px',
-// },
-// }, [
-// h('button', {
-// onClick: (event) => {
-// this.resetGasFields()
-// event.preventDefault()
-// },
-// }, 'Reset'),
-
-// // Accept Button or Buy Button
-// insufficientBalance ? h('button.btn-green', { onClick: props.buyEth }, 'Buy Ether') :
-// h('input.confirm.btn-green', {
-// type: 'submit',
-// value: 'SUBMIT',
-// style: { marginLeft: '10px' },
-// disabled: buyDisabled,
-// }),
-
-// h('button.cancel.btn-red', {
-// onClick: props.cancelTransaction,
-// }, 'Reject'),
-// ]),
-// showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', {
-// style: {
-// display: 'flex',
-// justifyContent: 'flex-end',
-// margin: '14px 25px',
-// },
-// }, [
-// h('button.cancel.btn-red', {
-// onClick: props.cancelAllTransactions,
-// }, 'Reject All'),
-// ]) : null,
-// ]),
-// ])
-// )
-// }
- ]),
-
- h('form#pending-tx-form', {
- className: 'confirm-screen-form',
- onSubmit: this.onSubmit,
- }, [
- this.renderErrorMessage('simulationFails'),
- h('.page-container__footer', [
- // Cancel Button
- h('button.btn-cancel.page-container__footer-button.allcaps', {
- onClick: (event) => {
- clearSend()
- this.cancel(event, txMeta)
- },
- }, this.context.t('cancel')),
-
- // Accept Button
- h('button.btn-confirm.page-container__footer-button.allcaps', {
- onClick: event => this.onSubmit(event),
- }, this.context.t('confirm')),
- ]),
- ]),
- ])
- )
-}
-
-ConfirmSendEther.prototype.renderErrorMessage = function (message) {
- const { send: { errors } } = this.props
-
- return errors[message]
- ? h('div.confirm-screen-error', [ errors[message] ])
- : null
-}
-
-ConfirmSendEther.prototype.onSubmit = function (event) {
- event.preventDefault()
- const { updateSendErrors } = this.props
- const txMeta = this.gatherTxMeta()
- const valid = this.checkValidity()
- const balanceIsSufficient = this.isBalanceSufficient(txMeta)
- this.setState({ valid, submitting: true })
-
- if (valid && this.verifyGasParams() && balanceIsSufficient) {
- this.props.sendTransaction(txMeta, event)
- } else if (!balanceIsSufficient) {
- updateSendErrors({ insufficientFunds: 'insufficientFunds' })
- } else {
- updateSendErrors({ invalidGasParams: 'invalidGasParams' })
- this.setState({ submitting: false })
- }
-}
-
-ConfirmSendEther.prototype.cancel = function (event, txMeta) {
- event.preventDefault()
- const { cancelTransaction } = this.props
-
- cancelTransaction(txMeta)
- .then(() => this.props.history.push(DEFAULT_ROUTE))
-}
-
-ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) {
- const {
- balance,
- conversionRate,
- } = this.props
- const {
- txParams: {
- gas,
- gasPrice,
- value: amount,
- },
- } = txMeta
- const gasTotal = calcGasTotal(gas, gasPrice)
-
- return isBalanceSufficient({
- amount,
- gasTotal,
- balance,
- conversionRate,
- })
-}
-
-ConfirmSendEther.prototype.checkValidity = function () {
- const form = this.getFormEl()
- const valid = form.checkValidity()
- return valid
-}
-
-ConfirmSendEther.prototype.getFormEl = function () {
- const form = document.querySelector('form#pending-tx-form')
- // Stub out form for unit tests:
- if (!form) {
- return { checkValidity () { return true } }
- }
- return form
-}
-
-// After a customizable state value has been updated,
-ConfirmSendEther.prototype.gatherTxMeta = function () {
- const props = this.props
- const state = this.state
- const txData = clone(state.txData) || clone(props.txData)
-
- const { gasPrice: sendGasPrice, gasLimit: sendGasLimit } = props.send
- const {
- lastGasPrice,
- txParams: {
- gasPrice: txGasPrice,
- gas: txGasLimit,
- },
- } = txData
-
- let forceGasMin
- if (lastGasPrice) {
- forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
- multiplicandBase: 16,
- multiplierBase: 10,
- toNumericBase: 'hex',
- }))
- }
-
- txData.txParams.gasPrice = sendGasPrice || forceGasMin || txGasPrice
- txData.txParams.gas = sendGasLimit || txGasLimit
-
- // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
- return txData
-}
-
-ConfirmSendEther.prototype.verifyGasParams = function () {
- // We call this in case the gas has not been modified at all
- if (!this.state) { return true }
- return (
- this._notZeroOrEmptyString(this.state.gas) &&
- this._notZeroOrEmptyString(this.state.gasPrice)
- )
-}
-
-ConfirmSendEther.prototype._notZeroOrEmptyString = function (obj) {
- return obj !== '' && obj !== '0x0'
-}
-
-ConfirmSendEther.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
- const numBN = new BN(numerator)
- const denomBN = new BN(denominator)
- return targetBN.mul(numBN).div(denomBN)
-}
diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js
deleted file mode 100644
index 535347cee..000000000
--- a/ui/app/components/pending-tx/confirm-send-token.js
+++ /dev/null
@@ -1,696 +0,0 @@
-const Component = require('react').Component
-const { withRouter } = require('react-router-dom')
-const { compose } = require('recompose')
-const PropTypes = require('prop-types')
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const tokenAbi = require('human-standard-token-abi')
-const abiDecoder = require('abi-decoder')
-abiDecoder.addABI(tokenAbi)
-const actions = require('../../actions')
-const clone = require('clone')
-const Identicon = require('../identicon')
-const GasFeeDisplay = require('../send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js').default
-const NetworkDisplay = require('../network-display')
-const ethUtil = require('ethereumjs-util')
-const BN = ethUtil.BN
-const {
- conversionUtil,
- multiplyCurrencies,
- addCurrencies,
-} = require('../../conversion-util')
-const {
- calcGasTotal,
- isBalanceSufficient,
-} = require('../send_/send.utils')
-const {
- calcTokenAmount,
-} = require('../../token-util')
-const classnames = require('classnames')
-const currencyFormatter = require('currency-formatter')
-const currencies = require('currency-formatter/currencies')
-
-const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
-
-const {
- getTokenExchangeRate,
- getSelectedAddress,
- getSelectedTokenContract,
-} = require('../../selectors')
-const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes')
-
-import {
- updateSendErrors,
-} from '../../ducks/send.duck'
-
-const {
- ENVIRONMENT_TYPE_POPUP,
- ENVIRONMENT_TYPE_NOTIFICATION,
-} = require('../../../../app/scripts/lib/enums')
-
-ConfirmSendToken.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = compose(
- withRouter,
- connect(mapStateToProps, mapDispatchToProps)
-)(ConfirmSendToken)
-
-
-function mapStateToProps (state, ownProps) {
- const { token: { address }, txData } = ownProps
- const { txParams } = txData || {}
- const tokenData = txParams.data && abiDecoder.decodeMethod(txParams.data)
-
- const {
- conversionRate,
- identities,
- currentCurrency,
- } = state.metamask
- const accounts = state.metamask.accounts
- const selectedAddress = getSelectedAddress(state)
- const tokenExchangeRate = getTokenExchangeRate(state, address)
- const { balance } = accounts[selectedAddress]
- return {
- conversionRate,
- identities,
- selectedAddress,
- tokenExchangeRate,
- tokenData: tokenData || {},
- currentCurrency: currentCurrency.toUpperCase(),
- send: state.metamask.send,
- tokenContract: getSelectedTokenContract(state),
- balance,
- }
-}
-
-function mapDispatchToProps (dispatch, ownProps) {
- return {
- backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
- cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
- editTransaction: txMeta => {
- const { token: { address } } = ownProps
- const { txParams = {}, id } = txMeta
- const tokenData = txParams.data && abiDecoder.decodeMethod(txParams.data) || {}
- const { params = [] } = tokenData
- const { value: to } = params[0] || {}
- const { value: tokenAmountInDec } = params[1] || {}
- const tokenAmountInHex = conversionUtil(tokenAmountInDec, {
- fromNumericBase: 'dec',
- toNumericBase: 'hex',
- })
- const {
- gas: gasLimit,
- gasPrice,
- } = txParams
- dispatch(actions.setSelectedToken(address))
- dispatch(actions.updateSend({
- gasLimit,
- gasPrice,
- gasTotal: null,
- to,
- amount: tokenAmountInHex,
- errors: { to: null, amount: null },
- editingTransactionId: id && id.toString(),
- token: ownProps.token,
- }))
- dispatch(actions.showSendTokenPage())
- },
- showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
- const { id, txParams, lastGasPrice } = txMeta
- const { gas: txGasLimit, gasPrice: txGasPrice } = txParams
- const tokenData = txParams.data && abiDecoder.decodeMethod(txParams.data)
- const { params = [] } = tokenData
- const { value: to } = params[0] || {}
- const { value: tokenAmountInDec } = params[1] || {}
- const tokenAmountInHex = conversionUtil(tokenAmountInDec, {
- fromNumericBase: 'dec',
- toNumericBase: 'hex',
- })
-
- let forceGasMin
- if (lastGasPrice) {
- forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
- multiplicandBase: 16,
- multiplierBase: 10,
- toNumericBase: 'hex',
- fromDenomination: 'WEI',
- }))
- }
-
- dispatch(actions.updateSend({
- gasLimit: sendGasLimit || txGasLimit,
- gasPrice: sendGasPrice || txGasPrice,
- editingTransactionId: id,
- gasTotal: sendGasTotal,
- to,
- amount: tokenAmountInHex,
- forceGasMin,
- }))
- dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
- },
- updateSendErrors: error => dispatch(updateSendErrors(error)),
- }
-}
-
-inherits(ConfirmSendToken, Component)
-function ConfirmSendToken () {
- Component.call(this)
- this.state = {}
- this.onSubmit = this.onSubmit.bind(this)
-}
-
-ConfirmSendToken.prototype.editTransaction = function (txMeta) {
- const { editTransaction, history } = this.props
- editTransaction(txMeta)
- history.push(SEND_ROUTE)
-}
-
-ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) {
- const {
- balance: oldBalance,
- conversionRate: oldConversionRate,
- } = prevProps
- const {
- updateSendErrors,
- balance,
- conversionRate,
- send: {
- errors: {
- simulationFails,
- },
- },
- } = this.props
- const txMeta = this.gatherTxMeta()
-
- const shouldUpdateBalanceSendErrors = balance && [
- balance !== oldBalance,
- conversionRate !== oldConversionRate,
- ].some(x => Boolean(x))
-
- if (shouldUpdateBalanceSendErrors) {
- const balanceIsSufficient = this.isBalanceSufficient(txMeta)
- updateSendErrors({
- insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'),
- })
- }
-
- const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails)
-
- if (shouldUpdateSimulationSendError) {
- updateSendErrors({
- simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'),
- })
- }
-}
-
-ConfirmSendToken.prototype.componentWillMount = function () {
- const { tokenContract, selectedAddress } = this.props
- tokenContract && tokenContract
- .balanceOf(selectedAddress)
- .then(usersToken => {
- })
- this.updateComponentSendErrors({})
-}
-
-ConfirmSendToken.prototype.componentDidUpdate = function (prevProps) {
- this.updateComponentSendErrors(prevProps)
-}
-
-ConfirmSendToken.prototype.getAmount = function () {
- const {
- conversionRate,
- tokenExchangeRate,
- token,
- tokenData,
- send: { amount, editingTransactionId },
- } = this.props
- const { params = [] } = tokenData
- let { value } = params[1] || {}
- const { decimals } = token
-
- if (editingTransactionId) {
- value = conversionUtil(amount, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- })
- }
-
- const sendTokenAmount = calcTokenAmount(value, decimals)
-
- return {
- fiat: tokenExchangeRate
- ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2)
- : null,
- token: typeof value === 'undefined'
- ? this.context.t('unknown')
- : +sendTokenAmount.toFixed(decimals),
- }
-
-}
-
-ConfirmSendToken.prototype.getGasFee = function () {
- const { conversionRate, tokenExchangeRate, token, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
- const { decimals } = token
-
- const gas = txParams.gas
- const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
- const gasTotal = multiplyCurrencies(gas, gasPrice, {
- multiplicandBase: 16,
- multiplierBase: 16,
- })
-
- const FIAT = conversionUtil(gasTotal, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- conversionRate,
- })
- const ETH = conversionUtil(gasTotal, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- numberOfDecimals: 6,
- conversionRate,
- })
- const tokenGas = multiplyCurrencies(gas, gasPrice, {
- toNumericBase: 'dec',
- multiplicandBase: 16,
- multiplierBase: 16,
- toCurrency: 'BAT',
- conversionRate: tokenExchangeRate,
- invertConversionRate: true,
- fromDenomination: 'WEI',
- numberOfDecimals: decimals || 4,
- })
-
- return {
- fiat: +Number(FIAT).toFixed(2),
- eth: ETH,
- token: tokenExchangeRate
- ? tokenGas
- : null,
- gasFeeInHex: gasTotal.toString(16),
- }
-}
-
-ConfirmSendToken.prototype.getData = function () {
- const { identities, tokenData } = this.props
- const { params = [] } = tokenData
- const { value } = params[0] || {}
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- return {
- from: {
- address: txParams.from,
- name: identities[txParams.from].name,
- },
- to: {
- address: value,
- name: identities[value] ? identities[value].name : this.context.t('newRecipient'),
- },
- memo: txParams.memo || '',
- }
-}
-
-ConfirmSendToken.prototype.renderHeroAmount = function () {
- const { token: { symbol }, currentCurrency } = this.props
- const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
- const { memo = '' } = txParams
-
- const convertedAmountInFiat = this.convertToRenderableCurrency(fiatAmount, currentCurrency)
-
- return fiatAmount
- ? (
- h('div.confirm-send-token__hero-amount-wrapper', [
- h('h3.flex-center.confirm-screen-send-amount', `${convertedAmountInFiat}`),
- h('h3.flex-center.confirm-screen-send-amount-currency', currentCurrency),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', [ memo ? `"${memo}"` : '' ]),
- ]),
- ])
- )
- : (
- h('div.confirm-send-token__hero-amount-wrapper', [
- h('h3.flex-center.confirm-screen-send-amount', tokenAmount),
- h('h3.flex-center.confirm-screen-send-amount-currency', symbol),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', [ memo ? `"${memo}"` : '' ]),
- ]),
- ])
- )
-}
-
-ConfirmSendToken.prototype.renderGasFee = function () {
- const {
- currentCurrency: convertedCurrency,
- conversionRate,
- send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice },
- showCustomizeGasModal,
- } = this.props
- const txMeta = this.gatherTxMeta()
- const { gasFeeInHex } = this.getGasFee()
-
- return (
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]),
- h('div.confirm-screen-section-column', [
- h(GasFeeDisplay, {
- gasTotal: gasTotal || gasFeeInHex,
- conversionRate,
- convertedCurrency,
- onClick: () => showCustomizeGasModal(txMeta, sendGasLimit, sendGasPrice, gasTotal),
- }),
- ]),
- ])
- )
-}
-
-ConfirmSendToken.prototype.renderTotalPlusGas = function () {
- const { token: { symbol }, currentCurrency, send: { errors } } = this.props
- const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
- const { fiat: fiatGas, token: tokenGas } = this.getGasFee()
-
- const totalInFIAT = fiatAmount && fiatGas && addCurrencies(fiatAmount, fiatGas)
- const convertedTotalInFiat = this.convertToRenderableCurrency(totalInFIAT, currentCurrency)
-
- return fiatAmount && fiatGas
- ? (
- h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
- h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
- h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
- ]),
-
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${convertedTotalInFiat} ${currentCurrency}`),
- h('div.confirm-screen-row-detail', `${addCurrencies(tokenAmount, tokenGas || '0')} ${symbol}`),
- ]),
- ])
- )
- : (
- h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
- h('div', {
- className: classnames({
- 'confirm-screen-section-column--with-error': errors['insufficientFunds'],
- 'confirm-screen-section-column': !errors['insufficientFunds'],
- }),
- }, [
- h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
- h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
- ]),
-
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`),
- h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.context.t('gas')}`),
- ]),
-
- this.renderErrorMessage('insufficientFunds'),
- ])
- )
-}
-
-ConfirmSendToken.prototype.renderErrorMessage = function (message) {
- const { send: { errors } } = this.props
-
- return errors[message]
- ? h('div.confirm-screen-error', [ errors[message] ])
- : null
-}
-
-ConfirmSendToken.prototype.convertToRenderableCurrency = function (value, currencyCode) {
- const upperCaseCurrencyCode = currencyCode.toUpperCase()
-
- return currencies.find(currency => currency.code === upperCaseCurrencyCode)
- ? currencyFormatter.format(Number(value), {
- code: upperCaseCurrencyCode,
- })
- : value
-}
-
-ConfirmSendToken.prototype.renderHeaderRow = function (isTxReprice) {
- const windowType = window.METAMASK_UI_TYPE
- const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION &&
- windowType !== ENVIRONMENT_TYPE_POPUP
-
- if (isTxReprice && isFullScreen) {
- return null
- }
-
- return (
- h('.page-container__header-row', [
- h('span.page-container__back-button', {
- onClick: () => this.editTransaction(),
- style: {
- visibility: isTxReprice ? 'hidden' : 'initial',
- },
- }, 'Edit'),
- !isFullScreen && h(NetworkDisplay),
- ])
- )
-}
-
-ConfirmSendToken.prototype.renderHeader = function (isTxReprice) {
- const title = isTxReprice ? this.context.t('speedUpTitle') : this.context.t('confirm')
- const subtitle = isTxReprice
- ? this.context.t('speedUpSubtitle')
- : this.context.t('pleaseReviewTransaction')
-
- return (
- h('.page-container__header', [
- this.renderHeaderRow(isTxReprice),
- h('.page-container__title', title),
- h('.page-container__subtitle', subtitle),
- ])
- )
-}
-
-ConfirmSendToken.prototype.render = function () {
- const txMeta = this.gatherTxMeta()
- const {
- from: {
- address: fromAddress,
- name: fromName,
- },
- to: {
- address: toAddress,
- name: toName,
- },
- } = this.getData()
-
- const isTxReprice = Boolean(txMeta.lastGasPrice)
-
- return (
- h('div.confirm-screen-container.confirm-send-token', [
- // Main Send token Card
- h('div.page-container', [
- this.renderHeader(isTxReprice),
- h('.page-container__content', [
- h('div.flex-row.flex-center.confirm-screen-identicons', [
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: fromAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', fromName),
- // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
- ]),
- h('i.fa.fa-arrow-right.fa-lg'),
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: toAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', toName),
- // h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
- ]),
- ]),
-
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
- // ]),
-
- this.renderHeroAmount(),
-
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
- ]),
- ]),
-
- toAddress && h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', toName),
- h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
- ]),
- ]),
-
- this.renderGasFee(),
-
- this.renderTotalPlusGas(),
-
- ]),
-
- ]),
-
- h('form#pending-tx-form', {
- className: 'confirm-screen-form',
- onSubmit: this.onSubmit,
- }, [
- this.renderErrorMessage('simulationFails'),
- h('.page-container__footer', [
- // Cancel Button
- h('button.btn-cancel.page-container__footer-button.allcaps', {
- onClick: (event) => this.cancel(event, txMeta),
- }, this.context.t('cancel')),
-
- // Accept Button
- h('button.btn-confirm.page-container__footer-button.allcaps', {
- onClick: event => this.onSubmit(event),
- }, [this.context.t('confirm')]),
- ]),
- ]),
- ]),
- ])
- )
-}
-
-ConfirmSendToken.prototype.onSubmit = function (event) {
- event.preventDefault()
- const { updateSendErrors } = this.props
- const txMeta = this.gatherTxMeta()
- const valid = this.checkValidity()
- const balanceIsSufficient = this.isBalanceSufficient(txMeta)
- this.setState({ valid, submitting: true })
-
- if (valid && this.verifyGasParams() && balanceIsSufficient) {
- this.props.sendTransaction(txMeta, event)
- } else if (!balanceIsSufficient) {
- updateSendErrors({ insufficientFunds: 'insufficientFunds' })
- } else {
- updateSendErrors({ invalidGasParams: 'invalidGasParams' })
- this.setState({ submitting: false })
- }
-}
-
-ConfirmSendToken.prototype.isBalanceSufficient = function (txMeta) {
- const {
- balance,
- conversionRate,
- } = this.props
- const {
- txParams: {
- gas,
- gasPrice,
- },
- } = txMeta
- const gasTotal = calcGasTotal(gas, gasPrice)
-
- return isBalanceSufficient({
- amount: '0',
- gasTotal,
- balance,
- conversionRate,
- })
-}
-
-
-ConfirmSendToken.prototype.cancel = function (event, txMeta) {
- event.preventDefault()
- const { cancelTransaction } = this.props
-
- cancelTransaction(txMeta)
- .then(() => this.props.history.push(DEFAULT_ROUTE))
-}
-
-ConfirmSendToken.prototype.checkValidity = function () {
- const form = this.getFormEl()
- const valid = form.checkValidity()
- return valid
-}
-
-ConfirmSendToken.prototype.getFormEl = function () {
- const form = document.querySelector('form#pending-tx-form')
- // Stub out form for unit tests:
- if (!form) {
- return { checkValidity () { return true } }
- }
- return form
-}
-
-// After a customizable state value has been updated,
-ConfirmSendToken.prototype.gatherTxMeta = function () {
- const props = this.props
- const state = this.state
- const txData = clone(state.txData) || clone(props.txData)
-
- const { gasPrice: sendGasPrice, gasLimit: sendGasLimit } = props.send
- const {
- lastGasPrice,
- txParams: {
- gasPrice: txGasPrice,
- gas: txGasLimit,
- },
- } = txData
-
- let forceGasMin
- if (lastGasPrice) {
- forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
- multiplicandBase: 16,
- multiplierBase: 10,
- toNumericBase: 'hex',
- }))
- }
-
- txData.txParams.gasPrice = sendGasPrice || forceGasMin || txGasPrice
- txData.txParams.gas = sendGasLimit || txGasLimit
-
- // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
- return txData
-}
-
-ConfirmSendToken.prototype.verifyGasParams = function () {
- // We call this in case the gas has not been modified at all
- if (!this.state) { return true }
- return (
- this._notZeroOrEmptyString(this.state.gas) &&
- this._notZeroOrEmptyString(this.state.gasPrice)
- )
-}
-
-ConfirmSendToken.prototype._notZeroOrEmptyString = function (obj) {
- return obj !== '' && obj !== '0x0'
-}
-
-ConfirmSendToken.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
- const numBN = new BN(numerator)
- const denomBN = new BN(denominator)
- return targetBN.mul(numBN).div(denomBN)
-}
diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js
deleted file mode 100644
index 3f8cd8823..000000000
--- a/ui/app/components/pending-tx/index.js
+++ /dev/null
@@ -1,165 +0,0 @@
-const Component = require('react').Component
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const PropTypes = require('prop-types')
-const clone = require('clone')
-const abi = require('human-standard-token-abi')
-const abiDecoder = require('abi-decoder')
-abiDecoder.addABI(abi)
-const inherits = require('util').inherits
-const actions = require('../../actions')
-const { getSymbolAndDecimals } = require('../../token-util')
-const ConfirmSendEther = require('./confirm-send-ether')
-const ConfirmSendToken = require('./confirm-send-token')
-const ConfirmDeployContract = require('./confirm-deploy-contract')
-const Loading = require('../loading-screen')
-
-const TX_TYPES = {
- DEPLOY_CONTRACT: 'deploy_contract',
- SEND_ETHER: 'send_ether',
- SEND_TOKEN: 'send_token',
-}
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(PendingTx)
-
-function mapStateToProps (state) {
- const {
- conversionRate,
- identities,
- tokens: existingTokens,
- } = state.metamask
- const accounts = state.metamask.accounts
- const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
- return {
- conversionRate,
- identities,
- selectedAddress,
- existingTokens,
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
- cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
- }
-}
-
-inherits(PendingTx, Component)
-function PendingTx () {
- Component.call(this)
- this.state = {
- isFetching: true,
- transactionType: '',
- tokenAddress: '',
- tokenSymbol: '',
- tokenDecimals: '',
- }
-}
-
-PendingTx.prototype.componentDidMount = function () {
- this.setTokenData()
-}
-
-PendingTx.prototype.componentDidUpdate = function (prevProps, prevState) {
- if (prevState.isFetching) {
- this.setTokenData()
- }
-}
-
-PendingTx.prototype.setTokenData = async function () {
- const { existingTokens } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- if (txMeta.loadingDefaults) {
- return
- }
-
- if (!txParams.to) {
- return this.setState({
- transactionType: TX_TYPES.DEPLOY_CONTRACT,
- isFetching: false,
- })
- }
-
- // inspect tx data for supported special confirmation screens
- let isTokenTransaction = false
- if (txParams.data) {
- const tokenData = abiDecoder.decodeMethod(txParams.data)
- const { name: tokenMethodName } = tokenData || {}
- isTokenTransaction = (tokenMethodName === 'transfer')
- }
-
- if (isTokenTransaction) {
- const { symbol, decimals } = await getSymbolAndDecimals(txParams.to, existingTokens)
-
- this.setState({
- transactionType: TX_TYPES.SEND_TOKEN,
- tokenAddress: txParams.to,
- tokenSymbol: symbol,
- tokenDecimals: decimals,
- isFetching: false,
- })
- } else {
- this.setState({
- transactionType: TX_TYPES.SEND_ETHER,
- isFetching: false,
- })
- }
-}
-
-PendingTx.prototype.gatherTxMeta = function () {
- const props = this.props
- const state = this.state
- const txData = clone(state.txData) || clone(props.txData)
-
- return txData
-}
-
-PendingTx.prototype.render = function () {
- const {
- isFetching,
- transactionType,
- tokenAddress,
- tokenSymbol,
- tokenDecimals,
- } = this.state
-
- const { sendTransaction } = this.props
-
- if (isFetching) {
- return h(Loading, {
- loadingMessage: this.context.t('generatingTransaction'),
- })
- }
-
- switch (transactionType) {
- case TX_TYPES.SEND_ETHER:
- return h(ConfirmSendEther, {
- txData: this.gatherTxMeta(),
- sendTransaction,
- })
- case TX_TYPES.SEND_TOKEN:
- return h(ConfirmSendToken, {
- txData: this.gatherTxMeta(),
- sendTransaction,
- token: {
- address: tokenAddress,
- symbol: tokenSymbol,
- decimals: tokenDecimals,
- },
- })
- case TX_TYPES.DEPLOY_CONTRACT:
- return h(ConfirmDeployContract, {
- txData: this.gatherTxMeta(),
- sendTransaction,
- })
- default:
- return h(Loading)
- }
-}
-
-PendingTx.contextTypes = {
- t: PropTypes.func,
-}
diff --git a/ui/app/components/selected-account/selected-account.component.js b/ui/app/components/selected-account/selected-account.component.js
index 3386a4196..6c202141e 100644
--- a/ui/app/components/selected-account/selected-account.component.js
+++ b/ui/app/components/selected-account/selected-account.component.js
@@ -1,17 +1,10 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import copyToClipboard from 'copy-to-clipboard'
+import { addressSlicer } from '../../util'
const Tooltip = require('../tooltip-v2.js')
-const addressStripper = (address = '') => {
- if (address.length < 4) {
- return address
- }
-
- return `${address.slice(0, 4)}...${address.slice(-4)}`
-}
-
class SelectedAccount extends Component {
state = {
copied: false,
@@ -48,7 +41,7 @@ class SelectedAccount extends Component {
{ selectedIdentity.name }
</div>
<div className="selected-account__address">
- { addressStripper(selectedAddress) }
+ { addressSlicer(selectedAddress) }
</div>
</div>
</Tooltip>
diff --git a/ui/app/components/send_/README.md b/ui/app/components/send/README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/README.md
+++ b/ui/app/components/send/README.md
diff --git a/ui/app/components/send_/account-list-item/account-list-item-README.md b/ui/app/components/send/account-list-item/account-list-item-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/account-list-item/account-list-item-README.md
+++ b/ui/app/components/send/account-list-item/account-list-item-README.md
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 322246f61..9f4a96e61 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,7 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { checksumAddress } from '../../../util'
import Identicon from '../../identicon'
-import CurrencyDisplay from '../../send/currency-display'
+import CurrencyDisplay from '../currency-display'
export default class AccountListItem extends Component {
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..4b4519288 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
diff --git a/ui/app/components/send_/account-list-item/account-list-item.scss b/ui/app/components/send/account-list-item/account-list-item.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/account-list-item/account-list-item.scss
+++ b/ui/app/components/send/account-list-item/account-list-item.scss
diff --git a/ui/app/components/send_/account-list-item/index.js b/ui/app/components/send/account-list-item/index.js
index 907485cf7..907485cf7 100644
--- a/ui/app/components/send_/account-list-item/index.js
+++ b/ui/app/components/send/account-list-item/index.js
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 bb7f3776c..ef152d2e7 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 '../../../send/currency-display'
+import CurrencyDisplay from '../../currency-display'
const utilsMethodStubs = {
checksumAddress: sinon.stub().returns('mockCheckSumAddress'),
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..af0859117 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
diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display/currency-display.js
index 1cf55ce1a..2b8eaa41f 100644
--- a/ui/app/components/send/currency-display.js
+++ b/ui/app/components/send/currency-display/currency-display.js
@@ -1,11 +1,16 @@
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_/send.utils')
+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
@@ -75,6 +80,12 @@ CurrencyDisplay.prototype.getValueToRender = function ({ selectedToken, conversi
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,
@@ -82,16 +93,15 @@ CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValu
numberOfDecimals: 2,
conversionRate,
})
- convertedValue = Number(convertedValue).toFixed(2)
+ convertedValue = Number(convertedValue).toFixed(2)
const upperCaseCurrencyCode = convertedCurrency.toUpperCase()
-
return currencies.find(currency => currency.code === upperCaseCurrencyCode)
? currencyFormatter.format(Number(convertedValue), {
code: upperCaseCurrencyCode,
})
- : convertedValue
-}
+ : convertedValue
+ }
CurrencyDisplay.prototype.handleChange = function (newVal) {
this.setState({ valueToRender: removeLeadingZeroes(newVal) })
@@ -105,13 +115,24 @@ CurrencyDisplay.prototype.getInputWidth = function (valueToRender, readOnly) {
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',
- convertedBalanceClassName = 'currency-display__converted-value',
primaryCurrency,
- convertedCurrency,
readOnly = false,
inError = false,
onBlur,
@@ -157,11 +178,7 @@ CurrencyDisplay.prototype.render = function () {
]),
- ]),
-
- h('div', {
- className: convertedBalanceClassName,
- }, `${convertedValueToRender} ${convertedCurrency.toUpperCase()}`),
+ ]), this.onlyRenderConversions(convertedValueToRender),
])
diff --git a/ui/app/components/send/currency-display/index.js b/ui/app/components/send/currency-display/index.js
new file mode 100644
index 000000000..5dc269c5a
--- /dev/null
+++ b/ui/app/components/send/currency-display/index.js
@@ -0,0 +1 @@
+export { default } from './currency-display.js'
diff --git a/ui/app/components/send_/index.js b/ui/app/components/send/index.js
index b5114babc..b5114babc 100644
--- a/ui/app/components/send_/index.js
+++ b/ui/app/components/send/index.js
diff --git a/ui/app/components/send_/send-content/index.js b/ui/app/components/send/send-content/index.js
index 891c17e6a..891c17e6a 100644
--- a/ui/app/components/send_/send-content/index.js
+++ b/ui/app/components/send/send-content/index.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/README.md b/ui/app/components/send/send-content/send-amount-row/README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-amount-row/README.md
+++ b/ui/app/components/send/send-content/send-amount-row/README.md
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..4d0d36ab4 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
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js
index 2d2ec42f7..2d2ec42f7 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js
index 69fec1994..69fec1994 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js
index b490a7fd7..b490a7fd7 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/index.js
index ee8271494..ee8271494 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/index.js
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..86a05ff21 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
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js
index 2cc00d6d6..2cc00d6d6 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js
index 655fe1969..655fe1969 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js
index 816df6a12..816df6a12 100644
--- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/index.js b/ui/app/components/send/send-content/send-amount-row/index.js
index abc6852fe..abc6852fe 100644
--- a/ui/app/components/send_/send-content/send-amount-row/index.js
+++ b/ui/app/components/send/send-content/send-amount-row/index.js
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 6e30d29a4..c548a5695 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,7 @@ 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 '../../../send/currency-display'
+import CurrencyDisplay from '../../currency-display'
export default class SendAmountRow extends Component {
diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js b/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js
index 3504d1b73..3504d1b73 100644
--- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js
+++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss b/ui/app/components/send/send-content/send-amount-row/send-amount-row.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss
+++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.scss
diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js b/ui/app/components/send/send-content/send-amount-row/send-amount-row.selectors.js
index fb08c7ed7..fb08c7ed7 100644
--- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js
+++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.selectors.js
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 95c000a34..8425e076e 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 '../../../../send/currency-display'
+import CurrencyDisplay from '../../../currency-display'
const propsMethodSpies = {
setMaxModeTo: sinon.spy(),
diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-container.test.js
index 52e351aee..52e351aee 100644
--- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-container.test.js
diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-selectors.test.js
index 4672cb8a7..4672cb8a7 100644
--- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js
+++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-selectors.test.js
diff --git a/ui/app/components/send_/send-content/send-content-README.md b/ui/app/components/send/send-content/send-content-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-content-README.md
+++ b/ui/app/components/send/send-content/send-content-README.md
diff --git a/ui/app/components/send_/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js
index adc114c0e..7a0b1a18e 100644
--- a/ui/app/components/send_/send-content/send-content.component.js
+++ b/ui/app/components/send/send-content/send-content.component.js
@@ -4,6 +4,7 @@ import PageContainerContent from '../../page-container/page-container-content.co
import SendAmountRow from './send-amount-row/'
import SendFromRow from './send-from-row/'
import SendGasRow from './send-gas-row/'
+import SendHexDataRow from './send-hex-data-row'
import SendToRow from './send-to-row/'
export default class SendContent extends Component {
@@ -20,6 +21,7 @@ export default class SendContent extends Component {
<SendToRow updateGas={(updateData) => this.props.updateGas(updateData)} />
<SendAmountRow updateGas={(updateData) => this.props.updateGas(updateData)} />
<SendGasRow />
+ <SendHexDataRow />
</div>
</PageContainerContent>
)
diff --git a/ui/app/components/send_/send-content/send-content.scss b/ui/app/components/send/send-content/send-content.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-content.scss
+++ b/ui/app/components/send/send-content/send-content.scss
diff --git a/ui/app/components/send_/send-content/send-dropdown-list/index.js b/ui/app/components/send/send-content/send-dropdown-list/index.js
index 04af6536c..04af6536c 100644
--- a/ui/app/components/send_/send-content/send-dropdown-list/index.js
+++ b/ui/app/components/send/send-content/send-dropdown-list/index.js
diff --git a/ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js b/ui/app/components/send/send-content/send-dropdown-list/send-dropdown-list.component.js
index bedac1259..bedac1259 100644
--- a/ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js
+++ b/ui/app/components/send/send-content/send-dropdown-list/send-dropdown-list.component.js
diff --git a/ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js b/ui/app/components/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js
index b92dd4dfe..b92dd4dfe 100644
--- a/ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js
+++ b/ui/app/components/send/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js
diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md
+++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown-README.md
diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js
index 4f43a9d61..4f43a9d61 100644
--- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js
+++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js
diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss
+++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.scss
diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js b/ui/app/components/send/send-content/send-from-row/from-dropdown/index.js
index 2314ef4e3..2314ef4e3 100644
--- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js
+++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/index.js
diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js b/ui/app/components/send/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js
index 84fcb281e..84fcb281e 100644
--- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js
+++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js
diff --git a/ui/app/components/send_/send-content/send-from-row/index.js b/ui/app/components/send/send-content/send-from-row/index.js
index 0a79726b2..0a79726b2 100644
--- a/ui/app/components/send_/send-content/send-from-row/index.js
+++ b/ui/app/components/send/send-content/send-from-row/index.js
diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row-README.md b/ui/app/components/send/send-content/send-from-row/send-from-row-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-from-row/send-from-row-README.md
+++ b/ui/app/components/send/send-content/send-from-row/send-from-row-README.md
diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.component.js b/ui/app/components/send/send-content/send-from-row/send-from-row.component.js
index 3e0e0de22..3e0e0de22 100644
--- a/ui/app/components/send_/send-content/send-from-row/send-from-row.component.js
+++ b/ui/app/components/send/send-content/send-from-row/send-from-row.component.js
diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.container.js b/ui/app/components/send/send-content/send-from-row/send-from-row.container.js
index 33cb63b43..33cb63b43 100644
--- a/ui/app/components/send_/send-content/send-from-row/send-from-row.container.js
+++ b/ui/app/components/send/send-content/send-from-row/send-from-row.container.js
diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js b/ui/app/components/send/send-content/send-from-row/send-from-row.selectors.js
index 03ef4806b..03ef4806b 100644
--- a/ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js
+++ b/ui/app/components/send/send-content/send-from-row/send-from-row.selectors.js
diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-component.test.js
index 9ba8d1739..9ba8d1739 100644
--- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js
+++ b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-component.test.js
diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-container.test.js
index e080b2fe3..e080b2fe3 100644
--- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js
+++ b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-container.test.js
diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-selectors.test.js
index ecb57bbc3..ecb57bbc3 100644
--- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js
+++ b/ui/app/components/send/send-content/send-from-row/tests/send-from-row-selectors.test.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/README.md b/ui/app/components/send/send-content/send-gas-row/README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-gas-row/README.md
+++ b/ui/app/components/send/send-content/send-gas-row/README.md
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..bb9a94428 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
diff --git a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/index.js
index dba0edb7b..dba0edb7b 100644
--- a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js
+++ b/ui/app/components/send/send-content/send-gas-row/gas-fee-display/index.js
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..7cbe8d0df 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
diff --git a/ui/app/components/send_/send-content/send-gas-row/index.js b/ui/app/components/send/send-content/send-gas-row/index.js
index 3c7ff1d5f..3c7ff1d5f 100644
--- a/ui/app/components/send_/send-content/send-gas-row/index.js
+++ b/ui/app/components/send/send-content/send-gas-row/index.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js b/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js
index 91b58cfd0..91b58cfd0 100644
--- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js
+++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js b/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js
index 8f8e3e4dd..8f8e3e4dd 100644
--- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js
+++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss b/ui/app/components/send/send-content/send-gas-row/send-gas-row.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss
+++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.scss
diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js b/ui/app/components/send/send-content/send-gas-row/send-gas-row.selectors.js
index 96f6293c2..96f6293c2 100644
--- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js
+++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.selectors.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-component.test.js
index 54a92bd2d..54a92bd2d 100644
--- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js
+++ b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-component.test.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-container.test.js
index 2ce062505..2ce062505 100644
--- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js
+++ b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-container.test.js
diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-selectors.test.js
index d46dd9d8b..d46dd9d8b 100644
--- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js
+++ b/ui/app/components/send/send-content/send-gas-row/tests/send-gas-row-selectors.test.js
diff --git a/ui/app/components/send/send-content/send-hex-data-row/index.js b/ui/app/components/send/send-content/send-hex-data-row/index.js
new file mode 100644
index 000000000..08c341067
--- /dev/null
+++ b/ui/app/components/send/send-content/send-hex-data-row/index.js
@@ -0,0 +1 @@
+export { default } from './send-hex-data-row.container'
diff --git a/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js
new file mode 100644
index 000000000..063930db3
--- /dev/null
+++ b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js
@@ -0,0 +1,40 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import SendRowWrapper from '../send-row-wrapper'
+
+export default class SendHexDataRow extends Component {
+ static propTypes = {
+ data: PropTypes.string,
+ inError: PropTypes.bool,
+ updateSendHexData: PropTypes.func.isRequired,
+ };
+
+ static contextTypes = {
+ t: PropTypes.func,
+ };
+
+ onInput = (event) => {
+ const {updateSendHexData} = this.props
+ event.target.value = event.target.value.replace(/\n/g, '')
+ updateSendHexData(event.target.value || null)
+ }
+
+ render () {
+ const {inError} = this.props
+ const {t} = this.context
+
+ return (
+ <SendRowWrapper
+ label={`${t('hexData')}:`}
+ showError={inError}
+ errorType={'amount'}
+ >
+ <textarea
+ onInput={this.onInput}
+ placeholder="Optional"
+ className="send-v2__hex-data__input"
+ />
+ </SendRowWrapper>
+ )
+ }
+}
diff --git a/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.container.js b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.container.js
new file mode 100644
index 000000000..df554ca5f
--- /dev/null
+++ b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.container.js
@@ -0,0 +1,21 @@
+import { connect } from 'react-redux'
+import {
+ updateSendHexData,
+} from '../../../../actions'
+import SendHexDataRow from './send-hex-data-row.component'
+
+export default connect(mapStateToProps, mapDispatchToProps)(SendHexDataRow)
+
+function mapStateToProps (state) {
+ return {
+ data: state.metamask.send.data,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ updateSendHexData (data) {
+ return dispatch(updateSendHexData(data))
+ },
+ }
+}
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/index.js b/ui/app/components/send/send-content/send-row-wrapper/index.js
index d17545dcc..d17545dcc 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/index.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/index.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/index.js
index c00617f83..c00617f83 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/index.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js
index 61bc7bab7..61bc7bab7 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js
index 59622047f..59622047f 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js
index 2304a43d2..2304a43d2 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js
index eecff165d..eecff165d 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper-README.md
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js
index b7528a15f..b7528a15f 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss
+++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.scss
diff --git a/ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js b/ui/app/components/send/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js
index 30280e1d0..30280e1d0 100644
--- a/ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js
+++ b/ui/app/components/send/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js
diff --git a/ui/app/components/send_/send-content/send-to-row/index.js b/ui/app/components/send/send-content/send-to-row/index.js
index 121f15148..121f15148 100644
--- a/ui/app/components/send_/send-content/send-to-row/index.js
+++ b/ui/app/components/send/send-content/send-to-row/index.js
diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row-README.md b/ui/app/components/send/send-content/send-to-row/send-to-row-README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-content/send-to-row/send-to-row-README.md
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row-README.md
diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
index 892ad5d67..892ad5d67 100644
--- a/ui/app/components/send_/send-content/send-to-row/send-to-row.component.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.container.js b/ui/app/components/send/send-content/send-to-row/send-to-row.container.js
index 1c9c9d518..1c9c9d518 100644
--- a/ui/app/components/send_/send-content/send-to-row/send-to-row.container.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.container.js
diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js b/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js
index 8919014be..8919014be 100644
--- a/ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js
diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js b/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js
index 6b90a9f09..6b90a9f09 100644
--- a/ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js
diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js
index 781371004..781371004 100644
--- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js
+++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js
diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js
index 92355c00a..92355c00a 100644
--- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js
+++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js
diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-selectors.test.js
index 122ad3265..122ad3265 100644
--- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js
+++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-selectors.test.js
diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js
index 4d2447c32..4d2447c32 100644
--- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js
+++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js
diff --git a/ui/app/components/send_/send-content/tests/send-content-component.test.js b/ui/app/components/send/send-content/tests/send-content-component.test.js
index d5bb6693c..d5bb6693c 100644
--- a/ui/app/components/send_/send-content/tests/send-content-component.test.js
+++ b/ui/app/components/send/send-content/tests/send-content-component.test.js
diff --git a/ui/app/components/send_/send-footer/README.md b/ui/app/components/send/send-footer/README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-footer/README.md
+++ b/ui/app/components/send/send-footer/README.md
diff --git a/ui/app/components/send_/send-footer/index.js b/ui/app/components/send/send-footer/index.js
index 58e91d622..58e91d622 100644
--- a/ui/app/components/send_/send-footer/index.js
+++ b/ui/app/components/send/send-footer/index.js
diff --git a/ui/app/components/send_/send-footer/send-footer.component.js b/ui/app/components/send/send-footer/send-footer.component.js
index 2085f1dce..518cff06e 100644
--- a/ui/app/components/send_/send-footer/send-footer.component.js
+++ b/ui/app/components/send/send-footer/send-footer.component.js
@@ -8,6 +8,7 @@ export default class SendFooter extends Component {
static propTypes = {
addToAddressBookIfNew: PropTypes.func,
amount: PropTypes.string,
+ data: PropTypes.string,
clearSend: PropTypes.func,
disabled: PropTypes.bool,
editingTransactionId: PropTypes.string,
@@ -41,6 +42,7 @@ export default class SendFooter extends Component {
const {
addToAddressBookIfNew,
amount,
+ data,
editingTransactionId,
from: {address: from},
gasLimit: gas,
@@ -68,6 +70,7 @@ export default class SendFooter extends Component {
const promise = editingTransactionId
? update({
amount,
+ data,
editingTransactionId,
from,
gas,
@@ -76,7 +79,7 @@ export default class SendFooter extends Component {
to,
unapprovedTxs,
})
- : sign({ selectedToken, to, amount, from, gas, gasPrice })
+ : sign({ data, selectedToken, to, amount, from, gas, gasPrice })
Promise.resolve(promise)
.then(() => history.push(CONFIRM_TRANSACTION_ROUTE))
diff --git a/ui/app/components/send_/send-footer/send-footer.container.js b/ui/app/components/send/send-footer/send-footer.container.js
index 0af6fcfa1..60de4d030 100644
--- a/ui/app/components/send_/send-footer/send-footer.container.js
+++ b/ui/app/components/send/send-footer/send-footer.container.js
@@ -18,6 +18,7 @@ import {
getSendFromObject,
getSendTo,
getSendToAccounts,
+ getSendHexData,
getTokenBalance,
getUnapprovedTxs,
} from '../send.selectors'
@@ -35,6 +36,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(SendFooter)
function mapStateToProps (state) {
return {
amount: getSendAmount(state),
+ data: getSendHexData(state),
editingTransactionId: getSendEditingTransactionId(state),
from: getSendFromObject(state),
gasLimit: getGasLimit(state),
@@ -52,9 +54,10 @@ function mapStateToProps (state) {
function mapDispatchToProps (dispatch) {
return {
clearSend: () => dispatch(clearSend()),
- sign: ({ selectedToken, to, amount, from, gas, gasPrice }) => {
+ sign: ({ selectedToken, to, amount, from, gas, gasPrice, data }) => {
const txParams = constructTxParams({
amount,
+ data,
from,
gas,
gasPrice,
@@ -68,6 +71,7 @@ function mapDispatchToProps (dispatch) {
},
update: ({
amount,
+ data,
editingTransactionId,
from,
gas,
@@ -78,6 +82,7 @@ function mapDispatchToProps (dispatch) {
}) => {
const editingTx = constructUpdatedTx({
amount,
+ data,
editingTransactionId,
from,
gas,
diff --git a/ui/app/components/send_/send-footer/send-footer.scss b/ui/app/components/send/send-footer/send-footer.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-footer/send-footer.scss
+++ b/ui/app/components/send/send-footer/send-footer.scss
diff --git a/ui/app/components/send_/send-footer/send-footer.selectors.js b/ui/app/components/send/send-footer/send-footer.selectors.js
index e20addfdc..e20addfdc 100644
--- a/ui/app/components/send_/send-footer/send-footer.selectors.js
+++ b/ui/app/components/send/send-footer/send-footer.selectors.js
diff --git a/ui/app/components/send_/send-footer/send-footer.utils.js b/ui/app/components/send/send-footer/send-footer.utils.js
index 875e7d948..f82ff1e9b 100644
--- a/ui/app/components/send_/send-footer/send-footer.utils.js
+++ b/ui/app/components/send/send-footer/send-footer.utils.js
@@ -8,8 +8,9 @@ function addHexPrefixToObjectValues (obj) {
}, {})
}
-function constructTxParams ({ selectedToken, to, amount, from, gas, gasPrice }) {
+function constructTxParams ({ selectedToken, data, to, amount, from, gas, gasPrice }) {
const txParams = {
+ data,
from,
value: '0',
gas,
@@ -21,13 +22,12 @@ function constructTxParams ({ selectedToken, to, amount, from, gas, gasPrice })
txParams.to = to
}
- const hexPrefixedTxParams = addHexPrefixToObjectValues(txParams)
-
- return hexPrefixedTxParams
+ return addHexPrefixToObjectValues(txParams)
}
function constructUpdatedTx ({
amount,
+ data,
editingTransactionId,
from,
gas,
@@ -36,9 +36,21 @@ function constructUpdatedTx ({
to,
unapprovedTxs,
}) {
+ const unapprovedTx = unapprovedTxs[editingTransactionId]
+ const txParamsData = unapprovedTx.txParams.data ? unapprovedTx.txParams.data : data
const editingTx = {
- ...unapprovedTxs[editingTransactionId],
- txParams: addHexPrefixToObjectValues({ from, gas, gasPrice }),
+ ...unapprovedTx,
+ txParams: Object.assign(
+ unapprovedTx.txParams,
+ addHexPrefixToObjectValues({
+ data: txParamsData,
+ to,
+ from,
+ gas,
+ gasPrice,
+ value: amount,
+ })
+ ),
}
if (selectedToken) {
@@ -52,18 +64,10 @@ function constructUpdatedTx ({
to: selectedToken.address,
data,
}))
- } else {
- const { data } = unapprovedTxs[editingTransactionId].txParams
-
- Object.assign(editingTx.txParams, addHexPrefixToObjectValues({
- value: amount,
- to,
- data,
- }))
+ }
- if (typeof editingTx.txParams.data === 'undefined') {
- delete editingTx.txParams.data
- }
+ if (typeof editingTx.txParams.data === 'undefined') {
+ delete editingTx.txParams.data
}
return editingTx
diff --git a/ui/app/components/send_/send-footer/tests/send-footer-component.test.js b/ui/app/components/send/send-footer/tests/send-footer-component.test.js
index 4b2cd327d..65e4bb654 100644
--- a/ui/app/components/send_/send-footer/tests/send-footer-component.test.js
+++ b/ui/app/components/send/send-footer/tests/send-footer-component.test.js
@@ -129,6 +129,7 @@ describe('SendFooter Component', function () {
assert.deepEqual(
propsMethodSpies.update.getCall(0).args[0],
{
+ data: undefined,
amount: 'mockAmount',
editingTransactionId: 'mockEditingTransactionId',
from: 'mockAddress',
@@ -152,6 +153,7 @@ describe('SendFooter Component', function () {
assert.deepEqual(
propsMethodSpies.sign.getCall(0).args[0],
{
+ data: undefined,
amount: 'mockAmount',
from: 'mockAddress',
gas: 'mockGasLimit',
diff --git a/ui/app/components/send_/send-footer/tests/send-footer-container.test.js b/ui/app/components/send/send-footer/tests/send-footer-container.test.js
index 39d6a7686..cf4c893ee 100644
--- a/ui/app/components/send_/send-footer/tests/send-footer-container.test.js
+++ b/ui/app/components/send/send-footer/tests/send-footer-container.test.js
@@ -38,6 +38,7 @@ proxyquire('../send-footer.container.js', {
getSendTo: (s) => `mockTo:${s}`,
getSendToAccounts: (s) => `mockToAccounts:${s}`,
getTokenBalance: (s) => `mockTokenBalance:${s}`,
+ getSendHexData: (s) => `mockHexData:${s}`,
getUnapprovedTxs: (s) => `mockUnapprovedTxs:${s}`,
},
'./send-footer.selectors': { isSendFormInError: (s) => `mockInError:${s}` },
@@ -51,6 +52,7 @@ describe('send-footer container', () => {
it('should map the correct properties to props', () => {
assert.deepEqual(mapStateToProps('mockState'), {
amount: 'mockAmount:mockState',
+ data: 'mockHexData:mockState',
selectedToken: 'mockSelectedToken:mockState',
editingTransactionId: 'mockEditingTransactionId:mockState',
from: 'mockFromObject:mockState',
@@ -100,6 +102,7 @@ describe('send-footer container', () => {
assert.deepEqual(
utilsStubs.constructTxParams.getCall(0).args[0],
{
+ data: undefined,
selectedToken: {
address: '0xabc',
},
@@ -129,6 +132,7 @@ describe('send-footer container', () => {
assert.deepEqual(
utilsStubs.constructTxParams.getCall(0).args[0],
{
+ data: undefined,
selectedToken: undefined,
to: 'mockTo',
amount: 'mockAmount',
@@ -160,6 +164,7 @@ describe('send-footer container', () => {
assert.deepEqual(
utilsStubs.constructUpdatedTx.getCall(0).args[0],
{
+ data: undefined,
to: 'mockTo',
amount: 'mockAmount',
from: 'mockFrom',
diff --git a/ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js b/ui/app/components/send/send-footer/tests/send-footer-selectors.test.js
index 8de032f57..8de032f57 100644
--- a/ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js
+++ b/ui/app/components/send/send-footer/tests/send-footer-selectors.test.js
diff --git a/ui/app/components/send_/send-footer/tests/send-footer-utils.test.js b/ui/app/components/send/send-footer/tests/send-footer-utils.test.js
index 2d3135995..28ff0c891 100644
--- a/ui/app/components/send_/send-footer/tests/send-footer-utils.test.js
+++ b/ui/app/components/send/send-footer/tests/send-footer-utils.test.js
@@ -65,6 +65,28 @@ describe('send-footer utils', () => {
})
describe('constructTxParams()', () => {
+ it('should return a new txParams object with data if there data is given', () => {
+ assert.deepEqual(
+ constructTxParams({
+ data: 'someData',
+ selectedToken: false,
+ to: 'mockTo',
+ amount: 'mockAmount',
+ from: 'mockFrom',
+ gas: 'mockGas',
+ gasPrice: 'mockGasPrice',
+ }),
+ {
+ data: '0xsomeData',
+ to: '0xmockTo',
+ value: '0xmockAmount',
+ from: '0xmockFrom',
+ gas: '0xmockGas',
+ gasPrice: '0xmockGasPrice',
+ }
+ )
+ })
+
it('should return a new txParams object with value and to properties if there is no selectedToken', () => {
assert.deepEqual(
constructTxParams({
@@ -76,6 +98,7 @@ describe('send-footer utils', () => {
gasPrice: 'mockGasPrice',
}),
{
+ data: undefined,
to: '0xmockTo',
value: '0xmockAmount',
from: '0xmockFrom',
@@ -96,6 +119,7 @@ describe('send-footer utils', () => {
gasPrice: 'mockGasPrice',
}),
{
+ data: undefined,
value: '0x0',
from: '0xmockFrom',
gas: '0xmockGas',
diff --git a/ui/app/components/send_/send-header/README.md b/ui/app/components/send/send-header/README.md
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send-header/README.md
+++ b/ui/app/components/send/send-header/README.md
diff --git a/ui/app/components/send_/send-header/index.js b/ui/app/components/send/send-header/index.js
index 0b17f0b7d..0b17f0b7d 100644
--- a/ui/app/components/send_/send-header/index.js
+++ b/ui/app/components/send/send-header/index.js
diff --git a/ui/app/components/send_/send-header/send-header.component.js b/ui/app/components/send/send-header/send-header.component.js
index efc4bbf27..efc4bbf27 100644
--- a/ui/app/components/send_/send-header/send-header.component.js
+++ b/ui/app/components/send/send-header/send-header.component.js
diff --git a/ui/app/components/send_/send-header/send-header.container.js b/ui/app/components/send/send-header/send-header.container.js
index 4bcd0d1b6..4bcd0d1b6 100644
--- a/ui/app/components/send_/send-header/send-header.container.js
+++ b/ui/app/components/send/send-header/send-header.container.js
diff --git a/ui/app/components/send_/send-header/send-header.selectors.js b/ui/app/components/send/send-header/send-header.selectors.js
index d7c9d3766..d7c9d3766 100644
--- a/ui/app/components/send_/send-header/send-header.selectors.js
+++ b/ui/app/components/send/send-header/send-header.selectors.js
diff --git a/ui/app/components/send_/send-header/tests/send-header-component.test.js b/ui/app/components/send/send-header/tests/send-header-component.test.js
index 930bfa387..930bfa387 100644
--- a/ui/app/components/send_/send-header/tests/send-header-component.test.js
+++ b/ui/app/components/send/send-header/tests/send-header-component.test.js
diff --git a/ui/app/components/send_/send-header/tests/send-header-container.test.js b/ui/app/components/send/send-header/tests/send-header-container.test.js
index 41a7e8a89..41a7e8a89 100644
--- a/ui/app/components/send_/send-header/tests/send-header-container.test.js
+++ b/ui/app/components/send/send-header/tests/send-header-container.test.js
diff --git a/ui/app/components/send_/send-header/tests/send-header-selectors.test.js b/ui/app/components/send/send-header/tests/send-header-selectors.test.js
index e0c6a3ab3..e0c6a3ab3 100644
--- a/ui/app/components/send_/send-header/tests/send-header-selectors.test.js
+++ b/ui/app/components/send/send-header/tests/send-header-selectors.test.js
diff --git a/ui/app/components/send_/send.component.js b/ui/app/components/send/send.component.js
index 6f1b20c55..6f1b20c55 100644
--- a/ui/app/components/send_/send.component.js
+++ b/ui/app/components/send/send.component.js
diff --git a/ui/app/components/send_/send.constants.js b/ui/app/components/send/send.constants.js
index 8acdf0641..8acdf0641 100644
--- a/ui/app/components/send_/send.constants.js
+++ b/ui/app/components/send/send.constants.js
diff --git a/ui/app/components/send_/send.container.js b/ui/app/components/send/send.container.js
index 44ebd2792..44ebd2792 100644
--- a/ui/app/components/send_/send.container.js
+++ b/ui/app/components/send/send.container.js
diff --git a/ui/app/components/send_/send.scss b/ui/app/components/send/send.scss
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/send_/send.scss
+++ b/ui/app/components/send/send.scss
diff --git a/ui/app/components/send_/send.selectors.js b/ui/app/components/send/send.selectors.js
index f910f7caf..cf07eafe1 100644
--- a/ui/app/components/send_/send.selectors.js
+++ b/ui/app/components/send/send.selectors.js
@@ -33,6 +33,7 @@ const selectors = {
getSelectedTokenExchangeRate,
getSelectedTokenToFiatRate,
getSendAmount,
+ getSendHexData,
getSendEditingTransactionId,
getSendErrors,
getSendFrom,
@@ -210,6 +211,10 @@ function getSendAmount (state) {
return state.metamask.send.amount
}
+function getSendHexData (state) {
+ return state.metamask.send.data
+}
+
function getSendEditingTransactionId (state) {
return state.metamask.send.editingTransactionId
}
diff --git a/ui/app/components/send_/send.utils.js b/ui/app/components/send/send.utils.js
index aa255c3d4..aa255c3d4 100644
--- a/ui/app/components/send_/send.utils.js
+++ b/ui/app/components/send/send.utils.js
diff --git a/ui/app/components/send_/tests/send-component.test.js b/ui/app/components/send/tests/send-component.test.js
index 6194ec508..6194ec508 100644
--- a/ui/app/components/send_/tests/send-component.test.js
+++ b/ui/app/components/send/tests/send-component.test.js
diff --git a/ui/app/components/send_/tests/send-container.test.js b/ui/app/components/send/tests/send-container.test.js
index 7a9120d24..7a9120d24 100644
--- a/ui/app/components/send_/tests/send-container.test.js
+++ b/ui/app/components/send/tests/send-container.test.js
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 8f9c19314..8f9c19314 100644
--- a/ui/app/components/send_/tests/send-selectors-test-data.js
+++ b/ui/app/components/send/tests/send-selectors-test-data.js
diff --git a/ui/app/components/send_/tests/send-selectors.test.js b/ui/app/components/send/tests/send-selectors.test.js
index 218da656b..218da656b 100644
--- a/ui/app/components/send_/tests/send-selectors.test.js
+++ b/ui/app/components/send/tests/send-selectors.test.js
diff --git a/ui/app/components/send_/tests/send-utils.test.js b/ui/app/components/send/tests/send-utils.test.js
index b8579e0e4..18dde495a 100644
--- a/ui/app/components/send_/tests/send-utils.test.js
+++ b/ui/app/components/send/tests/send-utils.test.js
@@ -58,6 +58,7 @@ const {
calcTokenBalance,
isBalanceSufficient,
isTokenBalanceSufficient,
+ removeLeadingZeroes,
} = sendUtils
describe('send utils', () => {
@@ -483,4 +484,29 @@ describe('send utils', () => {
assert.equal(getToAddressForGasUpdate(undefined, 'B'), 'b')
})
})
+
+ describe('removeLeadingZeroes()', () => {
+ it('should remove leading zeroes from int when user types', () => {
+ assert.equal(removeLeadingZeroes('0'), '0')
+ assert.equal(removeLeadingZeroes('1'), '1')
+ assert.equal(removeLeadingZeroes('00'), '0')
+ assert.equal(removeLeadingZeroes('01'), '1')
+ })
+
+ it('should remove leading zeroes from int when user copy/paste', () => {
+ assert.equal(removeLeadingZeroes('001'), '1')
+ })
+
+ it('should remove leading zeroes from float when user types', () => {
+ assert.equal(removeLeadingZeroes('0.'), '0.')
+ assert.equal(removeLeadingZeroes('0.0'), '0.0')
+ assert.equal(removeLeadingZeroes('0.00'), '0.00')
+ assert.equal(removeLeadingZeroes('0.001'), '0.001')
+ assert.equal(removeLeadingZeroes('0.10'), '0.10')
+ })
+
+ it('should remove leading zeroes from float when user copy/paste', () => {
+ assert.equal(removeLeadingZeroes('00.1'), '0.1')
+ })
+ })
})
diff --git a/ui/app/components/send/to-autocomplete.component.js b/ui/app/components/send/to-autocomplete.component.js
index 19f534b94..9e270db75 100644
--- a/ui/app/components/send/to-autocomplete.component.js
+++ b/ui/app/components/send/to-autocomplete.component.js
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
-import AccountListItem from '../send_/account-list-item/account-list-item.component'
+import AccountListItem from '../send/account-list-item/account-list-item.component'
export default class ToAutoComplete extends Component {
diff --git a/ui/app/components/send/to-autocomplete/index.js b/ui/app/components/send/to-autocomplete/index.js
new file mode 100644
index 000000000..244d301d1
--- /dev/null
+++ b/ui/app/components/send/to-autocomplete/index.js
@@ -0,0 +1 @@
+export { default } from './to-autocomplete.js'
diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js
new file mode 100644
index 000000000..80cfa7a85
--- /dev/null
+++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js
@@ -0,0 +1,120 @@
+const Component = require('react').Component
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const AccountListItem = require('../account-list-item/account-list-item.component').default
+const connect = require('react-redux').connect
+
+ToAutoComplete.contextTypes = {
+ t: PropTypes.func,
+}
+
+module.exports = connect()(ToAutoComplete)
+
+
+inherits(ToAutoComplete, Component)
+function ToAutoComplete () {
+ Component.call(this)
+
+ this.state = { accountsToRender: [] }
+}
+
+ToAutoComplete.prototype.getListItemIcon = function (listItemAddress, toAddress) {
+ const listItemIcon = h(`i.fa.fa-check.fa-lg`, { style: { color: '#02c9b1' } })
+
+ return toAddress && listItemAddress === toAddress
+ ? listItemIcon
+ : null
+}
+
+ToAutoComplete.prototype.renderDropdown = function () {
+ const {
+ closeDropdown,
+ onChange,
+ to,
+ } = this.props
+ const { accountsToRender } = this.state
+
+ return accountsToRender.length && h('div', {}, [
+
+ h('div.send-v2__from-dropdown__close-area', {
+ onClick: closeDropdown,
+ }),
+
+ h('div.send-v2__from-dropdown__list', {}, [
+
+ ...accountsToRender.map(account => h(AccountListItem, {
+ account,
+ className: 'account-list-item__dropdown',
+ handleClick: () => {
+ onChange(account.address)
+ closeDropdown()
+ },
+ icon: this.getListItemIcon(account.address, to),
+ displayBalance: false,
+ displayAddress: true,
+ })),
+
+ ]),
+
+ ])
+}
+
+ToAutoComplete.prototype.handleInputEvent = function (event = {}, cb) {
+ const {
+ to,
+ accounts,
+ closeDropdown,
+ openDropdown,
+ } = this.props
+
+ const matchingAccounts = accounts.filter(({ address }) => address.match(to || ''))
+ const matches = matchingAccounts.length
+
+ if (!matches || matchingAccounts[0].address === to) {
+ this.setState({ accountsToRender: [] })
+ event.target && event.target.select()
+ closeDropdown()
+ } else {
+ this.setState({ accountsToRender: matchingAccounts })
+ openDropdown()
+ }
+ cb && cb(event.target.value)
+}
+
+ToAutoComplete.prototype.componentDidUpdate = function (nextProps, nextState) {
+ if (this.props.to !== nextProps.to) {
+ this.handleInputEvent()
+ }
+}
+
+ToAutoComplete.prototype.render = function () {
+ const {
+ to,
+ dropdownOpen,
+ onChange,
+ inError,
+ } = this.props
+
+ return h('div.send-v2__to-autocomplete', {}, [
+
+ h('input.send-v2__to-autocomplete__input', {
+ placeholder: this.context.t('recipientAddress'),
+ className: inError ? `send-v2__error-border` : '',
+ value: to,
+ onChange: event => onChange(event.target.value),
+ onFocus: event => this.handleInputEvent(event),
+ style: {
+ borderColor: inError ? 'red' : null,
+ },
+ }),
+
+ !to && h(`i.fa.fa-caret-down.fa-lg.send-v2__to-autocomplete__down-caret`, {
+ style: { color: '#dedede' },
+ onClick: () => this.handleInputEvent(),
+ }),
+
+ dropdownOpen && this.renderDropdown(),
+
+ ])
+}
diff --git a/ui/app/components/send_/send.utils.test.js b/ui/app/components/send_/send.utils.test.js
deleted file mode 100644
index 36f3a5c10..000000000
--- a/ui/app/components/send_/send.utils.test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import assert from 'assert'
-import { removeLeadingZeroes } from './send.utils'
-
-
-describe('send utils', () => {
- describe('removeLeadingZeroes()', () => {
- it('should remove leading zeroes from int when user types', () => {
- assert.equal(removeLeadingZeroes('0'), '0')
- assert.equal(removeLeadingZeroes('1'), '1')
- assert.equal(removeLeadingZeroes('00'), '0')
- assert.equal(removeLeadingZeroes('01'), '1')
- })
-
- it('should remove leading zeroes from int when user copy/paste', () => {
- assert.equal(removeLeadingZeroes('001'), '1')
- })
-
- it('should remove leading zeroes from float when user types', () => {
- assert.equal(removeLeadingZeroes('0.'), '0.')
- assert.equal(removeLeadingZeroes('0.0'), '0.0')
- assert.equal(removeLeadingZeroes('0.00'), '0.00')
- assert.equal(removeLeadingZeroes('0.001'), '0.001')
- assert.equal(removeLeadingZeroes('0.10'), '0.10')
- })
-
- it('should remove leading zeroes from float when user copy/paste', () => {
- assert.equal(removeLeadingZeroes('00.1'), '0.1')
- })
- })
-})
diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js
index e539514ec..0d693b805 100644
--- a/ui/app/components/tx-list-item.js
+++ b/ui/app/components/tx-list-item.js
@@ -307,20 +307,16 @@ TxListItem.prototype.render = function () {
]),
]),
- this.showRetryButton() && h('div.tx-list-item-retry-container', [
-
- h('span.tx-list-item-retry-copy', 'Taking too long?'),
-
- h('span.tx-list-item-retry-link', {
- onClick: (event) => {
- event.stopPropagation()
- if (isTokenTx) {
- this.setSelectedToken(txParams.to)
- }
- this.resubmit()
- },
- }, 'Increase the gas price on your transaction'),
-
+ this.showRetryButton() && h('.tx-list-item-retry-container', {
+ onClick: (event) => {
+ event.stopPropagation()
+ if (isTokenTx) {
+ this.setSelectedToken(txParams.to)
+ }
+ this.resubmit()
+ },
+ }, [
+ h('span', 'Taking too long? Increase the gas price on your transaction'),
]),
]), // holding on icon from design
diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js
index da142fad8..20c2be0f1 100644
--- a/ui/app/components/wallet-view.js
+++ b/ui/app/components/wallet-view.js
@@ -175,7 +175,7 @@ WalletView.prototype.render = function () {
this.setState({ copyToClipboardPressed: false })
},
}, [
- `${checksummedAddress.slice(0, 4)}...${checksummedAddress.slice(-4)}`,
+ `${checksummedAddress.slice(0, 6)}...${checksummedAddress.slice(-4)}`,
h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }),
]),
]),
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index 4e8aaa07d..112ea6bca 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -9,11 +9,7 @@ const txHelper = require('../lib/tx-helper')
const log = require('loglevel')
const R = require('ramda')
-const PendingTx = require('./components/pending-tx')
const SignatureRequest = require('./components/signature-request')
-// const PendingMsg = require('./components/pending-msg')
-// const PendingPersonalMsg = require('./components/pending-personal-msg')
-// const PendingTypedMsg = require('./components/pending-typed-msg')
const Loading = require('./components/loading-screen')
const { DEFAULT_ROUTE } = require('./routes')
@@ -151,101 +147,32 @@ ConfirmTxScreen.prototype.render = function () {
currentCurrency,
conversionRate,
blockGasLimit,
- // provider,
- // computedBalances,
} = props
var txData = this.getTxData() || {}
- var txParams = txData.params || {}
-
- // var isNotification = isPopupOrNotification() === 'notification'
- /*
- Client is using the flag above to render the following in conf screen
- // subtitle and nav
- h('.section-title.flex-row.flex-center', [
- !isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: this.goHome.bind(this),
- }) : null,
- h('h2.page-subtitle', 'Confirm Transaction'),
- isNotification ? h(NetworkIndicator, {
- network: network,
- provider: provider,
- }) : null,
- ]),
- */
-
- return currentTxView({
- // Properties
- txData: txData,
- key: txData.id,
- selectedAddress: props.selectedAddress,
- accounts: props.accounts,
- identities: props.identities,
- conversionRate,
- currentCurrency,
- blockGasLimit,
- // Actions
- buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress),
- sendTransaction: this.sendTransaction.bind(this),
- cancelTransaction: this.cancelTransaction.bind(this, txData),
- signMessage: this.signMessage.bind(this, txData),
- signPersonalMessage: this.signPersonalMessage.bind(this, txData),
- signTypedMessage: this.signTypedMessage.bind(this, txData),
- cancelMessage: this.cancelMessage.bind(this, txData),
- cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
- cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
- })
-}
-
-function currentTxView (opts) {
- log.info('rendering current tx view')
- const { txData } = opts
- const { txParams, msgParams } = txData
-
- if (txParams) {
- log.debug('txParams detected, rendering pending tx')
- return h(PendingTx, opts)
- } else if (msgParams) {
- log.debug('msgParams detected, rendering pending msg')
-
- return h(SignatureRequest, opts)
-
- // if (type === 'eth_sign') {
- // log.debug('rendering eth_sign message')
- // return h(PendingMsg, opts)
- // } else if (type === 'personal_sign') {
- // log.debug('rendering personal_sign message')
- // return h(PendingPersonalMsg, opts)
- // } else if (type === 'eth_signTypedData') {
- // log.debug('rendering eth_signTypedData message')
- // return h(PendingTypedMsg, opts)
- // }
- }
-
- return h(Loading)
-}
-
-ConfirmTxScreen.prototype.buyEth = function (address, event) {
- event.preventDefault()
- this.props.dispatch(actions.buyEthView(address))
-}
-
-ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
- this.stopPropagation(event)
- this.props.dispatch(actions.updateAndApproveTx(txData))
- .then(() => this.props.history.push(DEFAULT_ROUTE))
-}
-
-ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
- this.stopPropagation(event)
- event.preventDefault()
- this.props.dispatch(actions.cancelTx(txData))
-}
-
-ConfirmTxScreen.prototype.cancelAllTransactions = function (unconfTxList, event) {
- this.stopPropagation(event)
- event.preventDefault()
- this.props.dispatch(actions.cancelAllTx(unconfTxList))
+ const { msgParams } = txData
+ log.debug('msgParams detected, rendering pending msg')
+
+ return msgParams
+ ? h(SignatureRequest, {
+ // Properties
+ txData: txData,
+ key: txData.id,
+ selectedAddress: props.selectedAddress,
+ accounts: props.accounts,
+ identities: props.identities,
+ conversionRate,
+ currentCurrency,
+ blockGasLimit,
+ // Actions
+ signMessage: this.signMessage.bind(this, txData),
+ signPersonalMessage: this.signPersonalMessage.bind(this, txData),
+ signTypedMessage: this.signTypedMessage.bind(this, txData),
+ cancelMessage: this.cancelMessage.bind(this, txData),
+ cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
+ cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
+ })
+ : h(Loading)
}
ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
@@ -295,20 +222,3 @@ ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) {
this.stopPropagation(event)
return this.props.dispatch(actions.cancelTypedMsg(msgData))
}
-
-ConfirmTxScreen.prototype.goHome = function (event) {
- this.stopPropagation(event)
- this.props.dispatch(actions.goHome())
-}
-
-// function warningIfExists (warning) {
-// if (warning &&
-// // Do not display user rejections on this screen:
-// warning.indexOf('User denied transaction signature') === -1) {
-// return h('.error', {
-// style: {
-// margin: 'auto',
-// },
-// }, warning)
-// }
-// }
diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss
index 96fba890c..b14753e23 100644
--- a/ui/app/css/itcss/components/account-menu.scss
+++ b/ui/app/css/itcss/components/account-menu.scss
@@ -72,6 +72,7 @@
background-color: $dusty-gray;
color: $black;
font-weight: normal;
+ letter-spacing: .5px;
}
}
@@ -84,6 +85,23 @@
@media screen and (max-width: 575px) {
padding: 12px 14px;
}
+
+ .remove-account-icon {
+ width: 15px;
+ margin-left: 10px;
+ height: 15px;
+ }
+
+ &:hover {
+ .remove-account-icon::after {
+ content: '\00D7';
+ font-size: 25px;
+ color: $white;
+ cursor: pointer;
+ position: absolute;
+ margin-top: -5px;
+ }
+ }
}
&__account-info {
diff --git a/ui/app/css/itcss/components/alert.scss b/ui/app/css/itcss/components/alert.scss
new file mode 100644
index 000000000..930fc3f54
--- /dev/null
+++ b/ui/app/css/itcss/components/alert.scss
@@ -0,0 +1,57 @@
+.global-alert {
+ position: relative;
+ width: 100%;
+ background-color: #33A4E7;
+
+ .msg {
+ width: 100%;
+ display: block;
+ color: white;
+ font-size: 12px;
+ text-align: center;
+ }
+}
+
+.global-alert.hidden {
+ animation: alertHidden .5s ease forwards;
+}
+
+.global-alert.visible {
+ animation: alert .5s ease forwards;
+}
+
+/* Animation */
+@keyframes alert {
+ 0% {
+ opacity: 0;
+ top: -50px;
+ padding: 0px;
+ line-height: 12px;
+ }
+
+ 50% {
+ opacity: 1;
+ }
+
+ 100% {
+ top: 0;
+ padding: 8px;
+ line-height: 12px;
+ }
+}
+
+@keyframes alertHidden {
+ 0% {
+ top: 0;
+ opacity: 1;
+ padding: 8px;
+ line-height: 12px;
+ }
+
+ 100% {
+ opacity: 0;
+ top: -50px;
+ padding: 0px;
+ line-height: 0px;
+ }
+}
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
index 5be040906..96ad5fe64 100644
--- a/ui/app/css/itcss/components/index.scss
+++ b/ui/app/css/itcss/components/index.scss
@@ -8,6 +8,8 @@
@import './modal.scss';
+@import './alert.scss';
+
@import './newui-sections.scss';
@import './account-dropdown.scss';
diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss
index 293579058..b12afb124 100644
--- a/ui/app/css/itcss/components/new-account.scss
+++ b/ui/app/css/itcss/components/new-account.scss
@@ -1,9 +1,8 @@
.new-account {
- width: 376px;
+ width: 375px;
background-color: #FFFFFF;
box-shadow: 0 0 7px 0 rgba(0,0,0,0.08);
z-index: 25;
- padding-bottom: 31px;
&__header {
display: flex;
@@ -28,7 +27,6 @@
&__tab {
height: 54px;
- width: 75px;
padding: 15px 10px;
color: $dusty-gray;
font-family: Roboto;
@@ -38,10 +36,6 @@
cursor: pointer;
}
- &__tab:first-of-type {
- margin-right: 20px;
- }
-
&__tab:hover {
color: $black;
border-bottom: none;
@@ -69,7 +63,7 @@
display: flex;
flex-flow: column;
align-items: center;
- padding: 0 30px;
+ padding: 0 30px 30px;
&__select-section {
display: flex;
@@ -158,11 +152,296 @@
}
}
+.hw-tutorial {
+ width: 375px;
+ border-top: 1px solid #D2D8DD;
+ border-bottom: 1px solid #D2D8DD;
+ overflow: visible;
+ display: block;
+ padding: 15px 30px;
+}
+
+.hw-connect {
+ &__header {
+ &__title {
+ margin-top: 5px;
+ margin-bottom: 15px;
+ font-size: 22px;
+ text-align: center;
+ }
+
+ &__msg {
+ font-size: 14px;
+ color: #9b9b9b;
+ margin-top: 10px;
+ margin-bottom: 0px;
+ }
+ }
+
+ &__learn-more {
+ margin-top: 15px;
+ font-size: 14px;
+ color: #5B5D67;
+ line-height: 19px;
+ text-align: center;
+ cursor: pointer;
+
+ &__arrow {
+ transform: rotate(90deg);
+ display: block;
+ text-align: center;
+ height: 30px;
+ margin: 0px auto 10px;
+ }
+ }
+
+ &__title {
+ padding-top: 10px;
+ font-weight: 400;
+ font-size: 18px;
+ }
+
+ &__msg {
+ font-size: 14px;
+ color: #9b9b9b;
+ margin-top: 10px;
+ margin-bottom: 15px;
+ }
+
+ &__link {
+ color: #2f9ae0;
+ }
+
+ &__footer {
+ width: 100%;
+
+ &__title {
+ padding-top: 15px;
+ padding-bottom: 12px;
+ font-weight: 400;
+ font-size: 18px;
+ text-align: center;
+ }
+
+ &__msg {
+ font-size: 14px;
+ color: #9b9b9b;
+ margin-top: 12px;
+ margin-bottom: 27px;
+ }
+
+ &__link {
+ color: #2f9ae0;
+ margin-left: 5px;
+ }
+ }
+
+ &__get-trezor {
+ width: 100%;
+ padding-bottom: 20px;
+ padding-top: 20px;
+
+ &__msg {
+ font-size: 14px;
+ color: #9b9b9b;
+ }
+
+ &__link {
+ font-size: 14px;
+ text-align: center;
+ color: #2f9ae0;
+ cursor: pointer;
+ }
+ }
+
+ &__step-asset {
+ margin: 0px auto 20px;
+ display: flex;
+ }
+}
+
+.hw-account-list {
+ display: flex;
+ flex: 1;
+ flex-flow: column;
+ width: 100%;
+
+ &__title_wrapper {
+ display: flex;
+ flex-direction: row;
+ flex: 1;
+ }
+
+ &__title {
+ margin-bottom: 23px;
+ align-self: flex-start;
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ font-weight: bold;
+ display: flex;
+ flex: 1;
+ }
+
+ &__device {
+ margin-bottom: 23px;
+ align-self: flex-end;
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ font-weight: normal;
+ display: flex;
+ }
+
+ &__item {
+ font-size: 15px;
+ flex-direction: row;
+ display: flex;
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+
+ &__item:nth-of-type(even) {
+ background-color: #fbfbfb;
+ }
+
+ &__item:nth-of-type(odd) {
+ background: rgba(0, 0, 0, 0.03);
+ }
+
+ &__item:hover {
+ background-color: rgba(0, 0, 0, 0.06);
+ }
+
+ &__item__index {
+ display: flex;
+ width: 24px;
+ }
+
+ &__item__radio {
+ display: flex;
+ flex: 1;
+
+ input {
+ padding: 10px;
+ margin-top: 13px;
+ }
+ }
+
+ &__item__label {
+ display: flex;
+ flex: 1;
+ padding-left: 10px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ }
+
+ &__item__balance {
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ }
+
+ &__item__link {
+ display: flex;
+ margin-top: 13px;
+ }
+
+ &__item__link img {
+ width: 15px;
+ height: 15px;
+ }
+}
+
+.hw-list-pagination {
+ display: flex;
+ align-self: flex-end;
+ margin-top: 10px;
+
+ &__button {
+ height: 19px;
+ display: flex;
+ color: #33a4e7;
+ font-size: 14px;
+ line-height: 19px;
+ border: none;
+ min-width: 46px;
+ margin-right: 0px;
+ margin-left: 16px;
+ padding: 0px;
+ text-transform: uppercase;
+ font-family: Roboto;
+ }
+}
+
+.new-account-connect-form {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ padding: 15px 30px 0;
+ height: 710px;
+ overflow: auto;
+
+ &.unsupported-browser {
+ height: 210px;
+ }
+
+ &.account-list {
+ height: auto;
+ }
+
+ &__buttons {
+ margin-top: 39px;
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ &__button {
+ width: 150px;
+ min-width: initial;
+ }
+
+ .btn-primary {
+ background-color: #259DE5;
+ color: #FFFFFF;
+ border: none;
+ width: 100%;
+ min-height: 54px;
+ font-weight: 300;
+ font-size: 14px;
+ }
+
+ &__button.unlock {
+ width: 50%;
+ }
+
+ &__button.btn-primary--disabled {
+ cursor: not-allowed;
+ opacity: .5;
+ }
+}
+
+.hw-forget-device-container {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ padding: 22px;
+
+ a {
+ color: #2f9ae0;
+ font-size: 14px;
+ cursor: pointer;
+ }
+}
+
.new-account-create-form {
display: flex;
flex-flow: column;
align-items: center;
- padding: 30px 30px 0;
+ padding: 30px;
&__input-label {
color: $scorpion;
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index c168242cf..e9c872ea7 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -628,7 +628,7 @@
}
}
- &__to-autocomplete, &__memo-text-area {
+ &__to-autocomplete, &__memo-text-area, &__hex-data {
&__input {
height: 54px;
width: 100%;
@@ -899,4 +899,4 @@
.sliders-icon {
color: $curious-blue;
-} \ No newline at end of file
+}
diff --git a/ui/app/css/itcss/components/transaction-list.scss b/ui/app/css/itcss/components/transaction-list.scss
index d03faf486..1d45ff13b 100644
--- a/ui/app/css/itcss/components/transaction-list.scss
+++ b/ui/app/css/itcss/components/transaction-list.scss
@@ -129,12 +129,14 @@
.tx-list-item-retry-container {
background: #d1edff;
width: 100%;
- border-radius: 4px;
- font-size: 0.8em;
+ border-radius: 12px;
+ font-size: .75rem;
display: flex;
justify-content: center;
margin-left: 44px;
width: calc(100% - 44px);
+ padding: 4px;
+ cursor: pointer;
@media screen and (min-width: 576px) and (max-width: 679px) {
flex-flow: column;
@@ -151,10 +153,6 @@
}
}
-.tx-list-item-retry-copy {
- font-family: Roboto;
-}
-
.tx-list-item-retry-link {
text-decoration: underline;
margin-left: 6px;
diff --git a/ui/app/helpers/confirm-transaction/util.js b/ui/app/helpers/confirm-transaction/util.js
index ad247a348..1373d28df 100644
--- a/ui/app/helpers/confirm-transaction/util.js
+++ b/ui/app/helpers/confirm-transaction/util.js
@@ -114,3 +114,20 @@ export function formatCurrency (value, currencyCode) {
? currencyFormatter.format(Number(value), { code: upperCaseCurrencyCode })
: value
}
+
+export function convertTokenToFiat ({
+ value,
+ toCurrency,
+ conversionRate,
+ contractExchangeRate,
+}) {
+ const totalExchangeRate = conversionRate * contractExchangeRate
+
+ return conversionUtil(value, {
+ fromNumericBase: 'dec',
+ toNumericBase: 'dec',
+ toCurrency,
+ numberOfDecimals: 2,
+ conversionRate: totalExchangeRate,
+ })
+}
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index f453812b9..50d8bcba7 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -49,6 +49,8 @@ function reduceApp (state, action) {
},
},
sidebarOpen: false,
+ alertOpen: false,
+ alertMessage: null,
networkDropdownOpen: false,
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
@@ -88,6 +90,19 @@ function reduceApp (state, action) {
sidebarOpen: false,
})
+ // sidebar methods
+ case actions.ALERT_OPEN:
+ return extend(appState, {
+ alertOpen: true,
+ alertMessage: action.value,
+ })
+
+ case actions.ALERT_CLOSE:
+ return extend(appState, {
+ alertOpen: false,
+ alertMessage: null,
+ })
+
// modal methods:
case actions.MODAL_OPEN:
const { name, ...modalProps } = action.payload
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 6c8ac9ed7..3f1d3394f 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -222,6 +222,14 @@ function reduceMetamask (state, action) {
},
})
+ case actions.UPDATE_SEND_HEX_DATA:
+ return extend(metamaskState, {
+ send: {
+ ...metamaskState.send,
+ data: action.value,
+ },
+ })
+
case actions.UPDATE_SEND_FROM:
return extend(metamaskState, {
send: {
diff --git a/ui/app/routes.js b/ui/app/routes.js
index 7ac606b1a..f6b2a7a55 100644
--- a/ui/app/routes.js
+++ b/ui/app/routes.js
@@ -9,6 +9,7 @@ const ADD_TOKEN_ROUTE = '/add-token'
const CONFIRM_ADD_TOKEN_ROUTE = '/confirm-add-token'
const NEW_ACCOUNT_ROUTE = '/new-account'
const IMPORT_ACCOUNT_ROUTE = '/new-account/import'
+const CONNECT_HARDWARE_ROUTE = '/new-account/connect'
const SEND_ROUTE = '/send'
const NOTICE_ROUTE = '/notice'
const WELCOME_ROUTE = '/welcome'
@@ -26,6 +27,7 @@ const CONFIRM_SEND_ETHER_PATH = '/send-ether'
const CONFIRM_SEND_TOKEN_PATH = '/send-token'
const CONFIRM_DEPLOY_CONTRACT_PATH = '/deploy-contract'
const CONFIRM_APPROVE_PATH = '/approve'
+const CONFIRM_TRANSFER_FROM_PATH = '/transfer-from'
const CONFIRM_TOKEN_METHOD_PATH = '/token-method'
const SIGNATURE_REQUEST_PATH = '/signature-request'
@@ -41,6 +43,7 @@ module.exports = {
CONFIRM_ADD_TOKEN_ROUTE,
NEW_ACCOUNT_ROUTE,
IMPORT_ACCOUNT_ROUTE,
+ CONNECT_HARDWARE_ROUTE,
SEND_ROUTE,
NOTICE_ROUTE,
WELCOME_ROUTE,
@@ -57,6 +60,7 @@ module.exports = {
CONFIRM_SEND_TOKEN_PATH,
CONFIRM_DEPLOY_CONTRACT_PATH,
CONFIRM_APPROVE_PATH,
+ CONFIRM_TRANSFER_FROM_PATH,
CONFIRM_TOKEN_METHOD_PATH,
SIGNATURE_REQUEST_PATH,
}
diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js
index cde83804d..54016a30e 100644
--- a/ui/app/selectors/confirm-transaction.js
+++ b/ui/app/selectors/confirm-transaction.js
@@ -1,5 +1,6 @@
import { createSelector } from 'reselect'
import txHelper from '../../lib/tx-helper'
+import { calcTokenAmount } from '../token-util'
const unapprovedTxsSelector = state => state.metamask.unapprovedTxs
const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs
@@ -63,3 +64,101 @@ export const unconfirmedTransactionsHashSelector = createSelector(
export const currentCurrencySelector = state => state.metamask.currentCurrency
export const conversionRateSelector = state => state.metamask.conversionRate
+
+const txDataSelector = state => state.confirmTransaction.txData
+const tokenDataSelector = state => state.confirmTransaction.tokenData
+const tokenPropsSelector = state => state.confirmTransaction.tokenProps
+
+const contractExchangeRatesSelector = state => state.metamask.contractExchangeRates
+
+const tokenDecimalsSelector = createSelector(
+ tokenPropsSelector,
+ tokenProps => tokenProps && tokenProps.tokenDecimals
+)
+
+const tokenDataParamsSelector = createSelector(
+ tokenDataSelector,
+ tokenData => tokenData && tokenData.params || []
+)
+
+const txParamsSelector = createSelector(
+ txDataSelector,
+ txData => txData && txData.txParams || {}
+)
+
+export const tokenAddressSelector = createSelector(
+ txParamsSelector,
+ txParams => txParams && txParams.to
+)
+
+const TOKEN_PARAM_SPENDER = '_spender'
+const TOKEN_PARAM_TO = '_to'
+const TOKEN_PARAM_VALUE = '_value'
+
+export const tokenAmountAndToAddressSelector = createSelector(
+ tokenDataParamsSelector,
+ params => {
+ let toAddress = ''
+ let tokenAmount = 0
+
+ if (params && params.length) {
+ const toParam = params.find(param => param.name === TOKEN_PARAM_TO)
+ const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE)
+ toAddress = toParam ? toParam.value : params[0].value
+ tokenAmount = valueParam ? Number(valueParam.value) : Number(params[1].value)
+ }
+
+ return {
+ toAddress,
+ tokenAmount,
+ }
+ }
+)
+
+export const approveTokenAmountAndToAddressSelector = createSelector(
+ tokenDataParamsSelector,
+ params => {
+ let toAddress = ''
+ let tokenAmount = 0
+
+ if (params && params.length) {
+ toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value
+ tokenAmount = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
+ }
+
+ return {
+ toAddress,
+ tokenAmount,
+ }
+ }
+)
+
+export const sendTokenTokenAmountAndToAddressSelector = createSelector(
+ tokenDataParamsSelector,
+ tokenDecimalsSelector,
+ (params, tokenDecimals) => {
+ let toAddress = ''
+ let tokenAmount = 0
+
+ if (params && params.length) {
+ toAddress = params.find(param => param.name === TOKEN_PARAM_TO).value
+ tokenAmount = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
+
+ if (tokenDecimals) {
+ tokenAmount = calcTokenAmount(tokenAmount, tokenDecimals)
+ }
+ }
+
+ return {
+ toAddress,
+ tokenAmount,
+ }
+ }
+)
+
+
+export const contractExchangeRateSelector = createSelector(
+ contractExchangeRatesSelector,
+ tokenAddressSelector,
+ (contractExchangeRates, tokenAddress) => contractExchangeRates[tokenAddress]
+)
diff --git a/ui/app/util.js b/ui/app/util.js
index 8c85c5926..8b194e0c7 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -59,6 +59,7 @@ module.exports = {
allNull,
getTokenAddressFromTokenObject,
checksumAddress,
+ addressSlicer,
}
function valuesFor (obj) {
@@ -303,3 +304,11 @@ function getTokenAddressFromTokenObject (token) {
function checksumAddress (address) {
return address ? ethUtil.toChecksumAddress(address) : ''
}
+
+function addressSlicer (address = '') {
+ if (address.length < 11) {
+ return address
+ }
+
+ return `${address.slice(0, 6)}...${address.slice(-4)}`
+}