Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 packages/transaction-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Bump `@metamask/remote-feature-flag-controller` from `^4.0.0` to `^4.1.0` ([#8041](https://github.com/MetaMask/core/pull/8041))
- Allow `updateTransactionGasFees` to be called for transactions with status submitted in addition to unapproved ([#8042](https://github.com/MetaMask/core/pull/8042))

## [62.19.0]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5093,7 +5093,7 @@ describe('TransactionController', () => {
).toThrow('Cannot update transaction as no transaction metadata found');
});

it('throws if transaction not unapproved status', async () => {
it('throws if transaction not unapproved or submitted status', async () => {
const transactionId = '123';
const fnName = 'updateTransactionGasFees';
const status = TransactionStatus.failed;
Expand All @@ -5118,9 +5118,45 @@ describe('TransactionController', () => {
controller.updateTransactionGasFees(transactionId, {
gasPrice: '0x1',
}),
)
.toThrow(`TransactionsController: Can only call ${fnName} on an unapproved transaction.
Current tx status: ${status}`);
).toThrow(
`TransactionsController: Can only call ${fnName} on an unapproved or submitted transaction.\n Current tx status: ${status}`,
);
});

it('allows update when transaction status is submitted', async () => {
const transactionId = '123';
const { controller } = setupController({
options: {
state: {
transactions: [
{
id: transactionId,
chainId: '0x1',
networkClientId: NETWORK_CLIENT_ID_MOCK,
time: 123456789,
status: TransactionStatus.submitted as const,
txParams: {
from: ACCOUNT_MOCK,
to: ACCOUNT_2_MOCK,
},
},
],
},
},
updateToInitialState: true,
});

const gasPrice = '0x12';
expect(() =>
controller.updateTransactionGasFees(transactionId, {
gasPrice,
}),
).not.toThrow();

const transaction = controller.state.transactions.find(
({ id }) => id === transactionId,
);
expect(transaction?.txParams?.gasPrice).toBe(gasPrice);
});

it('updates provided legacy gas values', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ import {
isEIP1559Transaction,
validateGasValues,
validateIfTransactionUnapproved,
validateIfTransactionUnapprovedOrSubmitted,
normalizeTxError,
normalizeGasFeeValues,
setEnvelopeType,
Expand Down Expand Up @@ -2076,7 +2077,7 @@ export class TransactionController extends BaseController<
);
}

validateIfTransactionUnapproved(
validateIfTransactionUnapprovedOrSubmitted(
transactionMeta,
'updateTransactionGasFees',
);
Expand Down
49 changes: 49 additions & 0 deletions packages/transaction-controller/src/utils/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
GasPriceValue,
TransactionParams,
} from '../types';
import { TransactionStatus } from '../types';

const MAX_FEE_PER_GAS = 'maxFeePerGas';
const MAX_PRIORITY_FEE_PER_GAS = 'maxPriorityFeePerGas';
Expand Down Expand Up @@ -378,4 +379,52 @@ describe('utils', () => {
expect(util.caip2ToHex('not:valid:format')).toBeUndefined();
});
});

describe('validateIfTransactionUnapprovedOrSubmitted', () => {
const fnName = 'testFn';

it('does not throw when transaction status is unapproved', () => {
expect(() =>
util.validateIfTransactionUnapprovedOrSubmitted(
{ status: TransactionStatus.unapproved },
fnName,
),
).not.toThrow();
});

it('does not throw when transaction status is submitted', () => {
expect(() =>
util.validateIfTransactionUnapprovedOrSubmitted(
{ status: TransactionStatus.submitted },
fnName,
),
).not.toThrow();
});

it('throws when transactionMeta is undefined', () => {
expect(() =>
util.validateIfTransactionUnapprovedOrSubmitted(undefined, fnName),
).toThrow(
`TransactionsController: Can only call ${fnName} on an unapproved or submitted transaction.\n Current tx status: undefined`,
);
});

it('throws when transaction status is not unapproved or submitted', () => {
const status = TransactionStatus.failed;
expect(() =>
util.validateIfTransactionUnapprovedOrSubmitted({ status }, fnName),
).toThrow(
`TransactionsController: Can only call ${fnName} on an unapproved or submitted transaction.\n Current tx status: ${status}`,
);
});

it('throws when transaction status is confirmed', () => {
const status = TransactionStatus.confirmed;
expect(() =>
util.validateIfTransactionUnapprovedOrSubmitted({ status }, fnName),
).toThrow(
`TransactionsController: Can only call ${fnName} on an unapproved or submitted transaction.\n Current tx status: ${status}`,
);
});
});
});
22 changes: 22 additions & 0 deletions packages/transaction-controller/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,28 @@ export function validateIfTransactionUnapproved(
}
}

/**
* Validates that a transaction is unapproved or submitted.
* Throws if the transaction is not unapproved or submitted.
*
* @param transactionMeta - The transaction metadata to check.
* @param fnName - The name of the function calling this helper.
*/
export function validateIfTransactionUnapprovedOrSubmitted(
transactionMeta: TransactionMeta | undefined,
fnName: string,
): void {
const allowedStatuses = [
TransactionStatus.unapproved,
TransactionStatus.submitted,
];
if (!transactionMeta || !allowedStatuses.includes(transactionMeta.status)) {
throw new Error(
`TransactionsController: Can only call ${fnName} on an unapproved or submitted transaction.\n Current tx status: ${transactionMeta?.status}`,
);
}
}

/**
* Normalizes properties on transaction params.
*
Expand Down
Loading