Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
65cffa9
feat: add getAmountData callback to TransactionPayController
OGPoyraz Jun 3, 2026
95d33b4
fix: fiat moneyAccountDeposit three-phase relay submit
OGPoyraz Jun 3, 2026
5a91c7d
fix: lint errors and update tests for fiat submit changes
OGPoyraz Jun 3, 2026
a511f02
Fix lint
OGPoyraz Jun 3, 2026
3692675
docs: update transaction-pay-controller changelog
OGPoyraz Jun 3, 2026
45e37c7
Update changelog
OGPoyraz Jun 3, 2026
e1f1f94
fix: only reject rate drift when rate worsens, not improves
OGPoyraz Jun 3, 2026
44dd21f
Update changelog
OGPoyraz Jun 3, 2026
73182b9
fix: lint errors in fiat-submit tests
OGPoyraz Jun 3, 2026
220c6c6
fix: skip source balance check for relay execute flow
OGPoyraz Jun 3, 2026
cab349c
fix: use accountOverride for wallet address in fiat flow
OGPoyraz Jun 3, 2026
3ab8779
fix: revert isExecute balance skip test changes
OGPoyraz Jun 3, 2026
16fe6be
fix: remove hasFiatStrategy totals test
OGPoyraz Jun 3, 2026
5ea4519
fix: pass fiatPaymentAmount to totals for correct fiat total calculation
OGPoyraz Jun 3, 2026
660cac3
Fix the total derivation
OGPoyraz Jun 3, 2026
44f7ca3
test: add coverage for fiat strategy payment amount in totals
OGPoyraz Jun 3, 2026
0671fa6
Address PR review feedback from matthewwalsh0
OGPoyraz Jun 4, 2026
d9d35fd
feat: skip discovery quote for simple fiat deposits (Perps, Predict)
OGPoyraz Jun 4, 2026
a65eb72
feat: fee-as-buffer strategy, simple relay path, and file split for f…
OGPoyraz Jun 4, 2026
9f3d322
fix: decouple processTransactions from isPostQuote in relay-quotes
OGPoyraz Jun 4, 2026
056e2bc
fix: set skipProcessTransactions for simple fiat relay to fix recipie…
OGPoyraz Jun 4, 2026
26dbbe4
fix: sum nested call values for EIP-7702 batch transaction
OGPoyraz Jun 5, 2026
eb1521d
fix: post-quote gas handling for zero-balance fiat-funded accounts
OGPoyraz Jun 5, 2026
d477e33
test: add coverage for EIP-7702 batch value summing and update changelog
OGPoyraz Jun 5, 2026
15bd404
test: achieve 100% coverage for relay-quotes, feature-flags, and fiat…
OGPoyraz Jun 5, 2026
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-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

- Fix EIP-7702 batch transactions not forwarding native value from nested calls ([#8987](https://github.com/MetaMask/core/pull/8987))
- `generateEIP7702BatchTransaction` now sums the `value` fields of all nested calls and sets the total as the top-level transaction value. Previously the top-level value was always omitted, causing batches that include native token transfers (e.g. POL swaps) to revert.

## [66.0.1]

### Changed
Expand Down
41 changes: 41 additions & 0 deletions packages/transaction-controller/src/utils/eip7702.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ describe('EIP-7702 Utils', () => {
expect(result).toStrictEqual({
data: DATA_MOCK,
to: ADDRESS_MOCK,
value: '0x13568',
});
});

Expand Down Expand Up @@ -665,6 +666,7 @@ describe('EIP-7702 Utils', () => {
expect(result).toStrictEqual({
data: DATA_MOCK,
to: ADDRESS_MOCK,
value: '0x13568',
});
});

Expand All @@ -689,9 +691,47 @@ describe('EIP-7702 Utils', () => {
expect(result).toStrictEqual({
data: DATA_MOCK,
to: ADDRESS_MOCK,
value: '0x13568',
});
});

it('omits value when all nested calls have zero value', () => {
const result = generateEIP7702BatchTransaction(ADDRESS_MOCK, [
{
data: '0x1234',
to: ADDRESS_2_MOCK,
value: '0x0',
},
{
data: '0x9abc',
to: ADDRESS_3_MOCK,
},
]);

expect(result).toStrictEqual({
data: expect.any(String),
to: ADDRESS_MOCK,
});
expect(result.value).toBeUndefined();
});

it('sums values from nested calls with mixed zero and non-zero values', () => {
const result = generateEIP7702BatchTransaction(ADDRESS_MOCK, [
{
data: '0x1234',
to: ADDRESS_2_MOCK,
value: '0x0',
},
{
data: '0x9abc',
to: ADDRESS_3_MOCK,
value: '0x5678',
},
]);

expect(result.value).toBe('0x5678');
});

it('uses non-atomic mode when atomic is false', () => {
const result = generateEIP7702BatchTransaction(
ADDRESS_MOCK,
Expand All @@ -713,6 +753,7 @@ describe('EIP-7702 Utils', () => {
expect(result).toStrictEqual({
data: DATA_NON_ATOMIC_MOCK,
to: ADDRESS_MOCK,
value: '0x13568',
});
});
});
Expand Down
6 changes: 6 additions & 0 deletions packages/transaction-controller/src/utils/eip7702.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,15 @@ export function generateEIP7702BatchTransaction(

log('Transaction data', data);

const totalValue = transactions.reduce(
(sum, tx) => sum + BigInt(tx.value ?? '0x0'),
BigInt(0),
);

return {
data,
to: from,
...(totalValue > BigInt(0) ? { value: toHex(totalValue) } : {}),
};
}

Expand Down
5 changes: 5 additions & 0 deletions packages/transaction-pay-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Fiat submit now uses a three-phase relay flow with fee-as-buffer strategy after on-ramp settlement, and simple deposits (Perps, Predict) skip to a single EXACT_INPUT relay quote for cheaper fees ([#8987](https://github.com/MetaMask/core/pull/8987))
- Fiat quote submission now treats the provider code (e.g. `transak-native`) as the canonical form when resolving the provider from a ramps quote, while continuing to accept the legacy path form (e.g. `/providers/transak-native`) for backwards compatibility ([#9004](https://github.com/MetaMask/core/pull/9004))
- Live token balance queries now respect the `confirmations_pay_extended.excludeChainIdsFromInfura` feature flag, skipping the Infura endpoint preference for excluded chains ([#8992](https://github.com/MetaMask/core/pull/8992))
- Bump `@metamask/assets-controllers` from `^108.3.0` to `^108.5.0` ([#8981](https://github.com/MetaMask/core/pull/8981), [#8999](https://github.com/MetaMask/core/pull/8999))
- Bump `@metamask/assets-controller` from `^8.0.2` to `^8.3.2` ([#8981](https://github.com/MetaMask/core/pull/8981), [#8985](https://github.com/MetaMask/core/pull/8985), [#8999](https://github.com/MetaMask/core/pull/8999))

### Fixed

- Fix fiat `moneyAccountDeposit` failing after on-ramp settlement by adding `getAmountData` callback for calldata re-encoding and correcting wallet address, quote amount, and slippage validation ([#8987](https://github.com/MetaMask/core/pull/8987))
- Bump `@metamask/remote-feature-flag-controller` from `^4.2.1` to `^4.2.2` ([#8986](https://github.com/MetaMask/core/pull/8986))
- Bump `@metamask/ramps-controller` from `^14.1.0` to `^14.1.1` ([#8989](https://github.com/MetaMask/core/pull/8989))
- Bump `@metamask/bridge-status-controller` from `^72.0.0` to `^72.0.2` ([#8990](https://github.com/MetaMask/core/pull/8990), [#8999](https://github.com/MetaMask/core/pull/8999))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export type TransactionPayControllerGetDelegationTransactionAction = {
* @param args - The arguments forwarded to the {@link GetPaymentOverrideDataCallback}.
* @returns A promise resolving to the additional transactions array.
*/
export type TransactionPayControllerGetAmountDataAction = {
type: `TransactionPayController:getAmountData`;
handler: TransactionPayController['getAmountData'];
};

export type TransactionPayControllerGetPaymentOverrideDataAction = {
type: `TransactionPayController:getPaymentOverrideData`;
handler: TransactionPayController['getPaymentOverrideData'];
Expand Down Expand Up @@ -128,6 +133,7 @@ export type TransactionPayControllerMethodActions =
| TransactionPayControllerUpdatePaymentTokenAction
| TransactionPayControllerUpdateFiatPaymentAction
| TransactionPayControllerGetDelegationTransactionAction
| TransactionPayControllerGetAmountDataAction
| TransactionPayControllerGetPaymentOverrideDataAction
| TransactionPayControllerGetStrategyAction
| TransactionPayControllerPolymarketGetDepositWalletAddressAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,51 @@ describe('TransactionPayController', () => {
});
});

describe('getAmountData', () => {
it('delegates to the callback', async () => {
const resultMock = {
updates: [{ nestedTransactionIndex: 0, data: '0xabc' as const }],
};
const getAmountDataMock = jest.fn().mockResolvedValue(resultMock);

new TransactionPayController({
getAmountData: getAmountDataMock,
getDelegationTransaction: jest.fn(),
messenger,
});

const requestMock = {
amount: '5000000',
transaction: TRANSACTION_META_MOCK,
};

const result = await messenger.call(
'TransactionPayController:getAmountData',
requestMock,
);

expect(getAmountDataMock).toHaveBeenCalledWith(requestMock);
expect(result).toStrictEqual(resultMock);
});

it('returns empty updates when no callback is configured', async () => {
new TransactionPayController({
getDelegationTransaction: jest.fn(),
messenger,
});

const result = await messenger.call(
'TransactionPayController:getAmountData',
{
amount: '5000000',
transaction: TRANSACTION_META_MOCK,
},
);

expect(result).toStrictEqual({ updates: [] });
});
});

describe('polymarket callbacks', () => {
const EOA_MOCK = '0x1111111111111111111111111111111111111111' as Hex;
const DEPOSIT_WALLET_MOCK =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { QuoteRefresher } from './helpers/QuoteRefresher';
import { deriveFiatAssetForFiatPayment } from './strategy/fiat/utils';
import type {
GetAmountDataCallback,
GetDelegationTransactionCallback,
GetPaymentOverrideDataCallback,
PolymarketCallbacks,
Expand All @@ -36,6 +37,7 @@ import {
} from './utils/transaction';

const MESSENGER_EXPOSED_METHODS = [
'getAmountData',
'getDelegationTransaction',
'getPaymentOverrideData',
'getStrategy',
Expand Down Expand Up @@ -64,6 +66,8 @@ export class TransactionPayController extends BaseController<
TransactionPayControllerState,
TransactionPayControllerMessenger
> {
readonly #getAmountData?: GetAmountDataCallback;

readonly #getDelegationTransaction: GetDelegationTransactionCallback;

readonly #getPaymentOverrideData?: GetPaymentOverrideDataCallback;
Expand All @@ -79,6 +83,7 @@ export class TransactionPayController extends BaseController<
readonly #polymarket?: PolymarketCallbacks;

constructor({
getAmountData,
getDelegationTransaction,
getPaymentOverrideData,
getStrategy,
Expand All @@ -94,6 +99,7 @@ export class TransactionPayController extends BaseController<
state: { ...getDefaultState(), ...state },
});

this.#getAmountData = getAmountData;
this.#getDelegationTransaction = getDelegationTransaction;
this.#getPaymentOverrideData = getPaymentOverrideData;
this.#getStrategy = getStrategy;
Expand Down Expand Up @@ -233,6 +239,12 @@ export class TransactionPayController extends BaseController<
* @param args - The arguments forwarded to the {@link GetPaymentOverrideDataCallback}.
* @returns A promise resolving to the additional transactions array.
*/
getAmountData(
...args: Parameters<GetAmountDataCallback>
): ReturnType<GetAmountDataCallback> {
return this.#getAmountData?.(...args) ?? Promise.resolve({ updates: [] });
}

getPaymentOverrideData(
...args: Parameters<GetPaymentOverrideDataCallback>
): ReturnType<GetPaymentOverrideDataCallback> {
Expand Down
4 changes: 4 additions & 0 deletions packages/transaction-pay-controller/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export type {
GetAmountDataCallback,
GetAmountDataRequest,
GetAmountDataResponse,
GetPaymentOverrideDataRequest,
GetPaymentOverrideDataResponse,
TransactionConfig,
Expand All @@ -23,6 +26,7 @@ export type {
UpdatePaymentTokenRequest,
} from './types';
export type {
TransactionPayControllerGetAmountDataAction,
TransactionPayControllerGetDelegationTransactionAction,
TransactionPayControllerGetStrategyAction,
TransactionPayControllerPolymarketGetDepositWalletAddressAction,
Expand Down
Loading
Loading