Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Estimated time to pending tx #6924

Merged
merged 21 commits into from
Nov 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b2bb3c2
Add estimated time to pending transactions
Jul 27, 2019
ae63cd4
add sytles for pending transactions component
Jul 27, 2019
5b1ff8d
add media queries styling for pending transactions component
Jul 27, 2019
c6569b9
fix lint errors, remove extra spaces
Jul 27, 2019
09ec0ae
refactor code to call `fetchBasicGasAndTimeEstimates` method once
Jul 30, 2019
368f5a4
refactor code to call `getgetRenderableTimeEstimate` method once
Jul 30, 2019
87f11f6
fix, correct export to use `transaction-time-remaining-component`
Aug 6, 2019
b7e148f
fix indentation issues after running `yarn lint`
Krist14n Aug 7, 2019
a62d7ed
newBigSigDig in gas-price-chart.utils supports strings
danjm Oct 11, 2019
3bf32ff
Code cleanup
danjm Oct 22, 2019
4715bcb
Ensure fetchBasicGasAndTimeEstimates is only called from tx-list if t…
danjm Oct 22, 2019
7bd5704
Move gas time estimate utilities into utility file
danjm Oct 22, 2019
b8b9f56
Move getTxParams to transaction selector file
danjm Oct 22, 2019
87d522e
Add feature flag for display of remaining transaction time in tx hist…
danjm Oct 22, 2019
47e5b08
Fix circular dependency by removing unused import of transactionSelec…
danjm Oct 23, 2019
cfab3e7
Use correct feature flag property name transactionTime
danjm Oct 23, 2019
d95bab0
Ensure that tx list component correctly responds to turning tx time f…
danjm Oct 23, 2019
6ab6bd3
Prevent precision errors in newBigSigDig
danjm Oct 23, 2019
b578d80
Code clean up for pending transaction times
danjm Oct 28, 2019
fcd619e
Update transaction-time-remaining feature to count down seconds, coun…
danjm Oct 31, 2019
625412c
Code clean up for transaction-time-remaining feature
danjm Oct 31, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class PreferencesController {
// perform sensitive operations.
featureFlags: {
showIncomingTransactions: true,
transactionTime: false,
},
knownMethodData: {},
participateInMetaMetrics: null,
Expand Down
6 changes: 0 additions & 6 deletions test/unit/ui/app/selectors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,6 @@ describe('Selectors', function () {
assert.equal(currentAccountwithSendEther.name, 'Test Account')
})

describe('#transactionSelector', function () {
it('returns transactions from state', function () {
selectors.transactionsSelector(mockState)
})
})

it('#getGasIsLoading', () => {
const gasIsLoading = selectors.getGasIsLoading(mockState)
assert.equal(gasIsLoading, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import {
preferencesSelector,
} from '../../../../selectors/selectors.js'
import {
formatTimeEstimate,
getFastPriceEstimateInHexWEI,
getBasicGasEstimateLoadingStatus,
getGasEstimatesLoadingStatus,
getCustomGasLimit,
Expand All @@ -47,6 +45,9 @@ import {
getBasicGasEstimateBlockTime,
isCustomPriceSafe,
} from '../../../../selectors/custom-gas'
import {
getTxParams,
} from '../../../../selectors/transactions'
import {
getTokenBalance,
} from '../../../../pages/send/send.selectors'
Expand All @@ -59,6 +60,7 @@ import {
decEthToConvertedCurrency as ethTotalToConvertedCurrency,
hexWEIToDecGWEI,
} from '../../../../helpers/utils/conversions.util'
import { getRenderableTimeEstimate } from '../../../../helpers/utils/gas-time-estimates.util'
import {
formatETHFee,
} from '../../../../helpers/utils/formatters'
Expand All @@ -67,7 +69,6 @@ import {
isBalanceSufficient,
} from '../../../../pages/send/send.utils'
import { addHexPrefix } from 'ethereumjs-util'
import { getAdjacentGasPrices, extrapolateY } from '../gas-price-chart/gas-price-chart.utils'
import { getMaxModeOn } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors'
import { calcMaxAmount } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils'

Expand Down Expand Up @@ -301,18 +302,6 @@ function calcCustomGasLimit (customGasLimitInHex) {
return parseInt(customGasLimitInHex, 16)
}

function getTxParams (state, selectedTransaction = {}) {
const { metamask: { send } } = state
const { txParams } = selectedTransaction
return txParams || {
from: send.from,
gas: send.gasLimit || '0x5208',
gasPrice: send.gasPrice || getFastPriceEstimateInHexWEI(state, true),
to: send.to,
value: getSelectedToken(state) ? '0x0' : send.amount,
}
}

function addHexWEIsToRenderableEth (aHexWEI, bHexWEI) {
return pipe(
addHexWEIsToDec,
Expand All @@ -334,31 +323,3 @@ function addHexWEIsToRenderableFiat (aHexWEI, bHexWEI, convertedCurrency, conver
partialRight(formatCurrency, [convertedCurrency]),
)(aHexWEI, bHexWEI)
}

function getRenderableTimeEstimate (currentGasPrice, gasPrices, estimatedTimes) {
const minGasPrice = gasPrices[0]
const maxGasPrice = gasPrices[gasPrices.length - 1]
let priceForEstimation = currentGasPrice
if (currentGasPrice < minGasPrice) {
priceForEstimation = minGasPrice
} else if (currentGasPrice > maxGasPrice) {
priceForEstimation = maxGasPrice
}

const {
closestLowerValueIndex,
closestHigherValueIndex,
closestHigherValue,
closestLowerValue,
} = getAdjacentGasPrices({ gasPrices, priceToPosition: priceForEstimation })

const newTimeEstimate = extrapolateY({
higherY: estimatedTimes[closestHigherValueIndex],
lowerY: estimatedTimes[closestLowerValueIndex],
higherX: closestHigherValue,
lowerX: closestLowerValue,
xForExtrapolation: priceForEstimation,
})

return formatTimeEstimate(newTimeEstimate, currentGasPrice > maxGasPrice, currentGasPrice < minGasPrice)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as d3 from 'd3'
import c3 from 'c3'
import BigNumber from 'bignumber.js'

const newBigSigDig = n => (new BigNumber(n.toPrecision(15)))
const createOp = (a, b, op) => (newBigSigDig(a))[op](newBigSigDig(b))
const bigNumMinus = (a = 0, b = 0) => createOp(a, b, 'minus')
const bigNumDiv = (a = 0, b = 1) => createOp(a, b, 'div')
import {
extrapolateY,
getAdjacentGasPrices,
newBigSigDig,
bigNumMinus,
bigNumDiv,
} from '../../../../helpers/utils/gas-time-estimates.util'

export function handleMouseMove ({ xMousePos, chartXStart, chartWidth, gasPrices, estimatedTimes, chart }) {
const { currentPosValue, newTimeEstimate } = getNewXandTimeEstimate({
Expand Down Expand Up @@ -66,25 +67,6 @@ export function handleChartUpdate ({ chart, gasPrices, newPrice, cssId }) {
}
}

export function getAdjacentGasPrices ({ gasPrices, priceToPosition }) {
const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => e <= priceToPosition && a[i + 1] >= priceToPosition)
const closestHigherValueIndex = gasPrices.findIndex((e) => e > priceToPosition)
return {
closestLowerValueIndex,
closestHigherValueIndex,
closestHigherValue: gasPrices[closestHigherValueIndex],
closestLowerValue: gasPrices[closestLowerValueIndex],
}
}

export function extrapolateY ({ higherY = 0, lowerY = 0, higherX = 0, lowerX = 0, xForExtrapolation = 0 }) {
const slope = bigNumMinus(higherY, lowerY).div(bigNumMinus(higherX, lowerX))
const newTimeEstimate = slope.times(bigNumMinus(higherX, xForExtrapolation)).minus(newBigSigDig(higherY)).negated()

return newTimeEstimate.toNumber()
}


export function getNewXandTimeEstimate ({ xMousePos, chartXStart, chartWidth, gasPrices, estimatedTimes }) {
const chartMouseXPos = bigNumMinus(xMousePos, chartXStart)
const posPercentile = bigNumDiv(chartMouseXPos, chartWidth)
Expand Down
22 changes: 17 additions & 5 deletions ui/app/components/app/transaction-list-item/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
display: grid;
grid-template-columns: 45px 1fr 1fr 1fr;
grid-template-areas:
"identicon action status primary-amount"
"identicon nonce status secondary-amount";
"identicon action status estimated-time primary-amount"
"identicon nonce status estimated-time secondary-amount";
grid-template-rows: 24px;

@media screen and (max-width: $break-small) {
padding: .5rem 1rem;
grid-template-columns: 45px 5fr 3fr;
grid-template-areas:
"nonce nonce nonce"
"identicon action primary-amount"
"identicon status secondary-amount";
"nonce nonce nonce nonce"
"identicon action estimated-time primary-amount"
"identicon status estimated-time secondary-amount";
grid-template-rows: auto 24px;
}

Expand Down Expand Up @@ -65,6 +65,18 @@
}
}

&__estimated-time {
grid-area: estimated-time;
grid-row: 1 / span 2;
align-self: center;

@media screen and (max-width: $break-small) {
grid-row: 3;
grid-column: 4;
font-size: small;
}
}

&__nonce {
font-size: .75rem;
color: #5e6064;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import TransactionAction from '../transaction-action'
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
import TokenCurrencyDisplay from '../../ui/token-currency-display'
import TransactionListItemDetails from '../transaction-list-item-details'
import TransactionTimeRemaining from '../transaction-time-remaining'
import { CONFIRM_TRANSACTION_ROUTE } from '../../../helpers/constants/routes'
import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../../helpers/constants/transactions'
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'
Expand Down Expand Up @@ -38,6 +39,8 @@ export default class TransactionListItem extends PureComponent {
data: PropTypes.string,
getContractMethodData: PropTypes.func,
isDeposit: PropTypes.bool,
transactionTimeFeatureActive: PropTypes.bool,
firstPendingTransactionId: PropTypes.number,
}

static defaultProps = {
Expand All @@ -52,6 +55,13 @@ export default class TransactionListItem extends PureComponent {
showTransactionDetails: false,
}

componentDidMount () {
if (this.props.data) {
this.props.getContractMethodData(this.props.data)
}

}

handleClick = () => {
const {
transaction,
Expand Down Expand Up @@ -162,12 +172,6 @@ export default class TransactionListItem extends PureComponent {
)
}

componentDidMount () {
if (this.props.data) {
this.props.getContractMethodData(this.props.data)
}
}

render () {
const {
assetImages,
Expand All @@ -182,6 +186,8 @@ export default class TransactionListItem extends PureComponent {
transactionGroup,
rpcPrefs,
isEarliestNonce,
firstPendingTransactionId,
transactionTimeFeatureActive,
} = this.props
const { txParams = {} } = transaction
const { showTransactionDetails } = this.state
Expand Down Expand Up @@ -221,6 +227,13 @@ export default class TransactionListItem extends PureComponent {
: primaryTransaction.err && primaryTransaction.err.message
)}
/>
{ transactionTimeFeatureActive && (transaction.id === firstPendingTransactionId)
? <TransactionTimeRemaining
className="transaction-list-item__estimated-time"
transaction={ primaryTransaction }
/>
: null
}
{ this.renderPrimaryCurrency() }
{ this.renderSecondaryCurrency() }
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ import { getTokenData } from '../../../helpers/utils/transactions.util'
import { getHexGasTotal, increaseLastGasPrice } from '../../../helpers/utils/confirm-tx.util'
import { formatDate } from '../../../helpers/utils/util'
import {
fetchBasicGasAndTimeEstimates,
fetchGasEstimates,
fetchBasicGasAndTimeEstimates,
setCustomGasPriceForRetry,
setCustomGasLimit,
} from '../../../ducks/gas/gas.duck'
import { getIsMainnet, preferencesSelector, getSelectedAddress, conversionRateSelector, getKnownMethodData } from '../../../selectors/selectors'
import {
getIsMainnet,
preferencesSelector,
getSelectedAddress,
conversionRateSelector,
getKnownMethodData,
getFeatureFlags,
} from '../../../selectors/selectors'
import { isBalanceSufficient } from '../../../pages/send/send.utils'

const mapStateToProps = (state, ownProps) => {
Expand All @@ -38,13 +45,16 @@ const mapStateToProps = (state, ownProps) => {
conversionRate: conversionRateSelector(state),
})

const transactionTimeFeatureActive = getFeatureFlags(state).transactionTime

return {
methodData: getKnownMethodData(state, data) || {},
showFiat: (isMainnet || !!showFiatInTestnets),
selectedAccountBalance,
hasEnoughCancelGas,
rpcPrefs,
isDeposit,
transactionTimeFeatureActive,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,50 @@ export default class TransactionList extends PureComponent {
selectedToken: PropTypes.object,
updateNetworkNonce: PropTypes.func,
assetImages: PropTypes.object,
fetchBasicGasAndTimeEstimates: PropTypes.func,
fetchGasEstimates: PropTypes.func,
transactionTimeFeatureActive: PropTypes.bool,
firstPendingTransactionId: PropTypes.number,
}

componentDidMount () {
this.props.updateNetworkNonce()
const {
pendingTransactions,
updateNetworkNonce,
fetchBasicGasAndTimeEstimates,
fetchGasEstimates,
transactionTimeFeatureActive,
} = this.props

updateNetworkNonce()

if (transactionTimeFeatureActive && pendingTransactions.length) {
fetchBasicGasAndTimeEstimates()
.then(({ blockTime }) => fetchGasEstimates(blockTime))
}
}

componentDidUpdate (prevProps) {
const { pendingTransactions: prevPendingTransactions = [] } = prevProps
const { pendingTransactions = [], updateNetworkNonce } = this.props
const {
pendingTransactions = [],
updateNetworkNonce,
fetchBasicGasAndTimeEstimates,
fetchGasEstimates,
transactionTimeFeatureActive,
} = this.props

if (pendingTransactions.length > prevPendingTransactions.length) {
updateNetworkNonce()
}

const transactionTimeFeatureWasActivated = !prevProps.transactionTimeFeatureActive && transactionTimeFeatureActive
const pendingTransactionAdded = pendingTransactions.length > 0 && prevPendingTransactions.length === 0

if (transactionTimeFeatureActive && pendingTransactions.length > 0 && (transactionTimeFeatureWasActivated || pendingTransactionAdded)) {
fetchBasicGasAndTimeEstimates()
.then(({ blockTime }) => fetchGasEstimates(blockTime))
}
}

shouldShowSpeedUp = (transactionGroup, isEarliestNonce) => {
Expand Down Expand Up @@ -87,7 +118,7 @@ export default class TransactionList extends PureComponent {
}

renderTransaction (transactionGroup, index, isPendingTx = false) {
const { selectedToken, assetImages } = this.props
const { selectedToken, assetImages, firstPendingTransactionId } = this.props
const { transactions = [] } = transactionGroup

return transactions[0].key === TRANSACTION_TYPE_SHAPESHIFT
Expand All @@ -105,6 +136,7 @@ export default class TransactionList extends PureComponent {
isEarliestNonce={isPendingTx && index === 0}
token={selectedToken}
assetImages={assetImages}
firstPendingTransactionId={firstPendingTransactionId}
/>
)
}
Expand Down
Loading