Skip to content

fix(pp): single-URL Add Provider + drop pubkey storage + link out to KYC#21

Merged
AquiGorka merged 2 commits into
mainfrom
fix/pp-add-input-and-kyc-link
Jun 4, 2026
Merged

fix(pp): single-URL Add Provider + drop pubkey storage + link out to KYC#21
AquiGorka merged 2 commits into
mainfrom
fix/pp-add-input-and-kyc-link

Conversation

@AquiGorka

@AquiGorka AquiGorka commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

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-pubkey input is gone. Pubkey is extracted from the URL at call-time via a 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 returns per-PP entityStatus + kycSubmissionUrl. PrivateChannelsState bumped to v4; per-account sessions[accountId] 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-linked PRs

Test plan

  • CI green (fmt + lint)
  • Add Provider with a URL ending in /G… (56-char G-address) succeeds
  • Add Provider with a URL lacking the G-address path segment is rejected with the inline error
  • On connect, the sheet shows "Connected — not authorized yet." with a Submit KYC link that opens provider-console/#/entities/register?provider=<pp> in a new tab
  • Pre-existing stored PPs with no pubkey path segment surface the stale-URL notice + Remove
  • Spec 03 passes against this build (covered in local-dev cross-link)

AquiGorka added 2 commits June 4, 2026 13:19
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 AquiGorka merged commit 325fc41 into main Jun 4, 2026
2 checks passed
@AquiGorka AquiGorka deleted the fix/pp-add-input-and-kyc-link branch June 4, 2026 17:05
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
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