Skip to content

feat: STAS / DSTAS / BSV-21 token support (templates, overlays, PeerTokenClient)#261

Open
MatiasJF wants to merge 8 commits into
bsv-blockchain:mainfrom
MatiasJF:stas-overlay-peertokenclient
Open

feat: STAS / DSTAS / BSV-21 token support (templates, overlays, PeerTokenClient)#261
MatiasJF wants to merge 8 commits into
bsv-blockchain:mainfrom
MatiasJF:stas-overlay-peertokenclient

Conversation

@MatiasJF

@MatiasJF MatiasJF commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Adds first-class support for the three BSV token standards — classic STAS (P2STAS), DSTAS (STAS 3.0), and BSV-21 — across the templates, overlay, and messaging layers, plus a peer-to-peer token-transfer client (the token analog of PeerPay). Purely additive; no changes to existing behavior. Spans three packages:

@bsv/templates — decoders

StasToken, Bsv21Token, DstasToken — structural decoders for each standard's locking script (owner, tokenId/protoID, flags, frozen state). DstasToken is validated against real dxs-SDK output.

@bsv/overlay-topics — discovery overlays

  • tm_stas/ls_stas, tm_bsv21/ls_bsv21, tm_dstas/ls_dstas — topic managers + Mongo-backed lookup services (index by tokenId / owner / outpoint). DSTAS matters most: it has no third-party indexer, so this overlay is its only discovery surface.
  • Admissibility is structural: template validity + per-tokenId value conservation.
  • Admission hardening (src/admission/): an optional TokenIssuerPolicy (allowIssuance gate — minting is permissionless in Script and token authority is off-chain via the issuer's TokenScheme, per the STAS protocol study §4) wired into all three managers (default stays permissionless), plus DSTAS frozen-state discovery (a frozen query filter). Full trust model in src/admission/ADMISSION.md.

@bsv/message-box-client — peer token transfers

PeerTokenClient (extends MessageBoxClient) + a pluggable TokenSettlementAdapter seam — one client, per-standard adapters. Moves tokens peer-to-peer over MessageBox using BRC-29-style owner derivation, mirroring PeerPayClient for payments. Includes a token-request flow (request / fulfill / decline / cancel).

Testing

  • 32 unit tests (22 overlay + 10 PeerTokenClient), all green.
  • Builds clean (tsc + webpack) across all three packages against current main.
  • Live-verified on mainnet: STAS / DSTAS / BSV-21 peer transfers (send / receive / re-spend / partial) cross-machine; and ls_dstas indexing a real mainnet DSTAS UTXO end-to-end (submit → admit → lookup by owner / tokenId / outpoint).

Testing

  • Added unit tests — 32 (22 overlay + 10 PeerTokenClient)
  • All tests pass locally (Node 24, against current main)
  • Builds clean — tsc + webpack across all three packages
  • Lint — the new stas/bsv21/dstas/admission/template code is clean
  • No package.json / lockfile changes (purely additive; --frozen-lockfile safe)

Out of scope (follow-up)

Registering these tm_*/ls_* services in infra/overlay-server — that consumes the published @bsv/overlay-topics, so it's a post-merge/post-publish step (a few lines: configureTopicManager + configureLookupServiceWithMongo).

Notes

  • Rebased onto current main; the only conflict was the additive ts-templates/mod.ts export index.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC

MatiasJF and others added 5 commits July 1, 2026 10:11
Mirror the mandala overlay pattern for classic STAS and add a
standard-agnostic peer token client, the token analog of PeerPayClient.

- @bsv/templates: StasToken decoder for classic STAS (P2STAS) scripts
  (owner pkh + symbol from the OP_RETURN trailer); satoshi-denominated.
- @bsv/overlay-topics: tm_stas / ls_stas — structural admissibility with
  per-asset value conservation (no key-linkage/screening, unlike mandala),
  Mongo index by assetId/owner/outpoint.
- @bsv/message-box-client: PeerTokenClient (extends MessageBoxClient) +
  pluggable TokenSettlementAdapter seam; send/accept/list/listen + token
  request/fulfill/decline/cancel with HMAC proofs. Token message-body types.

Builds across all three packages; 5+4+6 unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC
Replicate the STAS token surface for BSV-21 (1Sat ordinals-style fungible
tokens) using the same PeerTokenClient + overlay pattern.

- @bsv/templates: Bsv21Token decoder for the ord-inscription envelope
  (id/amt/dec/sym/owner pkh, mint vs transfer), divisible bigint amounts.
- @bsv/overlay-topics: tm_bsv21 / ls_bsv21 — structural admissibility with
  per-tokenId conservation on bigint amounts (deploy+mint = issuance whose
  tokenId is its own outpoint); Mongo index by tokenId/owner/outpoint.

PeerTokenClient is unchanged — BSV-21 plugs in via a new adapter on the
existing TokenSettlementAdapter seam. Builds; 5 template + 4 overlay tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC
Complete the three-standard token surface with DSTAS (Divisible STAS /
STAS 3.0), whose overlay is the highest-value one since DSTAS has no
third-party indexer (classic STAS has Bitails, BSV-21 has 1Sat).

- @bsv/templates: DstasToken — a minimal structural decoder for the dxs
  DSTAS template (owner pkh, redemption/tokenId, flags, frozen marker),
  no dependency on the dxs SDK. Validated against real SDK-generated
  scripts (buildDstasLockingScript) embedded as test fixtures.
- @bsv/overlay-topics: tm_dstas / ls_dstas — structural admissibility with
  per-tokenId satoshi conservation (DSTAS is satoshi-denominated; issuance
  admitted, inflation rejected), Mongo index by tokenId/owner/outpoint,
  frozen marker surfaced for indexing.

PeerTokenClient unchanged — DSTAS plugs in via a new adapter on the shared
seam. Builds; 4 template + 4 overlay tests pass against real DSTAS scripts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC
…discovery)

Token authority cannot be derived from the chain (minting is permissionless;
issuer identity is off-chain via the TokenScheme — STAS protocol study §4), and
transfer/freeze validity is already enforced by Bitcoin Script (§6). So the
overlay's role is accurate discovery, and the meaningful controls are:

- TokenIssuerPolicy (shared) — optional allowIssuance(tokenId) gate consulted
  only for issuance outputs (a tokenId with no input of that id); transfers are
  never gated. Wired into all three topic managers (STAS/BSV-21/DSTAS); default
  stays permissionless. allowlistIssuerPolicy() helper for the common case.
- DSTAS frozen-state discovery — frozen UTXOs stay indexed (real on-chain state);
  ls_dstas gains a 'frozen' query filter so consumers can surface or exclude them.

admission/ADMISSION.md documents the trust model. +12 unit tests (22 total).
Verified live on a real mainnet DSTAS UTXO: admit+index, frozen filter
(false=>1/true=>0), issuer allowlist gates issuance while leaving transfers intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC
…v-desktop

The canonical PeerTokenClient predated the cross-machine mainnet testing done
against the vendored copy in bsv-desktop. Bring it up to parity:

- Mainnet transport: thread the configured MessageBox host through every token
  call and read inboxes via listMessagesLite — the ls_messagebox overlay (SLAP)
  has no advertised mainnet hosts, so overlay-resolving listMessages fails.
- Surface the broadcast txid (TokenToken.txid + TokenSettlementArtifact.txid)
  and return the sent token from sendToken/sendLiveToken (explorer links).
- Plumb a dryRun flag through createTokenToken → TokenAdapterContext so adapters
  can derive+validate without signing/broadcasting (mainnet rehearsal).

+4 unit tests (10 total). Verified equivalent to the bsv-desktop vendored client
that round-tripped STAS/DSTAS/BSV-21 peer transfers live on mainnet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXLVMoumqtvDXx7AP2e8BC
sirdeggen added 3 commits July 1, 2026 09:03
…Cloud gate

Extract shared admission (conservation check, issuer-policy gating,
try/catch wrapper) into BaseTokenTopicManager, and shared owner/outpoint
lookup fallback into tokenLookupTail — the near-identical STAS/BSV-21/DSTAS
implementations were pushing new_duplicated_lines_density over the 3%
quality gate threshold.
- Number.parseInt/Number.isNaN over the global forms (S7773)
- Extract pushDataLength/readOrdEnvelope/readP2pkhOwner/parseDecimals
  helpers to bring StasToken.readPushes and Bsv21Token.decode cognitive
  complexity under the 15 threshold (S3776)
- optional-chain payload?.p check, nested ternary moved to its own
  statement (S6582, S3358)
- log the caught error in safeParse instead of discarding it (S2486)
- explicit number annotation on the hmac-byte map callback (S6551)
Extracting the nested ternary to its own statement didn't clear the
rule — the nesting itself was still there. Collapse to a single
condition instead.
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@sirdeggen sirdeggen marked this pull request as ready for review July 2, 2026 15:53
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.

2 participants