Skip to content

feat: add Paykit server accounts#630

Merged
jvsena42 merged 19 commits into
masterfrom
codex/paykit-watch-only-accounts
Jul 24, 2026
Merged

feat: add Paykit server accounts#630
jvsena42 merged 19 commits into
masterfrom
codex/paykit-watch-only-accounts

Conversation

@ben-kaufman

@ben-kaufman ben-kaufman commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Description

This PR builds on #620 to add Paykit Server watch-only accounts:

  • Presents a dedicated watch-only consent step before the normal Pubky authorization screen.
  • Requires x-bitkit-claim=watch-only-account-v1 and the exact /pub/paykit/v0/bitkit/server/:rw capability, rejecting missing, unknown, duplicate, or mismatched companion parameters.
  • Uses Paykit companion authorization and fails closed if companion delivery or normal authorization fails.
  • Allocates monotonic BIP84 accounts, reuses the same incomplete account on retry, and exports the exact versioned 84-byte claim payload.
  • Automatically names new accounts from the requesting service; users can rename them later from Settings.
  • Hides Settings → Advanced → Server Accounts until the experimental Paykit UI is enabled.
  • Persists and backs up account metadata, serializes lifecycle and reconciliation changes, and supports disabling or restoring LDK tracking without deleting wallet state.
  • Configures additional-wallet scanning and the rolling 1,000-address lookahead.
  • Deterministically derives the receiver Noise key from the wallet's BIP39 seed using domain-separated HKDF-SHA256 with version, network, and receiver-path context; securely caches and verifies it so the wallet seed remains the only backup required.
  • Reuses the derived Noise key across authentication and restarts, and publishes only its receiver marker when live session access becomes available.
  • Updates to Paykit 0.1.0-rc37, LDK Node 0.7.0-rc.57, and Bitkit Core 0.4.2; Bitkit Core now supplies trusted extended-public-key serialization, so Base58Swift and its BigInt dependency are no longer required.

The relay claim contains only the versioned account index, address type, and serialized xpub. Local names and tracking state are not disclosed. Ordinary Pubky Auth remains unchanged.

References:

QA Notes

This slice implements ADR 0001's watch-only-account-v1 claim, which is the currently agreed protocol. ADR 0002's proposed watch-only-account-service-v1 delegation flow has not been agreed and is not part of the current implementation.

Reviewers can exercise the complete Bitkit-side setup and account lifecycle with this disposable test request:

pubkyauth://signin?caps=/pub/paykit/v0/bitkit/server/:rw&relay=https://httprelay.pubky.app/inbox/&secret=e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3s&x-bitkit-claim=watch-only-account-v1

Enable Paykit UI, then scan or paste the URL. It exercises watch-only consent, normal Pubky authorization, account allocation and xpub export, companion-claim delivery followed by AuthToken delivery, local activation, and Server Accounts management. The xpub can be copied from the account details and used for external address derivation, funding, restart discovery, spending, and tracking disable/re-enable testing.

The request secret is public, so this URL must only be used with a disposable regtest wallet. A Paykit Server listener or receiver harness is still required to verify requester-side relay polling, decryption, and signature verification. A staging deployment is intended once Paykit Server runtime/listener composition is available.

Manual Tests

  • Enable Paykit UI → Settings → Advanced: Server Accounts is visible; disable Paykit UI: it is hidden.
  • Scanner/paste → use the disposable setup request above → approve watch-only sharing → complete normal Pubky authorization: the account becomes active.
  • Copy the xpub from Server Accounts → externally derive a nonzero receive address → send funds → restart Bitkit: the additional-wallet full scan discovers the funds.
  • Spend the externally received funds from Bitkit.
  • Settings → Advanced → Server Accounts → disable and re-enable tracking: the same account and balance return without allocating another account.
  • Missing, duplicate, unknown, or mismatched companion parameters/capability are rejected; ordinary Pubky Auth remains unchanged.

Automated Checks

  • WatchOnlyAccountServiceTests.swift
  • PubkyAuthApprovalSheetTests.swift
  • PubkyAuthRequestTests.swift
  • PaykitReceiverNoiseKeyStoreTests.swift
  • Paykit rc37 simulator build succeeded against LDK Node rc.57.
  • The exact E2E app-build mode (DEBUG E2E_BUILD) succeeds with the notification target's watch-only/localization membership dependencies.
  • The iOS and Android receiver-key tests share an independently verified derivation vector and cover persistence, reuse, invalid caches, and wrong-seed fail-closed behavior.
  • Post-delivery normal-auth failure, retry after delivery, restart retry, activation, and wallet Paykit regressions are covered by the selected suites.
  • 101 selected watch-only, Paykit, Pubky Auth, endpoint, and receiver-key tests passed after rebase.
  • SwiftFormat and git diff --check passed.

@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Paykit Server watch-only accounts. The main changes are:

  • Strict parsing for the watch-only companion claim and capability.
  • Companion authorization with tracked setup and retry states.
  • Monotonic account allocation, backup, restore, and reconciliation.
  • LDK scanning and tracking controls for additional wallet accounts.
  • Deterministic receiver Noise-key derivation and persistence.
  • Settings screens for managing account names and tracking.

Confidence Score: 5/5

This looks safe to merge.

  • The updated delivery-error handling keeps the account tracked after the documented post-delivery authorization failure.
  • No blocking issue remains in the reviewed changes.

Important Files Changed

Filename Overview
Bitkit/Services/PubkyService.swift Adds companion authorization and preserves account tracking for the documented post-delivery authorization failure.
Bitkit/Services/WatchOnlyAccountService.swift Adds account allocation, persistence, authorization lifecycle, backup restoration, and tracking reconciliation.
Bitkit/Services/LightningService.swift Integrates watch-only accounts with LDK startup, scanning, address lookahead, and tracking controls.

Reviews (3): Last reviewed commit: "fix: derive Paykit Noise key from wallet..." | Re-trigger Greptile

Comment thread Bitkit/Services/PubkyService.swift
@ben-kaufman
ben-kaufman marked this pull request as draft July 15, 2026 21:23
@ben-kaufman
ben-kaufman marked this pull request as ready for review July 16, 2026 15:19
@ben-kaufman
ben-kaufman marked this pull request as draft July 20, 2026 11:18
@ben-kaufman
ben-kaufman marked this pull request as ready for review July 20, 2026 11:48
@piotr-iohk

Copy link
Copy Markdown
Collaborator

Same review notes as the companion Android PR: synonymdev/bitkit-android#1084 (comment)

(Please apply the same UI gating / testing / ADR questions there.)

CI / merge

  • Merge conflicts with the base branch (codex/paykit-rc33-receivers) — please rebase/resolve.
  • E2E build-local / build-staging currently fail: LightningService references WatchOnlyAccountRecord from the BitkitNotification target where that type isn’t in scope. Please fix so CI builds again.

@ben-kaufman
ben-kaufman force-pushed the codex/paykit-watch-only-accounts branch from 67d11d0 to 3d5c9be Compare July 22, 2026 10:15
Base automatically changed from codex/paykit-rc33-receivers to master July 22, 2026 11:10
@ben-kaufman
ben-kaufman force-pushed the codex/paykit-watch-only-accounts branch from 990db23 to e4a5c92 Compare July 22, 2026 11:39

Copy link
Copy Markdown
Contributor Author

Thanks — the corresponding iOS items are now addressed on the latest commit.

UI gating

Settings → Advanced → Server Accounts is now only visible when Enable Paykit UI is enabled.

Testing the flow

Reviewers can exercise the Bitkit-side flow using this disposable request:

pubkyauth://signin?caps=/pub/paykit/v0/bitkit/server/:rw&relay=https://httprelay.pubky.app/inbox/&secret=e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3s&x-bitkit-claim=watch-only-account-v1

Enable Paykit UI, then paste or scan it. This exercises the watch-only consent, normal Pubky authorization, account allocation/xpub export, both relay deliveries, local activation, and Server Accounts UI.

The xpub can then be copied from the account details sheet and used to test external address derivation, funding, restart discovery, spending, and disabling/re-enabling tracking. Because the request secret is public, this should only be done with a disposable regtest wallet.

The missing part is requester-side polling, decryption, and signature verification; that requires a Paykit Server listener or receiver harness.

Server staging

The intended next server-side QA step is to deploy Paykit Server on staging once runtime/listener composition exists. There is no staging endpoint yet, and that work is outside these mobile PRs.

Retry and activation behavior

The same post-delivery behavior is covered on iOS:

  • Paykit's documented post-delivery AuthorizationFailure leaves the account authorizing and tracked.
  • Retries and retries after restart reuse the same account index, xpub, and payload.
  • Pre-delivery failures return newly pending accounts to an unloaded state.
  • Activation is protected from caller cancellation.
  • A local activation failure after remote delivery is recovered by retrying the same combined authorization and activating the same account.

Protocol version

ADR 0001's watch-only-account-v1 is the currently agreed protocol and is intentionally implemented here. ADR 0002's proposed watch-only-account-service-v1 delegation flow has not been agreed and is not part of the current implementation.

CI and regression

The branch was rebased and is currently mergeable. The notification-target failure was fixed through the target membership exclusion list; build-local and build-staging now pass. The selected 101 watch-only, Pubky Auth, endpoint, receiver-key, and wallet Paykit regression tests pass.

The existing pubky_paykit E2E fixture issue uses outdated pre-made profiles and reproduces on the base PR, so it is inherited CI noise rather than a regression from this watch-only change.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Same retest notes as the companion Android PR: synonymdev/bitkit-android#1084 (comment)

iOS-specific bits already covered there: Enter-manually gap for pubkyauth, timeout → Incomplete setup → retry OBS, and the icon/title/copy parity nits.

@ovitrif
ovitrif requested a review from piotr-iohk July 23, 2026 20:04
@piotr-iohk

Copy link
Copy Markdown
Collaborator

Retested after the alignment fixes. Looks good to approve on my side.

Verified:

  • Settings row icon / title casing aligned
  • Server Accounts header burger present
  • pubkyauth limited to main scan (Send paste / Enter manually reject as intended)
  • Disposable watch-only setup URL → consent → authorize → Server Accounts still works

No remaining iOS blockers from this pass. Android still has a home-Scan gating bug (home Scan is modeled as Send, so pubkyauth is rejected there); noted on the companion PR.

@jvsena42 jvsena42 added this to the 2.5.0 milestone Jul 24, 2026

@jvsena42 jvsena42 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simulator.Screen.Recording.-.iPhone.17.-.2026-07-24.at.10.05.22.mov

Approved with some nits

Comment thread Bitkit/Services/PubkyService.swift
Comment thread Bitkit/Managers/ScannerManager.swift
@jvsena42
jvsena42 merged commit 95c1766 into master Jul 24, 2026
11 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-watch-only-accounts branch July 24, 2026 13:48
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.

4 participants