Skip to content

fix: MMPay fiat payment fixes #8987

Open
OGPoyraz wants to merge 19 commits into
mainfrom
ogp/fiat-money-account-deposit-fix
Open

fix: MMPay fiat payment fixes #8987
OGPoyraz wants to merge 19 commits into
mainfrom
ogp/fiat-money-account-deposit-fix

Conversation

@OGPoyraz
Copy link
Copy Markdown
Member

@OGPoyraz OGPoyraz commented Jun 3, 2026

Explanation

Fiat payments for moneyAccountDeposit transactions fail with multiple sequential errors after the on-ramp order settles:

  1. isMaxAmount: true in the fiat re-quote — after Transak settles, submitRelayAfterFiatCompletion re-quotes with isMaxAmount: true, isPostQuote: false. This calls processTransactions, which throws "Max amount quotes do not support included transactions" because moneyAccountDeposit has nested txs (approve + deposit) that require delegation.

  2. validateRelaySlippage compares wrong amounts — it compares currencyOut.amount from two relay quotes made with different source amounts (theoretical $5 quoting phase vs actual ~$4.95 post-Transak settlement). This produces ~25% apparent "slippage" that is not real slippage — it is just a smaller input producing a smaller output.

  3. Nested calldata has zero amounts — the fiat path in handleDone only sets amountFiat and never calls updateTokenAmount(), so requiredAssets.amount stays 0x0 and the nested approve + deposit calldata encodes zero amounts.

  4. Wrong wallet address in fiat flowfiat-quotes.ts and fiat-submit.ts used transaction.txParams.from as the wallet address. For moneyAccountDeposit, txParams.from is the money account address on the target chain (Monad), not the user's EOA. This caused Ramps/Transak to receive the wrong deposit address, resolveSourceAmountRaw to look for on-chain ETH at the wrong address, and all relay quotes to use the wrong from/user address — resulting in TRANSFER_FROM_FAILED reverts.

  5. Fiat total calculation using wrong amountcalculateTotals derived the payment amount from token amounts or targetAmount, which is incorrect for fiat flows where the user enters a specific fiat amount.

Changes

fiat-quotes.ts — uses accountOverride when available for walletAddress, matching the existing pattern in quotes.ts. This ensures Ramps/Transak receives the user's actual EOA address, not the money account address.

fiat-submit.ts — two wallet address fixes plus three-phase relay flow:

  • submitFiatQuotes: uses accountOverride ?? txParams.from for order polling wallet address
  • submitRelayAfterFiatCompletion: uses baseRequest.from (already accountOverride-aware from the quote) for on-chain amount lookup
  • Phase 1: Discovery relay quote (isPostQuote: true, EXACT_INPUT) with the settled source amount to learn currencyOut.minimumAmount
  • Phase 2: Calls getAmountData via messenger to delegate calldata re-encoding to the client, then patches nested tx data + requiredAssets[0].amount
  • Phase 3: Real relay quote (isPostQuote: false, EXACT_OUTPUT) with delegation

relay-submit.ts — reverts the isExecute balance skip (no longer needed with correct wallet address). The balance check now correctly validates the user's EOA balance.

validateRelaySlippagevalidateRelayRateDrift — compares USD exchange rate ratios (output_usd / input_usd) between original and discovery quotes instead of absolute amounts, normalising for different source amounts.

TransactionPayController — adds optional getAmountData callback on the constructor, exposed via messenger as TransactionPayController:getAmountData. Keeps ABI knowledge on the client side.

totals.ts — adds fiatPaymentAmount parameter to calculateTotals. When a fiat strategy quote is present, uses the user-entered fiat payment amount directly instead of deriving it from token amounts or relay targetAmount. Falls back to '0' if fiat amount is unavailable.

quotes.ts — passes fiatPayment.amountFiat from the transaction pay state into calculateTotals as fiatPaymentAmount.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Add optional getAmountData callback that re-encodes nested transaction
calldata for a given token amount. Used by transaction types with
non-standard nested data (e.g. vault approve + deposit) that require
client-side context (vault config, RPC providers) to encode.
@OGPoyraz OGPoyraz requested a review from a team as a code owner June 3, 2026 12:24
@OGPoyraz OGPoyraz marked this pull request as draft June 3, 2026 12:24
@OGPoyraz OGPoyraz temporarily deployed to default-branch June 3, 2026 12:24 — with GitHub Actions Inactive
@OGPoyraz OGPoyraz changed the title Ogp/fiat money account deposit fix fix: Fiat flow on MoneyAccountDeposit Jun 3, 2026
After fiat order settlement, use a three-phase relay flow:
1. Discovery quote (EXACT_INPUT) to find settled target token output
2. Re-encode nested calldata via getAmountData callback
3. Real relay quote with delegation (EXACT_OUTPUT) for execution

Also removes validateRelaySlippage which incorrectly compared outputs
from relay quotes made with different source amounts, and removes
isMaxAmount:true which caused delegation errors with nested transactions.
@OGPoyraz OGPoyraz force-pushed the ogp/fiat-money-account-deposit-fix branch from 3f77b67 to 0560a35 Compare June 3, 2026 12:31
OGPoyraz added 4 commits June 3, 2026 14:53
- Fix unnecessary type assertion on requiredAssets hex amount
- Add JSDoc @param tags to validateRelayRateDrift
- Update fiat-submit tests for three-phase relay flow
- Add getAmountData controller tests
- Add rate drift, stale calldata, and discovery quote error tests
- 100% test coverage maintained
@OGPoyraz OGPoyraz marked this pull request as ready for review June 3, 2026 13:04
@OGPoyraz OGPoyraz requested a review from a team as a code owner June 3, 2026 13:04
@OGPoyraz OGPoyraz temporarily deployed to default-branch June 3, 2026 13:04 — with GitHub Actions Inactive
OGPoyraz added 2 commits June 3, 2026 15:15
A better post-settlement rate benefits the user and should not block
fiat completion. Remove .abs() so only positive drift (rate worsened)
is rejected.
@OGPoyraz OGPoyraz force-pushed the ogp/fiat-money-account-deposit-fix branch from b3b05dd to 8ca96e8 Compare June 3, 2026 13:25
OGPoyraz added 3 commits June 3, 2026 16:00
- Remove unused args parameter
- Replace non-null assertions with optional chaining
The execute flow uses Relay's relayer to handle the source-side
transaction, so the user's EOA does not need to hold the source
tokens at submit time. This was causing fiat moneyAccountDeposit
to fail with 'Insufficient source token balance' after Transak
settlement.
The fiat quoting and submission flows used transaction.txParams.from as
the wallet address. For moneyAccountDeposit, txParams.from is the money
account address on the target chain, not the user's EOA. This caused:

- Ramps/Transak to receive the wrong deposit address
- resolveSourceAmountRaw to look for on-chain ETH at the wrong address
- Relay quotes to use the wrong from/user address
- Balance validation to check the wrong account

Use accountOverride (the user's selected EVM account) when available,
matching the pattern already used in quotes.ts.

Also revert the isExecute balance skip (no longer needed with correct
address) and remove hasFiatStrategy from totals calculation.
Comment thread packages/transaction-pay-controller/src/strategy/relay/relay-submit.test.ts Outdated
Reverts the test changes from the isExecute balance skip commit since
the source code was also reverted. Restores the original test that
validates source balance for execute flows.
const state = messenger.call('TransactionPayController:getState');
const transactionData = state.transactionData[transactionId];
const walletAddress = (transactionData?.accountOverride ??
transaction.txParams.from) as Hex | undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fiat poll wallet diverges

Medium Severity

submitFiatQuotes derives the wallet for RampsController:getOrder from current transactionData.accountOverride (or txParams.from), while submitRelayAfterFiatCompletion resolves the settled source amount using quotes[0].request.from. If pay state and the executed quote disagree, order polling can target the wrong address and time out even though relay steps use the quote wallet.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2333bcd. Configure here.

OGPoyraz added 2 commits June 3, 2026 23:02
The test validated the removed hasFiatStrategy path in calculateTotals.
With fiat strategy now using amountFiat consistently, this test case
is no longer applicable.
Pass fiatPayment.amountFiat from quote context into calculateTotals so
the fiat flow uses the user-entered fiat amount for the total instead
of deriving it from token amounts or targetAmount.
Comment thread packages/transaction-pay-controller/src/utils/totals.ts
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7e8e999. Configure here.

Comment thread packages/transaction-pay-controller/src/utils/totals.ts
@OGPoyraz OGPoyraz changed the title fix: Fiat flow on MoneyAccountDeposit fix: MMPay fiat payment fixes Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant