Skip to content

WalletPay integration - #803

Closed
gemdev111 wants to merge 27 commits into
mainfrom
feature/payment-links
Closed

WalletPay integration#803
gemdev111 wants to merge 27 commits into
mainfrom
feature/payment-links

Conversation

@gemdev111

@gemdev111 gemdev111 commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@gemdev111 gemdev111 changed the title Decode payment links into a model both apps share WalletPay integration Jul 29, 2026
@gemdev111
gemdev111 force-pushed the feature/payment-links branch from e68cac3 to f0d713d Compare July 30, 2026 20:23
ApprovalData is an ERC-20 allowance, not a swap concept, and it was
already used by yielder, Tron's signer and preload, contract_call_data
and transaction_input_type. Move it to primitives::approval_data and
give gemstone a models/approval module for its FFI record.
The RPC decoders and the session half are two independent halves of the
crate, and a payment provider needs only the first. Gate them as
`request` and `session`, with base64 and url following their half, so a
consumer that only decodes requests does not build the session code.
@gemdev111
gemdev111 force-pushed the feature/payment-links branch 4 times, most recently from 7d7cabf to f5e6e76 Compare August 4, 2026 11:35
SignMessage and the per-chain transaction payloads are what a wallet
signs, and with payments a second producer speaks them. Move them to
primitives::signing and drop the WalletConnect prefix, so the neutral
payment action does not name a transport: WalletConnectTransaction
becomes SignableTransaction, the name iOS already uses for it.
A scanned or opened payment link decodes to Payment::Link(PaymentLink),
carrying the provider and the id only that provider can read. The quote,
outcome and merchant models are typeshared so both apps read one
definition, and a paid transaction records which provider settled it.
A PaymentProvider trait and a registry that routes a link to the one
provider that can settle it, so every layer above stays provider
agnostic. WalletConnect Pay is the first provider, living inside the
crate the way swapper and yielder hold theirs: it turns the gateway's
JSON-RPC into the four actions a wallet can be asked to perform, and
reads results back by position.
One GemPaymentService object over the neutral registry, and PaymentError
crossing the FFI as itself through a remote enum, the way SwapperError
already does, so the apps localize one closed set of failures.
The sheets a signing request can ask for, and nothing more: sign a
message, sign a transaction, send one. WalletConnect and payments both
drive the same three, so the payload types, the transfer-data factory
and the simulator live in one service rather than in either feature.
The app-side view of a payment provider: the gateway client over the
gemstone object, the four actions a payment can ask for, and the two
screens only a payment has. Everything above it speaks PaymentAction,
never the gateway.
TransferExecutor, TransferTransactionProvider and the types they need
are UI-free services, but they lived in a feature package, so Payments
would have to depend on Features/Transfer, the app's only
feature-to-feature dependency. Move them to FeatureServices with their
TestKit and tests, alongside SwapService and EarnService.
Resolve a link to its quotes, let the buyer pick one, then run the
actions the provider returned: signatures first, so a rejection never
costs gas, and approvals broadcast silently and wait to be mined the way
swap does. Results go back to the provider by position, and a confirm
that fails leaves the payment pending for its status to settle.
Scanned and opened payment links reach the payment manager instead of a
no-op, the pending payment is tracked by the transaction state job, and
PaymentError is localized as the buyer's failure, not the gateway's.
The generated payment models plus the extensions that map a decoded link
and an approval across the FFI boundary.
Merchant, payment expiry and the payment failure copy, in every language
file, with the generated iOS and Android outputs.
The URL decoder resolves a payment link into the shared model, the
scanner and the deep-link route hand it to the payment manager, and the
app metadata a signing request carries no longer comes from a live
WalletConnect session.
PaymentsTests was reachable only from the scheme, so the plan CI runs
would have skipped it silently.
The transfer and sign-message sheets are the wallet's own approval screens,
not WalletConnect's: payments drive them too. SigningRequestService now owns
SigningRequestSheetType and the SheetPresenter that serializes presentation,
so WalletConnectorSheetType is only the connection proposal and every host
shares one dismissal gate.
@gemdev111
gemdev111 force-pushed the feature/payment-links branch from f5e6e76 to a8978ba Compare August 4, 2026 11:55
SheetPresenter, its callback and the cancellation error move to Primitives:
none of them touch UI or localization, so every feature can host a sheet
without depending on SigningRequestService. The per-feature presenter
wrappers collapse into conditional conformances, the payment protocols move
next to the types that implement them, and SignableTransaction maps the
Gemstone Ethereum payload at the boundary instead of exposing it. Removes
21 imports left dead by the move.
WalletConnect built ConfirmParams from a SignableTransaction inline. The
payment flow needs the same mapping, so move it to gemcore as a shared
extension and have WCRequest delegate to it.
The message preview, payload details sheet and full message sheet were
internal to the bridge feature. Move them to ui alongside the simulation
payload content so the payment flow can present the same review.
The gallery path reduced every scanned code to a recipient address, so a
payment link decoded to nothing and reported an unreadable image. Pass the
raw text through as the camera path already does, and keep the address as
display text only. Recipient codes also keep their amount and memo now.
Add the payment feature: quote selection, the compliance capture web view,
permit signing and token approval, driven from a single view model and
reusing the confirm screen for anything that broadcasts.

The web view speaks the iOS message handler shape, so a shim exposes it and
forwards window messages to the Android bridge. Payment links reach the app
through the wallet scanner and a deep link on the payment host.
A relayed payment is recorded under its payment id before a chain hash
exists. Poll the gateway for that hash, then either rename the record or,
when the indexer already delivered the same transaction, drop the
placeholder and adopt the existing row.

Stay pending until a hash arrives so the poller keeps checking, and hand the
adopted record back so the polling job finishes on it instead of writing the
deleted row again at timeout.
A payment has no recipient address, so the activity row read "To" with
nothing after it and the details screen offered an address link that led
nowhere. Take the merchant from the payment metadata for both, and give the
details screen a destination that renders as plain text.
Any unrecognised failure became a fee calculation error with the cause
discarded, so the screen reported an estimation problem for faults that had
nothing to do with fees. Log the throwable where it is swallowed.
@gemdev111 gemdev111 closed this Aug 5, 2026
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