镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Pin network and verify order for MoonPay sell links - #6236

Open
j0ntz wants to merge 4 commits into
developfrom
jon/moonpay-send-with-edge-pin-network
Open

j0ntz wants to merge 4 commits into
developfrom
jon/moonpay-send-with-edge-pin-network

Conversation

@j0ntz

@j0ntz j0ntz commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Description

MoonPay's "Send with Edge" sell link names the currency by a ticker that several networks share, and it carries the deposit address and amount in a URL anybody can write. The handler trusted all of it and offered every wallet with a matching ticker. An ETH-on-Arbitrum order could be paid from an Ethereum or Base wallet.

The link now only identifies the order. Edge looks the order up at MoonPay (GET /v3/sell_transactions/{transactionId}) and takes the asset, deposit address, tag and amount from that response:

  • The wallet picker gets exactly one asset, resolved from the order's networkCode and contractAddress. Only wallets on the order's network are listed.
  • The Send scene opens only while the order status is waitingForDeposit. A closed order shows "Sell Order Closed". An order that cannot be read (unknown id, network failure, no id on the link, unresolvable asset) shows "Unable to Verify Sell Order". Neither opens Send.
  • When the link's query disagrees with the order, the mismatch is logged and the order's values are used.
  • The ticker-based picker is removed for this link type.

New sell orders register a redirect URL that names the provider and asset, https://deep.edge.app/redirect/payment/moonpay/<pluginId>[_<tokenId>]/, built by makePaymentReturnUrl. The parser reads the optional provider, asset and transactionId. Bare legacy links still parse and go through the same lookup.

Analytics: Sell_Payment_Redirect fires on every handled link with the provider, order id and order status. Sell_Success fires with fiatProviderId and orderId when the send completes.

The MoonPay network-to-plugin map lives in moonpayAssetUtils.ts, shared by the ramp plugin, the legacy provider and the order lookup.

The Send scene opens with the wallet, address and amount tiles locked, because the order fixes all three.

The deposit is saved as a MoonPay sell, the same record the in-app sell flow writes: assetAction sell plus a savedAction with the order id, the receipt URL, MoonPay's display name and support email, and MoonPay's quote for the order (fiat amount and currency, marked as an estimate). An order with no quote gets no record and the send still goes out. Token sends also save the action on the transaction after broadcast, as the in-app flow does. The display name, support email and receipt URL builder now live in moonpaySellOrder.ts and the ramp plugin imports them.

Not in this PR: Paybis redirect handling.

Testing on the iOS simulator (frames below):

  • Real failed order 6ae325aa-d930-47cd-9ef0-d26e03b68f3c: "Sell Order Closed", no Send.
  • Unknown order id on a bare legacy link: "Unable to Verify Sell Order", no Send.
  • Open ETH-on-Arbitrum order (order response forced locally, link query set to 5 ETH and a different address): the picker lists Arbitrum One only, and Send opens with the order's address and 0.0001 ETH. Taps on the wallet, address and amount tiles open nothing.
  • Same forced order with a funded wallet and the deposit address set to the test account's own address: 0.0001 ETH was sent on Arbitrum One, the app opened Transaction Details, and Sell_Success went out with fiatProviderId: moonpay and the order id.
  • Same forced order with MoonPay's quote (0.26 USD): after the send, Transaction Details shows "Sell Ethereum", category "Exchange:To USD", the exchange details marked "Estimated Quote", the order id, the receipt URL and support@moonpay.com.
  • Forced order with no quote: Send still opens ready to confirm.
  • In-app sell: the MoonPay widget opens with the per-order redirect URL. The sell was not completed.

Unit tests cover the parser (DeepLink.test.ts), the URL helper (common.test.ts), the lookup with mocked fetch, and the sell record builder including the missing-quote case (moonpaySellOrder.test.ts).

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

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)

Test evidence

9e249a3
Verify MoonPay order before opening Send
2026-10-02
🪓 HACK-NOTE: fetchMoonpaySellOrder returns a canned waitingForDeposit ETH-on-Arbitrum order (0.0001 ETH, quote 0.26 USD, or no quote for the -noquote id) paying the account's own Ethereum-wallet address, instead of calling MoonPay; reverted before commit

1. failed order closed no send

2. unknown order unverified no send

3. 🪓 open arbitrum order picker arbitrum only

5. in app sell moonpay widget opens with per order redirect

4. 🪓 open order send uses order address and amount

6. 🪓 open order send tiles locked after taps

7. 🪓 open order funded send ready

8. 🪓 open order send broadcast transaction success

10. 🪓 quoted order send ready

11. 🪓 quoted order details show moonpay sell

12. 🪓 quoted order details order id receipt support

13. 🪓 unquoted order send still opens

j0ntz added 3 commits October 2, 2026 14:07
MoonPay persists the sell redirect URL and resurfaces it in its "Send
with Edge" email and order-history button. The bare payment URL only
carried a ticker in the query, which cannot tell Ethereum from Arbitrum
or Base. Build a per-order URL with the provider id and the asset as
path segments so the deep link identifies the network.
Move the networkCode to pluginId map and the contract lookup out of the
ramp plugin into moonpayAssetUtils so other callers resolve a MoonPay
currency to an Edge asset the same way. The legacy provider carried an
identical copy of the map and now imports the shared one.
A payment redirect link now carries the provider and asset named in its
path, plus the provider's transactionId from the query. All three are
optional: links from older orders have no path segments, and a segment
that is empty or badly percent-encoded is dropped instead of failing the
link. Nothing reads the new fields yet.
@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-send-with-edge-pin-network branch from a21d986 to 0fed003 Compare October 2, 2026 22:07
A "Send with Edge" link is a URL anybody can write, and it names the
currency by a ticker several networks share. The handler now treats the
link as an order id only: it looks the sell order up with the MoonPay
ramp plugin's configured API, resolves the one asset the order names,
and takes the deposit address, tag and amount from that response.

The wallet picker gets exactly that asset, replacing the scan for every
wallet matching the ticker. An order that is no longer waiting for a
deposit shows a message and opens no Send scene, and so does a lookup
that fails or names an asset Edge cannot resolve.

Handling the link logs Sell_Payment_Redirect with the provider and
order status, and a completed send logs Sell_Success with the provider
and order id.
@j0ntz
j0ntz force-pushed the jon/moonpay-send-with-edge-pin-network branch from 0fed003 to 9e249a3 Compare October 2, 2026 23:07
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