feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: support paykit receiver paths - #620

Merged
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers
Jul 22, 2026
Merged

feat: support paykit receiver paths#620
ben-kaufman merged 4 commits into
masterfrom
codex/paykit-rc33-receivers

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This PR:

  1. Updates Paykit to v0.1.0-rc33 and configures the mobile app as the bitkit/wallet receiver.
  2. Discovers and saves supported bitkit/wallet and bitkit/server receivers while keeping one visible contact per Pubky identity.
  3. Scopes private links, payment details, reservations, retries, and cleanup to the exact receiver path.
  4. Publishes the wallet receiver marker with the app's current public/private capabilities and removes it when Paykit sharing is disabled.
  5. Refreshes receiver discovery when an existing contact is scanned or pasted, while normal send-to-contact continues to target bitkit/wallet explicitly.

Description

Paykit now supports multiple apps under one Pubky identity. This change adopts that model without changing Bitkit's contact UI: a person remains one contact, while their saved SDK contact record can track multiple receiver paths.

Private links are maintained for supported receivers that advertise private capabilities. Receiving details are published independently per receiver and only when that receiver can send payments, so a bitkit/server receiver can be discovered and linked without receiving wallet invoices or addresses. Public contact payments and fallback remain scoped to bitkit/wallet.

Receiver-record failures are isolated per contact, successful delivery reports are still persisted, and rescanning an existing contact shows the validation result immediately while its receiver metadata refreshes.

No migration is included because the receiver-path Paykit state has not shipped and existing development state can be discarded.

Companion Android PR: synonymdev/bitkit-android#1066

Linked Issues/Tasks

Screenshot / Video

N/A

QA Notes

Manual Tests

  • 1. Contacts → add a Paykit-enabled Bitkit user: one contact is saved and its bitkit/wallet receiver is available for payment.
  • 2. Send → Contact → select the saved contact: private payment resolves through bitkit/wallet; public fallback still works when private payment is unavailable.
  • 3. Existing contact → scan or paste the same Pubky key after a bitkit/server receiver is published: the contact remains one row and the new receiver is saved in the background.
  • 4. Contact with a bitkit/server marker that cannot send payments: Bitkit may maintain its private link but does not publish wallet invoices or addresses to that receiver.
  • 5. Settings → Payment Preferences → disable contact payment sharing: receiver-scoped payment details and the local receiver marker are cleaned up.

Automated Checks

  • PrivatePaykitServiceTests.swift covers receiver-scoped publication, cleanup, reservations, and wallet/server capability behavior.
  • ContactsManagerTests.swift covers receiver discovery refresh for an already-saved contact.
  • Local iOS simulator build passed; 25 focused public/private Paykit tests and the touched contact receiver-refresh test passed.
  • SwiftFormat lint and git diff --check passed on the changed files.
  • A full ContactsManagerTests class run remains blocked locally by the existing app-group/keychain entitlement failure in testDeleteAllContactsThrowsWithoutActiveSession; the changed receiver-refresh test passes independently.

@ben-kaufman
ben-kaufman marked this pull request as ready for review July 10, 2026 10:55
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR adds receiver-path support for Paykit contacts. The main changes are:

  • Paykit is upgraded and configured for the bitkit/wallet receiver.
  • Contacts can store supported bitkit/wallet and bitkit/server receiver paths.
  • Private links, reservations, invoices, retries, and cleanup are scoped per receiver path.
  • The wallet receiver marker is published or removed from sharing flows.
  • Scanner, paste, and contact flows refresh receiver metadata for existing contacts.

Confidence Score: 4/5

The sign-out, profile deletion, and old private-state decode paths need fixes before merging.

  • Private cleanup failures can stop profile deletion and sign-out before mandatory cleanup runs.
  • Existing private Paykit state can decode with invoices and publication flags missing after the schema change.
  • The receiver-path publication flow is otherwise scoped consistently in the changed code reviewed.

Bitkit/Managers/PubkyProfileManager.swift; Bitkit/Services/PrivatePaykitService+Models.swift

Security Review

Sign-out and profile deletion can remain incomplete when private Paykit cleanup fails, leaving receiver/public state active until the cleanup path is fixed.

Important Files Changed

FilenameOverview
Bitkit/Managers/PubkyProfileManager.swiftProfile deletion and sign-out now depend on throwing private Paykit cleanup, which can block required account and local-state cleanup.
Bitkit/Services/PrivatePaykitService+Models.swiftPrivate Paykit contact state was reshaped for receiver paths without migration for old persisted invoices and publication flags.
Bitkit/Services/PrivatePaykitService+Contacts.swiftPrivate payment publication, cleanup, delivery retries, and saved contact state are now keyed by receiver path.
Bitkit/Services/PrivatePaykitAddressReservationStore.swiftAddress reservations now distinguish wallet and server receivers while preserving wallet as the legacy key.
Bitkit/Services/PubkyService.swiftPaykit SDK calls now pass receiver paths, receiver marker capabilities, and receiver-aware contact records.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Save or refresh contact] --> B[Discover supported receiver paths]
B --> C[Store one contact record]
C --> D[Select linkable and publishable receivers]
D --> E[Publish private payment details per receiver path]
D --> F[Clean stale receiver-path lists]
G[Sharing disabled or sign-out] --> H[Remove private lists]
G --> I[Remove public endpoints and receiver marker]
H --> J[Clear receiver-scoped local state]
I --> K[Receiver no longer discoverable]
Loading

Reviews (1): Last reviewed commit: "fix: harden paykit receiver refresh" | Re-trigger Greptile

Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Managers/PubkyProfileManager.swift
Comment threadBitkit/Services/PrivatePaykitService+Models.swift
@jvsena42

Copy link
Copy Markdown
Member

Starting review

@jvsena42jvsena42 added this to the 2.5.0 milestone Jul 21, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tACK

Manual regression (regtest / staging), iOS ↔ Android, on codex/paykit-rc33-receivers:

  • Native profile create + mutual contacts ✅
  • Cross-platform contact LN payments (both directions) ✅
  • Contact attribution after payments (setContact) ✅
  • Profile delete → recreate → re-add → pay again ✅
  • Pubky Ring import ✅ (Pubky auth completed)
  • Staging paykit fixtures republished under receiver paths; e2e @paykit / @pubky green ✅

Companion to android#1066. Android Ring import failure remains the known deferred follow-up from the prior Paykit PR, not a blocker for receiver-path support.

@jvsena42jvsena42 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.

some questions and some suggestions for future improvements

Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PubkyService.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
Comment threadBitkit/Services/PrivatePaykitService+Contacts.swift
@ben-kaufman
ben-kaufman enabled auto-merge (squash) July 22, 2026 09:42
@ben-kaufman
ben-kaufman merged commit adf8bd9 into masterJul 22, 2026
11 checks passed
@ben-kaufman
ben-kaufman deleted the codex/paykit-rc33-receivers branch July 22, 2026 11:10
Sign up for freeto 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.

3 participants

@ben-kaufman@jvsena42@piotr-iohk