Skip to content

feat: add private paykit payments#941

Merged
ovitrif merged 17 commits into
masterfrom
codex/paykit-private-payments
May 20, 2026
Merged

feat: add private paykit payments#941
ovitrif merged 17 commits into
masterfrom
codex/paykit-private-payments

Conversation

@ben-kaufman
Copy link
Copy Markdown
Contributor

Description

Implements private Paykit contact payments with iOS parity:

  • Adds private Paykit link state, endpoint publishing, stale-link recovery, tombstones, and cleanup retry handling.
  • Adds private on-chain address reservation and restore safety so normal receive flows avoid private indexes.
  • Resolves saved-contact payments private-first with public Paykit fallback, and discards one-time private invoices/addresses after send attempts.
  • Wires private Lightning and on-chain activity attribution through repository-backed contact resolution.
  • Adds backup/restore payloads, contact cleanup handling, address viewer resilience, and focused unit coverage.

Preview

N/A

QA Notes

Passed local checks:

  • ./gradlew compileDevDebugKotlin
  • ./gradlew testDevDebugUnitTest
  • ./gradlew detekt
  • git diff --check

Passed Android emulator E2E coverage:

  • Fresh profile and saved-contact setup
  • Private endpoint resolution both directions
  • Private on-chain Alice to Bob payment
  • Bob inbound Received from attribution
  • Private on-chain address rotation after receive
  • Contact deletion cleanup
  • Restore from seed and normal receive address skip safety

Private Lightning emulator E2E reached endpoint resolution and route construction, but the local regtest run did not produce a successful payment due to LDK RETRIES_EXHAUSTED and receiver peer connectivity timing. The send failure path is handled and covered by unit test, but a clean private Lightning back-and-forth pass should still be repeated in QA when the regtest/LSP route is healthy.

@ben-kaufman ben-kaufman requested review from ovitrif and piotr-iohk May 15, 2026 03:38
@piotr-iohk

This comment was marked as resolved.

@ovitrif ovitrif modified the milestones: 2.3.0, 2.4.0 May 20, 2026
@ovitrif ovitrif modified the milestones: 2.4.0, 2.3.0 May 20, 2026
Copy link
Copy Markdown
Collaborator

@ovitrif ovitrif left a comment

Choose a reason for hiding this comment

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

utAck

Left the review for later, unchecked the files yet to have a way to track my progress

@ovitrif ovitrif enabled auto-merge May 20, 2026 19:48
@ovitrif ovitrif disabled auto-merge May 20, 2026 19:48
@ovitrif ovitrif merged commit f1b93c8 into master May 20, 2026
7 checks passed
@ovitrif ovitrif deleted the codex/paykit-private-payments branch May 20, 2026 19:48
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a32966803

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +399 to +404
val result = lightningRepo.addressInfosForType(
addressType = addressType,
isChange = isChange,
startIndex = startIndex.toUInt(),
count = count.toUInt(),
)
startIndex = startIndex,
count = count,
).getOrThrow()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve address listing when LDK node is not running

Switching getAddresses to lightningRepo.addressInfosForType(...).getOrThrow() makes address retrieval depend on executeWhenNodeRunning, so the address viewer now blocks/fails whenever the node is stopped or cannot reach Running (for example during startup/recovery). The previous derivation path used mnemonic-based derivation and worked without node runtime state, so this change introduces a user-visible regression where existing wallets can no longer inspect addresses in those states.

Useful? React with 👍 / 👎.

Comment on lines +625 to +628
.restoreBackup(parsed.privatePaykitHighestReservedReceiveIndexByAddressType)
.onFailure {
Logger.warn("Failed to restore private Paykit reservations", it, context = TAG)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Propagate private restore failures during wallet restore

restoreWalletBackup logs and ignores failures from restoring private Paykit reservation/link state, then still returns success (createdAt). In failure scenarios (e.g., datastore write/read issues), full restore is marked successful while private reservation ceilings are not restored, which can allow reusing previously reserved private receive indexes after recovery and silently losing private-contact state.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants