From d72b478c897b1cd5b227f4a776ecdffb294920b3 Mon Sep 17 00:00:00 2001 From: Daniel Ternyak Date: Mon, 23 Oct 2017 13:48:55 -0700 Subject: [PATCH] Broadcast Tx (#304) * create MVP of broadcast TX component * add broadcastTx to routes and tab options * Update BroadcastTx path to /pushTx * - add sanitizeHex and padLeftEven functions from V3 * - Move decodeTransaction logic out of ConfirmationModal. - Add from key to getTransactionFields * Simplify ConfirmationModal: 1. Move business logic out of component (decodeTransaction). 2. Don't pass node props when Component is already smart. Map from state instead. 3. Pass walletAddress instead of the entire wallet object to component as prop. 4. Handle * - Don't map node state (child component grabs from state) - implement and call setWalletAddressOnUpdate * correct tab to path. * 1. Integrate Confirmation Modal 2. Validate signedTx input and disable Send Transaction button when invalid * disable tslint error. EthTx expect a Data type object, but a string is passed. However, tx object is created as expected. Need to investigate * adjust type definition to match allowed string input. Remove tslint disable * fix tslint errors * add textarea valid/invalid stlying based on disabled status * remove unused imports * cleanup / address PR comments * Address PR comments --- common/Root.tsx | 2 + .../Header/components/Navigation.tsx | 4 + common/containers/Tabs/BroadcastTx/index.scss | 7 + common/containers/Tabs/BroadcastTx/index.tsx | 140 ++++++++++++++++++ .../components/ConfirmationModal.tsx | 87 ++++------- .../containers/Tabs/SendTransaction/index.tsx | 38 +++-- common/libs/transaction.ts | 38 ++++- common/libs/values.ts | 13 ++ common/typescript/ethereumjs-tx.d.ts | 2 +- 9 files changed, 252 insertions(+), 79 deletions(-) create mode 100644 common/containers/Tabs/BroadcastTx/index.scss create mode 100644 common/containers/Tabs/BroadcastTx/index.tsx diff --git a/common/Root.tsx b/common/Root.tsx index 34e362a571d..e3dfbb23ccd 100644 --- a/common/Root.tsx +++ b/common/Root.tsx @@ -9,6 +9,7 @@ import Help from 'containers/Tabs/Help'; import SendTransaction from 'containers/Tabs/SendTransaction'; import Swap from 'containers/Tabs/Swap'; import ViewWallet from 'containers/Tabs/ViewWallet'; +import BroadcastTx from 'containers/Tabs/BroadcastTx'; // TODO: fix this interface Props { @@ -31,6 +32,7 @@ export default class Root extends Component { + diff --git a/common/components/Header/components/Navigation.tsx b/common/components/Header/components/Navigation.tsx index dd230aa75a7..d20a30530a3 100644 --- a/common/components/Header/components/Navigation.tsx +++ b/common/components/Header/components/Navigation.tsx @@ -28,6 +28,10 @@ const tabs = [ name: 'NAV_ENS', to: 'ens' }, + { + name: 'Broadcast Transaction', + to: 'pushTx' + }, { name: 'NAV_Help', to: 'https://myetherwallet.groovehq.com/help_center', diff --git a/common/containers/Tabs/BroadcastTx/index.scss b/common/containers/Tabs/BroadcastTx/index.scss new file mode 100644 index 00000000000..1ed9ce43f54 --- /dev/null +++ b/common/containers/Tabs/BroadcastTx/index.scss @@ -0,0 +1,7 @@ +@import "common/sass/variables"; + +.BroadcastTx { + &-title { + margin: $space auto $space * 2.5; + } +} diff --git a/common/containers/Tabs/BroadcastTx/index.tsx b/common/containers/Tabs/BroadcastTx/index.tsx new file mode 100644 index 00000000000..d06bb7873d8 --- /dev/null +++ b/common/containers/Tabs/BroadcastTx/index.tsx @@ -0,0 +1,140 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { AppState } from 'reducers'; +import TabSection from 'containers/TabSection'; +import { translateRaw } from 'translations'; +import { broadcastTx as dBroadcastTx, TBroadcastTx } from 'actions/wallet'; +import { QRCode } from 'components/ui'; +import './index.scss'; +import { + BroadcastTransactionStatus, + getTransactionFields +} from 'libs/transaction'; +import EthTx from 'ethereumjs-tx'; +import { ConfirmationModal } from 'containers/Tabs/SendTransaction/components'; +import classnames from 'classnames'; + +interface Props { + broadcastTx: TBroadcastTx; + transactions: BroadcastTransactionStatus[]; +} + +interface State { + signedTx: string; + showConfirmationModal: boolean; + disabled: boolean; +} + +const initialState: State = { + showConfirmationModal: false, + signedTx: '', + disabled: true +}; + +class BroadcastTx extends Component { + public state = initialState; + + public ensureValidSignedTxInputOnUpdate() { + try { + const tx = new EthTx(this.state.signedTx); + getTransactionFields(tx); + if (this.state.disabled) { + this.setState({ disabled: false }); + } + } catch (e) { + if (!this.state.disabled) { + this.setState({ disabled: true }); + } + } + } + + public componentDidUpdate() { + this.ensureValidSignedTxInputOnUpdate(); + } + + public render() { + const { signedTx, disabled, showConfirmationModal } = this.state; + + const inputClasses = classnames({ + 'form-control': true, + 'is-valid': !disabled, + 'is-invalid': disabled + }); + + return ( + +
+
+
+

Broadcast Signed Transaction

+
+

+ Paste a signed transaction and press the "SEND TRANSACTION" + button. +

+ +