feat(dashboard): add litkey payment entrypoint#395
Conversation
| return item && (item.wallet_address || item.address || item.name || ''); | ||
| } | ||
|
|
||
| function pickAccountFundingWallet(wallets) { |
There was a problem hiding this comment.
@GTC6244 is this the right way to pick their master wallet?
There was a problem hiding this comment.
@glitch003 - looks like you want the billingWalletAddress, not the master wallet, in this case ? I'm going to Claude trace through to see.
There was a problem hiding this comment.
A bit wordy, but here's Claude's confirmation of the flow:
Answer to the question
Yes — the question is appropriate, and the answer is to use the billing wallet. I validated the full flow and fixed the code.
Why it matters (the data flow)
The pay-with-LITKEY page is given a wallet via ?wallet=…, and the payments backend maps it directly to a Stripe customer with no resolution step:
- preview_customer / find_summary_by_wallet → find_by_wallet does metadata['wallet_address'] == (
lit-billing-core/src/customer.rs:46). - The on-chain listener credits the same way (chain.rs:695).
So the?wallet=value must be the billing wallet — the address the Stripe customer is keyed on. The authoritative source is the contract’s getBillingWalletAddress(apiKeyHash), which is set at account creation and preserved across convert-to-ChainSecured and admin-wallet rotation (CPL-313/CPL-324). That’s exactly what the server uses internally (accounts::get_billing_wallet_address).
The bug the question caught
The old resolveLitkeyPaymentWallet returned getChainSecuredWallet() for ChainSecured sessions — the current admin/owner wallet. After a conversion or ownership transfer, that wallet diverges from the billing wallet, so the payment page would find no customer and credits would be stranded. The API-key branch picked the “Account Master Wallet” — coincidentally correct (managed accounts never rotate, so getBillingWalletAddress falls back to the admin wallet = AMW), but the wrong concept.
Changes
lit-static/account_config_view_abi.js— added the getBillingWalletAddress view ABI entry.lit-static/core_sdk.js— added getBillingWalletAddress({ apiKey }), reading the on-chain view in sovereign mode (mirrors the server). No signer/popup needed — it uses the read provider.lit-static/dapps/dashboard/billing.js— resolveLitkeyPaymentWallet now:
- Sovereign/ChainSecured: reads the billing wallet on-chain via client.getBillingWalletAddress(...) instead of the connected wallet.
- API-key mode: keeps the AMW path (provably == billing wallet for managed accounts) with a comment explaining the invariant.
- Error messages now say “billing wallet”.
plans/lit-payments-app.md— wording updated to “billing wallet”.
All three JS files pass node --check. Note: no changes to Rust/Rocket routes, so the k6 client-check gate isn’t triggered.
One thing worth flagging: the API-key branch relies on the invariant that managed accounts never rotate their admin wallet. If a converted (ChainSecured) account is ever accessed via a still-active raw API key, that branch would return the AMW, which may differ from the billing wallet — but in practice such accounts authenticate via wallet (sovereign), which is now handled correctly.
Use window.open with _blank/noopener so the dashboard isn't navigated away from when a user starts a LITKEY payment, matching the documented user flow. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… wallet The pay-with-LITKEY page maps its ?wallet= param straight to a Stripe customer via metadata.wallet_address with no resolution, so the prefilled address must be the account's billing wallet. The billing wallet is set at account creation and preserved across convert-to-ChainSecured and admin-wallet rotation (CPL-313/CPL-324), so the connected ChainSecured wallet can diverge from it — sending the login wallet would strand credits on a customer that doesn't exist. Read the authoritative billing wallet on-chain via getBillingWalletAddress in sovereign mode (mirrors accounts::get_billing_wallet_address). API-key mode keeps the Account Master Wallet path, which provably equals the billing wallet for managed accounts (getBillingWalletAddress falls back to the admin wallet). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Pay with LITKEY for 25% offoption inside the dashboard Add Funds modalhttps://payments.litprotocol.com/payWithLitkey?wallet=…with the account funding wallet prefilledor pay with credit carddividerConfig note
For a 25% LITKEY buyer discount, payments should run with:
Test Plan
node --check billing.jsnode --check app.jsgit diff --checkcargo +1.91 fmt --all -- --checkcargo +1.91 test --locked --all-targets -qcargo +1.91 clippy --locked --all-features -- -D warningsReview notes