Skip to content

Commit e30b500

Browse files
authored
fix: MM pay request amount used when both paymentProvider and isPostQuote is defined (MetaMask#9070)
## Explanation Fix MM pay request amount used when both paymentOverride and isPostQuote is defined. ## References Related to https://consensyssoftware.atlassian.net/browse/CONF-1520 ## Checklist - [X] I've updated the test suite for new or updated code as appropriate - [X] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [X] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [X] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes payment quote amounts sent to the relay API for a specific MM Pay path; wrong amounts could affect funding quotes, though scope is narrow and well-tested. > > **Overview** > Fixes **MetaMask Pay** relay quote bodies when **`paymentOverride` is Money Account** and **`isPostQuote`** is true: the relay request **`amount`** for **`EXACT_OUTPUT`** now comes from **`transactionData.tokens[0].amountRaw`** instead of **`request.sourceTokenAmount`**, so the quoted output matches the destination token’s units when decimals differ. > > Missing token data falls back to **`'0'`**. Tests cover the new amount source, decimal mismatch, and empty/missing **`transactionData`**; the package changelog records the fix. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6d89828. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 4bf4fda commit e30b500

3 files changed

Lines changed: 98 additions & 4 deletions

File tree

packages/transaction-pay-controller/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Bump `@metamask/bridge-controller` from `^75.0.0` to `^75.1.0` ([#9072](https://github.com/MetaMask/core/pull/9072))
1313

14+
### Fixed
15+
16+
- Fix request amount used for cases when paymentOverride is defined and also isPostQuote is true ([#9070](https://github.com/MetaMask/core/pull/9070))
17+
1418
## [23.4.0]
1519

1620
### Changed

packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,19 +3073,21 @@ describe('Relay Quotes Utils', () => {
30733073

30743074
function setupMoneyAccountMocks({
30753075
amountHuman = AMOUNT_HUMAN_MOCK,
3076+
amountRaw = AMOUNT_RAW_MOCK,
30763077
overrideCalls = [OVERRIDE_CALL_MOCK],
30773078
recipient,
30783079
authorizationList = DELEGATION_RESULT_MOCK.authorizationList,
30793080
}: {
30803081
amountHuman?: string;
3082+
amountRaw?: string;
30813083
overrideCalls?: { to: Hex; data: Hex; value: Hex }[];
30823084
recipient?: Hex;
30833085
authorizationList?: typeof DELEGATION_RESULT_MOCK.authorizationList;
30843086
} = {}): void {
30853087
getControllerStateMock.mockReturnValue({
30863088
transactionData: {
30873089
[TRANSACTION_ID_MOCK]: {
3088-
tokens: [{ amountHuman }],
3090+
tokens: [{ amountHuman, amountRaw }],
30893091
},
30903092
},
30913093
} as never);
@@ -3097,7 +3099,7 @@ describe('Relay Quotes Utils', () => {
30973099
});
30983100
}
30993101

3100-
it('sets tradeType to EXACT_OUTPUT and amount from request sourceTokenAmount', async () => {
3102+
it('sets tradeType to EXACT_OUTPUT and amount from transactionData amountRaw', async () => {
31013103
setupMoneyAccountMocks();
31023104
successfulFetchMock.mockResolvedValue({
31033105
ok: true,
@@ -3116,7 +3118,95 @@ describe('Relay Quotes Utils', () => {
31163118
);
31173119

31183120
expect(body.tradeType).toBe('EXACT_OUTPUT');
3119-
expect(body.amount).toBe(QUOTE_REQUEST_MOCK.sourceTokenAmount);
3121+
expect(body.amount).toBe(AMOUNT_RAW_MOCK);
3122+
});
3123+
3124+
it('uses amountRaw rather than sourceTokenAmount when decimals differ', async () => {
3125+
const destinationAmountRaw = '100000';
3126+
const sourceTokenAmountWithDifferentDecimals = '10000000';
3127+
3128+
setupMoneyAccountMocks({ amountRaw: destinationAmountRaw });
3129+
successfulFetchMock.mockResolvedValue({
3130+
ok: true,
3131+
json: async () => QUOTE_MOCK,
3132+
} as never);
3133+
3134+
await getRelayQuotes({
3135+
accountSupports7702: true,
3136+
messenger,
3137+
requests: [
3138+
{
3139+
...MONEY_ACCOUNT_REQUEST_MOCK,
3140+
sourceTokenAmount: sourceTokenAmountWithDifferentDecimals,
3141+
},
3142+
],
3143+
transaction: MONEY_ACCOUNT_TX_MOCK,
3144+
});
3145+
3146+
const body = JSON.parse(
3147+
successfulFetchMock.mock.calls[0][1]?.body as string,
3148+
);
3149+
3150+
expect(body.amount).toBe(destinationAmountRaw);
3151+
expect(body.amount).not.toBe(sourceTokenAmountWithDifferentDecimals);
3152+
});
3153+
3154+
it('defaults amount to 0 when transactionData has no tokens', async () => {
3155+
getControllerStateMock.mockReturnValue({
3156+
transactionData: {
3157+
[TRANSACTION_ID_MOCK]: {},
3158+
},
3159+
} as never);
3160+
3161+
getPaymentOverrideDataMock.mockResolvedValue({
3162+
calls: [OVERRIDE_CALL_MOCK],
3163+
});
3164+
3165+
successfulFetchMock.mockResolvedValue({
3166+
ok: true,
3167+
json: async () => QUOTE_MOCK,
3168+
} as never);
3169+
3170+
await getRelayQuotes({
3171+
accountSupports7702: true,
3172+
messenger,
3173+
requests: [MONEY_ACCOUNT_REQUEST_MOCK],
3174+
transaction: MONEY_ACCOUNT_TX_MOCK,
3175+
});
3176+
3177+
const body = JSON.parse(
3178+
successfulFetchMock.mock.calls[0][1]?.body as string,
3179+
);
3180+
3181+
expect(body.amount).toBe('0');
3182+
});
3183+
3184+
it('defaults amount to 0 when transactionData is missing', async () => {
3185+
getControllerStateMock.mockReturnValue({
3186+
transactionData: {},
3187+
} as never);
3188+
3189+
getPaymentOverrideDataMock.mockResolvedValue({
3190+
calls: [OVERRIDE_CALL_MOCK],
3191+
});
3192+
3193+
successfulFetchMock.mockResolvedValue({
3194+
ok: true,
3195+
json: async () => QUOTE_MOCK,
3196+
} as never);
3197+
3198+
await getRelayQuotes({
3199+
accountSupports7702: true,
3200+
messenger,
3201+
requests: [MONEY_ACCOUNT_REQUEST_MOCK],
3202+
transaction: MONEY_ACCOUNT_TX_MOCK,
3203+
});
3204+
3205+
const body = JSON.parse(
3206+
successfulFetchMock.mock.calls[0][1]?.body as string,
3207+
);
3208+
3209+
expect(body.amount).toBe('0');
31203210
});
31213211

31223212
it('includes token transfer and override calls in txs', async () => {

packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ async function processMoneyAccountPostQuote(
464464

465465
requestBody.authorizationList = normalizeAuthorizationList(authorizationList);
466466
requestBody.tradeType = 'EXACT_OUTPUT';
467-
requestBody.amount = request.sourceTokenAmount;
467+
requestBody.amount = transactionData?.tokens?.[0]?.amountRaw ?? '0';
468468
requestBody.txs = [
469469
{
470470
to: request.targetTokenAddress,

0 commit comments

Comments
 (0)