aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/components')
-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
160 files changed, 1364 insertions, 2140 deletions
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' } }),
]),
]),