fix(pp): single-URL Add Provider + drop pubkey storage + link out to KYC#21
Merged
Conversation
Three coupled rewrites correcting #20's off-spec choices. ### 1. Single URL input The Add Provider form takes ONE field — the URL — and validates that its last path segment is a 56-char Stellar G-address. The `#provider-pubkey` input is gone. Pubkey is extracted from the URL at call-time via the new `extractPpPubkeyFromUrl(url)` helper in `services/pp-url.ts`. Persisted shape reverts to `{ id, name, url }` (plus per-account `sessions`). ### 2. PP-aware verify body + per-PP session `PrivacyProviderClient.postAuth(signedChallenge, ppPublicKey)` posts both fields so SEP-10 verify can return a per-PP `entityStatus` + `kycSubmissionUrl`. `PrivateChannelsState` bumped to v4; per-account `sessions[accountId]` now carries `{ token, expiresAt, entityStatus, kycSubmissionUrl }`. ### 3. KYC link-out `submit-entity-kyc` background handler + popup API gone. When `session.entityStatus !== "APPROVED"` and `session.kycSubmissionUrl !== null`, the channel-picker sheet renders an `<a target="_blank">` pointing at the provider-console KYC route the operator configured (server-side `payment_providers.kyc_submission_url`). ### Stale-URL detection Persisted PPs whose URL has no pubkey path segment surface a per-row "Provider <label> needs re-adding — URL format updated." with a one-click Remove. No auto-delete. No backfill (no discovery endpoint exists). ### Cross-references Depends on provider-platform's PP-aware SEP-10 verify pipeline + the new `pp_entity_approvals` table.
AquiGorka
added a commit
to Moonlight-Protocol/local-dev
that referenced
this pull request
Jun 4, 2026
…p-dist default (#111) ## Summary Keeps Spec 03 (recording rig's private-transfer demo) green against the corrected wallet + PP-aware provider-platform. ### Spec 03 rewrite — two-pass per user Each user (Bob, then Alice) runs setup TWICE in their own context. Pass 1 runs the full setup (browser-wallet onboard → Freighter onboard + local network → channel → add provider + connect) then `followKycLinkOut`: clicks the "Submit KYC" anchor that the corrected wallet renders, drives provider-console's `#/entities/register?provider=<pp>` route end-to-end (Connect Wallet → Stellar Wallets Kit modal → Freighter → signMessage approve → submit), then tears the context down. Pass 2 launches a fresh context, redoes setup (same mnemonic = same account = `entityStatus=APPROVED` for the PP from pass 1, so the KYC link isn't surfaced), and runs the remaining beats (receive / deposit / send / balance / withdraw / public toggles). `addAndConnectProvider` is split into `addProviderAndConnect` (no KYC follow) + `followKycLinkOut` so pass 1 can drive the KYC link-out explicitly while pass 2 just connects and moves on. ### Freighter warm-up fixture `recording/playwright/fixtures/freighter-setup.ts` (new). After `setupFreighterAccount` imports the user's secret it calls `addLocalNetwork(page)` (or `switchToTestnet`) so Freighter is in the same warmed-up state that the verification rig's `setupUserContext` leaves it in before its own `withWalletApproval` call sites fire. Without that network step the signMessage popup opens onto Freighter's Welcome screen and the approve UI never renders. ### `BROWSER_WALLET_PATH` default `recording/playwright/fixtures/wallet-context.ts` now defaults `BROWSER_WALLET_PATH` to a `__dirname`-relative path mirroring `playwright.config.ts`. Previously the default was `~/repos/browser-wallet/dist`, pinning every run to the user's primary repo regardless of which clone the rig was launched from. ### Other touchpoints - `playwright/fixtures/freighter.ts`: `SEL_APPROVE_BUTTON` now matches Freighter v5.39+ data-testids (`grant-access-connect-button`, `sign-message-approve-button`, etc.) before the text fallbacks. - `setup-pp.ts`: registers each seeded PP with a `kycSubmissionUrl` pointing at `provider-console/#/entities/register?provider=<pp>` so the recording stack mirrors what an operator configures. - `recording/setup-recording-keys.ts` + `recording/playwright/helpers/run-env.ts`: expose Alice/Bob secret keys so `setupFreighterForKyc` can import them. ### Smoke run `RUN_ID=phase4-smoke npx playwright test --project=chromium --grep "03 —"` → **1 passed (11.0m)**, driving every beat including both Freighter signMessage popups. ## Cross-linked PRs - provider-platform: Moonlight-Protocol/provider-platform#110 - browser-wallet: Moonlight-Protocol/browser-wallet#21 ## Notes - 5 pre-existing lint errors in `setup-pp.ts`, `playwright/fixtures/freighter.ts`, `recording/recording-keys.ts` (npm: import prefixes, sloppy import, unused `page` param on a pre-existing fixture). All predate this branch. The repo's `fmt-lint.yml` CI doesn't lint `recording/` or `playwright/` paths so they don't gate the merge; not touched here to keep the change scoped. - `deno.json` has no version field in this repo, so no deno.json patch-bump applies. (provider-platform's auto-tag is the version-driven release; this repo has no equivalent.) ## Test plan - [ ] CI green (fmt-lint matrix on testnet / lifecycle / e2e dirs — recording/playwright untouched) - [ ] Spec 03 passes locally end-to-end against the cross-linked browser-wallet build - [ ] Pass 2's wallet shows the provider as Connected without a "Submit KYC" anchor (entityStatus APPROVED from pass 1)
AquiGorka
added a commit
to Moonlight-Protocol/provider-platform
that referenced
this pull request
Jun 4, 2026
## Summary
SEP-10 verify becomes PP-scoped. The wallet posts `ppPublicKey`
alongside the signed challenge; the response carries per-PP
`entityStatus` + the operator-configured KYC submission URL for that PP.
A wallet APPROVED on PP-A no longer appears APPROVED on PP-B.
### Schema changes (migration `0017_pp_aware_entity_status_and_kyc_url`)
- `payment_providers.kyc_submission_url` (text, nullable) — per-PP KYC
URL surfaced to the wallet when the submitter is not yet APPROVED.
- `pp_entity_approvals` (new table): `(pp_public_key, account_pubkey)` →
`EntityStatus` + timestamps, unique on the pair. Sole source of truth
for per-PP approval state.
- `entities.status` — **dropped**. Eliminates the dual-write that the
old global column would have required.
### Pipeline changes
- `requestSchema` for POST `/v1/stellar/auth` requires `ppPublicKey:
z.string().min(1)`.
- `responseSchema` carries `{ jwt, entityStatus, kycSubmissionUrl }`.
- `P_UpdateChallengeDB` returns the narrow
`ContextWithJWTAndPpPublicKey` (just `ppPublicKey`, not the full request
body — principle of least information).
- New `P_AttachEntityStatus` looks up the per-PP approval row +
`pp.kyc_submission_url` and fills the response shape.
- POST `/v1/entities` writes/promotes a per-PP approval row (UNVERIFIED
→ APPROVED) instead of mutating `entity.status`.
- `add-bundle.process` gates on the per-PP approval row.
### Test
Full suite green locally (`deno task test`: 200 passed).
## Cross-linked PRs
- browser-wallet:
Moonlight-Protocol/browser-wallet#21
- local-dev: Moonlight-Protocol/local-dev#111
## Test plan
- [ ] CI green
- [ ] Migration applies cleanly (drops `entities.status`, adds
`kyc_submission_url` + `pp_entity_approvals`)
- [ ] SEP-10 verify call with `ppPublicKey` returns `{jwt, entityStatus,
kycSubmissionUrl}`
- [ ] POST `/v1/entities` creates a per-PP approval row, not an
`entity.status` write
- [ ] Bundle submit rejects when no per-PP approval row exists for the
submitter
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
Corrective on #20 — three coupled rewrites bringing the Add Provider flow + storage shape + KYC handling back on-spec.
1. Single URL input
The Add Provider form takes ONE field — the URL — and validates that its last path segment is a 56-char Stellar G-address. The
#provider-pubkeyinput is gone. Pubkey is extracted from the URL at call-time via a newextractPpPubkeyFromUrl(url)helper inservices/pp-url.ts. Persisted shape reverts to{ id, name, url }(plus per-accountsessions).2. PP-aware verify body + per-PP session
PrivacyProviderClient.postAuth(signedChallenge, ppPublicKey)posts both fields so SEP-10 verify returns per-PPentityStatus+kycSubmissionUrl.PrivateChannelsStatebumped to v4; per-accountsessions[accountId]carries{ token, expiresAt, entityStatus, kycSubmissionUrl }.3. KYC link-out
submit-entity-kycbackground handler + popup API gone. Whensession.entityStatus !== "APPROVED"andsession.kycSubmissionUrl !== null, the channel-picker sheet renders an<a target="_blank">pointing at the provider-console KYC route the operator configured (server-sidepayment_providers.kyc_submission_url).Stale-URL detection
Persisted PPs whose URL has no pubkey path segment surface a per-row "Provider <label> needs re-adding — URL format updated." with a one-click Remove. No auto-delete. No backfill (no discovery endpoint exists).
Cross-linked PRs
Test plan
/G…(56-char G-address) succeedsprovider-console/#/entities/register?provider=<pp>in a new tab