Metadata-Version: 2.4
Name: axiomatic_verifier
Version: 0.1.2
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests<3.0,>=2.31

**Axiomatic Verifier (Python)** is the SDK for independently verifying on-chain **p1** Proof-of-Valuation (PoVal) attestations (and related formats) published on Algorand.

Given a transaction ID, it:

1. Fetches the transaction via an Algorand Indexer.
2. Extracts and parses the note.
3. Re-canonicalizes the JSON (JCS/ACJ-style).
4. Recomputes the SHA-256.
5. Applies lightweight validation rules (schema, hash, timestamp).
6. Returns a structured JSON-style result.

There is **no dependency** on any Axiomatic backend: anyone can verify.

---

## Who is this for?

Use `axiomatic_verifier` if you:

- Need to **verify** PoVal attestations issued by Axiomatic Oracle or compatible tooling.
- Build Python-based dashboards, risk engines, monitoring or audit scripts.
- Want to validate `p1` notes (and selected legacy formats) directly from Algorand.

If you need to **create and publish** `p1` attestations, see [`axiomatic_proofkit`](https://pypi.org/project/axiomatic_proofkit/).

---

## Typical use cases

1. **RWA dashboards and explorers**
   - Given a `txid`, show whether a PoVal attestation is valid and fresh.
   - Display `v`, `u`, `ts`, model metadata and hashes.

2. **Risk / compliance engines**
   - Check that incoming PoVal proofs are well-formed, hash-consistent and within a time window.
   - Combine `verified`, `reason`, `mode` and timestamps into your own policies.

3. **Back-office audit scripts**
   - Periodically scan a set of transactions.
   - Verify notes and export structured data for further analysis.

---

## Installation

Requires **Python 3.10+**.

```bash
pip install axiomatic_verifier
```

`requests` is installed automatically as a dependency.

---

## Exposed API

From `axiomatic_verifier`:

* `verify_tx(txid, network="testnet", indexer_url=None, max_skew_past_sec=..., max_skew_future_sec=...)`

Utility helpers:

* `to_jcs_bytes(obj)`
* `sha256_hex(b)`

`verify_tx` always returns a dict-like structure (plain `dict`).

---

## Quickstart: verify a p1 transaction

This example mirrors the internal smoke test and is suitable as a public snippet.

### 1. Environment (optional)

Create a `.env` file next to your script (optional):

```env
ALGORAND_NETWORK=testnet
# INDEXER_URL=https://testnet-idx.algonode.cloud
```

If `INDEXER_URL` is not set, the SDK will default to Algonode:

* `https://mainnet-idx.algonode.cloud` for `mainnet`
* `https://testnet-idx.algonode.cloud` for `testnet`

### 2. Example script (`verify_tx_example.py`)

```python
import os
import sys
import json
from pathlib import Path

from axiomatic_verifier import verify_tx

ROOT = Path(__file__).resolve().parent


def load_env(env_path: Path) -> None:
    try:
        for line in env_path.read_text(encoding="utf-8").splitlines():
            if not line or line.strip().startswith("#") or "=" not in line:
                continue
            if "=" not in line:
                continue
            k, v = line.split("=", 1)
            k, v = k.strip(), v.strip()
            if k and (k not in os.environ):
                os.environ[k] = v
    except FileNotFoundError:
        pass


load_env(ROOT / ".env")


def main() -> None:
    if len(sys.argv) < 2:
        print("Usage:", file=sys.stderr)
        print("  python verify_tx_example.py <TXID>", file=sys.stderr)
        sys.exit(1)

    txid = sys.argv[1].strip()
    network = (os.getenv("ALGORAND_NETWORK") or "testnet").strip()

    # Default Indexer: Algonode (can be overridden via INDEXER_URL)
    indexer_url = (
        os.getenv("INDEXER_URL")
        or (
            "https://mainnet-idx.algonode.cloud"
            if network == "mainnet"
            else "https://testnet-idx.algonode.cloud"
        )
    ).strip()

    res = verify_tx(
        txid=txid,
        network=network,
        indexer_url=indexer_url,
        # Example policy: accept p1 issued within the last hour,
        # and up to 5 minutes in the future (clock skew).
        max_skew_past_sec=3600,
        max_skew_future_sec=300,
    )

    print(json.dumps(res, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()
```

Run:

```bash
python verify_tx_example.py <TXID>
```

Use a `txid` produced by `axiomatic_proofkit` or the Node ProofKit on the same network.

---

## Response model

`verify_tx` always returns a dict. Typical shapes:

### Valid p1

```json
{
  "txid": "...",
  "verified": true,
  "mode": "p1",
  "reason": null,
  "note_sha256": "...",
  "rebuilt_sha256": "...",
  "confirmed_round": 57318625,
  "explorer_url": "https://testnet.explorer.perawallet.app/tx/...",
  "note": {
    "s": "p1",
    "a": "re:EUR",
    "mv": "v2",
    "mh": "",
    "ih": "...",
    "v": 550000.0,
    "u": [520000.0, 580000.0],
    "ts": 1762609210
  }
}
```

### Stale / out-of-window p1

```json
{
  "txid": "...",
  "verified": false,
  "mode": "p1",
  "reason": "ts_out_of_window",
  "note_sha256": "...",
  "rebuilt_sha256": "...",
  "explorer_url": "..."
}
```

Meaning: the attestation is structurally and cryptographically correct, but `ts` is outside the allowed time window (`max_skew_past_sec` / `max_skew_future_sec`).

### Unsupported / missing note

```json
{
  "txid": "...",
  "verified": false,
  "mode": "unknown",
  "reason": "unsupported_or_empty_note",
  "explorer_url": "..."
}
```

Legacy formats (if enabled in your version) are reported with:

```json
{
  "txid": "...",
  "verified": true,
  "mode": "legacy",
  "reason": null,
  "note": { "ref": "...", "schema_version": "..." }
}
```

---

## Canonical JSON helpers (optional)

You can use the bundled JCS/ACJ-style helpers for your own golden tests:

```python
from axiomatic_verifier import to_jcs_bytes, sha256_hex
import json

with open("p1.json", "r", encoding="utf-8") as f:
    obj = json.load(f)

b = to_jcs_bytes(obj)
print(sha256_hex(b))
```

This lets you confirm that your own tooling matches the canonicalization used on-chain.

---

## Security and policy notes

* `axiomatic_verifier` **does not** execute any business logic for you.
* Treat its output as structured signals:

  * `verified`, `reason`, `mode`,
  * hashes, timestamps, explorer/indexer links,
  * the decoded `note`.
* You are expected to layer your own risk / policy logic on top:

  * which models and asset tags are allowed,
  * which issuers (addresses) you trust,
  * how strict your time windows should be.

This is an early-access verifier: feedback and issues are very welcome.
