Skip to content

Route MoonPay iOS buys through a Private Relay interstitial check - #6151

Open
j0ntz wants to merge 2 commits into
developfrom
jon/moonpay-relay-interstitial
Open

Route MoonPay iOS buys through a Private Relay interstitial check#6151
j0ntz wants to merge 2 commits into
developfrom
jon/moonpay-relay-interstitial

Conversation

@j0ntz

@j0ntz j0ntz commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Technical Design Document

moonpay-private-relay-interstitial.md

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

EdgeApp/edge-info-server#160 (soft dependency: without it the app falls back to today's bound flow, so this PR is safe to land first)

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)
  • iCloud+ Private Relay on-device buy pass (MoonPay enforcement for our key stays off until this completes)

No visual changes: only the URL handed to the external Safari view differs; the relay pass above is the outstanding device item.

Description

Asana task

iOS buys open the MoonPay widget through the server's Private Relay relay-check interstitial instead of a directly IP-bound URL, so the server can compare the app-fetch and Safari-view egress addresses and sign the widget URL with or without the binding. Any interstitial failure falls back to today's bound flow, so buys cannot regress; sell and Android are untouched. MOONPAY_RELAY_CHECK_SIGN_PROXY (dev builds only) makes the divergence branch reproducible on a simulator.

The TDD linked above carries the full design for both repos. The physical-device Private Relay pass is the outstanding manual item; MoonPay enforcement stays off until it completes.


Note

Medium Risk
Changes the critical path for iOS fiat on-ramp URL signing and IP binding, with intentional fallback to the old flow on failure; paired info-server behavior determines whether relay users succeed under MoonPay enforcement.

Overview
iOS MoonPay buys no longer open a directly IP-bound widget URL in Safari. They first request a relay-check interstitial from the info server (relayCheck: true on signUrl); that URL is opened in SFSafariViewController so the server can compare app-fetch vs Safari egress and redirect to a signed widget with or without allowedIpAddress. Sell and Android buy still use direct bound signing.

If the interstitial request fails (network, old server, empty URL), the buy path falls back to today’s bound signMoonpayUrl flow so buys should not regress without the paired info-server deploy.

moonpaySign.ts centralizes postSignUrl (shared timeout and error handling). Dev-only MOONPAY_RELAY_CHECK_SIGN_PROXY reroutes the relay-check POST through an alternate egress for simulator testing of the unbound branch.

Adds unit tests for signing and interstitial fetch, a CHANGELOG entry, and a cross-repo TDD in moonpay-private-relay-interstitial.md.

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

@j0ntz

j0ntz commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence

moonpay buy quotes

moonpay buy quotes

safari widget fallback bound

safari widget fallback bound

safari interstitial unbound

safari interstitial unbound

Captured by the agent's in-app test run (build-and-test).

@j0ntz
j0ntz force-pushed the jon/moonpay-relay-interstitial branch 2 times, most recently from 1c042b5 to 4cf563e Compare August 13, 2026 20:19
@j0ntz
j0ntz marked this pull request as ready for review August 13, 2026 20:21
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@j0ntz
j0ntz force-pushed the jon/moonpay-relay-interstitial branch 6 times, most recently from 18a9532 to aab11af Compare August 14, 2026 07:22

@claude claude 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.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@j0ntz
j0ntz force-pushed the jon/moonpay-relay-interstitial branch 2 times, most recently from 51ea824 to 0c8bd6d Compare August 17, 2026 22:02
iOS buy opens the MoonPay widget in an SFSafariViewController whose
traffic can egress through iCloud Private Relay, so a widget URL bound
to the app-fetch IP mismatches what MoonPay observes for relay users
and will fail their buys once IP-match enforcement turns on.

The buy path now asks the info server for a relay-check interstitial
URL and opens that in the Safari view: the server observes the Safari
view's own egress and 302s to the widget URL signed with the IP binding
when the addresses agree, or without it when they diverge. Any
interstitial failure falls back to today's bound flow, so the change
cannot regress buys even against servers without relay-check support.
Sell and Android are untouched.

MOONPAY_RELAY_CHECK_SIGN_PROXY (dev builds only) reroutes the one
relay-check POST through an alternate egress so the unbound branch is
reproducible on a simulator. The TDD at
src/docs/moonpay-private-relay-interstitial.md documents both repos'
changes.
@j0ntz
j0ntz force-pushed the jon/moonpay-relay-interstitial branch from 0c8bd6d to d16b014 Compare August 17, 2026 22:12

@paullinator paullinator left a comment

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.

Additional Findings

  • suggestion: PR Requirements leaves all device-test boxes unchecked with "No visual changes", while the Description/TDD correctly call out that the physical-device Private Relay pass is still outstanding and that MoonPay enforcement must stay off until it completes.
    • Keep the no-visual-changes note, but add an explicit checklist item for the iCloud+ Private Relay on-device buy pass, and leave it unchecked until done.

Comment thread src/plugins/gui/providers/moonpaySign.ts
Comment thread src/plugins/gui/providers/moonpaySign.ts
Comment thread src/plugins/ramps/moonpay/moonpayRampPlugin.ts Outdated
Comment thread src/plugins/ramps/moonpay/moonpayRampPlugin.ts
Comment thread src/docs/moonpay-private-relay-interstitial.md Outdated
Comment thread src/plugins/ramps/moonpay/moonpayRampPlugin.ts Outdated
Comment thread src/plugins/gui/providers/moonpaySign.ts Outdated
Comment thread CHANGELOG.md Outdated
@j0ntz

j0ntz commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Top-level review note (review 4965479992) addressed: the Requirements checklist now carries an explicit unchecked item for the iCloud+ Private Relay on-device buy pass (MoonPay enforcement stays off until it completes), alongside the no-visual-changes note.

@j0ntz

j0ntz commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Addressed (Requirements now carries the unchecked iCloud+ Private Relay on-device buy pass item; details in the earlier reply comment).

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.

2 participants