You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When Alice mints an invoice targeting @bob-tag (or DIRECT://...), Bob's wallet has no automatic path to discover the invoice. sphere invoice pay $INV errors with No invoice found matching prefix: ... even after Bob explicitly runs sphere payments sync AND sphere payments receive --finalize.
This blocks the §C invoice round-trip in manual-test-full-recovery.sh (PR #222 / docs/issue-218-full-recovery-manual-test) and is the practical reason the §C end-to-end didn't pass on testnet during today's #223 cross-process validation.
Reproduction
# Alice mints invoice targeting @bobcd ./peer1/.alice
sphere invoice create --target @bob-tag --asset "11000000 UCT" --memo "test"# Capture INV=<invoiceId from JSON output># Bob tries to pay — invoice is invisible to himcd ./peer1/.bob
sphere payments sync # ← does NOT pull alice's invoice
sphere payments receive --finalize # ← does NOT pull alice's invoice
sphere invoice pay "$INV"# → No invoice found matching prefix: 00009ccb170b3f9e182499d7f2bae130e78593b71622cdd9299cb80f440c9ae6f8c0# → Error: Cannot read properties of undefined (reading 'invoiceId')
Validated against live testnet on 2026-05-22 (full log: /tmp/manual-cli-test-223-v10.log from today's session).
What we know
sphere invoice pay <id> calls sphere.accounting.getInvoices() and filters locally (legacy-cli.ts:4049). No network lookup is attempted for unknown invoice IDs.
The invoice token is minted in Alice's profile/wallet. It's an L3 token owned by Alice (with tokenType = INVOICE_TOKEN_TYPE_HEX) whose terms target Bob's DIRECT:// address.
payments sync and payments receive --finalize on Bob's side don't pull invoices, even though Bob's address is in the invoice's terms.targets[0].address.
The daemon path itself has a separate --detach stale-PID bug (tracked separately)
Even with daemons running, the SDK lacks a clear "deliver invoice to payer" mechanism
Suggested solutions (architectural alternatives)
Pick one of the three or some combination:
Option A: Per-invoice DM delivery (NIP-17)
At invoice mint time, Alice sends Bob a NIP-17 gift-wrapped DM containing the invoice token JSON (or a CID reference + payload). Bob's CommunicationsModule / receive pipeline parses the DM, recognizes the invoice envelope, calls accounting.importInvoice(tokenJson), and the invoice lands in Bob's local ledger.
Pros: leverages existing NIP-17 plumbing; explicit point-to-point delivery; works without OrbitDB cross-profile reads. Cons: requires Bob to be subscribed to Nostr at mint time OR catch up via fetchPendingEvents; one more DM-shape to spec.
Option B: Cross-profile OrbitDB lookup
Bob's profile sync queries Alice's published profile (already discoverable via Alice's identity binding event) for invoices targeting <bob's directAddress>. This is effectively a per-target index inside the OrbitDB Profile.
Pros: no extra wire format; works for any third-party invoice (Bob can also discover invoices Eve minted for him without prior pairing). Cons: requires Bob to know about Alice (or to brute-poll the directory); cross-profile OrbitDB reads have their own scaling/permissions story.
Option C: IPFS-pinned per-target invoice index
A discoverable index keyed by recipient DIRECT://: at mint time the creator publishes an entry { target, invoiceId, ts } to an aggregator-side index (or a per-target pubsub topic). Payer sync queries the index for entries matching their address.
Pros: aggregator-mediated, central-but-content-addressed. Cons: requires aggregator support; less private (any peer could query).
Acceptance criteria
sphere payments sync (or equivalent) on Bob's side, after Alice mints an invoice targeting @bob, populates Bob's local invoice ledger so that sphere.accounting.getInvoices() returns the invoice and invoice pay $INV succeeds.
Daemon --detach stale-PID — separate issue in sphere-cli; even if daemons worked, the underlying SDK invoice-delivery path is unclear (covered here).
Priority / blast radius
Medium-high. Invoices are advertised as a wallet feature (CLAUDE.md "Invoicing — sphere.accounting"); the create→pay flow as designed is incomplete cross-process without this. End-to-end CLI invoice testing is blocked.
Summary
When Alice mints an invoice targeting
@bob-tag(orDIRECT://...), Bob's wallet has no automatic path to discover the invoice.sphere invoice pay $INVerrors withNo invoice found matching prefix: ...even after Bob explicitly runssphere payments syncANDsphere payments receive --finalize.This blocks the §C invoice round-trip in
manual-test-full-recovery.sh(PR #222 / docs/issue-218-full-recovery-manual-test) and is the practical reason the §C end-to-end didn't pass on testnet during today's #223 cross-process validation.Reproduction
Validated against live testnet on 2026-05-22 (full log:
/tmp/manual-cli-test-223-v10.logfrom today's session).What we know
sphere invoice pay <id>callssphere.accounting.getInvoices()and filters locally (legacy-cli.ts:4049). No network lookup is attempted for unknown invoice IDs.tokenType = INVOICE_TOKEN_TYPE_HEX) whose terms target Bob's DIRECT:// address.payments syncandpayments receive --finalizeon Bob's side don't pull invoices, even though Bob's address is in the invoice'sterms.targets[0].address.invoice:payment/transfer:incoming, but:--detachstale-PID bug (tracked separately)Suggested solutions (architectural alternatives)
Pick one of the three or some combination:
Option A: Per-invoice DM delivery (NIP-17)
At invoice mint time, Alice sends Bob a NIP-17 gift-wrapped DM containing the invoice token JSON (or a CID reference + payload). Bob's
CommunicationsModule/ receive pipeline parses the DM, recognizes the invoice envelope, callsaccounting.importInvoice(tokenJson), and the invoice lands in Bob's local ledger.Pros: leverages existing NIP-17 plumbing; explicit point-to-point delivery; works without OrbitDB cross-profile reads. Cons: requires Bob to be subscribed to Nostr at mint time OR catch up via
fetchPendingEvents; one more DM-shape to spec.Option B: Cross-profile OrbitDB lookup
Bob's profile sync queries Alice's published profile (already discoverable via Alice's identity binding event) for
invoices targeting <bob's directAddress>. This is effectively a per-target index inside the OrbitDB Profile.Pros: no extra wire format; works for any third-party invoice (Bob can also discover invoices Eve minted for him without prior pairing). Cons: requires Bob to know about Alice (or to brute-poll the directory); cross-profile OrbitDB reads have their own scaling/permissions story.
Option C: IPFS-pinned per-target invoice index
A discoverable index keyed by recipient DIRECT://: at mint time the creator publishes an entry
{ target, invoiceId, ts }to an aggregator-side index (or a per-target pubsub topic). Payer sync queries the index for entries matching their address.Pros: aggregator-mediated, central-but-content-addressed. Cons: requires aggregator support; less private (any peer could query).
Acceptance criteria
sphere payments sync(or equivalent) on Bob's side, after Alice mints an invoice targeting@bob, populates Bob's local invoice ledger so thatsphere.accounting.getInvoices()returns the invoice andinvoice pay $INVsucceeds.manual-test-full-recovery.sh(PR docs(manual-test)(#218): full two-peer + daemon + IPFS-only recovery walkthrough #222). Re-running the script with the fix should now reach §C.4 with bob's balance increased and alice's invoice inCOVEREDstate.Related work
@nametagresolution oninvoice create --target. Companion fix; doesn't address discovery.--detachstale-PID — separate issue in sphere-cli; even if daemons worked, the underlying SDK invoice-delivery path is unclear (covered here).Priority / blast radius
Medium-high. Invoices are advertised as a wallet feature (CLAUDE.md "Invoicing —
sphere.accounting"); the create→pay flow as designed is incomplete cross-process without this. End-to-end CLI invoice testing is blocked.