Skip to content

feat: Implement FiatStrategy submit flow with order polling and relay execution#8347

Merged
OGPoyraz merged 20 commits intomainfrom
ogp/CONF-960
May 5, 2026
Merged

feat: Implement FiatStrategy submit flow with order polling and relay execution#8347
OGPoyraz merged 20 commits intomainfrom
ogp/CONF-960

Conversation

@OGPoyraz
Copy link
Copy Markdown
Member

@OGPoyraz OGPoyraz commented Mar 31, 2026

Explanation

Implements FiatStrategy submit flow with order polling and relay execution.

  • Implement submitFiatQuotes to poll the on-ramp order via RampsController:getOrder until completion, then re-quote and submit the relay leg with the settled crypto amount
  • Add order validation that verifies the completed order's asset and chain match the expected fiat asset before proceeding with relay
  • Update relay quote request filtering to support exact-input max amount requests used by the fiat submit re-quote path
  • Add orderCode field to TransactionFiatPayment and RampsControllerGetOrderAction to AllowedActions to enable order polling from the fiat strategy
  • Fail-closed on terminal order statuses (failed/cancelled), polling timeout with last-status reporting, asset mismatches, and invalid crypto amounts

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

Note

Medium Risk
Adds a new fiat submission path that polls on-ramp orders and then re-quotes/submits Relay based on the settled amount; mistakes here can cause failed submissions or unexpected amounts. Also changes Relay quote filtering logic, which may affect which quote requests are processed.

Overview
Implements the FiatStrategy submit flow: submitFiatQuotes now polls RampsController:getOrder until completion (with timeout, terminal failure handling, and transient error tolerance), validates the completed order’s asset/chain, converts the settled crypto amount to raw units, re-quotes Relay with an exact-input max-amount request, checks re-quote slippage (5% cap), and submits via submitRelayQuotes.

Updates TransactionPayController so changes to fiatPayment trigger quote refreshes, and changing the fiat payment method attempts to sync RampsController:setSelectedToken (best-effort, errors swallowed). Extends types to include TransactionFiatPayment.orderId and adds RampsController:getOrder/RampsController:setSelectedToken to AllowedActions, plus broad new test coverage for the fiat submit flow and token-selection behavior.

Reviewed by Cursor Bugbot for commit 45c2c79. Bugbot is set up for automated code reviews on this repo. Configure here.

@OGPoyraz OGPoyraz marked this pull request as ready for review March 31, 2026 09:04
@OGPoyraz OGPoyraz requested review from a team as code owners March 31, 2026 09:04
Comment on lines +218 to +219
/** Order identifier - `orderCode` specifically used as RampsService:getOrder parameter in normalized format (/providers/{provider}/orders/{id}). */
orderCode?: string;
Copy link
Copy Markdown
Member Author

@OGPoyraz OGPoyraz Mar 31, 2026

Choose a reason for hiding this comment

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

Originally we talked Ramps team to add metadata into fiat orders and also filtering mechanism.
Due to limitation of timeframe this may not be option to deliver besides headless ramp, hence we are adding orderCode (meaning order id) into TransactionFiatPayment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor, orderId or rampsId to be more generic?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done - renamed to orderId

Comment on lines +81 to +89
.filter((singleRequest) => {
const hasTargetMinimum = singleRequest.targetAmountMinimum !== '0';
const isPostQuote = Boolean(singleRequest.isPostQuote);
const isExactInputRequest =
Boolean(singleRequest.isMaxAmount) &&
new BigNumber(singleRequest.sourceTokenAmount).gt(0);

return hasTargetMinimum || isPostQuote || isExactInputRequest;
})
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The fiat re-quote request could get dropped by this filter if targetAmountMinimum happened to be '0' - it's not a post-quote, so the second condition wouldn't save it. The isExactInputRequest check distinguishes real exact-input requests (positive source amount + max amount flag) from empty gas fee token requests (zero source amount), ensuring the fiat re-quote passes through.

@OGPoyraz OGPoyraz changed the title feat: Implement fiat strategy submit flow with order polling and relay execution feat: Implement FiatStrategy submit flow with order polling and relay execution Mar 31, 2026
vinistevam
vinistevam previously approved these changes Mar 31, 2026
Comment thread packages/transaction-pay-controller/src/strategy/fiat/fiat-submit.ts Outdated
Comment on lines +218 to +219
/** Order identifier - `orderCode` specifically used as RampsService:getOrder parameter in normalized format (/providers/{provider}/orders/{id}). */
orderCode?: string;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor, orderId or rampsId to be more generic?

Comment thread packages/transaction-pay-controller/src/strategy/fiat/fiat-submit.ts Outdated

if (!original.gt(0) || !reQuoted.gt(0)) {
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Slippage check skips when re-quoted amount is zero

Medium Severity

validateRelaySlippage early-returns when either original or reQuoted is not positive. Skipping when the original is zero is correct (can't compute percentage slippage), but also skipping when the re-quoted amount is zero silently accepts a 100% loss scenario. The test only covers the "original is zero" case, confirming the developer's intent was narrower than what the || condition implements.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5091f0a. Configure here.

matthewwalsh0
matthewwalsh0 previously approved these changes May 1, 2026
Comment thread packages/transaction-pay-controller/src/strategy/fiat/fiat-submit.ts Outdated
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 23e00be. Configure here.

matthewwalsh0
matthewwalsh0 previously approved these changes May 4, 2026
@OGPoyraz OGPoyraz requested a review from matthewwalsh0 May 4, 2026 17:50
@OGPoyraz OGPoyraz added this pull request to the merge queue May 5, 2026
Merged via the queue into main with commit 420522b May 5, 2026
366 checks passed
@OGPoyraz OGPoyraz deleted the ogp/CONF-960 branch May 5, 2026 09:02
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.

3 participants