Skip to content

feat(bsv): add exact scheme support for BSV - #2

Closed
sirdeggen wants to merge 1 commit into
mainfrom
feat/bsv-exact-scheme
Closed

sirdeggen wants to merge 1 commit into
mainfrom
feat/bsv-exact-scheme

Conversation

@sirdeggen

@sirdeggen sirdeggen commented Jul 17, 2026

Copy link
Copy Markdown

What

Adds BSV as an x402 payment mechanism for the exact scheme, for internal discussion before anything goes to the x402 Foundation. New package @x402/bsv, a protocol spec, example wiring, and a WhatsOnChain USD price feed — built on the BRC-121 / BRC-29 flow already shipped in @bsv/402-pay.

How it maps BRC-121 onto x402

  • payTo = the recipient wallet's BRC-100 identity public key (never appears on chain — every payment pays a fresh BRC-42-derived key)
  • Payload = a BRC-29 remittance: { transaction (base64 BEEF), derivationPrefix, derivationSuffix, senderIdentityKey, outputIndex }; the suffix decodes to a Unix-ms timestamp (BRC-121 freshness)
  • The client's BRC-100 wallet funds, fees, and signs the transaction via createAction — no gas sponsorship
  • The facilitator is the recipient's own wallet. BRC-42 destinations are ECDH-derived, so a third party cannot take custody, and cannot verify the destination unilaterally (either counterparty can disclose a BRC-69 key linkage, verifiable via BRC-94 Schnorr ZKP — see the spec's auditability appendix, and the discussion point below). verify checks structure, wallet-chain agreement, freshness, exact amount, and the derived destination; settle = internalizeAction, with a txid dedup cache + isMerge for replay defense
  • Networks bsv:mainnet / bsv:testnet — a bsv CAIP-2 namespace now proposed at ChainAgnostic/namespaces#190 (human-readable network names, casper precedent; note bip122 can also represent BSV via its fork-block hash, as it does for Bitcoin Cash)

What's in the PR

@x402/bsv package (typescript/packages/mechanisms/bsv), modeled on the Concordium mechanism:

  • exact/client — derives the per-payment key and builds the funded BEEF payment
  • exact/facilitator — verifies and settles into the recipient wallet
  • exact/server — builds PaymentRequirements, satoshi price parsing (8 decimals)
  • createWhatsOnChainMoneyParser — converts USD route prices ("$0.001") to satoshis via the WhatsOnChain exchange-rate API (60 s cache, single-flight refresh, bounded stale fallback)
  • constants / types, README, package/tsup/tsconfig/vitest config, changeset, and an npm publish workflow

Spec: specs/schemes/exact/scheme_exact_bsv.md (full exact-on-BSV spec incl. a Key Linkage Revelation & Auditability appendix) + BSV safety invariants in the shared scheme_exact.md appendix.

Examples: all three all_networks examples wired —

  • client: BSV_WALLET=true + a running BRC-100 wallet (e.g. BSV Desktop)
  • facilitator: BSV_SERVER_PRIVATE_KEY + BSV_WALLET_STORAGE_URL via @bsv/simple ServerWallet
  • server: BSV_IDENTITY_KEY, priced in USD through the money parser

Hardening (adversarial review)

A multi-lens review (interface correctness, security, @bsv/sdk fidelity, spec consistency, conventions) surfaced 24 confirmed findings, all fixed on this branch:

  • Free-work exploitverify now derives the BRC-42 destination (getPublicKey forSelf) and matches it against the P2PKH script, so unfundable/mispaid BEEFs fail before any resource work
  • Decoy-tx divergence — subject tx resolved via Atomic BEEF atomicTxid, matching what the wallet internalizes
  • Settlement expiry — settle extends the freshness window by maxTimeoutSeconds, so slow handlers don't void valid payments
  • ReplayisMerge is a wallet-toolbox extension (not core BRC-100), so a facilitator-side txid dedup cache backs it up
  • Chain agreement — facilitator checks getNetwork() against the requested network
  • Plus: transaction: "" on all failures per core v2, non-BSV assets rejected at config time, case-insensitive payee comparison

Testing

  • 103 unit tests (pnpm test in the package) — payload construction, verify/settle rules, Atomic BEEF subject resolution, replay paths, timestamp windows, and the rate-feed parser (cache / stale / error paths)
  • Live smoke: money parser against the real WhatsOnChain API ($0.001 → 7,440 sats at $13.44/BSV)
  • Live wallet round trip: BSV_INTEGRATION=true pnpm test:integration with BSV Desktop running (create → verify → settle → replay-reject) — not yet run, needs a funded wallet
  • Deferred: e2e-harness wiring, Go/Python ports (upstream wants the TS reference first)

Points to discuss before a Foundation PR

  1. Namespace: the bsv namespace is now up for review at ChainAgnostic/namespaces#190please review/comment there. Open question: keep the name-based bsv:mainnet/bsv:testnet scheme, or fall back to bip122:<fork-block-hash> if the editors prefer it (would mean reworking the network IDs here).
  2. Facilitator trust model: recipient-wallet facilitator is honest to BRC-29 but unusual for x402. Two extension paths for shared/third-party facilitators: a plain-P2PKH addressing variant (loses the privacy model), or a key-linkage-proof flow (revealSpecificKeyLinkage, BRC-69/BRC-94) enabling destination verification without custody — also the auditability path for regulated assets like BSV stablecoins.
  3. Strict amount equality (x402 exact) vs BRC-121's overpay-tolerant check — the spec documents the divergence.
  4. Upstream process is spec-PR-first with a prior issue; the spec commit is separable for that.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U8iaxitVKXh9EZR5HzAYfg

@github-actions github-actions Bot added typescript sdk examples specs ci unverified Pull request contains unverified commits labels Jul 17, 2026
@github-actions

Copy link
Copy Markdown

Thanks for your contribution @sirdeggen!
Note that we require commit signing, please rebase and verify your commits.

See here for instructions: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification

The team will not review this PR before ALL commits have been verified and it will be closed after 1 week of inactivity.

Unverified commits:

  • b7f97f4: unsigned

Add new @x402/bsv mechanism package implementing the exact payment scheme for the BSV blockchain, including client, server, and facilitator scheme implementations with unit and integration tests.

- Add scheme_exact_bsv.md spec and reference it from scheme_exact.md
- Wire BSV into advanced client, server, and facilitator all_networks examples
- Add scoped npm publish workflow and changeset for the new package

Signed-off-by: Deggen <d.kellenschwiler@bsvassociation.org>
@sirdeggen
sirdeggen force-pushed the feat/bsv-exact-scheme branch from b7f97f4 to e96ec4c Compare July 17, 2026 16:19
@github-actions github-actions Bot removed the unverified Pull request contains unverified commits label Jul 17, 2026
@sirdeggen sirdeggen closed this Jul 17, 2026
sirdeggen pushed a commit that referenced this pull request Aug 21, 2026
…dation#2698)

* docs(svm): add `batch-settlement` SVM scheme specification

SVM profile of the network-agnostic `batch-settlement` scheme: high-throughput
channel payments where a client deposits once, signs cumulative Ed25519 vouchers
verified off-chain, and the operator redeems the latest voucher per channel
on-chain in batches. The multi-voucher generalization of `upto`.

* docs(svm/batch): cascade upto role-model + cleanups to batch-settlement

Mirrors the upto spec revision, adapted for batch's client-signed cumulative
vouchers:

- Role model: the operator is the channel `payee` (the program requires the
  `settle_and_finalize` merchant == `channel.payee`), as well as fee payer and
  `rentPayer`; `authorizedSigner` stays the payer (client signs vouchers). `payTo`
  is realized as the payee (self-facilitating, `operator == payTo`) or a
  `distributionSplits` entry (separate facilitator). Added the self-facilitating
  reference-status note and set `payee = operator` / `rentPayer = operator` at open.
- Cleanups (match upto): dropped the `pay-kit`-controlled / `CHNLxY` program-id /
  "program we control" references.
- Clarified that `expiresAt` is a genuine *client* commitment here (the client
  signs each voucher), unlike upto's operator-attested field.

Deliberately NOT cascaded: `deposit == maxAmount` — batch's deposit is a
multi-request escrow, so the ceiling is `cumulativeAmount ≤ deposit`, not equality.

* docs(svm/batch): address review feedback (security, conformance, clarity)

Resolves @notorious-d-e-v's review on PR x402-foundation#2698 (verified against the
payment-channels program where relevant):

- Voucher replay (x402-foundation#8): the cumulativeAmount is the per-request nonce — a new
  request needs a strict increment (watermark + amount); an equal voucher is only
  an idempotent retry that replays the response cached at that cumulative, never a
  fresh serve.
- Async expiry (x402-foundation#9): expires_at is re-checked on-chain at settle (not just
  settleAndFinalize), so vouchers must use expiresAt == 0 or a TTL outlasting the
  redemption window (grace + buffer).
- Fee-payer guard (x402-foundation#7): validate the full compiled open tx (ALT resolution,
  allowed-instruction-set only, fee payer never an authority/source/writable
  except fees), per the exact SVM scheme.
- State ownership (#3): the watermark/ChannelStore is the resource server's state;
  a separate facilitator stays stateless.
- Response shape (x402-foundation#6): nest chargedAmount/channelState under extra, amount
  optional (core SettleResponse + EVM batch companion).
- asset is the concrete mint, not a symbol (#5); dropped SDK function names (#1);
  added a grace buffer SHOULD (#2); genericized the per-tx settle cap (x402-foundation#10).

* docs(svm): align batch-settlement spec with channels

* docs(svm): align batch settlement wire contract

* docs(svm): refine batch settlement lifecycle

* docs(svm): add batch refund authorization

* docs(svm): define batch refund fallback

Make payer-signed request_close the portable refund path, with facilitator-funded initiation and asynchronous finalization after a bounded grace period. Keep authenticated cooperative close as an optional fast path and align setup validation with the current SVM upto profile.

Co-authored-by: Ludo Galabru <ludo.galabru@solana.org>
Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>

* docs(svm): drop block height hint

Co-authored-by: Ludo Galabru <ludo.galabru@solana.org>
Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>

* docs(svm): batch-settlement review follow-ups

- switch the scheme to the protocol-default authorization payment flow:
  read-only verify before the handler, voucher commit and deposit
  broadcast in the post-handler settle
- clarify that the 900-2592000 withdrawDelay range is an x402
  conformance bound enforced by facilitators, not a program constraint
- quantify the voucher-expiry settlement buffer via an advertised
  extra.settlementBufferSeconds (default 60) so clients can compute a
  passing expiresAt from the 402 alone
- require clients to verify the corrective 402 voucherState signature
  before adopting chargedCumulativeAmount

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(svm): add settlement-buffer error code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(svm): make non-expiring vouchers normative

Voucher expiry added a second clock the server had to beat on top of the
forced-close grace period, and a nonzero expiresAt could make an accepted
voucher unredeemable while the channel was still open. The client MUST now
sign expiresAt = 0, the server and facilitator MUST reject nonzero values,
and extra.settlementBufferSeconds is dropped along with the expiry-window
bound.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant