WalletPay integration - #803
Draft
gemdev111 wants to merge 13 commits into
Draft
Conversation
A merchant QR carries the payment as a pay.walletconnect.com URL, as a WalletConnect pairing URI with a pay parameter, or as the gem://wc deep link wrapping that pairing URI. Unlike the other standards this one owns no scheme of its own, so it is matched by host, exactly or as a dotted suffix, and the payment id must carry the pay_ prefix so other pages on that host do not resolve.
The decoder's Payment lived only in Rust while gemstone re-declared its fields as PaymentWrapper, and a decoded link was flattened to a bare string, so neither app could tell which provider issued it. Payment is now typeshared as either a Request we can pay ourselves or a Link a provider settles, gemstone aliases it instead of redeclaring it, and each app maps it once at the boundary. Splitting the two cases also removes an empty address: scanning a provider link into the send recipient field used to blank the field with no error on iOS and paste the raw link on Android.
A payment link opened as a URL was consumed as a WalletConnect pairing attempt, because UrlAction checked WalletConnect first and knew nothing about payments, while the payment decoder checked payments first. The same URL meant different things depending on which door it arrived through. UrlAction now asks the payment decoder and takes only the delegated case, so both doors share one definition of a provider link and adding a provider updates them together. Neither app acts on it yet.
Sits behind developer mode while the flow is being proven, so it ships without a customer-facing entry point. The scan goes through UrlAction rather than the payment decoder: the decoder is built for an address field and treats any string as an address, so a pairing URI or a wifi code would have resolved to a nonsense payment. UrlAction reports what a code actually is, and anything that is not a payment link is refused.
Every sign and transaction request needs the name, url and icon of whoever asked, and only WalletConnect answers that with a session. TransactionAppMetadata replaces RequestingApp across core, gemstone and both apps, and the session types drop the WalletConnection prefix they never needed, so a request can be reviewed without a live connection behind it.
A bare app label next to the session metadata read as two different things. The transfer data, sign payload and bindings now call the field appMetadata, and the bindings field follows as app_metadata.
Parsing and decoding a request is protocol work with no session behind it, so it moves from gem_wallet_connect into gem_wallet_connect_request and the session crate re-exports it. Paying reuses the request layer without depending on sessions.
A payment from any provider resolves to the same typeshared models. Quoting yields PaymentQuotes: the merchant plus one PaymentQuote per route, each carrying its amount, an optional personal data url and the provider option it came from as an opaque payload the caller hands back. A settled payment reports a PaymentResult, and TransactionPaymentMetadata ties a recorded transaction to its payment and merchant so both apps can track and render it.
The gateway quotes a payment into routes and the wallet executes one: quote, collect data if the route demands it, fetch the wallet rpc actions, confirm with the signed results, follow the status. The service is stateless, the chosen quote rides with the caller, and gateway failures map to typed errors read from the response code so the apps never see a raw body.
Remote aliases keep one definition per payment model instead of a duplicate for the bindings, and the uniffi object hands an app the payment step, the actions for a chosen quote, confirm, cancel and status.
The sign message payload carried a WalletConnect session, so a review sheet could only render for a live connection. It now carries the requesting app metadata and its own request id, the scene view model reads only the payload, and the transfer data factory moves out of the signer so any caller can build the same transfer data.
gemdev111
force-pushed
the
feature/payment-links
branch
from
July 30, 2026 20:23
e68cac3 to
f0d713d
Compare
The generic transaction input now carries app metadata, and the short name helper takes the name itself, so the Kotlin call sites follow and the session mapping that nothing else used goes away. Cargo records the two new crates at the workspace version.
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.
No description provided.