feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} 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: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

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

feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } 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: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

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

feat: add private payment requests - #676

Merged
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui
Aug 25, 2026
Merged

feat: add private payment requests#676
jvsena42 merged 10 commits into
masterfrom
codex/paykit-payment-request-ui

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Linked Issues/Tasks

N/A

Screenshot / Video

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: Android creates two requests that iOS receives and pays, and iOS creates two requests that Android receives and pays, on clean regtest state.

Automated Checks

  • BitkitTests/PaykitPaymentRequestServiceTests.swift: 46 tests cover mapping, eligibility, proposal delivery, rejection, expiry, identity isolation, presentation races, queue durability, fresh-list retry, and action reconciliation.
  • BitkitTests/PaykitSdkClientConfigTests.swift: 4 tests cover production/local configuration and safe deferred session restoration.
  • Focused test run: 50 tests passed on the iOS simulator.
  • SwiftFormat lint passed for all 20 changed Swift files.
  • Translation validation passed with 0 errors.
  • Both final cross-platform proof videos decoded end to end without errors.

@greptile-apps

This comment has been minimized.

@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from 7ef6f37 to 1604cb7CompareAugust 20, 2026 11:41
ovitrif

This comment was marked as outdated.

@ovitrifovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufmanforce-pushed the codex/paykit-payment-request-ui branch from ad1803b to 5756057CompareAugust 21, 2026 01:15
@ben-kaufmanben-kaufman mentioned this pull request Aug 24, 2026
2 tasks
Comment threadBitkit/Views/PaymentRequests/CreatePaymentRequestView.swift

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

Approved. Choose Recipient keeps an in-sheet back control next to the timer, so users can return from that pushed page.

@jvsena42
jvsena42 merged commit 6449d95 into masterAug 25, 2026
17 of 19 checks passed
@jvsena42
jvsena42 deleted the codex/paykit-payment-request-ui branch August 25, 2026 17:02
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@ovitrif@jvsena42