Releases: SlowBearDigger/xmr-pay
Release list
v1.3.0 - digest hardening (RFC 7616)
- SHA-256 and SHA-256-sess digest challenges now authenticate; unknown algorithms still fail closed.
- A 401 with stale=true gets exactly one retry with the fresh nonce; a server that always claims stale gets that retry and then a hard node-auth, never a loop.
- A -sess response always carries the cnonce it folded into HA1, which was unverifiable without qop before.
- Each behaviour pinned by a mock-node test (35 checks in the node-auth suite).
v1.2.0 - authenticated daemon nodes
- Structured node config: per-node auth (basic / digest) with credentials, XMR_NODES_JSON for the agent, and an explicit allow_insecure_http opt-in before credentials ride plain HTTP.
- Native Basic/Digest transport that refuses redirects, caps response size, and never re-sends credentials to a host it was not given.
- Localhost bridge that allowlists daemon RPC routes so monero-ts can sync through an authenticated node; passwords stay in the agent process.
- xmr-pay init wizard prompts for authenticated nodes; docs/AGENT.md covers the config.
- Node URL validation rejects input the WHATWG parser silently repairs (empty userinfo/query/fragment, backslashes, missing authority slashes), keeping parity with the PHP engine.
v1.1.0 — Tier-0 spine, hardening, stress suite
Added
./state,./refund,./report— pure, zero-dep protocol contracts, mirrored 1:1 in the WooCommerce PHP engine and pinned by conformance vectors.hosted/— a fully static, zero-server checkout page hosting the<xmr-pay>widget.docs/EVENTS.md— state / event / webhook / refund-record contract.- Widget: visibility-triggered poll + adaptive backoff + 3-step progress + a11y.
- Stress/property suites:
agent.load(N=8000),chaos-reorg,invariant-stress(2.87M checks).
Fixed
createOrderstores the canonical amount (a float like0.1 + 0.2can no longer brick settlement).settledlatches oncheck()— a reorg-driven re-check can never un-settle a paid order.
Full suite green (~2.9M checks).
xmr-pay 1.0.2
Security: burning-bug defence. summarizeTransfers now deduplicates by the one-time output key (not txid alone), so two outputs sharing a key (a 2018-style burn, even across txids) can never credit one real payment twice. Bundled wallet2 transports already collapse burns; this hardens the public export for any transport. See CHANGELOG.
xmr-pay 1.0.1
First stable release of the xmr-pay toolkit.
Sovereign, non-custodial Monero payments: payment links + QR, a zero-dependency checkout widget, and trustless on-chain detection (proof mode + a watch-mode agent that sums payments). No accounts, no API keys, no third party in the payment path.
Settlement is order-independent and covered by an adversarial test suite (property, fuzz, mutation, soak, stress, quorum), verified live on stagenet.
Install: npm i xmr-pay monero-ts
Note: 1.0.0 shipped with an order-dependence bug in settlement dedup and is deprecated on npm; use 1.0.1.
v0.4.0-beta.1 — money-path correctness fixes
Patch beta over 0.4.0-beta.0 — three money-path correctness fixes from a deep adversarial review, each with new tests. Install: npm i xmr-pay@beta.
Fixes
- HIGH — wallet-rpc
unlock_timecould strand real payments.verifyPaymentViaRpcrejected any non-zerounlock_timeaslocked, so a legit, already-spendable payment was stuck forever on the wallet-rpc transport. It now checks whether the lock has elapsed (block-height vs unix-timestamp form), matching the monero-ts path. - MEDIUM — double-spend gate was dead on the wallet-rpc watcher.
createWatcher.incoming()didn't carrydouble_spend_seen, so a daemon-flagged contested tx could be credited. The flag is now surfaced and the gate holds the funds until it clears. - MEDIUM — a late payment could be orphaned at expiry. The agent now checks every unpaid order on fresh state before the expiry sweep, so funds that land in an order's final pre-expiry window are recorded and the order is never expired-then-dropped. The production batch path stays O(1) in network calls.
- LOW — receipts no longer derive piconero from a float when an exact
receivedPicois absent (falls back to the exact order amount).
Also
- Docs accuracy pass: agent/serverless env-var tables, order status vocabulary, signing fingerprint example, and a new
xmr-pay/widgetpackage export.
Full suite green (23 files + 92k-case math fuzz).
Verify
minisign -Vm SHA256SUMS -P RWSA/E4ogu5/1mQf2r66pkWK9fYBEeFdf2cvrjkhiALoXCWT3woSSRtH
sha256sum -c SHA256SUMS
v0.4.0-beta.0 — payment-correctness, reliability, scale
Beta. Install: npm i xmr-pay@beta · Run the agent: npx xmr-pay
This release is a payment-correctness and reliability pass — informed by a side-by-side study of MoneroPay and BTCPay's Monero plugin, plus an adversarial "make everything go wrong" audit. We hold nothing custodial, so the surface is small; we spent it on getting the money path exactly right.
Money-path correctness (all fuzz-tested)
- No false-paid on zero/invalid amounts; exact-piconero arithmetic everywhere (no float in money decisions)
- No double-credit from subaddress reuse, plus a concurrent-reservation (TOCTOU) guard
- Exact
overpaid/atomicToPico/ negativepicoToXmrString
Monero-grade verification (beyond the references)
double_spend_seengate — a flagged tx is held, not credited, until it clearsunlock_timeelapsed-awareness (both block-height and unix-timestamp forms) in watch and tx-proof paths
Reliability & scale
- Durable fulfillment webhook — signed (HMAC), replay-defended, idempotent, with redelivery + reconcile cron
- Node failover + sync timeout
- O(1)
getTransfersper tick (was O(N) per order) — the scale bottleneck
UX / fewer support tickets
- Overpayment detection + configurable underpayment tolerance (dust/fee/rounding)
- Partial payment never orphaned on expiry — funds-bearing orders are never dropped
- Sync-status surfaced ("node catching up…") instead of a silent "unpaid"
Verify this release
minisign -Vm SHA256SUMS -P RWSA/E4ogu5/1mQf2r66pkWK9fYBEeFdf2cvrjkhiALoXCWT3woSSRtH
sha256sum -c SHA256SUMS
Non-custodial: the agent holds only your view key — it can see payments, never spend them.
v0.3.1 — one-command agent (npx xmr-pay)
npx xmr-pay — run the non-custodial agent in one command
npx xmr-pay
An interactive setup wizard (network, primary address, private view key, node), then it runs. Designed to remove the setup friction:
- Truly one command — the bin name matches the package, so
npx xmr-payresolves with no prior install; the Monero engine (monero-ts, WASM) auto-installs into the data dir on first run. - No footguns — restore height is set to the current block automatically (no historical rescan / birthday-1 stall), the wallet + order ledger persist, SIGTERM is handled, and the agent token + webhook secret are generated for you.
- Closes the loop with your store — prints the exact Agent URL / token / webhook secret to paste into the WooCommerce settings.
- Config + view key stay on your machine (
./xmr-pay-data/config.json, mode 600).npx xmr-pay startruns it again later.
No change to the signed money-path modules since 0.3.0 (same SHA256SUMS) — this release adds the bin/ launcher + a CLI test.
Verify the signed manifest:
minisign -Vm SHA256SUMS -P RWSA/E4ogu5/1mQf2r66pkWK9fYBEeFdf2cvrjkhiALoXCWT3woSSRtH
v0.3.0 — verifiable receipts + widget watch-mode
Verifiable payment receipts (dual-root)
A new xmr-pay/receipt module: a self-contained, verifiable record of a paid order with two independent roots of trust:
- Merchant signature (Ed25519, offline) — verifies in a millisecond against the merchant's published fingerprint.
- On-chain tx_proof (trustless) — a recipient-side Monero InProof anyone can check against the chain with
check_tx_proof, no trust in the merchant at all. The same transaction that paid the order proves the order.
signReceipt / verifyReceipt / verifyReceiptOnChain / receiptFromOrder, domain-tagged, exact piconero math. Plus examples/verify-receipt.html — a standalone, zero-dependency, client-side (WebCrypto Ed25519) verifier you can host anywhere.
Verified live end-to-end on a real stagenet payment: receipt minted with InProof → signature valid + InProof confirmed on-chain.
Agent (examples/scanner-agent.js)
- Mints + signs a receipt on payment (best-effort InProof from the view-only wallet), serves
GET /receipt/:id, includes the receipt in theorder.paidwebhook. - Fix: handle
SIGTERM(systemd restart) + save the wallet on shutdown — a restart no longer re-creates subaddress indices (which could reuse a pending order's address). - Fix: persist the receipt on the live order so
GET /receipt/:idworks after the paid event.
Widget
- Watch-mode:
status-url+ an "I've paid — detect it" button with auto-polling (no txid/proof paste needed). - On paid: download the signed receipt + a one-click link to the offline verifier.
redirect-urlsupported. Retries the receipt fetch while the agent finishes minting.
Verify
verifyPaymentnow also returns exactreceivedPico.
Artifacts signed with minisign (minisign.pub in the repo):
minisign -Vm SHA256SUMS -P RWSA/E4ogu5/1mQf2r66pkWK9fYBEeFdf2cvrjkhiALoXCWT3woSSRtH
v0.2.5 — order persistence + create-order race fix
Added — agent order persistence
examples/scanner-agent.js persists its order ledger to XMR_ORDERS_FILE (default orders.json) — saved on create/update/paid/SIGINT/30s, reloaded on boot. On restart it re-checks every pending order against the persisted wallet, so a payment that landed during downtime still auto-completes. Pair with XMR_WALLET_PATH. Funds are never lost regardless (they're on-chain); this auto-completes the matching order across an agent restart.
Fixed — create-order race
Two concurrent createOrder calls with the same id both passed the has() check (before the await) and both allocated a subaddress. A reserving set now rejects the duplicate.
Docs
New docs/STORAGE.md — the storage-agnostic model (any Map-like store; JSON default; Redis/SQL; the WooCommerce two-layer model). New test/stress.test.js (concurrency, pool, adversarial summing, pico exactness). 12 offline suites green.
Verify: `minisign -Vm SHA256SUMS -P $(cat minisign.pub)` then `shasum -c SHA256SUMS`.