Integrate Open CryptoPay payment standard#1299
Open
reubenyap wants to merge 2 commits intocypherstack:stagingfrom
Open
Integrate Open CryptoPay payment standard#1299reubenyap wants to merge 2 commits intocypherstack:stagingfrom
reubenyap wants to merge 2 commits intocypherstack:stagingfrom
Conversation
ddbf4ba to
17c6dae
Compare
Adds support for the Open CryptoPay payment standard so users can pay at PoS systems like SPAR supermarkets in Switzerland by scanning a static QR code. Detects Open CryptoPay QR codes (URLs with a ?lightning=LNURL... param), decodes the bech32 LNURL, fetches payment details from the provider (e.g. DFX Swiss), lets the user pick a method/asset compatible with their wallet's coin, then forwards to the standard SendView pre-filled with the payment address and amount. After broadcast, the provider's /tx/ endpoint is notified with the tx ID and raw hex (best-effort) so the merchant can settle. A "Pay" shortcut is also added to the wallet view overflow menu for scanning an Open CryptoPay QR directly. Spec: https://github.com/openCryptoPay/landingPage Verified against DFX Swiss: https://github.com/DFXswiss/api New: - lib/utilities/lnurl_utils.dart — bech32 LNURL (LUD-01) decode - lib/services/open_crypto_pay/open_crypto_pay_api.dart — API client, Tor-aware - lib/services/open_crypto_pay/models.dart — response models - lib/pages/open_crypto_pay/open_crypto_pay_view.dart — method/asset picker - lib/pages/open_crypto_pay/open_crypto_pay_confirm_view.dart — summary + forward to SendView Modified: - lib/pages/send_view/send_view.dart — intercept QR before standard parser - lib/pages/send_view/confirm_transaction_view.dart — notify provider post-broadcast - lib/pages/wallet_view/wallet_view.dart — add "Pay" overflow menu button - lib/route_generator.dart — register OpenCryptoPayView route - lib/models/send_view_auto_fill_data.dart — carry OpenCryptoPay commit context Notes: - Existing QR handling is preserved — isOpenCryptoPayUrl only returns true when the URL has a ?lightning=LNURL... query param, which standard crypto URIs (bitcoin:, monero:, etc.) never have. - Only assets matching the current wallet's coin ticker are offered as selectable payment options. - After the client broadcasts the tx, we POST to the provider's /tx/ endpoint with tx ID (and raw hex where the wallet impl exposes it). This matches the spec's merchant-notification contract uniformly across Bitcoin/Monero/Ethereum/Solana; a notify failure is logged but does not unwind the already-broadcast transaction.
17c6dae to
ba0134e
Compare
- Move LNURL helper into open_crypto_pay/ since Stack does not support Lightning generally; OCP is its only consumer. - Reject non-https decoded LNURLs and callbacks (LUD-01 mandates HTTPS; also closes loopback SSRF and MITM via plain http). - Pin the callback host to the LNURL-decoded host so a malicious provider response cannot redirect the txid + raw hex elsewhere. - Apply a 15s connection timeout to the OCP HTTP calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
?lightning=LNURL...param), decodes the bech32 LNURL, fetches payment details from the provider (e.g. DFX Swiss), lets the user pick a method/asset compatible with their wallet's coin, then forwards to the standardSendViewpre-filled with the payment address and amount./tx/endpoint so the merchant-side can settle without waiting for on-chain confirmation.…) menu that scans and validates an Open CryptoPay QR directly.Spec: https://github.com/openCryptoPay/landingPage
Verified against DFX Swiss's implementation: https://github.com/DFXswiss/api
Files changed
New (all under
lib/services/open_crypto_pay/orlib/pages/open_crypto_pay/):lib/services/open_crypto_pay/lnurl_utils.dart— bech32 LNURL (LUD-01) decode and Open CryptoPay URL detection. Scoped to this folder because Stack does not support Lightning generally — OCP is currently the sole consumer.lib/services/open_crypto_pay/open_crypto_pay_api.dart— API client (payment details + transaction details + commit), Tor-aware, https-only, host-pinned.lib/services/open_crypto_pay/models.dart— response data models andOpenCryptoPayCommitcontext.lib/pages/open_crypto_pay/open_crypto_pay_view.dart— payment method/asset selection UI.lib/pages/open_crypto_pay/open_crypto_pay_confirm_view.dart— summary + forward toSendView.Modified:
lib/models/send_view_auto_fill_data.dart— adds optionalopenCryptoPayCommitfield carried through toConfirmTransactionView.lib/pages/send_view/send_view.dart— intercept Open CryptoPay QR codes in_scanQr()before the standard URI parser; passopenCryptoPayCommitintoConfirmTransactionView.lib/pages/send_view/confirm_transaction_view.dart— after a successful broadcast, best-effort notify the provider viaOpenCryptoPayApi.commit(...)with the txid and raw hex.lib/pages/wallet_view/wallet_view.dart— add "Pay" overflow menu button.lib/route_generator.dart— registerOpenCryptoPayViewroute.Notes
LnurlUtils.isOpenCryptoPayUrlonly returns true when the URL has a?lightning=LNURL...query param, which standard crypto URIs (bitcoin:,monero:, etc.) never have.methodlabel shown next to each option./tx/flows: (a) EVM / Bitcoin / Firo — submit raw signedhexto the provider and let the provider broadcast; (b) Monero / Solana / Tron / Cardano / Zano — broadcast locally, then submittx=<txid>. This integration always broadcasts locally via the standardSendViewand then calls/tx/withtx=<txid>(plushex=<raw>when the wallet exposes a raw serialization). For the flow-(b) chains this matches the spec. For Bitcoin / EVM / Firo it diverges — the client pre-broadcasts instead of deferring to the provider./tx/call is logged but does not unwind the send.Security
The API client hardens the network path against a malicious QR / compromised provider response:
/tx/endpoint are all rejected unless the scheme ishttpsand the URL has an authority. LUD-01 requires HTTPS; this also closes off MITM on plain http and SSRF into loopback.callbackURL returned in the payment details response must share its host with the LNURL-decoded URL. Without this, a compromised provider response could redirect the txid + raw hex to an attacker-controlled host. Verified compatible with DFX Swiss (both LNURL and callback are served fromapi.dfx.swiss).HttpClient.connectionTimeoutcovers connection setup only; a server that accepts and then stalls mid-body can still delay the request — improving this requires wrapping the HTTP layer.)Test plan
…) menu and scan a QR — same flowbitcoin:URI) — should be handled by the existing flow, not intercepted@chainIdsuffix should be stripped from the address/tx/commit fires (check logs) and the merchant-side reflects the paymenthttp://URL (hand-crafted test) — request should be rejected with an https error