From cd4d489b57ff48d53995d79cd8fde22a57d7724e Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 3 Feb 2017 20:01:09 +0100 Subject: [PATCH] Add block & timestamp conditions to Signer (#4411) * WIP * WIP (with lint) * Update ui/RadioButtons * transaction.condition * Date & Time selection in-place * Swap to condition-only * Fix tests, align naming * Pick error properly from validation * Update tests * condition: time sent withough ms * Format numbers as base-10 * override popup styles (zIndex) * Pass condition to signer * Update expectation (failing test typo) * Adjust min/max height for expanded bar * Fix address display * Fix name display * Number inputs for gas/gasPrice/blockNumber * Default blockNumber to 1 (align with min setting) * Update tests with min value * Add Block Number * Fix failing tests (after blockNumber intro) --- js/src/api/format/input.js | 16 ++ js/src/api/format/output.js | 20 +- .../AdvancedStep/advancedStep.js | 33 +-- .../modals/ExecuteContract/executeContract.js | 34 +-- js/src/modals/Transfer/Extras/extras.js | 25 +- js/src/modals/Transfer/store.js | 90 +++----- js/src/modals/Transfer/transfer.js | 4 +- js/src/redux/providers/signerMiddleware.js | 4 +- js/src/ui/Form/InputAddress/inputAddress.js | 5 +- js/src/ui/Form/InputDate/index.js | 17 ++ js/src/ui/Form/InputDate/inputDate.css | 22 ++ js/src/ui/Form/InputDate/inputDate.js | 53 +++++ js/src/ui/Form/InputTime/index.js | 17 ++ js/src/ui/Form/InputTime/inputTime.css | 22 ++ js/src/ui/Form/InputTime/inputTime.js | 54 +++++ js/src/ui/Form/Label/index.js | 17 ++ js/src/ui/Form/Label/label.css | 24 ++ js/src/ui/Form/Label/label.js | 40 ++++ js/src/ui/Form/RadioButtons/radioButtons.css | 27 ++- js/src/ui/Form/RadioButtons/radioButtons.js | 36 +-- js/src/ui/Form/index.js | 14 +- js/src/ui/GasPriceEditor/gasPriceEditor.css | 40 ++++ js/src/ui/GasPriceEditor/gasPriceEditor.js | 217 +++++++++++++++--- .../ui/GasPriceEditor/gasPriceEditor.spec.js | 72 ++++-- js/src/ui/GasPriceEditor/store.js | 91 +++++++- js/src/ui/GasPriceEditor/store.spec.js | 93 +++++++- js/src/ui/MethodDecoding/methodDecoding.js | 23 +- js/src/ui/index.js | 5 +- js/src/views/ParityBar/parityBar.css | 10 +- .../transactionMainDetails.js | 6 +- .../TransactionPending/transactionPending.js | 18 +- 31 files changed, 894 insertions(+), 255 deletions(-) create mode 100644 js/src/ui/Form/InputDate/index.js create mode 100644 js/src/ui/Form/InputDate/inputDate.css create mode 100644 js/src/ui/Form/InputDate/inputDate.js create mode 100644 js/src/ui/Form/InputTime/index.js create mode 100644 js/src/ui/Form/InputTime/inputTime.css create mode 100644 js/src/ui/Form/InputTime/inputTime.js create mode 100644 js/src/ui/Form/Label/index.js create mode 100644 js/src/ui/Form/Label/label.css create mode 100644 js/src/ui/Form/Label/label.js diff --git a/js/src/api/format/input.js b/js/src/api/format/input.js index 05593fc5e..74ddd4e56 100644 --- a/js/src/api/format/input.js +++ b/js/src/api/format/input.js @@ -127,6 +127,18 @@ export function inNumber16 (number) { return inHex(bn.toString(16)); } +export function inOptionsCondition (condition) { + if (condition) { + if (condition.block) { + condition.block = condition.block ? inNumber10(condition.block) : null; + } else if (condition.time) { + condition.time = inNumber10(Math.floor(condition.time.getTime() / 1000)); + } + } + + return condition; +} + export function inOptions (options) { if (options) { Object.keys(options).forEach((key) => { @@ -136,6 +148,10 @@ export function inOptions (options) { options[key] = inAddress(options[key]); break; + case 'condition': + options[key] = inOptionsCondition(options[key]); + break; + case 'gas': case 'gasPrice': options[key] = inNumber16((new BigNumber(options[key])).round()); diff --git a/js/src/api/format/output.js b/js/src/api/format/output.js index 35ec67ebf..dd61c82b1 100644 --- a/js/src/api/format/output.js +++ b/js/src/api/format/output.js @@ -221,6 +221,18 @@ export function outSyncing (syncing) { return syncing; } +export function outTransactionCondition (condition) { + if (condition) { + if (condition.block) { + condition.block = outNumber(condition.block); + } else if (condition.time) { + condition.time = outDate(condition.time); + } + } + + return condition; +} + export function outTransaction (tx) { if (tx) { Object.keys(tx).forEach((key) => { @@ -234,8 +246,14 @@ export function outTransaction (tx) { tx[key] = outNumber(tx[key]); break; + case 'condition': + tx[key] = outTransactionCondition(tx[key]); + break; + case 'minBlock': - tx[key] = tx[key] ? outNumber(tx[key]) : null; + tx[key] = tx[key] + ? outNumber(tx[key]) + : null; break; case 'creates': diff --git a/js/src/modals/ExecuteContract/AdvancedStep/advancedStep.js b/js/src/modals/ExecuteContract/AdvancedStep/advancedStep.js index cf592c5cb..268ca1f70 100644 --- a/js/src/modals/ExecuteContract/AdvancedStep/advancedStep.js +++ b/js/src/modals/ExecuteContract/AdvancedStep/advancedStep.js @@ -15,45 +15,22 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; -import { FormattedMessage } from 'react-intl'; -import { Input, GasPriceEditor } from '~/ui'; +import { GasPriceEditor } from '~/ui'; import styles from '../executeContract.css'; export default class AdvancedStep extends Component { static propTypes = { - gasStore: PropTypes.object.isRequired, - minBlock: PropTypes.string, - minBlockError: PropTypes.string, - onMinBlockChange: PropTypes.func + gasStore: PropTypes.object.isRequired }; render () { - const { gasStore, minBlock, minBlockError, onMinBlockChange } = this.props; + const { gasStore } = this.props; return ( -
- - } - label={ - - } - value={ minBlock } - onSubmit={ onMinBlockChange } - /> -
- -
+
+
); } diff --git a/js/src/modals/ExecuteContract/executeContract.js b/js/src/modals/ExecuteContract/executeContract.js index 6f750a8dc..0828a5f3e 100644 --- a/js/src/modals/ExecuteContract/executeContract.js +++ b/js/src/modals/ExecuteContract/executeContract.js @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import BigNumber from 'bignumber.js'; import { pick } from 'lodash'; import { observer } from 'mobx-react'; import React, { Component, PropTypes } from 'react'; @@ -100,8 +99,6 @@ class ExecuteContract extends Component { fromAddressError: null, func: null, funcError: null, - minBlock: '0', - minBlockError: null, rejected: false, sending: false, step: STEP_DETAILS, @@ -167,8 +164,8 @@ class ExecuteContract extends Component { renderDialogActions () { const { onClose, fromAddress } = this.props; - const { advancedOptions, sending, step, fromAddressError, minBlockError, valuesError } = this.state; - const hasError = fromAddressError || minBlockError || valuesError.find((error) => error); + const { advancedOptions, sending, step, fromAddressError, valuesError } = this.state; + const hasError = fromAddressError || valuesError.find((error) => error); const cancelBtn = (
diff --git a/js/src/views/Signer/components/TransactionPending/transactionPending.js b/js/src/views/Signer/components/TransactionPending/transactionPending.js index 24d8589c7..a49f5c2e0 100644 --- a/js/src/views/Signer/components/TransactionPending/transactionPending.js +++ b/js/src/views/Signer/components/TransactionPending/transactionPending.js @@ -45,6 +45,7 @@ export default class TransactionPending extends Component { onReject: PropTypes.func.isRequired, store: PropTypes.object.isRequired, transaction: PropTypes.shape({ + condition: PropTypes.object, data: PropTypes.string, from: PropTypes.string.isRequired, gas: PropTypes.object.isRequired, @@ -59,6 +60,7 @@ export default class TransactionPending extends Component { }; gasStore = new GasPriceEditor.Store(this.context.api, { + condition: this.props.transaction.condition, gas: this.props.transaction.gas.toFixed(), gasLimit: this.props.gasLimit, gasPrice: this.props.transaction.gasPrice.toFixed() @@ -80,7 +82,7 @@ export default class TransactionPending extends Component { render () { return this.gasStore.isEditing - ? this.renderGasEditor() + ? this.renderTxEditor() : this.renderTransaction(); } @@ -115,7 +117,7 @@ export default class TransactionPending extends Component { ); } - renderGasEditor () { + renderTxEditor () { const { className } = this.props; return ( @@ -133,15 +135,21 @@ export default class TransactionPending extends Component { onConfirm = (data) => { const { id, transaction } = this.props; const { password, wallet } = data; - const { gas, gasPrice } = this.gasStore.overrideTransaction(transaction); + const { condition, gas, gasPrice } = this.gasStore.overrideTransaction(transaction); - this.props.onConfirm({ + const options = { gas, gasPrice, id, password, wallet - }); + }; + + if (condition && (condition.block || condition.time)) { + options.condition = condition; + } + + this.props.onConfirm(options); } onReject = () => {