Skip to content

Latest commit

 

History

History
300 lines (210 loc) · 8.36 KB

File metadata and controls

300 lines (210 loc) · 8.36 KB

anchorregistry

Trustless Python client for the AnchorRegistry provenance chain on Base (Ethereum L2).

anchorregistry reads provenance records directly from the Base blockchain — no intermediary API, no account, no API key. It is the same library used in AnchorRegistry's own production backend.

Verify what existed, when, and who registered it — directly from the chain.

SPDX-Anchor: anchorregistry.ai/AR-2026-pJ53j6K


Installation

pip install anchorregistry

# With DataFrame support
pip install anchorregistry[analytics]

Requires Python 3.11+


Quickstart

from anchorregistry import configure, get_by_arid

configure(network="sepolia")

record = get_by_arid("AR-2026-dPXazj6")
print(record["title"])        # test sepolia anchor
print(record["author"])       # Ian Moore
print(record["manifest_hash"])
print(record["data"]["url"])  # https://anchorregistry.com/

Usage

Query by AR-ID

from anchorregistry import get_by_arid

record = get_by_arid("AR-2026-dPXazj6")

Query by registrant wallet

from anchorregistry import get_by_registrant

records = get_by_registrant("0xc7a7afde1177fbf0bb265ea5a616d1b8d7ed8c44")

Query by tree

from anchorregistry import get_by_tree

records = get_by_tree("0xf07140ce4deaf3b5dac859091a079f82e9656f173593feda7895d940b8fa5d13")

Query by artifact type

from anchorregistry import get_by_type
from anchorregistry.enums import ArtifactType

records = get_by_type(ArtifactType.CODE)

Full registry harvest

from anchorregistry import get_all

records = get_all()                                          # full registry
records = get_all(from_block=10000000)                       # from block
records = get_all(from_block=10000000, to_block=10500000)    # block range

Verify file integrity

from anchorregistry import verify

result = verify("AR-2026-dPXazj6")                          # record only
result = verify("AR-2026-dPXazj6", file_path="./myfile.py") # + SHA256 check
print(result["hash_match"])  # True / False

Generate watermark tag

from anchorregistry import watermark

line = watermark("AR-2026-yPZBgoP", artifact_type="CODE")
# → "SPDX-Anchor: anchorregistry.ai/AR-2026-yPZBgoP"

line = watermark("AR-2026-dPXazj6", artifact_type="RESEARCH")
# → "DAPX-Anchor: anchorregistry.ai/AR-2026-dPXazj6"

# Resolves type from chain if not provided
line = watermark("AR-2026-dPXazj6")

Authenticate anchor ownership

from anchorregistry import authenticate_anchor

result = authenticate_anchor("0xf4accdf917e8cf2b9e0ceb0b281fba1c1a176f8922fb5eb432bfa0a5664b0680", "AR-2026-dPXazj6")
print(result["authenticated"])  # True / False

The ownership token (K) is a 0x-prefixed bytes32 hex string generated client-side at registration time via keccak256(salt). It is never transmitted on-chain — only the commitment keccak256(K || arId) is stored.

Authenticate a full tree

from anchorregistry import authenticate_tree

result = authenticate_tree("0xf4accdf917e8cf2b9e0ceb0b281fba1c1a176f8922fb5eb432bfa0a5664b0680", "AR-2026-dPXazj6")
print(result["authenticated"])      # True if tree ownership + all anchors verified
print(result["anchors_verified"])   # count of verified user-initiated anchors
print(result["governance_count"])   # governance anchors (skipped, bytes32(0))

Two-layer verification: Layer 1 checks tree ownership via keccak256(K || rootArId) == treeId, Layer 2 verifies every user-initiated anchor's tokenCommitment in the tree.

Analytics — load into DataFrame

from anchorregistry import get_all, to_dataframe

df = to_dataframe(get_all())
df[df.artifact_type_name == "CODE"]
df[df.author == "Ian Moore"]
df.groupby("artifact_type_name").count()

Network Configuration

Works identically against Base mainnet and Sepolia testnet.

from anchorregistry import configure

# Mainnet (default)
configure(network="base")

# Sepolia testnet
configure(network="sepolia")

# Custom RPC
configure(network="base", rpc_url="https://my-rpc-node.com")

Or via environment variables:

export NETWORK=sepolia
export BASE_RPC_URL=https://my-rpc-node.com
export ANCHOR_REGISTRY_ADDRESS=0x...

Record Structure

Every record follows a consistent two-level structure regardless of artifact type:

{
    # Universal fields — identical for every type
    "ar_id":                "AR-2026-dPXazj6",
    "registered":           True,
    "artifact_type_index":  1,
    "artifact_type_name":   "RESEARCH",
    "tx":                   "0x826f62...",
    "block":                40225238,
    "registrant":           "0xc7a7af...",
    "manifest_hash":        "...",
    "parent_ar_id":         "",
    "descriptor":           "test sepolia anchor",
    "title":                "test sepolia anchor",
    "author":               "Ian Moore",
    "tree_id":              "0xf07140...",
    "token_commitment":     "0xf07140...",   # keccak256(K || arId), bytes32(0) for governance

    # Type-specific fields — only fields for this artifact type
    "data": {
        "doi":          "",
        "institution":  "",
        "co_authors":   "",
        "url":          "https://anchorregistry.com/"
    }
}

Watermark Standards

AnchorRegistry defines two watermark standards for embedding a provenance signal in any artifact:

SPDX-Anchor — for software (code, packages, repositories)

SPDX-Anchor: anchorregistry.ai/AR-2026-XXXXXXX

DAPX-Anchor — for all other artifacts (research, data, models, media, legal, proofs)

DAPX-Anchor: anchorregistry.ai/AR-2026-XXXXXXX

One line signals membership in a provenance tree — queryable by humans and AI agents alike.


Exported Constants

from anchorregistry import ARTIFACT_TYPE_MAP, READ_ABI, CONTRACT_ADDRESS, DEPLOY_BLOCK

ARTIFACT_TYPE_MAP and READ_ABI are the canonical source of truth for AnchorRegistry type ordering and ABI — used by AnchorRegistry's production backend directly.


Design

  • Trustless. Reads directly from Base blockchain events via RPC. No AnchorRegistry servers involved.
  • Read-only. Registration happens through anchorregistry.com. This package only reads.
  • No auth required. Verification is open and free to anyone with an RPC endpoint.
  • Production parity. The same library powering the AnchorRegistry backend — not a wrapper.
  • Network-agnostic. Works identically against Base mainnet and Sepolia testnet.
  • Built on Base. Base settles to Ethereum mainnet — provenance anchors inherit Ethereum-grade finality.

Testing

Unit tests (no RPC required)

python3 -m pytest tests/ -v --ignore=tests/test_client.py

Full suite with Sepolia integration tests

Create a .env file with your Sepolia RPC endpoint:

SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY

For authentication integration tests, also set:

ANCHOR_OWNERSHIP_TOKEN=0x...   # 0x-prefixed bytes32 hex (keccak256 token)
ANCHOR_ROOT_AR_ID=AR-2026-...  # root AR-ID for the ownership token

Then run:

set -a && source .env && set +a && python3 -m pytest tests/ -v

Integration tests in test_client.py are automatically skipped when SEPOLIA_RPC_URL is not set. Authentication tests are additionally skipped when ANCHOR_OWNERSHIP_TOKEN and ANCHOR_ROOT_AR_ID are not set.


References

The cryptographic commitment scheme and security proofs underlying this implementation are formally described in:

Trustless Provenance Trees: A Game-Theoretic Framework for Operator-Gated Blockchain Registries Ian C. Moore — arXiv:2604.03434 [cs.GT], April 2026 https://arxiv.org/abs/2604.03434

Status

Alpha. Core library under active development against Sepolia testnet. API surface stable per spec. Not yet published to PyPI.


License

Business Source License 1.1 (BUSL-1.1)
Change Date: March 12, 2028 → Apache License 2.0
Licensor: Ian Moore


Links