feat: add crypto payment options to dashboard Stripe modal (CPL-274)#314
Merged
GTC6244 merged 1 commit intoMay 21, 2026
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Updates the dashboard “Add Funds” modal to use Stripe’s Payment Element so enabled payment methods (including crypto) can be used in a single flow, and adds return-handling for redirect-based methods.
Changes:
- Replaced the Card Element UI with a two-step modal (amount → payment) and a Payment Element mount point.
- Reworked the billing flow to create a PaymentIntent on “Continue” and confirm via
stripe.confirmPayment(..., redirect: 'if_required')on “Pay”. - Added
handleBillingReturn()and wired it into the auth-ready callback to confirm redirect-based payments on return.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
lit-static/dapps/dashboard/index.html |
Updates modal markup for a two-step flow and Payment Element container/buttons. |
lit-static/dapps/dashboard/billing.js |
Implements Payment Element flow, confirm logic, and redirect-return processing. |
lit-static/dapps/dashboard/app.js |
Calls handleBillingReturn() after auth is ready so redirect returns are processed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Switch the Add Funds modal from Stripe Card Element to Payment Element, which auto-renders any payment methods enabled on the Stripe account (card and supported crypto: USDC, USDP, ETH, SOL). Backend billing endpoints already support crypto, so this is frontend-only. Flow: user picks an amount → Continue creates a PaymentIntent and mounts the Payment Element with its client_secret → Pay calls stripe.confirmPayment with redirect: 'if_required'. Card stays inline; crypto methods redirect to the wallet/Stripe-hosted flow and return to the dashboard with ?payment_intent=...&redirect_status=...; the new handleBillingReturn() picks that up on auth-ready, calls confirm_payment, and refreshes the balance. Carries forward the session-protection patterns the rest of billing.js adopted in CPL-285/286: every handler captures billingAuthKey() up front, uses ensureAbortController(), re-checks the captured key after each await, attaches walletAuthHeader via billingRequestOptions in sovereign mode, swallows AbortError, and evicts the wallet-auth cache on auth errors. Also primes the wallet-auth signature when the modal opens in sovereign mode so the user only sees one popup per session. Payment Element is configured with fields.billingDetails.address='never' so the address form is never rendered; confirmPayment passes a default billing country in payment_method_data so card AVS still works. handleBillingReturn treats Stripe's `processing` redirect_status as a non-error and shows "credits will appear once settled"; only `failed`, `canceled`, and `requires_*` surface as errors. The confirmPayment-backend-failure fallback now shows the pending-credit message via the top-level status banner so closeBillingModal() can't swallow it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
73da663 to
ba9fcb6
Compare
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
Switches the Add Funds modal in the dashboard from Stripe's Card Element to the Payment Element, which auto-renders whichever methods are enabled on the Stripe account (card + crypto: USDC, USDP, ETH, SOL). Backend billing endpoints already support crypto — this is a frontend-only change.
Linear: CPL-274
What changed
lit-static/dapps/dashboard/index.html— Billing modal split into a two-step flow: amount selector + Continue (step 1), then Payment Element mount point + Back/Pay (step 2).stripe-card-elementrenamed tostripe-payment-element.lit-static/dapps/dashboard/billing.js— Rewrote the payment flow. Continue creates the PaymentIntent and mountselements({ clientSecret }).create('payment'). Pay callsstripe.confirmPayment({ elements, confirmParams: { return_url }, redirect: 'if_required' })— card stays inline, crypto redirects to the wallet flow. Exports newhandleBillingReturn()that detects?payment_intent=…&redirect_status=…on page load, calls the backendconfirm_paymentendpoint, and strips the query params.lit-static/dapps/dashboard/app.js— Imports and invokeshandleBillingReturn()from thesetOnAuthReadycallback so the crypto-redirect return is processed once the API key is loaded.Why
The existing modal used
elements.create('card')+confirmCardPayment(), which is card-only and doesn't surface Stripe's crypto options. The Payment Element approach is a minimal frontend refactor that unlocks card + crypto in one UI — no backend changes needed.Pre-Landing Review
No blocking issues found.
return_urlis built fromwindow.location.origin + window.location.pathname(no user input). Status display usestextContent(no XSS surface). No new credentials/tokens exposed.handleContinue,handlePay, andhandleBillingReturnall wrap network calls in try/catch.confirmPayment-backend failure preserves the prior "card charged, credit pending" fallback. URL params stripped beforeconfirm_paymentcall so reloads don't retrigger.finally); amount change mid-flow (Back fully unmounts the element, next Continue creates a fresh intent); repeatedhandleBillingReturncalls (URL cleaned first, subsequent fires no-op); Stripe account without crypto enabled (Payment Element gracefully shows card only).Test plan
Requires a dev backend with Stripe test keys and a Stripe account that has crypto payment methods enabled.
4242…→ stays inline → balance updates → modal closeshandleBillingReturncallsconfirm_payment→ overview shows "Credits added" → balance refreshes?payment_intent=…silently strips the params without processing (no crash, no retry loop)Notes
node --checkpasses on both JS files.docs/management/crypto.mdxalready describe the intended user flow and reference the Payment Element approach this PR implements.🤖 Generated with Claude Code