Skip to content

Add DFX fiat ramp provider - #6061

Open
j0ntz wants to merge 2 commits into
developfrom
jon/integrate-dfx-ramp
Open

j0ntz wants to merge 2 commits into
developfrom
jon/integrate-dfx-ramp

Conversation

@j0ntz

@j0ntz j0ntz commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

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)

Description

Integrate DFX (API, docs) as a SEPA fiat buy/sell ramp (no swap), using the src/plugins/ramps/ external-ramp pattern (same shape as bitsofgold and libertyx): there is no quoting API. The user is deeplinked into the DFX web widget to complete the buy or sell.

What this adds:

  • src/plugins/ramps/dfx/dfxRampPlugin.ts and dfxRampTypes.ts: the DFX external ramp factory and its init-options cleaner.
  • src/plugins/ramps/dfx/dfxSession.ts: logs the selected wallet into DFX before the widget opens (see below).
  • An optional async resolveDeepQuery(request) hook in createExternalRampPlugin.ts (its own commit). A provider can use it to add query parameters that depend on the selected wallet; its result is merged over the static deepQuery when the quote is approved. Existing external ramps do not set it and behave as before.
  • dfx registered in allRampPlugins.ts.
  • The dfx GUI plugin (baseUri: https://app.dfx.swiss, camera permission for QR scanning).
  • dfx added to the preferProviders id list in src/docs/ramps-deeplink-provider-priority.md.

Session login (address prefill): on Bitcoin and the EVM chains, Edge signs DFX's ownership message with the selected wallet and opens DFX already logged in, with the wallet's address and asset selected. The user no longer connects a wallet or pastes an address on DFX's page.

  1. Address: the segwit receive address on Bitcoin, the public address on EVM chains.
  2. GET /v1/auth/signMessage?address=<address> returns the message and the blockchains DFX accepts for that address.
  3. Bitcoin signs with the engine's default signMessage format; EVM chains sign the UTF-8 message bytes with signBytes. DFX verifies both.
  4. POST /v1/auth with { address, signature, wallet } returns accessToken, a JWT that expires after about 48 hours.
  5. The widget opens at /buy or /sell with session, blockchain and asset-out (buy) or asset-in (sell), next to the existing wallet and lang parameters.

Solana and Monero keep the plain link. Any failure along the way (network, a DFX error, a chain DFX does not accept for the address, or a login that takes over 10 seconds) logs a warning and opens the plain link. The ramp never gets stuck behind the login. wallet: "Edge" is accepted by /v1/auth.

Enabling it: like every ramp plugin, DFX is off until the rampPlugins map carries it. Locally that is rampPlugins.dfx = true in config.json and rampPlugins.dfx = {} in keys.json. Through the remote keys (the info server appKeys overlay), the entry must be a non-empty object such as { "wallet": "Edge" }, because the overlay treats {} as no opinion. DFX needs no API key; the optional init fields are partnerIcon and wallet (the partner identifier DFX reads from the URL and the login, default Edge).

Support matrix: sepa payment type, EUR and CHF, for Bitcoin, Ethereum, Arbitrum, Optimism, Polygon, Base, BNB Smart Chain, Solana and Monero (mainnet coins only). Countries are the EEA members plus Switzerland where DFX's country list (api.dfx.swiss/v1/country) allows IBAN, bank and KYC: 30 countries, with Iceland and Norway included and Bulgaria left out because DFX disallows it.

Rebased onto current develop, including the remote env keys work.

Testing: on the iOS simulator with region Germany and fiat EUR, drove Buy 500 EUR and Sell 100 EUR on a Bitcoin wallet and Buy 500 EUR on an Ethereum wallet. Each time "SEPA Bank Transfer" ("Powered By: DFX") opened DFX logged in with the wallet's address bound: Buy stops at DFX's KYC step and Sell at its IBAN step (no order placed). A Solana wallet opened the plain link with no login, as intended. DFX fills in a default spend of 300 EUR because the amount is not passed through. Unit tests cover the Bitcoin and EVM login paths, the Solana skip, a rejected login, an unaccepted chain and a login timeout. Screenshots attached.

Asana task

Test evidence

3819441
2026-10-01

1. buy dfx sepa option

2. buy dfx webview

3. sell dfx sepa option

4. sell dfx webview
8c59823
Add DFX fiat ramp provider
2026-10-29

2. dfx buy btc logged in

4. dfx sell btc logged in

5. dfx buy eth logged in

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

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

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit fc8ddf3. Configure here.

Comment thread src/plugins/ramps/dfx/dfxRampPlugin.ts Resolved
@j0ntz
j0ntz force-pushed the jon/integrate-dfx-ramp branch 2 times, most recently from a096719 to ee8d927 Compare June 25, 2026 23:36
@j0ntz
j0ntz force-pushed the jon/integrate-dfx-ramp branch from ee8d927 to 3819441 Compare October 1, 2026 17:13
External ramp plugins can now resolve extra deep link query parameters
per quote request when the user approves the quote. The resolved values
merge over the static deepQuery, and returning undefined keeps the static
link.
@j0ntz
j0ntz force-pushed the jon/integrate-dfx-ramp branch from 3819441 to 17f68a1 Compare October 29, 2026 22:01
Integrate DFX (app.dfx.swiss) as a SEPA-based buy/sell fiat ramp using the
external ramp webview pattern. Registers the dfx ramp plugin and adds its
GUI plugin entry. Like every ramp plugin it is enabled through the
rampPlugins map (config.json plus keys.json). Supports EUR/CHF across the
SEPA region plus Switzerland and Liechtenstein for BTC, ETH and major EVM
chains, Solana and Monero.
@j0ntz
j0ntz force-pushed the jon/integrate-dfx-ramp branch from 17f68a1 to 8c59823 Compare October 29, 2026 23:18

@j0ntz j0ntz left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Self-review at 8c598230c (medium): no open findings.

Fixed before review (2)
  • src/plugins/ramps/dfx/dfxSession.ts:60: the quote approval awaited the DFX login with no time limit. A slow DFX API held the user on the quote list. Fixed: the login now races a 10 second timeout and falls back to the plain link, folded into "Add DFX fiat ramp provider".
  • src/plugins/ramps/dfx/dfxRampPlugin.ts:59: the crypto asset list repeated the session chain ids by hand. Fixed: the list is now derived from DFX_SESSION_CHAINS plus Solana and Monero, folded into "Add DFX fiat ramp provider".
Rejected in curation (3)
  • src/plugins/ramps/dfx/dfxSession.ts:101: the Bitcoin signature format (engine default) may not match what DFX verifies. Rejected: verified live on the simulator; POST /v1/auth issued a token and DFX showed the wallet's segwit address bound on Buy and Sell.
  • src/plugins/ramps/dfx/dfxSession.ts:118: the session token travels in the webview URL query. Rejected: session is the query parameter DFX's widget reads for this login, and the warning logged on a failed /auth holds DFX's error text, not the token.
  • src/plugins/ramps/dfx/dfxRampPlugin.ts:84: every quote approval signs and logs in again. Rejected: the signature is local with no user prompt, and each approval opens a new webview that needs its own session.

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