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
5 changes: 5 additions & 0 deletions packages/transaction-pay-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Use live `txParams.gas` for the original transaction in post-quote batch submissions ([#7933](https://github.com/MetaMask/core/pull/7933))
- Expand single EIP-7702 gas limit for post-quote batch transactions ([#7933](https://github.com/MetaMask/core/pull/7933))

## [15.0.0]

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,25 @@ async function calculateSourceNetworkGasLimitBatch(
return Math.ceil(limit * buffer);
});

const bufferedTotalGasLimit = bufferedGasLimits.reduce(
// When EIP-7702 returns a single combined gas limit for multiple
// transactions, expand gasLimits by prepending the original
// transaction's provided gas limit. This ensures relay-submit takes
// the individual transaction path (enabling beforeSign hooks) while
// using the gas limits determined at quote time.
let finalGasLimits = bufferedGasLimits;
if (bufferedGasLimits.length === 1 && params.length > 1) {
const originalTxGas = paramGasLimits[0];
if (originalTxGas !== undefined) {
finalGasLimits = [originalTxGas, ...bufferedGasLimits];

log('Expanded single EIP-7702 gas limit for batch', {
originalTxGas,
expandedGasLimits: finalGasLimits,
});
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIP-7702 expansion unscoped to post-quote flows

Medium Severity

The gas limit expansion in calculateSourceNetworkGasLimitBatch is not scoped to post-quote flows. For non-post-quote calls with 2+ relay params (e.g., approve + deposit) and an EIP-7702 single combined gas limit, params[0] is the first relay step — not the original transaction — so paramGasLimits[0] is the wrong value. The expansion changes gasLimits from [combinedLimit] to [relay1Gas, combinedLimit], which causes the gasLimit7702 check in relay-submit.ts to evaluate to undefined, inadvertently disabling 7702 batch mode for non-post-quote flows.

Additional Locations (1)

Fix in Cursor Fix in Web


const bufferedTotalGasLimit = finalGasLimits.reduce(
(acc, limit) => acc + limit,
0,
);
Expand All @@ -857,14 +875,14 @@ async function calculateSourceNetworkGasLimitBatch(
totalGasLimit,
gasLimits,
bufferedTotalGasLimit,
bufferedGasLimits,
bufferedGasLimits: finalGasLimits,
gasBuffer,
});

return {
totalGasEstimate: bufferedTotalGasLimit,
totalGasLimit: bufferedTotalGasLimit,
gasLimits: bufferedGasLimits,
gasLimits: finalGasLimits,
};
} catch (error) {
log('Failed to estimate gas limit for batch', error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ describe('Relay Submit Utils', () => {
to: '0xrecipient' as Hex,
data: '0xorigdata' as Hex,
value: '0x100' as Hex,
gas: '0x1D4C0' as Hex,
},
type: TransactionType.simpleSend,
} as TransactionMeta;
Expand Down Expand Up @@ -611,7 +612,7 @@ describe('Relay Submit Utils', () => {
transactions: [
expect.objectContaining({
params: expect.objectContaining({
gas: expect.any(String),
gas: '0x1D4C0',
}),
type: TransactionType.simpleSend,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,20 @@

const transactions = allParams.map((singleParams, index) => {
const gasLimit = gasLimits[index];
const gas =
gasLimit === undefined || gasLimit7702 ? undefined : toHex(gasLimit);

// For post-quote flows, the original transaction (index 0) may be
// transformed by a beforeSign hook (e.g. wrapped in a Safe execTransaction).
// Use the live txParams.gas so beforeSign's gas update is reflected.
const isOriginalTx = isPostQuote && index === 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mismatched conditions cause incorrect gas removal for relay step

Medium Severity

The isOriginalTx flag checks isPostQuote && index === 0, but the original transaction is only prepended to allParams when isPostQuote && transaction.txParams.to is truthy. If isPostQuote is true but transaction.txParams.to is falsy, the original tx isn't prepended, yet isOriginalTx would still be true for index 0 — incorrectly setting gas to undefined on the first relay step instead.

Additional Locations (1)

Fix in Cursor Fix in Web

const originalTxGas = transaction?.txParams?.gas
? (transaction.txParams.gas as Hex)
: undefined;

const gas = isOriginalTx

Check failure on line 339 in packages/transaction-pay-controller/src/strategy/relay/relay-submit.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (22.x)

Do not nest ternary expressions
? originalTxGas
: gasLimit === undefined || gasLimit7702
? undefined
: toHex(gasLimit);

return {
params: {
Expand Down
Loading