fix issues relating to race conditions where draftTx does not exist (#15420)

* fix issues relating to race conditions where draftTx does not exist

* add another fail safe for inflight initializations
feature/default_network_editable
Brad Decker 2 years ago committed by GitHub
parent fb191c865b
commit f425e482e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 96
      ui/ducks/send/send.js

@ -603,7 +603,7 @@ export const initializeSendState = createAsyncThunk(
// For instance, in the actions.js file we dispatch this action anytime the // For instance, in the actions.js file we dispatch this action anytime the
// chain changes. // chain changes.
if (!draftTransaction) { if (!draftTransaction) {
thunkApi.rejectWithValue( return thunkApi.rejectWithValue(
'draftTransaction not found, possibly not on send flow', 'draftTransaction not found, possibly not on send flow',
); );
} }
@ -678,6 +678,20 @@ export const initializeSendState = createAsyncThunk(
// We have to keep the gas slice in sync with the send slice state // We have to keep the gas slice in sync with the send slice state
// so that it'll be initialized correctly if the gas modal is opened. // so that it'll be initialized correctly if the gas modal is opened.
await thunkApi.dispatch(setCustomGasLimit(gasLimit)); await thunkApi.dispatch(setCustomGasLimit(gasLimit));
// There may be a case where the send has been canceled by the user while
// the gas estimate is being computed. So we check again to make sure that
// a currentTransactionUUID exists and matches the previous tx.
const newState = thunkApi.getState();
if (
newState.send.currentTransactionUUID !== sendState.currentTransactionUUID
) {
return thunkApi.rejectWithValue(
`draftTransaction changed during initialization.
A new initializeSendState action must be dispatched.`,
);
}
return { return {
account, account,
chainId: getCurrentChainId(state), chainId: getCurrentChainId(state),
@ -1396,28 +1410,30 @@ const slice = createSlice({
validateSendState: (state) => { validateSendState: (state) => {
const draftTransaction = const draftTransaction =
state.draftTransactions[state.currentTransactionUUID]; state.draftTransactions[state.currentTransactionUUID];
switch (true) { if (draftTransaction) {
case Boolean(draftTransaction.amount.error): switch (true) {
case Boolean(draftTransaction.gas.error): case Boolean(draftTransaction.amount.error):
case Boolean(draftTransaction.asset.error): case Boolean(draftTransaction.gas.error):
case draftTransaction.asset.type === ASSET_TYPES.TOKEN && case Boolean(draftTransaction.asset.error):
draftTransaction.asset.details === null: case draftTransaction.asset.type === ASSET_TYPES.TOKEN &&
case state.stage === SEND_STAGES.ADD_RECIPIENT: draftTransaction.asset.details === null:
case state.stage === SEND_STAGES.INACTIVE: case state.stage === SEND_STAGES.ADD_RECIPIENT:
case state.gasEstimateIsLoading: case state.stage === SEND_STAGES.INACTIVE:
case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan( case state.gasEstimateIsLoading:
new BigNumber(state.gasLimitMinimum), case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan(
): new BigNumber(state.gasLimitMinimum),
draftTransaction.status = SEND_STATUSES.INVALID; ):
break; draftTransaction.status = SEND_STATUSES.INVALID;
case draftTransaction.recipient.warning === 'loading': break;
case draftTransaction.recipient.warning === case draftTransaction.recipient.warning === 'loading':
KNOWN_RECIPIENT_ADDRESS_WARNING && case draftTransaction.recipient.warning ===
draftTransaction.recipient.recipientWarningAcknowledged === false: KNOWN_RECIPIENT_ADDRESS_WARNING &&
draftTransaction.status = SEND_STATUSES.INVALID; draftTransaction.recipient.recipientWarningAcknowledged === false:
break; draftTransaction.status = SEND_STATUSES.INVALID;
default: break;
draftTransaction.status = SEND_STATUSES.VALID; default:
draftTransaction.status = SEND_STATUSES.VALID;
}
} }
}, },
}, },
@ -1512,26 +1528,28 @@ const slice = createSlice({
state.selectedAccount.balance = action.payload.account.balance; state.selectedAccount.balance = action.payload.account.balance;
const draftTransaction = const draftTransaction =
state.draftTransactions[state.currentTransactionUUID]; state.draftTransactions[state.currentTransactionUUID];
draftTransaction.gas.gasLimit = action.payload.gasLimit; if (draftTransaction) {
draftTransaction.gas.gasLimit = action.payload.gasLimit;
draftTransaction.gas.gasTotal = action.payload.gasTotal;
if (action.payload.chainHasChanged) {
// If the state was reinitialized as a result of the user changing
// the network from the network dropdown, then the selected asset is
// no longer valid and should be set to the native asset for the
// network.
draftTransaction.asset.type = ASSET_TYPES.NATIVE;
draftTransaction.asset.balance =
draftTransaction.fromAccount?.balance ??
state.selectedAccount.balance;
draftTransaction.asset.details = null;
}
}
slice.caseReducers.updateGasFeeEstimates(state, { slice.caseReducers.updateGasFeeEstimates(state, {
payload: { payload: {
gasFeeEstimates: action.payload.gasFeeEstimates, gasFeeEstimates: action.payload.gasFeeEstimates,
gasEstimateType: action.payload.gasEstimateType, gasEstimateType: action.payload.gasEstimateType,
}, },
}); });
draftTransaction.gas.gasTotal = action.payload.gasTotal;
state.gasEstimatePollToken = action.payload.gasEstimatePollToken; state.gasEstimatePollToken = action.payload.gasEstimatePollToken;
if (action.payload.chainHasChanged) {
// If the state was reinitialized as a result of the user changing
// the network from the network dropdown, then the selected asset is
// no longer valid and should be set to the native asset for the
// network.
draftTransaction.asset.type = ASSET_TYPES.NATIVE;
draftTransaction.asset.balance =
draftTransaction.fromAccount?.balance ??
state.selectedAccount.balance;
draftTransaction.asset.details = null;
}
if (action.payload.gasEstimatePollToken) { if (action.payload.gasEstimatePollToken) {
state.gasEstimateIsLoading = false; state.gasEstimateIsLoading = false;
} }
@ -2641,7 +2659,11 @@ export function isSendStateInitialized(state) {
* @type {Selector<boolean>} * @type {Selector<boolean>}
*/ */
export function isSendFormInvalid(state) { export function isSendFormInvalid(state) {
return getCurrentDraftTransaction(state).status === SEND_STATUSES.INVALID; const draftTransaction = getCurrentDraftTransaction(state);
if (!draftTransaction) {
return true;
}
return draftTransaction.status === SEND_STATUSES.INVALID;
} }
/** /**

Loading…
Cancel
Save