mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add togglable advanced gas controls on send and confirm screens (#6112)
* Extract advanced gas input controls to their own component * Add advanced inline gas toggle to settings * Add optional advanced inline gas to send send screen * Adds optional advanced gas inputs to the confirm screen * Add info modals for advanced gas inputs. * Fix translation of advance gas toggle description. * Lint and unit test fixes for inline-advanced-gas-inputs * Increase margin above advanced options button on send screen * Move methods from constructor to property syntax in advanced-gas-inputs.component
This commit is contained in:
parent
c28fa31250
commit
38b91f63a2
@ -529,6 +529,9 @@
|
|||||||
"gasLimitCalculation": {
|
"gasLimitCalculation": {
|
||||||
"message": "We calculate the suggested gas limit based on network success rates."
|
"message": "We calculate the suggested gas limit based on network success rates."
|
||||||
},
|
},
|
||||||
|
"gasLimitInfoModalContent": {
|
||||||
|
"message": "Gas limit is the maximum amount of units of gas you are willing to spend."
|
||||||
|
},
|
||||||
"gasLimitRequired": {
|
"gasLimitRequired": {
|
||||||
"message": "Gas Limit Required"
|
"message": "Gas Limit Required"
|
||||||
},
|
},
|
||||||
@ -547,6 +550,9 @@
|
|||||||
"gasPriceExtremelyLow": {
|
"gasPriceExtremelyLow": {
|
||||||
"message": "Gas Price Extremely Low"
|
"message": "Gas Price Extremely Low"
|
||||||
},
|
},
|
||||||
|
"gasPriceInfoModalContent": {
|
||||||
|
"message": "Gas price specifies the amount of Ether you are willing to pay for each unit of gas."
|
||||||
|
},
|
||||||
"gasPriceNoDenom": {
|
"gasPriceNoDenom": {
|
||||||
"message": "Gas Price"
|
"message": "Gas Price"
|
||||||
},
|
},
|
||||||
@ -1210,6 +1216,12 @@
|
|||||||
"shapeshiftBuy": {
|
"shapeshiftBuy": {
|
||||||
"message": "Buy with Shapeshift"
|
"message": "Buy with Shapeshift"
|
||||||
},
|
},
|
||||||
|
"showAdvancedGasInline": {
|
||||||
|
"message": "Advanced gas controls"
|
||||||
|
},
|
||||||
|
"showAdvancedGasInlineDescription": {
|
||||||
|
"message": "Select this to show gas price and limit controls directly on the send and confirm screens."
|
||||||
|
},
|
||||||
"showPrivateKeys": {
|
"showPrivateKeys": {
|
||||||
"message": "Show Private Keys"
|
"message": "Show Private Keys"
|
||||||
},
|
},
|
||||||
|
@ -43,4 +43,8 @@
|
|||||||
font-size: .625rem;
|
font-size: .625rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.advanced-gas-inputs__gas-edit-rows {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,10 @@
|
|||||||
|
|
||||||
&__gas-fee {
|
&__gas-fee {
|
||||||
border-bottom: 1px solid $geyser;
|
border-bottom: 1px solid $geyser;
|
||||||
|
|
||||||
|
.advanced-gas-inputs__gas-edit-rows {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__function-type {
|
&__function-type {
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
|
export default class AdvancedTabContent extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
updateCustomGasPrice: PropTypes.func,
|
||||||
|
updateCustomGasLimit: PropTypes.func,
|
||||||
|
customGasPrice: PropTypes.number,
|
||||||
|
customGasLimit: PropTypes.number,
|
||||||
|
insufficientBalance: PropTypes.bool,
|
||||||
|
customPriceIsSafe: PropTypes.bool,
|
||||||
|
isSpeedUp: PropTypes.bool,
|
||||||
|
showGasPriceInfoModal: PropTypes.func,
|
||||||
|
showGasLimitInfoModal: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
debouncedGasLimitReset = debounce((dVal) => {
|
||||||
|
if (dVal < 21000) {
|
||||||
|
this.props.updateCustomGasLimit(21000)
|
||||||
|
}
|
||||||
|
}, 1000, { trailing: true })
|
||||||
|
|
||||||
|
onChangeGasLimit = (val) => {
|
||||||
|
this.props.updateCustomGasLimit(val)
|
||||||
|
this.debouncedGasLimitReset(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
gasInputError ({ labelKey, insufficientBalance, customPriceIsSafe, isSpeedUp, value }) {
|
||||||
|
const { t } = this.context
|
||||||
|
let errorText
|
||||||
|
let errorType
|
||||||
|
let isInError = true
|
||||||
|
|
||||||
|
|
||||||
|
if (insufficientBalance) {
|
||||||
|
errorText = t('insufficientBalance')
|
||||||
|
errorType = 'error'
|
||||||
|
} else if (labelKey === 'gasPrice' && isSpeedUp && value === 0) {
|
||||||
|
errorText = t('zeroGasPriceOnSpeedUpError')
|
||||||
|
errorType = 'error'
|
||||||
|
} else if (labelKey === 'gasPrice' && !customPriceIsSafe) {
|
||||||
|
errorText = t('gasPriceExtremelyLow')
|
||||||
|
errorType = 'warning'
|
||||||
|
} else {
|
||||||
|
isInError = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isInError,
|
||||||
|
errorText,
|
||||||
|
errorType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gasInput ({ labelKey, value, onChange, insufficientBalance, showGWEI, customPriceIsSafe, isSpeedUp }) {
|
||||||
|
const {
|
||||||
|
isInError,
|
||||||
|
errorText,
|
||||||
|
errorType,
|
||||||
|
} = this.gasInputError({ labelKey, insufficientBalance, customPriceIsSafe, isSpeedUp, value })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-row__input-wrapper">
|
||||||
|
<input
|
||||||
|
className={classnames('advanced-gas-inputs__gas-edit-row__input', {
|
||||||
|
'advanced-gas-inputs__gas-edit-row__input--error': isInError && errorType === 'error',
|
||||||
|
'advanced-gas-inputs__gas-edit-row__input--warning': isInError && errorType === 'warning',
|
||||||
|
})}
|
||||||
|
type="number"
|
||||||
|
value={value}
|
||||||
|
onChange={event => onChange(Number(event.target.value))}
|
||||||
|
/>
|
||||||
|
<div className={classnames('advanced-gas-inputs__gas-edit-row__input-arrows', {
|
||||||
|
'advanced-gas-inputs__gas-edit-row__input--error': isInError && errorType === 'error',
|
||||||
|
'advanced-gas-inputs__gas-edit-row__input--warning': isInError && errorType === 'warning',
|
||||||
|
})}>
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap" onClick={() => onChange(value + 1)}><i className="fa fa-sm fa-angle-up" /></div>
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap" onClick={() => onChange(value - 1)}><i className="fa fa-sm fa-angle-down" /></div>
|
||||||
|
</div>
|
||||||
|
{ isInError
|
||||||
|
? <div className={`advanced-gas-inputs__gas-edit-row__${errorType}-text`}>
|
||||||
|
{ errorText }
|
||||||
|
</div>
|
||||||
|
: null }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
infoButton (onClick) {
|
||||||
|
return <i className="fa fa-info-circle" onClick={onClick} />
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGasEditRow (gasInputArgs) {
|
||||||
|
return (
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-row">
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-row__label">
|
||||||
|
{ this.context.t(gasInputArgs.labelKey) }
|
||||||
|
{ this.infoButton(() => gasInputArgs.infoOnClick()) }
|
||||||
|
</div>
|
||||||
|
{ this.gasInput(gasInputArgs) }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
customGasPrice,
|
||||||
|
updateCustomGasPrice,
|
||||||
|
customGasLimit,
|
||||||
|
insufficientBalance,
|
||||||
|
customPriceIsSafe,
|
||||||
|
isSpeedUp,
|
||||||
|
showGasPriceInfoModal,
|
||||||
|
showGasLimitInfoModal,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="advanced-gas-inputs__gas-edit-rows">
|
||||||
|
{ this.renderGasEditRow({
|
||||||
|
labelKey: 'gasPrice',
|
||||||
|
value: customGasPrice,
|
||||||
|
onChange: updateCustomGasPrice,
|
||||||
|
insufficientBalance,
|
||||||
|
customPriceIsSafe,
|
||||||
|
showGWEI: true,
|
||||||
|
isSpeedUp,
|
||||||
|
infoOnClick: showGasPriceInfoModal,
|
||||||
|
}) }
|
||||||
|
{ this.renderGasEditRow({
|
||||||
|
labelKey: 'gasLimit',
|
||||||
|
value: customGasLimit,
|
||||||
|
onChange: this.onChangeGasLimit,
|
||||||
|
insufficientBalance,
|
||||||
|
customPriceIsSafe,
|
||||||
|
infoOnClick: showGasLimitInfoModal,
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { showModal } from '../../../actions'
|
||||||
|
import AdvancedGasInputs from './advanced-gas-inputs.component'
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
showGasPriceInfoModal: modalName => dispatch(showModal({ name: 'GAS_PRICE_INFO_MODAL' })),
|
||||||
|
showGasLimitInfoModal: modalName => dispatch(showModal({ name: 'GAS_LIMIT_INFO_MODAL' })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps)(AdvancedGasInputs)
|
@ -0,0 +1 @@
|
|||||||
|
export { default } from './advanced-gas-inputs.container'
|
@ -0,0 +1,133 @@
|
|||||||
|
.advanced-gas-inputs {
|
||||||
|
&__gas-edit-rows {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__gas-edit-row {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
width: 47.5%;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
color: #313B5E;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@media screen and (max-width: 576px) {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-info-circle {
|
||||||
|
color: $silver;
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-info-circle:hover {
|
||||||
|
color: $mid-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__error-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
border: 1px solid $dusty-gray;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: $mid-gray;
|
||||||
|
font-size: 16px;
|
||||||
|
height: 24px;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-top: 2px;
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input--error {
|
||||||
|
border: 1px solid $red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input--warning {
|
||||||
|
border: 1px solid $orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input-arrows {
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 0px;
|
||||||
|
width: 17px;
|
||||||
|
height: 24px;
|
||||||
|
border: 1px solid #dadada;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #9b9b9b;
|
||||||
|
font-size: .8em;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&__i-wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__i-wrap:hover {
|
||||||
|
background: #4EADE7;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
|
i:hover {
|
||||||
|
background: #4EADE7;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input-arrows--error {
|
||||||
|
border: 1px solid $red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input-arrows--warning {
|
||||||
|
border: 1px solid $orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]:hover::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__gwei-symbol {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 10px;
|
||||||
|
color: $dusty-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,3 +3,5 @@
|
|||||||
@import './gas-modal-page-container/index';
|
@import './gas-modal-page-container/index';
|
||||||
|
|
||||||
@import './gas-price-chart/index';
|
@import './gas-price-chart/index';
|
||||||
|
|
||||||
|
@import './advanced-gas-inputs/index';
|
||||||
|
@ -230,6 +230,40 @@ const MODALS = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
GAS_PRICE_INFO_MODAL: {
|
||||||
|
contents: [
|
||||||
|
h(NotifcationModal, {
|
||||||
|
header: 'gasPriceNoDenom',
|
||||||
|
message: 'gasPriceInfoModalContent',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
mobileModalStyle: {
|
||||||
|
width: '95%',
|
||||||
|
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
|
||||||
|
},
|
||||||
|
laptopModalStyle: {
|
||||||
|
width: '449px',
|
||||||
|
top: 'calc(33% + 45px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
GAS_LIMIT_INFO_MODAL: {
|
||||||
|
contents: [
|
||||||
|
h(NotifcationModal, {
|
||||||
|
header: 'gasLimit',
|
||||||
|
message: 'gasLimitInfoModalContent',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
mobileModalStyle: {
|
||||||
|
width: '95%',
|
||||||
|
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
|
||||||
|
},
|
||||||
|
laptopModalStyle: {
|
||||||
|
width: '449px',
|
||||||
|
top: 'calc(33% + 45px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
CONFIRM_RESET_ACCOUNT: {
|
CONFIRM_RESET_ACCOUNT: {
|
||||||
contents: h(ConfirmResetAccount),
|
contents: h(ConfirmResetAccount),
|
||||||
mobileModalStyle: {
|
mobileModalStyle: {
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions'
|
import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions'
|
||||||
import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
|
import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'
|
||||||
import { PRIMARY, SECONDARY } from '../../../constants/common'
|
import { PRIMARY, SECONDARY } from '../../../constants/common'
|
||||||
|
import AdvancedGasInputs from '../../gas-customization/advanced-gas-inputs'
|
||||||
|
|
||||||
export default class ConfirmTransactionBase extends Component {
|
export default class ConfirmTransactionBase extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
@ -81,6 +82,11 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
titleComponent: PropTypes.node,
|
titleComponent: PropTypes.node,
|
||||||
valid: PropTypes.bool,
|
valid: PropTypes.bool,
|
||||||
warning: PropTypes.string,
|
warning: PropTypes.string,
|
||||||
|
advancedInlineGasShown: PropTypes.bool,
|
||||||
|
gasPrice: PropTypes.number,
|
||||||
|
gasLimit: PropTypes.number,
|
||||||
|
insufficientBalance: PropTypes.bool,
|
||||||
|
convertThenUpdateGasAndCalculate: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -165,6 +171,11 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
hexTransactionFee,
|
hexTransactionFee,
|
||||||
hexTransactionTotal,
|
hexTransactionTotal,
|
||||||
hideDetails,
|
hideDetails,
|
||||||
|
advancedInlineGasShown,
|
||||||
|
gasPrice,
|
||||||
|
gasLimit,
|
||||||
|
insufficientBalance,
|
||||||
|
convertThenUpdateGasAndCalculate,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
if (hideDetails) {
|
if (hideDetails) {
|
||||||
@ -182,6 +193,18 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
headerTextClassName="confirm-detail-row__header-text--edit"
|
headerTextClassName="confirm-detail-row__header-text--edit"
|
||||||
onHeaderClick={() => this.handleEditGas()}
|
onHeaderClick={() => this.handleEditGas()}
|
||||||
/>
|
/>
|
||||||
|
{advancedInlineGasShown
|
||||||
|
? <AdvancedGasInputs
|
||||||
|
updateCustomGasPrice={newGasPrice => convertThenUpdateGasAndCalculate({ gasPrice: newGasPrice, gasLimit })}
|
||||||
|
updateCustomGasLimit={newGasLimit => convertThenUpdateGasAndCalculate({ gasLimit: newGasLimit, gasPrice })}
|
||||||
|
customGasPrice={gasPrice}
|
||||||
|
customGasLimit={gasLimit}
|
||||||
|
insufficientBalance={insufficientBalance}
|
||||||
|
customPriceIsSafe={true}
|
||||||
|
isSpeedUp={false}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ConfirmDetailRow
|
<ConfirmDetailRow
|
||||||
|
@ -14,11 +14,17 @@ import {
|
|||||||
GAS_LIMIT_TOO_LOW_ERROR_KEY,
|
GAS_LIMIT_TOO_LOW_ERROR_KEY,
|
||||||
} from '../../../constants/error-keys'
|
} from '../../../constants/error-keys'
|
||||||
import { getHexGasTotal } from '../../../helpers/confirm-transaction/util'
|
import { getHexGasTotal } from '../../../helpers/confirm-transaction/util'
|
||||||
import { isBalanceSufficient } from '../../send/send.utils'
|
import {
|
||||||
|
convertGasPriceForInputs,
|
||||||
|
convertGasLimitForInputs,
|
||||||
|
decimalToHex,
|
||||||
|
decGWEIToHexWEI,
|
||||||
|
} from '../../../helpers/conversions.util'
|
||||||
|
import { isBalanceSufficient, calcGasTotal } from '../../send/send.utils'
|
||||||
import { conversionGreaterThan } from '../../../conversion-util'
|
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, valuesFor } from '../../../util'
|
import { addressSlicer, valuesFor } from '../../../util'
|
||||||
import { getMetaMaskAccounts } from '../../../selectors'
|
import { getMetaMaskAccounts, getAdvancedInlineGasShown } from '../../../selectors'
|
||||||
|
|
||||||
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
|
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
|
||||||
return {
|
return {
|
||||||
@ -47,7 +53,13 @@ const mapStateToProps = (state, props) => {
|
|||||||
nonce,
|
nonce,
|
||||||
} = confirmTransaction
|
} = confirmTransaction
|
||||||
const { txParams = {}, lastGasPrice, id: transactionId } = txData
|
const { txParams = {}, lastGasPrice, id: transactionId } = txData
|
||||||
const { from: fromAddress, to: txParamsToAddress } = txParams
|
const {
|
||||||
|
from: fromAddress,
|
||||||
|
to: txParamsToAddress,
|
||||||
|
gasPrice,
|
||||||
|
gas: gasLimit,
|
||||||
|
value: amount,
|
||||||
|
} = txParams
|
||||||
const accounts = getMetaMaskAccounts(state)
|
const accounts = getMetaMaskAccounts(state)
|
||||||
const {
|
const {
|
||||||
conversionRate,
|
conversionRate,
|
||||||
@ -84,6 +96,13 @@ const mapStateToProps = (state, props) => {
|
|||||||
)
|
)
|
||||||
const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length
|
const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length
|
||||||
|
|
||||||
|
const insufficientBalance = !isBalanceSufficient({
|
||||||
|
amount,
|
||||||
|
gasTotal: calcGasTotal(gasLimit, gasPrice),
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
balance,
|
balance,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -113,9 +132,13 @@ const mapStateToProps = (state, props) => {
|
|||||||
unapprovedTxCount,
|
unapprovedTxCount,
|
||||||
currentNetworkUnapprovedTxs,
|
currentNetworkUnapprovedTxs,
|
||||||
customGas: {
|
customGas: {
|
||||||
gasLimit: customGasLimit || txData.gasPrice,
|
gasLimit: customGasLimit || gasPrice,
|
||||||
gasPrice: customGasPrice || txData.gasLimit,
|
gasPrice: customGasPrice || gasLimit,
|
||||||
},
|
},
|
||||||
|
advancedInlineGasShown: getAdvancedInlineGasShown(state),
|
||||||
|
gasPrice: convertGasPriceForInputs(gasPrice),
|
||||||
|
gasLimit: convertGasLimitForInputs(gasLimit),
|
||||||
|
insufficientBalance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +155,12 @@ const mapDispatchToProps = dispatch => {
|
|||||||
updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
|
updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
|
||||||
return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
|
return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
|
||||||
},
|
},
|
||||||
|
convertThenUpdateGasAndCalculate: ({ gasLimit, gasPrice }) => {
|
||||||
|
return dispatch(updateGasAndCalculate({
|
||||||
|
gasLimit: decimalToHex(gasLimit),
|
||||||
|
gasPrice: decGWEIToHexWEI(gasPrice),
|
||||||
|
}))
|
||||||
|
},
|
||||||
showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => {
|
showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => {
|
||||||
return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }))
|
return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }))
|
||||||
},
|
},
|
||||||
|
@ -59,6 +59,8 @@ export default class SettingsTab extends PureComponent {
|
|||||||
nativeCurrency: PropTypes.string,
|
nativeCurrency: PropTypes.string,
|
||||||
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
|
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
|
||||||
setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func,
|
setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func,
|
||||||
|
setAdvancedInlineGasFeatureFlag: PropTypes.func,
|
||||||
|
advancedInlineGas: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -412,6 +414,32 @@ export default class SettingsTab extends PureComponent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderAdvancedGasInputInline () {
|
||||||
|
const { t } = this.context
|
||||||
|
const { advancedInlineGas, setAdvancedInlineGasFeatureFlag } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="settings-page__content-row">
|
||||||
|
<div className="settings-page__content-item">
|
||||||
|
<span>{ t('showAdvancedGasInline') }</span>
|
||||||
|
<div className="settings-page__content-description">
|
||||||
|
{ t('showAdvancedGasInlineDescription') }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="settings-page__content-item">
|
||||||
|
<div className="settings-page__content-item-col">
|
||||||
|
<ToggleButton
|
||||||
|
value={advancedInlineGas}
|
||||||
|
onToggle={value => setAdvancedInlineGasFeatureFlag(!value)}
|
||||||
|
activeLabel=""
|
||||||
|
inactiveLabel=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
renderUsePrimaryCurrencyOptions () {
|
renderUsePrimaryCurrencyOptions () {
|
||||||
const { t } = this.context
|
const { t } = this.context
|
||||||
const {
|
const {
|
||||||
@ -508,6 +536,7 @@ export default class SettingsTab extends PureComponent {
|
|||||||
{ this.renderClearApproval() }
|
{ this.renderClearApproval() }
|
||||||
{ this.renderPrivacyOptIn() }
|
{ this.renderPrivacyOptIn() }
|
||||||
{ this.renderHexDataOptIn() }
|
{ this.renderHexDataOptIn() }
|
||||||
|
{ this.renderAdvancedGasInputInline() }
|
||||||
{ this.renderBlockieOptIn() }
|
{ this.renderBlockieOptIn() }
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -25,6 +25,7 @@ const mapStateToProps = state => {
|
|||||||
featureFlags: {
|
featureFlags: {
|
||||||
sendHexData,
|
sendHexData,
|
||||||
privacyMode,
|
privacyMode,
|
||||||
|
advancedInlineGas,
|
||||||
} = {},
|
} = {},
|
||||||
provider = {},
|
provider = {},
|
||||||
currentLocale,
|
currentLocale,
|
||||||
@ -39,6 +40,7 @@ const mapStateToProps = state => {
|
|||||||
nativeCurrency,
|
nativeCurrency,
|
||||||
useBlockie,
|
useBlockie,
|
||||||
sendHexData,
|
sendHexData,
|
||||||
|
advancedInlineGas,
|
||||||
privacyMode,
|
privacyMode,
|
||||||
provider,
|
provider,
|
||||||
useNativeCurrencyAsPrimaryCurrency,
|
useNativeCurrencyAsPrimaryCurrency,
|
||||||
@ -54,6 +56,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
setUseBlockie: value => dispatch(setUseBlockie(value)),
|
setUseBlockie: value => dispatch(setUseBlockie(value)),
|
||||||
updateCurrentLocale: key => dispatch(updateCurrentLocale(key)),
|
updateCurrentLocale: key => dispatch(updateCurrentLocale(key)),
|
||||||
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
|
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
|
||||||
|
setAdvancedInlineGasFeatureFlag: shouldShow => dispatch(setFeatureFlag('advancedInlineGas', shouldShow)),
|
||||||
setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)),
|
setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)),
|
||||||
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
|
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
|
||||||
setUseNativeCurrencyAsPrimaryCurrencyPreference: value => {
|
setUseNativeCurrencyAsPrimaryCurrencyPreference: value => {
|
||||||
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
|
|||||||
import SendRowWrapper from '../send-row-wrapper/'
|
import SendRowWrapper from '../send-row-wrapper/'
|
||||||
import GasFeeDisplay from './gas-fee-display/gas-fee-display.component'
|
import GasFeeDisplay from './gas-fee-display/gas-fee-display.component'
|
||||||
import GasPriceButtonGroup from '../../../gas-customization/gas-price-button-group'
|
import GasPriceButtonGroup from '../../../gas-customization/gas-price-button-group'
|
||||||
|
import AdvancedGasInputs from '../../../gas-customization/advanced-gas-inputs'
|
||||||
|
|
||||||
export default class SendGasRow extends Component {
|
export default class SendGasRow extends Component {
|
||||||
|
|
||||||
@ -13,54 +14,94 @@ export default class SendGasRow extends Component {
|
|||||||
gasLoadingError: PropTypes.bool,
|
gasLoadingError: PropTypes.bool,
|
||||||
gasTotal: PropTypes.string,
|
gasTotal: PropTypes.string,
|
||||||
showCustomizeGasModal: PropTypes.func,
|
showCustomizeGasModal: PropTypes.func,
|
||||||
|
setGasPrice: PropTypes.func,
|
||||||
|
setGasLimit: PropTypes.func,
|
||||||
gasPriceButtonGroupProps: PropTypes.object,
|
gasPriceButtonGroupProps: PropTypes.object,
|
||||||
gasButtonGroupShown: PropTypes.bool,
|
gasButtonGroupShown: PropTypes.bool,
|
||||||
|
advancedInlineGasShown: PropTypes.bool,
|
||||||
resetGasButtons: PropTypes.func,
|
resetGasButtons: PropTypes.func,
|
||||||
|
gasPrice: PropTypes.number,
|
||||||
|
gasLimit: PropTypes.number,
|
||||||
|
insufficientBalance: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
renderAdvancedOptionsButton () {
|
||||||
|
const { showCustomizeGasModal } = this.props
|
||||||
|
return <div className="advanced-gas-options-btn" onClick={() => showCustomizeGasModal()}>
|
||||||
|
{ this.context.t('advancedOptions') }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContent () {
|
||||||
const {
|
const {
|
||||||
conversionRate,
|
conversionRate,
|
||||||
convertedCurrency,
|
convertedCurrency,
|
||||||
gasLoadingError,
|
gasLoadingError,
|
||||||
gasTotal,
|
gasTotal,
|
||||||
gasFeeError,
|
|
||||||
showCustomizeGasModal,
|
showCustomizeGasModal,
|
||||||
gasPriceButtonGroupProps,
|
gasPriceButtonGroupProps,
|
||||||
gasButtonGroupShown,
|
gasButtonGroupShown,
|
||||||
|
advancedInlineGasShown,
|
||||||
resetGasButtons,
|
resetGasButtons,
|
||||||
|
setGasPrice,
|
||||||
|
setGasLimit,
|
||||||
|
gasPrice,
|
||||||
|
gasLimit,
|
||||||
|
insufficientBalance,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
|
const gasPriceButtonGroup = <div>
|
||||||
|
<GasPriceButtonGroup
|
||||||
|
className="gas-price-button-group--small"
|
||||||
|
showCheck={false}
|
||||||
|
{...gasPriceButtonGroupProps}
|
||||||
|
/>
|
||||||
|
{ this.renderAdvancedOptionsButton() }
|
||||||
|
</div>
|
||||||
|
const gasFeeDisplay = <GasFeeDisplay
|
||||||
|
conversionRate={conversionRate}
|
||||||
|
convertedCurrency={convertedCurrency}
|
||||||
|
gasLoadingError={gasLoadingError}
|
||||||
|
gasTotal={gasTotal}
|
||||||
|
onReset={resetGasButtons}
|
||||||
|
onClick={() => showCustomizeGasModal()}
|
||||||
|
/>
|
||||||
|
const advancedGasInputs = <div>
|
||||||
|
<AdvancedGasInputs
|
||||||
|
updateCustomGasPrice={newGasPrice => setGasPrice(newGasPrice, gasLimit)}
|
||||||
|
updateCustomGasLimit={newGasLimit => setGasLimit(newGasLimit, gasPrice)}
|
||||||
|
customGasPrice={gasPrice}
|
||||||
|
customGasLimit={gasLimit}
|
||||||
|
insufficientBalance={insufficientBalance}
|
||||||
|
customPriceIsSafe={true}
|
||||||
|
isSpeedUp={false}
|
||||||
|
/>
|
||||||
|
{ this.renderAdvancedOptionsButton() }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
if (advancedInlineGasShown) {
|
||||||
|
return advancedGasInputs
|
||||||
|
} else if (gasButtonGroupShown) {
|
||||||
|
return gasPriceButtonGroup
|
||||||
|
} else {
|
||||||
|
return gasFeeDisplay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { gasFeeError } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SendRowWrapper
|
<SendRowWrapper
|
||||||
label={`${this.context.t('transactionFee')}:`}
|
label={`${this.context.t('transactionFee')}:`}
|
||||||
showError={gasFeeError}
|
showError={gasFeeError}
|
||||||
errorType={'gasFee'}
|
errorType={'gasFee'}
|
||||||
>
|
>
|
||||||
{gasButtonGroupShown
|
{ this.renderContent() }
|
||||||
? <div>
|
|
||||||
<GasPriceButtonGroup
|
|
||||||
className="gas-price-button-group--small"
|
|
||||||
showCheck={false}
|
|
||||||
{...gasPriceButtonGroupProps}
|
|
||||||
/>
|
|
||||||
<div className="advanced-gas-options-btn" onClick={() => showCustomizeGasModal()}>
|
|
||||||
{ this.context.t('advancedOptions') }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
: <GasFeeDisplay
|
|
||||||
conversionRate={conversionRate}
|
|
||||||
convertedCurrency={convertedCurrency}
|
|
||||||
gasLoadingError={gasLoadingError}
|
|
||||||
gasTotal={gasTotal}
|
|
||||||
onReset={resetGasButtons}
|
|
||||||
onClick={() => showCustomizeGasModal()}
|
|
||||||
/>}
|
|
||||||
|
|
||||||
</SendRowWrapper>
|
</SendRowWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,24 @@ import {
|
|||||||
getCurrentCurrency,
|
getCurrentCurrency,
|
||||||
getGasTotal,
|
getGasTotal,
|
||||||
getGasPrice,
|
getGasPrice,
|
||||||
|
getGasLimit,
|
||||||
|
getSendAmount,
|
||||||
} from '../../send.selectors.js'
|
} from '../../send.selectors.js'
|
||||||
|
import {
|
||||||
|
isBalanceSufficient,
|
||||||
|
calcGasTotal,
|
||||||
|
} from '../../send.utils.js'
|
||||||
import {
|
import {
|
||||||
getBasicGasEstimateLoadingStatus,
|
getBasicGasEstimateLoadingStatus,
|
||||||
getRenderableEstimateDataForSmallButtonsFromGWEI,
|
getRenderableEstimateDataForSmallButtonsFromGWEI,
|
||||||
getDefaultActiveButtonIndex,
|
getDefaultActiveButtonIndex,
|
||||||
} from '../../../../selectors/custom-gas'
|
} from '../../../../selectors/custom-gas'
|
||||||
|
import {
|
||||||
|
decGWEIToHexWEI,
|
||||||
|
decimalToHex,
|
||||||
|
convertGasPriceForInputs,
|
||||||
|
convertGasLimitForInputs,
|
||||||
|
} from '../../../../helpers/conversions.util'
|
||||||
import {
|
import {
|
||||||
showGasButtonGroup,
|
showGasButtonGroup,
|
||||||
} from '../../../../ducks/send.duck'
|
} from '../../../../ducks/send.duck'
|
||||||
@ -17,19 +29,34 @@ import {
|
|||||||
resetCustomData,
|
resetCustomData,
|
||||||
} from '../../../../ducks/gas.duck'
|
} from '../../../../ducks/gas.duck'
|
||||||
import { getGasLoadingError, gasFeeIsInError, getGasButtonGroupShown } from './send-gas-row.selectors.js'
|
import { getGasLoadingError, gasFeeIsInError, getGasButtonGroupShown } from './send-gas-row.selectors.js'
|
||||||
import { showModal, setGasPrice } from '../../../../actions'
|
import { showModal, setGasPrice, setGasLimit, setGasTotal } from '../../../../actions'
|
||||||
|
import { getAdvancedInlineGasShown, getCurrentEthBalance } from '../../../../selectors'
|
||||||
import SendGasRow from './send-gas-row.component'
|
import SendGasRow from './send-gas-row.component'
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SendGasRow)
|
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SendGasRow)
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const gasButtonInfo = getRenderableEstimateDataForSmallButtonsFromGWEI(state)
|
const gasButtonInfo = getRenderableEstimateDataForSmallButtonsFromGWEI(state)
|
||||||
const activeButtonIndex = getDefaultActiveButtonIndex(gasButtonInfo, getGasPrice(state))
|
const gasPrice = getGasPrice(state)
|
||||||
|
const activeButtonIndex = getDefaultActiveButtonIndex(gasButtonInfo, gasPrice)
|
||||||
|
const renderableGasPrice = convertGasPriceForInputs(gasPrice)
|
||||||
|
const renderableGasLimit = convertGasLimitForInputs(getGasLimit(state))
|
||||||
|
|
||||||
|
const gasTotal = getGasTotal(state)
|
||||||
|
const conversionRate = getConversionRate(state)
|
||||||
|
const balance = getCurrentEthBalance(state)
|
||||||
|
|
||||||
|
const insufficientBalance = !isBalanceSufficient({
|
||||||
|
amount: getSendAmount(state),
|
||||||
|
gasTotal,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
conversionRate: getConversionRate(state),
|
conversionRate,
|
||||||
convertedCurrency: getCurrentCurrency(state),
|
convertedCurrency: getCurrentCurrency(state),
|
||||||
gasTotal: getGasTotal(state),
|
gasTotal,
|
||||||
gasFeeError: gasFeeIsInError(state),
|
gasFeeError: gasFeeIsInError(state),
|
||||||
gasLoadingError: getGasLoadingError(state),
|
gasLoadingError: getGasLoadingError(state),
|
||||||
gasPriceButtonGroupProps: {
|
gasPriceButtonGroupProps: {
|
||||||
@ -39,13 +66,26 @@ function mapStateToProps (state) {
|
|||||||
gasButtonInfo,
|
gasButtonInfo,
|
||||||
},
|
},
|
||||||
gasButtonGroupShown: getGasButtonGroupShown(state),
|
gasButtonGroupShown: getGasButtonGroupShown(state),
|
||||||
|
advancedInlineGasShown: getAdvancedInlineGasShown(state),
|
||||||
|
gasPrice: renderableGasPrice,
|
||||||
|
gasLimit: renderableGasLimit,
|
||||||
|
insufficientBalance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
return {
|
return {
|
||||||
showCustomizeGasModal: () => dispatch(showModal({ name: 'CUSTOMIZE_GAS', hideBasic: true })),
|
showCustomizeGasModal: () => dispatch(showModal({ name: 'CUSTOMIZE_GAS', hideBasic: true })),
|
||||||
setGasPrice: newPrice => dispatch(setGasPrice(newPrice)),
|
setGasPrice: (newPrice, gasLimit) => {
|
||||||
|
newPrice = decGWEIToHexWEI(newPrice)
|
||||||
|
dispatch(setGasPrice(newPrice))
|
||||||
|
dispatch(setGasTotal(calcGasTotal(gasLimit, newPrice)))
|
||||||
|
},
|
||||||
|
setGasLimit: (newLimit, gasPrice) => {
|
||||||
|
newLimit = decimalToHex(newLimit)
|
||||||
|
dispatch(setGasLimit(newLimit))
|
||||||
|
dispatch(setGasTotal(calcGasTotal(newLimit, gasPrice)))
|
||||||
|
},
|
||||||
showGasButtonGroup: () => dispatch(showGasButtonGroup()),
|
showGasButtonGroup: () => dispatch(showGasButtonGroup()),
|
||||||
resetCustomData: () => dispatch(resetCustomData()),
|
resetCustomData: () => dispatch(resetCustomData()),
|
||||||
}
|
}
|
||||||
@ -74,5 +114,6 @@ function mergeProps (stateProps, dispatchProps, ownProps) {
|
|||||||
dispatchSetGasPrice(gasButtonInfo[1].priceInHexWei)
|
dispatchSetGasPrice(gasButtonInfo[1].priceInHexWei)
|
||||||
dispatchShowGasButtonGroup()
|
dispatchShowGasButtonGroup()
|
||||||
},
|
},
|
||||||
|
setGasPrice: dispatchSetGasPrice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ let mergeProps
|
|||||||
const actionSpies = {
|
const actionSpies = {
|
||||||
showModal: sinon.spy(),
|
showModal: sinon.spy(),
|
||||||
setGasPrice: sinon.spy(),
|
setGasPrice: sinon.spy(),
|
||||||
|
setGasTotal: sinon.spy(),
|
||||||
|
setGasLimit: sinon.spy(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendDuckSpies = {
|
const sendDuckSpies = {
|
||||||
@ -28,11 +30,26 @@ proxyquire('../send-gas-row.container.js', {
|
|||||||
return () => ({})
|
return () => ({})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'../../../../selectors': {
|
||||||
|
getCurrentEthBalance: (s) => `mockCurrentEthBalance:${s}`,
|
||||||
|
getAdvancedInlineGasShown: (s) => `mockAdvancedInlineGasShown:${s}`,
|
||||||
|
},
|
||||||
'../../send.selectors.js': {
|
'../../send.selectors.js': {
|
||||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||||
getCurrentCurrency: (s) => `mockConvertedCurrency:${s}`,
|
getCurrentCurrency: (s) => `mockConvertedCurrency:${s}`,
|
||||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||||
getGasPrice: (s) => `mockGasPrice:${s}`,
|
getGasPrice: (s) => `mockGasPrice:${s}`,
|
||||||
|
getGasLimit: (s) => `mockGasLimit:${s}`,
|
||||||
|
getSendAmount: (s) => `mockSendAmount:${s}`,
|
||||||
|
},
|
||||||
|
'../../send.utils.js': {
|
||||||
|
isBalanceSufficient: ({
|
||||||
|
amount,
|
||||||
|
gasTotal,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
}) => `${amount}:${gasTotal}:${balance}:${conversionRate}`,
|
||||||
|
calcGasTotal: (gasLimit, gasPrice) => gasLimit + gasPrice,
|
||||||
},
|
},
|
||||||
'./send-gas-row.selectors.js': {
|
'./send-gas-row.selectors.js': {
|
||||||
getGasLoadingError: (s) => `mockGasLoadingError:${s}`,
|
getGasLoadingError: (s) => `mockGasLoadingError:${s}`,
|
||||||
@ -47,6 +64,12 @@ proxyquire('../send-gas-row.container.js', {
|
|||||||
},
|
},
|
||||||
'../../../../ducks/send.duck': sendDuckSpies,
|
'../../../../ducks/send.duck': sendDuckSpies,
|
||||||
'../../../../ducks/gas.duck': gasDuckSpies,
|
'../../../../ducks/gas.duck': gasDuckSpies,
|
||||||
|
'../../../../helpers/conversions.util': {
|
||||||
|
convertGasPriceForInputs: str => str + '*',
|
||||||
|
convertGasLimitForInputs: str => str + '**',
|
||||||
|
decGWEIToHexWEI: str => '0x' + str + '000',
|
||||||
|
decimalToHex: str => '0x' + str,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('send-gas-row container', () => {
|
describe('send-gas-row container', () => {
|
||||||
@ -67,6 +90,10 @@ describe('send-gas-row container', () => {
|
|||||||
gasButtonInfo: `mockGasButtonInfo:mockState`,
|
gasButtonInfo: `mockGasButtonInfo:mockState`,
|
||||||
},
|
},
|
||||||
gasButtonGroupShown: `mockGetGasButtonGroupShown:mockState`,
|
gasButtonGroupShown: `mockGetGasButtonGroupShown:mockState`,
|
||||||
|
advancedInlineGasShown: 'mockAdvancedInlineGasShown:mockState',
|
||||||
|
gasLimit: 'mockGasLimit:mockState**',
|
||||||
|
gasPrice: 'mockGasPrice:mockState*',
|
||||||
|
insufficientBalance: false,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -79,6 +106,7 @@ describe('send-gas-row container', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dispatchSpy = sinon.spy()
|
dispatchSpy = sinon.spy()
|
||||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||||
|
actionSpies.setGasTotal.resetHistory()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('showCustomizeGasModal()', () => {
|
describe('showCustomizeGasModal()', () => {
|
||||||
@ -94,10 +122,23 @@ describe('send-gas-row container', () => {
|
|||||||
|
|
||||||
describe('setGasPrice()', () => {
|
describe('setGasPrice()', () => {
|
||||||
it('should dispatch an action', () => {
|
it('should dispatch an action', () => {
|
||||||
mapDispatchToPropsObject.setGasPrice('mockNewPrice')
|
mapDispatchToPropsObject.setGasPrice('mockNewPrice', 'mockLimit')
|
||||||
assert(dispatchSpy.calledOnce)
|
assert(dispatchSpy.calledTwice)
|
||||||
assert(actionSpies.setGasPrice.calledOnce)
|
assert(actionSpies.setGasPrice.calledOnce)
|
||||||
assert.equal(actionSpies.setGasPrice.getCall(0).args[0], 'mockNewPrice')
|
assert.equal(actionSpies.setGasPrice.getCall(0).args[0], '0xmockNewPrice000')
|
||||||
|
assert(actionSpies.setGasTotal.calledOnce)
|
||||||
|
assert.equal(actionSpies.setGasTotal.getCall(0).args[0], 'mockLimit0xmockNewPrice000')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('setGasLimit()', () => {
|
||||||
|
it('should dispatch an action', () => {
|
||||||
|
mapDispatchToPropsObject.setGasLimit('mockNewLimit', 'mockPrice')
|
||||||
|
assert(dispatchSpy.calledTwice)
|
||||||
|
assert(actionSpies.setGasLimit.calledOnce)
|
||||||
|
assert.equal(actionSpies.setGasLimit.getCall(0).args[0], '0xmockNewLimit')
|
||||||
|
assert(actionSpies.setGasTotal.calledOnce)
|
||||||
|
assert.equal(actionSpies.setGasTotal.getCall(0).args[0], '0xmockNewLimitmockPrice')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -560,6 +560,7 @@
|
|||||||
&__form-field {
|
&__form-field {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
max-width: 277px;
|
||||||
|
|
||||||
.currency-display {
|
.currency-display {
|
||||||
color: $tundora;
|
color: $tundora;
|
||||||
@ -586,7 +587,7 @@
|
|||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
width: 88px;
|
width: 95px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
@ -934,6 +935,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #2f9ae0;
|
color: #2f9ae0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sliders-icon-container {
|
.sliders-icon-container {
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
|
|
||||||
import { getSymbolAndDecimals } from '../token-util'
|
import { getSymbolAndDecimals } from '../token-util'
|
||||||
import { conversionUtil } from '../conversion-util'
|
import { conversionUtil } from '../conversion-util'
|
||||||
|
import { addHexPrefix } from 'ethereumjs-util'
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
const createActionType = action => `metamask/confirm-transaction/${action}`
|
const createActionType = action => `metamask/confirm-transaction/${action}`
|
||||||
@ -256,6 +257,8 @@ export function setFetchingData (isFetching) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function updateGasAndCalculate ({ gasLimit, gasPrice }) {
|
export function updateGasAndCalculate ({ gasLimit, gasPrice }) {
|
||||||
|
gasLimit = addHexPrefix(gasLimit)
|
||||||
|
gasPrice = addHexPrefix(gasPrice)
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { confirmTransaction: { txData } } = getState()
|
const { confirmTransaction: { txData } } = getState()
|
||||||
const newTxData = {
|
const newTxData = {
|
||||||
|
@ -120,3 +120,11 @@ export function hexWEIToDecGWEI (decGWEI) {
|
|||||||
toDenomination: 'GWEI',
|
toDenomination: 'GWEI',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertGasPriceForInputs (gasPriceInHexWEI) {
|
||||||
|
return Number(hexWEIToDecGWEI(gasPriceInHexWEI))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertGasLimitForInputs (gasLimitInHexWEI) {
|
||||||
|
return parseInt(gasLimitInHexWEI, 16)
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ const selectors = {
|
|||||||
getCurrentEthBalance,
|
getCurrentEthBalance,
|
||||||
getNetworkIdentifier,
|
getNetworkIdentifier,
|
||||||
isBalanceCached,
|
isBalanceCached,
|
||||||
|
getAdvancedInlineGasShown,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = selectors
|
module.exports = selectors
|
||||||
@ -230,3 +231,7 @@ function getTotalUnapprovedCount ({ metamask }) {
|
|||||||
function preferencesSelector ({ metamask }) {
|
function preferencesSelector ({ metamask }) {
|
||||||
return metamask.preferences
|
return metamask.preferences
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAdvancedInlineGasShown (state) {
|
||||||
|
return Boolean(state.metamask.featureFlags.advancedInlineGas)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user