From 53b8d18a5f649c73a58a96e36a9458903d8af6aa Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 16 May 2017 15:30:22 -0700 Subject: Complete transition into BN. --- ui/app/components/bn-as-decimal-input.js | 143 +++++++++++++++++++++++++++++++ ui/app/components/pending-tx.js | 27 +++--- 2 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 ui/app/components/bn-as-decimal-input.js (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js new file mode 100644 index 000000000..6c2132ca1 --- /dev/null +++ b/ui/app/components/bn-as-decimal-input.js @@ -0,0 +1,143 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const ethUtil = require('ethereumjs-util') +const BN = ethUtil.BN +const extend = require('xtend') + +module.exports = BnAsDecimalInput + +inherits(BnAsDecimalInput, Component) +function BnAsDecimalInput () { + this.state = { invalid: null } + Component.call(this) +} + +/* Bn as Decimal Input + * + * A component for allowing easy, decimal editing + * of a passed in hex string value. + * + * On change, calls back its `onChange` function parameter + * and passes it an updated hex string. + */ + +BnAsDecimalInput.prototype.render = function () { + const props = this.props + const state = this.state + + const { value, precision, onChange, min, max } = props + + const suffix = props.suffix + const style = props.style + const newValue = value.toNumber(10) / scale + const scale = Math.pow(10, precision) + + return ( + h('.flex-column', [ + h('.flex-row', { + style: { + alignItems: 'flex-end', + lineHeight: '13px', + fontFamily: 'Montserrat Light', + textRendering: 'geometricPrecision', + }, + }, [ + h('input.hex-input', { + type: 'number', + step: 'any', + required: true, + min: min, + max: max, + style: extend({ + display: 'block', + textAlign: 'right', + backgroundColor: 'transparent', + border: '1px solid #bdbdbd', + + }, style), + value: newValue, + onBlur: (event) => { + this.updateValidity(event) + }, + onChange: (event) => { + this.updateValidity(event) + const value = (event.target.value === '') ? '' : event.target.value + const scaledNumber = Math.floor(scale * value) + const precisionBN = new BN(scaledNumber, 10) + onChange(precisionBN) + }, + onInvalid: (event) => { + const msg = this.constructWarning() + if (msg === state.invalid) { + return + } + this.setState({ invalid: msg }) + event.preventDefault() + return false + }, + }), + h('div', { + style: { + color: ' #AEAEAE', + fontSize: '12px', + marginLeft: '5px', + marginRight: '6px', + width: '20px', + }, + }, suffix), + ]), + + state.invalid ? h('span.error', { + style: { + position: 'absolute', + right: '0px', + textAlign: 'right', + transform: 'translateY(26px)', + padding: '3px', + background: 'rgba(255,255,255,0.85)', + zIndex: '1', + textTransform: 'capitalize', + border: '2px solid #E20202', + }, + }, state.invalid) : null, + ]) + ) +} + +BnAsDecimalInput.prototype.setValid = function (message) { + this.setState({ invalid: null }) +} + +BnAsDecimalInput.prototype.updateValidity = function (event) { + const target = event.target + const value = this.props.value + const newValue = target.value + + if (value === newValue) { + return + } + + const valid = target.checkValidity() + + if (valid) { + this.setState({ invalid: null }) + } +} + +BnAsDecimalInput.prototype.constructWarning = function () { + const { name, min, max } = this.props + let message = name ? name + ' ' : '' + + if (min && max) { + message += `must be greater than or equal to ${min} and less than or equal to ${max}.` + } else if (min) { + message += `must be greater than or equal to ${min}.` + } else if (max) { + message += `must be less than or equal to ${max}.` + } else { + message += 'Invalid input.' + } + + return message +} diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 5ea885195..95d345a3d 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -13,7 +13,7 @@ const EthBalance = require('./eth-balance') const util = require('../util') const addressSummary = util.addressSummary const nameForAddress = require('../../lib/contract-namer') -const HexInput = require('./hex-as-decimal-input') +const BNInput = require('./bn-as-decimal-input') const MIN_GAS_PRICE_GWEI_BN = new BN(2) const GWEI_FACTOR = new BN(1e9) @@ -54,7 +54,6 @@ PendingTx.prototype.render = function () { // Gas Price const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_BN.toString(16) const gasPriceBn = hexToBn(gasPrice) - const gasPriceGweiBn = gasPriceBn.div(GWEI_FACTOR) const txFeeBn = gasBn.mul(gasPriceBn) const valueBn = hexToBn(txParams.value) @@ -166,9 +165,10 @@ PendingTx.prototype.render = function () { h('.cell.label', 'Gas Limit'), h('.cell.value', { }, [ - h(HexInput, { + h(BNInput, { name: 'Gas Limit', - value: gas, + value: gasBn, + precision: 0, // The hard lower limit for gas. min: MIN_GAS_LIMIT_BN.toString(10), suffix: 'UNITS', @@ -176,10 +176,10 @@ PendingTx.prototype.render = function () { position: 'relative', top: '5px', }, - onChange: (newHex) => { - log.info(`Gas limit changed to ${newHex}`) + onChange: (newBN) => { + log.info(`Gas limit changed to ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() - txMeta.txParams.gas = newHex + txMeta.txParams.gas = '0x' + newBN.toString('hex') this.setState({ txData: txMeta }) }, ref: (hexInput) => { this.inputs.push(hexInput) }, @@ -192,20 +192,20 @@ PendingTx.prototype.render = function () { h('.cell.label', 'Gas Price'), h('.cell.value', { }, [ - h(HexInput, { + h(BNInput, { name: 'Gas Price', - value: gasPriceGweiBn.toString(16), + value: gasPriceBn, + precision: 9, suffix: 'GWEI', min: MIN_GAS_PRICE_GWEI_BN.toString(10), style: { position: 'relative', top: '5px', }, - onChange: (newHex) => { - log.info(`Gas price changed to: ${newHex}`) - const inWei = hexToBn(newHex).mul(GWEI_FACTOR) + onChange: (newBN) => { + log.info(`Gas price changed to: ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() - txMeta.txParams.gasPrice = inWei.toString(16) + txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') this.setState({ txData: txMeta }) }, ref: (hexInput) => { this.inputs.push(hexInput) }, @@ -368,6 +368,7 @@ PendingTx.prototype.miniAccountPanelForRecipient = function () { } PendingTx.prototype.resetGasFields = function () { + log.debug(`pending-tx resetGasFields`) this.inputs.forEach((hexInput) => { -- cgit v1.2.3 From d8130f1effc31a866476e10153bd854709ae23be Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 16 May 2017 16:20:58 -0700 Subject: Fix reset button. --- ui/app/components/bn-as-decimal-input.js | 6 +++--- ui/app/components/pending-tx.js | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 6c2132ca1..d0eebe09e 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -16,10 +16,10 @@ function BnAsDecimalInput () { /* Bn as Decimal Input * * A component for allowing easy, decimal editing - * of a passed in hex string value. + * of a passed in bn string value. * * On change, calls back its `onChange` function parameter - * and passes it an updated hex string. + * and passes it an updated bn string. */ BnAsDecimalInput.prototype.render = function () { @@ -30,8 +30,8 @@ BnAsDecimalInput.prototype.render = function () { const suffix = props.suffix const style = props.style - const newValue = value.toNumber(10) / scale const scale = Math.pow(10, precision) + const newValue = value.toNumber(10) / scale return ( h('.flex-column', [ diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 95d345a3d..5c8d81d07 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -180,7 +180,7 @@ PendingTx.prototype.render = function () { log.info(`Gas limit changed to ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gas = '0x' + newBN.toString('hex') - this.setState({ txData: txMeta }) + this.setState({ txData: cloneObj(txMeta) }) }, ref: (hexInput) => { this.inputs.push(hexInput) }, }), @@ -206,7 +206,7 @@ PendingTx.prototype.render = function () { log.info(`Gas price changed to: ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') - this.setState({ txData: txMeta }) + this.setState({ txData: cloneObj(txMeta) }) }, ref: (hexInput) => { this.inputs.push(hexInput) }, }), @@ -388,7 +388,7 @@ PendingTx.prototype.gatherTxMeta = function () { log.debug(`pending-tx gatherTxMeta`) const props = this.props const state = this.state - const txData = state.txData || props.txData + const txData = cloneObj(state.txData) || cloneObj(props.txData) log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`) return txData @@ -409,7 +409,6 @@ PendingTx.prototype._notZeroOrEmptyString = function (obj) { function forwardCarrat () { return ( - h('img', { src: 'images/forward-carrat.svg', style: { @@ -417,6 +416,9 @@ function forwardCarrat () { height: '37px', }, }) - ) } + +function cloneObj (obj) { + return JSON.parse(JSON.stringify(obj)) +} -- cgit v1.2.3 From 717db41d0b7bcd7b6f88a5c460aa4dcbc5828116 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 17 May 2017 14:18:01 -0700 Subject: Modify test, replace clone package. --- ui/app/components/pending-tx.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 37a3a3bf3..5b238187c 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -2,6 +2,7 @@ const Component = require('react').Component 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 @@ -347,14 +348,14 @@ PendingTx.prototype.gasPriceChanged = function (newBN) { log.info(`Gas price changed to: ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') - this.setState({ txData: cloneObj(txMeta) }) + this.setState({ txData: clone(txMeta) }) } PendingTx.prototype.gasLimitChanged = function (newBN) { log.info(`Gas limit changed to ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gas = '0x' + newBN.toString('hex') - this.setState({ txData: cloneObj(txMeta) }) + this.setState({ txData: clone(txMeta) }) } PendingTx.prototype.resetGasFields = function () { @@ -405,7 +406,7 @@ PendingTx.prototype.gatherTxMeta = function () { log.debug(`pending-tx gatherTxMeta`) const props = this.props const state = this.state - const txData = cloneObj(state.txData) || cloneObj(props.txData) + const txData = clone(state.txData) || clone(props.txData) log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`) return txData @@ -435,7 +436,3 @@ function forwardCarrat () { }) ) } - -function cloneObj (obj) { - return JSON.parse(JSON.stringify(obj)) -} -- cgit v1.2.3 From 959038132a6780f1dd7a4db3696d3fdbaad83b88 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 23 May 2017 10:43:37 -0700 Subject: Increase accuracy of our rounding schemes. --- ui/app/components/bn-as-decimal-input.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index d0eebe09e..fbe36abfb 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -30,8 +30,8 @@ BnAsDecimalInput.prototype.render = function () { const suffix = props.suffix const style = props.style - const scale = Math.pow(10, precision) - const newValue = value.toNumber(10) / scale + const valueString = value.toString(10) + const newValue = downsize(valueString, precision, precision) return ( h('.flex-column', [ @@ -63,7 +63,9 @@ BnAsDecimalInput.prototype.render = function () { onChange: (event) => { this.updateValidity(event) const value = (event.target.value === '') ? '' : event.target.value - const scaledNumber = Math.floor(scale * value) + + + const scaledNumber = upsize(value, precision, precision) const precisionBN = new BN(scaledNumber, 10) onChange(precisionBN) }, @@ -141,3 +143,24 @@ BnAsDecimalInput.prototype.constructWarning = function () { return message } + + +function downsize (number, scale, precision) { + if (scale === 0) { + return Number(number) + } else { + var decimals = (scale === precision) ? -1 : scale - precision + return Number(number.slice(0, -scale) + '.' + number.slice(-scale, decimals)) + } +} + +function upsize (number, scale, precision) { + var string = number.toString() + var stringArray = string.split('.') + var decimalLength = stringArray[1] ? stringArray[1].length : 0 + var newString = ((scale === 0) || (decimalLength === 0)) ? stringArray[0] : stringArray[0] + stringArray[1].slice(0, precision) + for (var i = decimalLength; i < scale; i++) { + newString += '0' + } + return newString +} -- cgit v1.2.3 From 31d17c9e25458cd47f8c18ec3b967aecff236ba6 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 23 May 2017 14:26:37 -0700 Subject: Fix test, create new value for precision/scale --- ui/app/components/bn-as-decimal-input.js | 6 +++--- ui/app/components/pending-tx.js | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index fbe36abfb..8f56f29ab 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -26,12 +26,12 @@ BnAsDecimalInput.prototype.render = function () { const props = this.props const state = this.state - const { value, precision, onChange, min, max } = props + const { value, scale, precision, onChange, min, max } = props const suffix = props.suffix const style = props.style const valueString = value.toString(10) - const newValue = downsize(valueString, precision, precision) + const newValue = downsize(valueString, scale, precision) return ( h('.flex-column', [ @@ -65,7 +65,7 @@ BnAsDecimalInput.prototype.render = function () { const value = (event.target.value === '') ? '' : event.target.value - const scaledNumber = upsize(value, precision, precision) + const scaledNumber = upsize(value, scale, precision) const precisionBN = new BN(scaledNumber, 10) onChange(precisionBN) }, diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 5b238187c..eed0fd9ae 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -156,6 +156,7 @@ PendingTx.prototype.render = function () { name: 'Gas Limit', value: gasBn, precision: 0, + scale: 0, // The hard lower limit for gas. min: MIN_GAS_LIMIT_BN.toString(10), suffix: 'UNITS', @@ -179,6 +180,7 @@ PendingTx.prototype.render = function () { name: 'Gas Price', value: gasPriceBn, precision: 9, + scale: 9, suffix: 'GWEI', min: MIN_GAS_PRICE_GWEI_BN.toString(10), style: { -- cgit v1.2.3 From 60281f72506c6b1775e75e8426a09d91893ab6ac Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 24 May 2017 09:55:16 -0700 Subject: Cleanup code. --- ui/app/components/bn-as-decimal-input.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 8f56f29ab..de01f8b5f 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -31,7 +31,7 @@ BnAsDecimalInput.prototype.render = function () { const suffix = props.suffix const style = props.style const valueString = value.toString(10) - const newValue = downsize(valueString, scale, precision) + const newValue = this.downsize(valueString, scale, precision) return ( h('.flex-column', [ @@ -65,7 +65,7 @@ BnAsDecimalInput.prototype.render = function () { const value = (event.target.value === '') ? '' : event.target.value - const scaledNumber = upsize(value, scale, precision) + const scaledNumber = this.upsize(value, scale, precision) const precisionBN = new BN(scaledNumber, 10) onChange(precisionBN) }, @@ -145,20 +145,28 @@ BnAsDecimalInput.prototype.constructWarning = function () { } -function downsize (number, scale, precision) { +BnAsDecimalInput.prototype.downsize = function (number, scale, precision) { + // if there is no scaling, simply return the number if (scale === 0) { return Number(number) } else { + // if the scale is the same as the precision, account for this edge case. var decimals = (scale === precision) ? -1 : scale - precision return Number(number.slice(0, -scale) + '.' + number.slice(-scale, decimals)) } } -function upsize (number, scale, precision) { - var string = number.toString() - var stringArray = string.split('.') +BnAsDecimalInput.prototype.upsize = function (number, scale, precision) { + var stringArray = number.toString().split('.') var decimalLength = stringArray[1] ? stringArray[1].length : 0 - var newString = ((scale === 0) || (decimalLength === 0)) ? stringArray[0] : stringArray[0] + stringArray[1].slice(0, precision) + var newString = stringArray[0] + + // If there is scaling and decimal parts exist, integrate them in. + if ((scale !== 0) && (decimalLength !== 0)) { + newString += stringArray[1].slice(0, precision) + } + + // Add 0s to account for the upscaling. for (var i = decimalLength; i < scale; i++) { newString += '0' } -- cgit v1.2.3 From 10ca3b6467af2bea723e661160ba5cf2a41ab3b0 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 24 May 2017 10:13:43 -0700 Subject: Fix bug where submit was enabled when invalid params were filled out. --- ui/app/components/bn-as-decimal-input.js | 2 +- ui/app/components/pending-tx.js | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index de01f8b5f..1d292ca2a 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -67,7 +67,7 @@ BnAsDecimalInput.prototype.render = function () { const scaledNumber = this.upsize(value, scale, precision) const precisionBN = new BN(scaledNumber, 10) - onChange(precisionBN) + onChange(precisionBN, event.target.checkValidity()) }, onInvalid: (event) => { const msg = this.constructWarning() diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index eed0fd9ae..8e63f5c76 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -346,18 +346,24 @@ PendingTx.prototype.miniAccountPanelForRecipient = function () { } } -PendingTx.prototype.gasPriceChanged = function (newBN) { +PendingTx.prototype.gasPriceChanged = function (newBN, valid) { log.info(`Gas price changed to: ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') - this.setState({ txData: clone(txMeta) }) + this.setState({ + txData: clone(txMeta), + valid, + }) } -PendingTx.prototype.gasLimitChanged = function (newBN) { +PendingTx.prototype.gasLimitChanged = function (newBN, valid) { log.info(`Gas limit changed to ${newBN.toString(10)}`) const txMeta = this.gatherTxMeta() txMeta.txParams.gas = '0x' + newBN.toString('hex') - this.setState({ txData: clone(txMeta) }) + this.setState({ + txData: clone(txMeta), + valid, + }) } PendingTx.prototype.resetGasFields = function () { -- cgit v1.2.3 From 293d0b4a574e5b20662da244d54357138ac81d5b Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 24 May 2017 11:02:26 -0700 Subject: Minor cleanup --- ui/app/components/bn-as-decimal-input.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 1d292ca2a..f3ace4720 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -47,8 +47,8 @@ BnAsDecimalInput.prototype.render = function () { type: 'number', step: 'any', required: true, - min: min, - max: max, + min, + max, style: extend({ display: 'block', textAlign: 'right', -- cgit v1.2.3 From 9554788c14eab7be51abe0496bab17f9fe40291b Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 24 May 2017 11:02:58 -0700 Subject: Minor cleanup of lint --- ui/app/components/pending-tx.js | 1 - 1 file changed, 1 deletion(-) (limited to 'ui') diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 8e63f5c76..d66d98dd5 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -367,7 +367,6 @@ PendingTx.prototype.gasLimitChanged = function (newBN, valid) { } PendingTx.prototype.resetGasFields = function () { - log.debug(`pending-tx resetGasFields`) this.inputs.forEach((hexInput) => { -- cgit v1.2.3