Skip to content

✨ server: support offramp transfer reference - #1165

Open
mainqueg wants to merge 2 commits into
mainfrom
reference
Open

✨ server: support offramp transfer reference#1165
mainqueg wants to merge 2 commits into
mainfrom
reference

Conversation

@mainqueg

@mainqueg mainqueg commented Jul 20, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Off-ramp transfers are now created automatically when an external account is added, and the response is returned only after the transfer succeeds.
    • Transfer references are supported across ACH, wire, SEPA, SPEI, PIX, and Faster Payments.
    • Deposit details can include an optional reference, including Optimism deposits.
  • Bug Fixes
    • Improved handling of missing off-ramp transfers with clearer errors.
    • Strengthened validation for rail-specific reference formats and lengths.

@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 06db66b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The Bridge offramp flow validates rail-specific references, creates transfers during external-account creation, reuses matching static templates, reports missing transfers, and exposes transfer references in deposit details. Tests and patch changesets cover the updated behavior.

Changes

Bridge offramp flow

Layer / File(s) Summary
Bridge schemas and transfer contracts
server/utils/ramps/bridge.ts
External-account, transfer destination, reference, and error-code schemas support rail-specific validation and missing-transfer reporting.
Offramp transfer and deposit details
server/utils/ramps/bridge.ts, server/test/utils/bridge.test.ts
Offramp transfers map references to rail-specific fields, deposit lookup requires matching static templates, and returned details expose a unified reference.
Ramp API integration and validation
server/api/ramp.ts, server/test/api/ramp.test.ts
External-account creation now creates an offramp transfer, missing transfers map to a client error, and validation and response tests cover references and failures.
Release metadata
.changeset/*.md
Two patch changesets document offramp reference support and transfer creation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RampAPI
  participant Bridge
  participant BridgeTransfers
  Client->>RampAPI: POST external-account with rail and reference
  RampAPI->>Bridge: createExternalAccount(payload)
  Bridge-->>RampAPI: external account
  RampAPI->>Bridge: createOfframpTransfer(account, rail, reference)
  Bridge->>BridgeTransfers: POST /transfers with rail-specific reference
  BridgeTransfers-->>Bridge: created transfer
  Bridge-->>RampAPI: transfer result
  RampAPI-->>Client: external account response
Loading

Possibly related PRs

  • exactly/exa#1024: Builds on the same Bridge offramp flow and modifies external-account and transfer handling.

Suggested reviewers: cruzdanilo, nfmelendez, dieguezguille

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: supporting references for offramp transfers in the server.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch reference
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch reference

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for offramp transfer references and updates the external account creation flow to automatically create an offramp transfer. The review feedback highlights a potential failure state where a failed transfer creation leaves an orphaned external account, recommending a nested try-catch block to clean up the account and a corresponding test update. Additionally, it suggests narrowing the currency parameter type in createOfframpTransfer to (typeof FiatCurrency)[number] to improve type safety.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread server/api/ramp.ts
Comment thread server/test/api/ramp.test.ts
Comment thread server/utils/ramps/bridge.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb8ce3926e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread server/utils/ramps/bridge.ts
Comment thread server/api/ramp.ts
@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.12%. Comparing base (836f057) to head (d3985eb).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1165      +/-   ##
==========================================
+ Coverage   70.69%   71.12%   +0.42%     
==========================================
  Files         263      263              
  Lines       11446    11626     +180     
  Branches     3833     3909      +76     
==========================================
+ Hits         8092     8269     +177     
+ Misses       3059     3057       -2     
- Partials      295      300       +5     
Flag Coverage Δ
e2e 70.09% <84.00%> (-0.61%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 291c6cc2-afde-432d-b96f-147e7a88f30d

📥 Commits

Reviewing files that changed from the base of the PR and between 260ca8f and 01b8875.

📒 Files selected for processing (6)
  • .changeset/quick-lions-attack.md
  • .changeset/swift-badgers-cheer.md
  • server/api/ramp.ts
  • server/test/api/ramp.test.ts
  • server/test/utils/bridge.test.ts
  • server/utils/ramps/bridge.ts

Comment thread server/api/ramp.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 67003a7fbf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread server/api/ramp.ts
Comment thread server/utils/ramps/bridge.ts
Comment thread server/utils/ramps/bridge.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/utils/ramps/bridge.ts (1)

974-1002: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Backfill static offramp templates before requiring them.

getOfframpDepositDetails now throws OFFRAMP_TRANSFER_NOT_FOUND for any external account without an active static template, and /ramp/quote surfaces that as a 400 TRANSFER_NOT_FOUND. Existing external accounts that relied on the previous create-on-fetch path will stop getting deposit info unless pre-existing templates are backfilled or a compatibility fallback is kept.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5a80c1af-d615-4276-8c0c-d94a3191e36d

📥 Commits

Reviewing files that changed from the base of the PR and between 67003a7 and 8ff8315.

📒 Files selected for processing (6)
  • .changeset/quick-lions-attack.md
  • .changeset/swift-badgers-cheer.md
  • server/api/ramp.ts
  • server/test/api/ramp.test.ts
  • server/test/utils/bridge.test.ts
  • server/utils/ramps/bridge.ts

Comment thread server/utils/ramps/bridge.ts
Comment thread server/utils/ramps/bridge.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/utils/ramps/bridge.ts (1)

974-1002: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider fetching the external account and static templates in parallel.

getExternalAccount and getStaticTemplates are awaited sequentially here, adding avoidable latency. removeExternalAccount (same file) already fetches both concurrently via Promise.all and validates afterward — the same pattern would work here since template lookup only needs customer.id/externalAccountId, not the resolved externalAccount.

♻️ Suggested refactor
-  const externalAccount = await getExternalAccount(customer.id, externalAccountId);
+  const [externalAccount, templates] = await Promise.all([
+    getExternalAccount(customer.id, externalAccountId),
+    getStaticTemplates(customer.id),
+  ]);
   if (!externalAccount) throw new Error(ErrorCodes.EXTERNAL_ACCOUNT_NOT_FOUND);
   if (externalAccount.currency !== CurrencyToBridge[currency]) {
     throw new Error(ErrorCodes.EXTERNAL_ACCOUNT_CURRENCY_MISMATCH);
   }
   const paymentRail = PaymentRailByBridgeCurrency[externalAccount.currency];
   if (!paymentRail) throw new Error(ErrorCodes.NOT_AVAILABLE_CURRENCY);
-  const templates = await getStaticTemplates(customer.id);
   const transfer = templates.find(

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 32ee92fb-00c0-461f-90b4-676d7fc45e4e

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff8315 and d3985eb.

📒 Files selected for processing (6)
  • .changeset/quick-lions-attack.md
  • .changeset/swift-badgers-cheer.md
  • server/api/ramp.ts
  • server/test/api/ramp.test.ts
  • server/test/utils/bridge.test.ts
  • server/utils/ramps/bridge.ts

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