Skip to content
View ordspv's full-sized avatar
  • Joined Jul 11, 2026

Block or report ordspv

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
ordspv/README.md

ordspv

Trustless resolution of Bitcoin ordinals inscription content. An ord: URI resolves to bytes verified against Bitcoin proof of work, with no trusted ord server.

A token on Ethereum (or anywhere) that wants its metadata to be a Bitcoin inscription currently points at https://ordinals.com/content/<id> and inherits one hosted server's uptime, rate limits, and honesty. This project is the missing plumbing: a URI scheme profile, a verification protocol that binds inscription bytes to Bitcoin proof-of-work, a verified-fetch client, and a gateway. ord:<id> can then work the way ipfs://<cid> works, except the "CID check" is an SPV proof.

tokenURI: ord:6fb976…2799i0/content#integrity=sha256-…
                     │
   ┌─────────────────┴────────────────────┐
   │            @ordspv/fetch              │  ordFetch("ord:…") → Response
   │  parse → proof-build → verify → serve │
   └──────┬──────────────────┬─────────────┘
          │ untrusted        │ untrusted
   esplora/electrum      ord gateways
   (txs, proofs,         (content, recursion;
    headers, blocks)       availability only)

The trick

Inscription content lives in the reveal transaction's witness, which the txid does NOT commit to. "The txid matched" therefore proves nothing about the bytes, and naive resolvers are forgeable. Two commitments close the gap using only generic Bitcoin data sources:

  • L2 (BIP-341 tapscript commitment): the reveal's txid-committed input points at the commit output, whose taproot key must commit to the served envelope script. About 0.9 KB of proof, all of it available from any esplora instance.
  • L3 (BIP-141 witness commitment): the coinbase's aa21a9ed commitment pins the exact reveal witness via the wtxid tree. This is what a full node enforces.

Levels L0 (trusted gateway), L1 (#integrity= sha256 pin, checkable with zero Bitcoin infrastructure), L2, and L3 are formalized in the specs. The L2 inscriber-level caveat is stated in the specs and surfaced at runtime as named assurances.

Custody proofs

Content verification answers what an inscription's bytes are. ord-resolve custody <id> answers where the inscribed sat is. The custody bundle walks the satpoint from the reveal through each confirmed spend: every hop transaction is merkle-proven into a PoW-checked header, and the ordinal transfer arithmetic is recomputed locally from input values proven by the previous transactions the spending inputs name. Backends only find the path; a lying backend can withhold a path and cannot fabricate one. v1 refuses fee and coinbase paths and inscriptions ord treats as unbound; these refusals throw CustodyUnsupportedError. The final outpoint's unspent status is reported as per-source observations, since no inclusion proof can express a negative. The bundle format and verification rules are in docs/spec/SPEC-CUSTODY.md.

Sat identity

ord-resolve sat <id> answers which sat an inscription lives on, with its ordinal name and rarity, by running the same machinery backward to the coinbase that mined it. Reversing the walk removes the pathfinder entirely: forward custody has to ask a backend which transaction spent an outpoint, while backward every input already names its funding txid, so ancestry is a hash chain and a backend serving wrong bytes fails the check locally. Intermediate transactions need no inclusion proofs at all, since each is pinned by the txid its successor names, and only the reveal and terminal coinbase anchor to headers. Sat numbers come from the ordinal theory closed forms. At heights at or above 230,000 the coinbase's own BIP34 height is cross-checked against the bundle's claim, so the one figure a server could otherwise choose freely is verified too; below that boundary no such push is required, and the claimed height is refused unless the caller's header trust hook attested the block hash at that height. Fee-tail ancestries and unbound inscriptions are refused loudly, as in custody. --bundle FILE writes the genealogy artifact, which re-verifies offline with no network. Rules are in docs/spec/SPEC-SAT.md.

Packages

package what
@ordspv/core zero-IO primitives: tx/header/block parsing, merkle and witness-commitment proofs, BIP-341 checks, ord-exact envelope parser, proof-bundle verifier, custody and sat-genealogy verifiers, gallery decoding, CBOR
@ordspv/fetch ordFetch() / OrdResolver: URI parsing, esplora/ord backends with failover, proof building, header trust (checkpoints, M-of-N, header sync), delegation, integrity pins
@ordspv/gateway reference HTTP gateway: ord-parity /content and /r/*, /ord/v1/proof bundles, verify-before-serve mode
@ordspv/cli ord-resolve <uri>, proof, verify, custody, sat, parse
@ordspv/proof-sidecar proof bundles straight from a Bitcoin Core node (txindex), for L2/L3 without hosting esplora

Quick start

npm install
npm test                                  # whole suite, incl. real mainnet vectors, offline

# resolve + verify inscription 0 at L2 (live network):
npx tsx packages/cli/src/main.ts ord:6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799i0 --out skull.png --json

# emit an offline-verifiable proof bundle:
npx tsx packages/cli/src/main.ts proof 6fb976…2799i0 --level L2 > bundle.json
npx tsx packages/cli/src/main.ts verify bundle.json

# prove where the inscribed sat is now (live network):
npx tsx packages/cli/src/main.ts custody 6fb976…2799i0 --json

# prove which sat it is, and keep the artifact:
npx tsx packages/cli/src/main.ts sat 6fb976…2799i0 --bundle genealogy.json

# run a verifying gateway:
GATEWAY_MODE=verify npx tsx packages/gateway/src/index.ts
import { ordFetch } from '@ordspv/fetch';
const res = await ordFetch('ord:<id>/content');   // verified at L2 by default

Try it

  • examples/verify-inscription-0.html: open the file. Your browser fetches inscription 0, verifies every byte against Bitcoin PoW client-side, and renders it. Also hosted on the docs site.
  • examples/evm-nft/: the cross-chain capstone. An ERC-721 token document whose image is an ord: URI with an integrity pin; the page pulls the URI out of the token metadata, resolves it, and verifies the image against Bitcoin PoW in your browser. Also hosted on the docs site.
  • extension/: MV3 extension with gateway-URL interception, ord: links, and an in-browser verifying viewer. chrome://extensions, Load unpacked, extension/dist-unpacked/.

Documents

Status

Working initial implementation. The cryptographic core is complete and tested against real mainnet data: inscription 0 verifies at L2 end-to-end offline from vendored fixtures, and L3 is verified on consensus-shaped synthetic blocks, including forgery rejection. Specs are v0.1 drafts. Not production software yet; see ROADMAP.md.

Popular repositories Loading

  1. ordspv ordspv Public

    Trustless resolution of Bitcoin ordinals inscription content. ord: URIs, SPV proof bundles (L1–L3), verified fetch, and gateway tooling.

    TypeScript

  2. electrs electrs Public

    Forked from Blockstream/electrs

    An efficient re-implementation of Electrum Server in Rust

    Rust

  3. namespaces namespaces Public

    Forked from ChainAgnostic/namespaces

    Chain-Agnostic Namespaces host informative specs and profiles of CAIPs (Chain-Agnostic Improvement Proposals) per blockchain ecosystem

    HTML