Commit Graph

5 Commits

Author SHA1 Message Date
Marco Argentieri
d3e0f0cd55
Report receiver's net amount in push, not payer's gross (#4)
The push notification's amtPaidSat was read from request.invoiceAmount,
which is the gross amount the payer pays over Lightning (e.g. 1003 sats).
The receiver actually claims response.onchainAmount, which is net of
Boltz fees (e.g. 1000 sats). Prefer onchainAmount so the notification
shows what was received; fall back to invoiceAmount only when the wallet
registered a swap without the Boltz response.

Tests now use distinct gross/net amounts to guard the distinction.

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 16:23:53 +02:00
Marco Argentieri
5c0731ebbd
Trigger the push on claimable (pending) instead of settled (#3) 2026-06-09 21:56:56 +02:00
Overtorment
dfa3f8957e
feat: groundcontrol as notifier (#2) 2026-06-09 15:19:54 +02:00
Claude
9a85fac528
Harden notification delivery and registry state
Addresses code-review findings on the push pipeline:

- Never lose the push (was: a transient ntfy failure on invoice.settled
  dropped the notification permanently, since the SwapManager dedupes an
  unchanged status and never re-emits). Delivery now retries with backoff and
  a periodic reconciliation sweep re-attempts any settled-but-still-registered
  swap, recovering from transient outages and from settling while down.
- Prevent double-send: a synchronous in-flight guard stops a re-entrant event
  (e.g. two rapid /simulate calls) from sending twice before the first resolves.
- Prune terminal swaps: delivered and failed reverse swaps are removed from
  both the registry and the manager, so neither grows unbounded (previously
  failed swaps lingered and were re-subscribed on every restart).
- Crash-safe persistence: the registry writes a temp file then renames, so a
  crash mid-write can't corrupt registrations.json. markStatus also skips the
  write when the status is unchanged.
- Consistent register/delete ordering so the registry and SwapManager can't
  diverge if one side errors.
- Drop the redundant top-level status/notifiedSettled fields; swap.status is
  the single source of truth.

Adds test/deliveryRetry.test.ts proving sweep-based recovery after a failed
delivery; updates registry/paymentFlow tests for the prune-on-terminal model.

https://claude.ai/code/session_018HhVgswGG7LynM25qTpejq
2026-06-05 13:46:12 +00:00
Claude
03e76240bc
Add Bitcoin Lightning payment push notification service
A sample service that pushes a phone notification when a Bitcoin Lightning
payment is received in an Arkade-enabled wallet, built on the official
@arkade-os/sdk and @arkade-os/boltz-swap packages.

Receiving Lightning uses a Boltz reverse submarine swap; the wallet registers
each invoice's pending swap per-payment (opt-in, privacy-friendly), and the
service notifies when it reaches invoice.settled.

- swapWatcher.ts: monitor-only @arkade-os/boltz-swap SwapManager
  (enableAutoActions: false) — needs no wallet keys. SwapManager owns the
  multiplexed Boltz websocket, polling fallback, and reconnect/backoff.
- paymentService.ts: wires SwapManager events to pushes via
  isReverseSuccessStatus (invoice.settled).
- registry.ts: persisted swapId -> {topic, swap} map, resubscribed on restart;
  the wallet may redact the preimage since monitoring never claims.
- notifier/: pluggable Notifier interface with an ntfy.sh implementation.
- server.ts: POST/GET/DELETE /register, /health, /simulate (Fastify + zod).
- scripts/demo-receive.ts: wallet side — creates an invoice via
  ArkadeSwaps.createLightningInvoice and registers the swap (no raw REST).
- Tests: registry persistence, plus a component test driving the REAL
  SwapManager with a mocked globalThis.WebSocket through
  register -> settle -> push.

https://claude.ai/code/session_018HhVgswGG7LynM25qTpejq
2026-06-05 13:17:09 +00:00