mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add "Retry" option for failed transactions (#7296)
* Begin mocking out retry ui * Remove "Failed" * I guess this works? * Update corresponding test * wip * Ok, this appears to be working now * cleanup * Move this back to 3 * I don't think I need this * Rename showRetry to showSpeedUp * Address PR feedback * Remove notes * Rename shouldShowRetry -> shouldShowSpeedUp * oops
This commit is contained in:
parent
c8878f46d4
commit
af888d0ab2
@ -1442,6 +1442,9 @@
|
|||||||
"viewOnEtherscan": {
|
"viewOnEtherscan": {
|
||||||
"message": "View on Etherscan"
|
"message": "View on Etherscan"
|
||||||
},
|
},
|
||||||
|
"retryTransaction": {
|
||||||
|
"message": "Retry Transaction"
|
||||||
|
},
|
||||||
"visitWebSite": {
|
"visitWebSite": {
|
||||||
"message": "Visit our web site"
|
"message": "Visit our web site"
|
||||||
},
|
},
|
||||||
|
@ -42,6 +42,7 @@ export default class GasModalPageContainer extends Component {
|
|||||||
]),
|
]),
|
||||||
customPriceIsSafe: PropTypes.bool,
|
customPriceIsSafe: PropTypes.bool,
|
||||||
isSpeedUp: PropTypes.bool,
|
isSpeedUp: PropTypes.bool,
|
||||||
|
isRetry: PropTypes.bool,
|
||||||
disableSave: PropTypes.bool,
|
disableSave: PropTypes.bool,
|
||||||
isEthereumNetwork: PropTypes.bool,
|
isEthereumNetwork: PropTypes.bool,
|
||||||
}
|
}
|
||||||
@ -80,6 +81,7 @@ export default class GasModalPageContainer extends Component {
|
|||||||
gasEstimatesLoading,
|
gasEstimatesLoading,
|
||||||
customPriceIsSafe,
|
customPriceIsSafe,
|
||||||
isSpeedUp,
|
isSpeedUp,
|
||||||
|
isRetry,
|
||||||
infoRowProps: {
|
infoRowProps: {
|
||||||
transactionFee,
|
transactionFee,
|
||||||
},
|
},
|
||||||
@ -99,6 +101,7 @@ export default class GasModalPageContainer extends Component {
|
|||||||
gasEstimatesLoading={gasEstimatesLoading}
|
gasEstimatesLoading={gasEstimatesLoading}
|
||||||
customPriceIsSafe={customPriceIsSafe}
|
customPriceIsSafe={customPriceIsSafe}
|
||||||
isSpeedUp={isSpeedUp}
|
isSpeedUp={isSpeedUp}
|
||||||
|
isRetry={isRetry}
|
||||||
isEthereumNetwork={isEthereumNetwork}
|
isEthereumNetwork={isEthereumNetwork}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
setGasLimit,
|
setGasLimit,
|
||||||
setGasPrice,
|
setGasPrice,
|
||||||
createSpeedUpTransaction,
|
createSpeedUpTransaction,
|
||||||
|
createRetryTransaction,
|
||||||
hideSidebar,
|
hideSidebar,
|
||||||
updateSendAmount,
|
updateSendAmount,
|
||||||
setGasTotal,
|
setGasTotal,
|
||||||
@ -153,6 +154,7 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
},
|
},
|
||||||
transaction: txData || transaction,
|
transaction: txData || transaction,
|
||||||
isSpeedUp: transaction.status === 'submitted',
|
isSpeedUp: transaction.status === 'submitted',
|
||||||
|
isRetry: transaction.status === 'failed',
|
||||||
txId: transaction.id,
|
txId: transaction.id,
|
||||||
insufficientBalance,
|
insufficientBalance,
|
||||||
gasEstimatesLoading,
|
gasEstimatesLoading,
|
||||||
@ -187,6 +189,9 @@ const mapDispatchToProps = dispatch => {
|
|||||||
createSpeedUpTransaction: (txId, gasPrice) => {
|
createSpeedUpTransaction: (txId, gasPrice) => {
|
||||||
return dispatch(createSpeedUpTransaction(txId, gasPrice))
|
return dispatch(createSpeedUpTransaction(txId, gasPrice))
|
||||||
},
|
},
|
||||||
|
createRetryTransaction: (txId, gasPrice) => {
|
||||||
|
return dispatch(createRetryTransaction(txId, gasPrice))
|
||||||
|
},
|
||||||
hideGasButtonGroup: () => dispatch(hideGasButtonGroup()),
|
hideGasButtonGroup: () => dispatch(hideGasButtonGroup()),
|
||||||
setCustomTimeEstimate: (timeEstimateInSeconds) => dispatch(setCustomTimeEstimate(timeEstimateInSeconds)),
|
setCustomTimeEstimate: (timeEstimateInSeconds) => dispatch(setCustomTimeEstimate(timeEstimateInSeconds)),
|
||||||
hideSidebar: () => dispatch(hideSidebar()),
|
hideSidebar: () => dispatch(hideSidebar()),
|
||||||
@ -206,6 +211,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||||||
isConfirm,
|
isConfirm,
|
||||||
txId,
|
txId,
|
||||||
isSpeedUp,
|
isSpeedUp,
|
||||||
|
isRetry,
|
||||||
insufficientBalance,
|
insufficientBalance,
|
||||||
maxModeOn,
|
maxModeOn,
|
||||||
customGasPrice,
|
customGasPrice,
|
||||||
@ -221,6 +227,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||||||
setGasData: dispatchSetGasData,
|
setGasData: dispatchSetGasData,
|
||||||
updateConfirmTxGasAndCalculate: dispatchUpdateConfirmTxGasAndCalculate,
|
updateConfirmTxGasAndCalculate: dispatchUpdateConfirmTxGasAndCalculate,
|
||||||
createSpeedUpTransaction: dispatchCreateSpeedUpTransaction,
|
createSpeedUpTransaction: dispatchCreateSpeedUpTransaction,
|
||||||
|
createRetryTransaction: dispatchCreateRetryTransaction,
|
||||||
hideSidebar: dispatchHideSidebar,
|
hideSidebar: dispatchHideSidebar,
|
||||||
cancelAndClose: dispatchCancelAndClose,
|
cancelAndClose: dispatchCancelAndClose,
|
||||||
hideModal: dispatchHideModal,
|
hideModal: dispatchHideModal,
|
||||||
@ -248,6 +255,10 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||||||
dispatchCreateSpeedUpTransaction(txId, gasPrice)
|
dispatchCreateSpeedUpTransaction(txId, gasPrice)
|
||||||
dispatchHideSidebar()
|
dispatchHideSidebar()
|
||||||
dispatchCancelAndClose()
|
dispatchCancelAndClose()
|
||||||
|
} else if (isRetry) {
|
||||||
|
dispatchCreateRetryTransaction(txId, gasPrice)
|
||||||
|
dispatchHideSidebar()
|
||||||
|
dispatchCancelAndClose()
|
||||||
} else {
|
} else {
|
||||||
dispatchSetGasData(gasLimit, gasPrice)
|
dispatchSetGasData(gasLimit, gasPrice)
|
||||||
dispatchHideGasButtonGroup()
|
dispatchHideGasButtonGroup()
|
||||||
@ -268,7 +279,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||||||
},
|
},
|
||||||
cancelAndClose: () => {
|
cancelAndClose: () => {
|
||||||
dispatchCancelAndClose()
|
dispatchCancelAndClose()
|
||||||
if (isSpeedUp) {
|
if (isSpeedUp || isRetry) {
|
||||||
dispatchHideSidebar()
|
dispatchHideSidebar()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -157,6 +157,7 @@ describe('gas-modal-page-container container', () => {
|
|||||||
},
|
},
|
||||||
insufficientBalance: true,
|
insufficientBalance: true,
|
||||||
isSpeedUp: false,
|
isSpeedUp: false,
|
||||||
|
isRetry: false,
|
||||||
txId: 34,
|
txId: 34,
|
||||||
isEthereumNetwork: true,
|
isEthereumNetwork: true,
|
||||||
isMainnet: true,
|
isMainnet: true,
|
||||||
|
@ -70,7 +70,7 @@ describe('TransactionListItemDetails Component', () => {
|
|||||||
const wrapper = shallow(
|
const wrapper = shallow(
|
||||||
<TransactionListItemDetails
|
<TransactionListItemDetails
|
||||||
transactionGroup={transactionGroup}
|
transactionGroup={transactionGroup}
|
||||||
showRetry={true}
|
showSpeedUp={true}
|
||||||
/>,
|
/>,
|
||||||
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
|
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,7 @@ export default class TransactionListItemDetails extends PureComponent {
|
|||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
onRetry: PropTypes.func,
|
onRetry: PropTypes.func,
|
||||||
showCancel: PropTypes.bool,
|
showCancel: PropTypes.bool,
|
||||||
|
showSpeedUp: PropTypes.bool,
|
||||||
showRetry: PropTypes.bool,
|
showRetry: PropTypes.bool,
|
||||||
isEarliestNonce: PropTypes.bool,
|
isEarliestNonce: PropTypes.bool,
|
||||||
cancelDisabled: PropTypes.bool,
|
cancelDisabled: PropTypes.bool,
|
||||||
@ -123,6 +124,7 @@ export default class TransactionListItemDetails extends PureComponent {
|
|||||||
const { justCopied } = this.state
|
const { justCopied } = this.state
|
||||||
const {
|
const {
|
||||||
transactionGroup,
|
transactionGroup,
|
||||||
|
showSpeedUp,
|
||||||
showRetry,
|
showRetry,
|
||||||
onCancel,
|
onCancel,
|
||||||
onRetry,
|
onRetry,
|
||||||
@ -138,7 +140,7 @@ export default class TransactionListItemDetails extends PureComponent {
|
|||||||
<div>{ t('details') }</div>
|
<div>{ t('details') }</div>
|
||||||
<div className="transaction-list-item-details__header-buttons">
|
<div className="transaction-list-item-details__header-buttons">
|
||||||
{
|
{
|
||||||
showRetry && (
|
showSpeedUp && (
|
||||||
<Button
|
<Button
|
||||||
type="raised"
|
type="raised"
|
||||||
onClick={this.handleRetry}
|
onClick={this.handleRetry}
|
||||||
@ -172,6 +174,17 @@ export default class TransactionListItemDetails extends PureComponent {
|
|||||||
<img src="/images/arrow-popout.svg" />
|
<img src="/images/arrow-popout.svg" />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{
|
||||||
|
showRetry && <Tooltip title={blockExplorerUrl ? t('viewOnCustomBlockExplorer', [blockExplorerUrl]) : t('retryTransaction')}>
|
||||||
|
<Button
|
||||||
|
type="raised"
|
||||||
|
onClick={this.handleRetry}
|
||||||
|
className="transaction-list-item-details__header-button"
|
||||||
|
>
|
||||||
|
<i className="fa fa-refresh"></i>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="transaction-list-item-details__body">
|
<div className="transaction-list-item-details__body">
|
||||||
|
@ -24,7 +24,7 @@ export default class TransactionListItem extends PureComponent {
|
|||||||
showCancelModal: PropTypes.func,
|
showCancelModal: PropTypes.func,
|
||||||
showCancel: PropTypes.bool,
|
showCancel: PropTypes.bool,
|
||||||
hasEnoughCancelGas: PropTypes.bool,
|
hasEnoughCancelGas: PropTypes.bool,
|
||||||
showRetry: PropTypes.bool,
|
showSpeedUp: PropTypes.bool,
|
||||||
isEarliestNonce: PropTypes.bool,
|
isEarliestNonce: PropTypes.bool,
|
||||||
showFiat: PropTypes.bool,
|
showFiat: PropTypes.bool,
|
||||||
token: PropTypes.object,
|
token: PropTypes.object,
|
||||||
@ -177,7 +177,7 @@ export default class TransactionListItem extends PureComponent {
|
|||||||
primaryTransaction,
|
primaryTransaction,
|
||||||
showCancel,
|
showCancel,
|
||||||
hasEnoughCancelGas,
|
hasEnoughCancelGas,
|
||||||
showRetry,
|
showSpeedUp,
|
||||||
tokenData,
|
tokenData,
|
||||||
transactionGroup,
|
transactionGroup,
|
||||||
rpcPrefs,
|
rpcPrefs,
|
||||||
@ -233,7 +233,8 @@ export default class TransactionListItem extends PureComponent {
|
|||||||
<TransactionListItemDetails
|
<TransactionListItemDetails
|
||||||
transactionGroup={transactionGroup}
|
transactionGroup={transactionGroup}
|
||||||
onRetry={this.handleRetry}
|
onRetry={this.handleRetry}
|
||||||
showRetry={showRetry}
|
showSpeedUp={showSpeedUp}
|
||||||
|
showRetry={getStatusKey(primaryTransaction) === 'failed'}
|
||||||
isEarliestNonce={isEarliestNonce}
|
isEarliestNonce={isEarliestNonce}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
showCancel={showCancel}
|
showCancel={showCancel}
|
||||||
|
@ -37,7 +37,7 @@ export default class TransactionList extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowRetry = (transactionGroup, isEarliestNonce) => {
|
shouldShowSpeedUp = (transactionGroup, isEarliestNonce) => {
|
||||||
const { transactions = [], hasRetried } = transactionGroup
|
const { transactions = [], hasRetried } = transactionGroup
|
||||||
const [earliestTransaction = {}] = transactions
|
const [earliestTransaction = {}] = transactions
|
||||||
const { submittedTime } = earliestTransaction
|
const { submittedTime } = earliestTransaction
|
||||||
@ -100,7 +100,7 @@ export default class TransactionList extends PureComponent {
|
|||||||
<TransactionListItem
|
<TransactionListItem
|
||||||
transactionGroup={transactionGroup}
|
transactionGroup={transactionGroup}
|
||||||
key={`${transactionGroup.nonce}:${index}`}
|
key={`${transactionGroup.nonce}:${index}`}
|
||||||
showRetry={isPendingTx && this.shouldShowRetry(transactionGroup, index === 0)}
|
showSpeedUp={isPendingTx && this.shouldShowSpeedUp(transactionGroup, index === 0)}
|
||||||
showCancel={isPendingTx && this.shouldShowCancel(transactionGroup)}
|
showCancel={isPendingTx && this.shouldShowCancel(transactionGroup)}
|
||||||
isEarliestNonce={isPendingTx && index === 0}
|
isEarliestNonce={isPendingTx && index === 0}
|
||||||
token={selectedToken}
|
token={selectedToken}
|
||||||
|
@ -206,6 +206,10 @@ class Routes extends Component {
|
|||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
const sidebarShouldClose = sidebarTransaction &&
|
||||||
|
!sidebarTransaction.status === 'failed' &&
|
||||||
|
!submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('app', { 'mouse-user-styles': isMouseUser})}
|
className={classnames('app', { 'mouse-user-styles': isMouseUser})}
|
||||||
@ -232,7 +236,7 @@ class Routes extends Component {
|
|||||||
}
|
}
|
||||||
<Sidebar
|
<Sidebar
|
||||||
sidebarOpen={sidebarIsOpen}
|
sidebarOpen={sidebarIsOpen}
|
||||||
sidebarShouldClose={sidebarTransaction && !submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)}
|
sidebarShouldClose={sidebarShouldClose}
|
||||||
hideSidebar={this.props.hideSidebar}
|
hideSidebar={this.props.hideSidebar}
|
||||||
transitionName={sidebarTransitionName}
|
transitionName={sidebarTransitionName}
|
||||||
type={sidebarType}
|
type={sidebarType}
|
||||||
|
@ -350,6 +350,7 @@ var actions = {
|
|||||||
|
|
||||||
createCancelTransaction,
|
createCancelTransaction,
|
||||||
createSpeedUpTransaction,
|
createSpeedUpTransaction,
|
||||||
|
createRetryTransaction,
|
||||||
|
|
||||||
approveProviderRequestByOrigin,
|
approveProviderRequestByOrigin,
|
||||||
rejectProviderRequestByOrigin,
|
rejectProviderRequestByOrigin,
|
||||||
@ -1860,6 +1861,28 @@ function createSpeedUpTransaction (txId, customGasPrice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRetryTransaction (txId, customGasPrice) {
|
||||||
|
log.debug('background.createRetryTransaction')
|
||||||
|
let newTx
|
||||||
|
|
||||||
|
return dispatch => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
background.createSpeedUpTransaction(txId, customGasPrice, (err, newState) => {
|
||||||
|
if (err) {
|
||||||
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { selectedAddressTxList } = newState
|
||||||
|
newTx = selectedAddressTxList[selectedAddressTxList.length - 1]
|
||||||
|
resolve(newState)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
||||||
|
.then(() => newTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// config
|
// config
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user