Python SDK for the Invarians panel API — direction-agnostic cross-chain attestations (L1, L2, bridges) for autonomous agents
Project description
invarians-py
Invarians makes invisible blockchain infrastructure failures observable — before they show up in gas fees.
L2 activity no longer shows up in L1 gas fees. Sequencer failures and bridge delays leave no economic trace. Fee monitors stay silent. Invarians detects them.
Since v0.2.0 (2026-04-20), the API is a direction-agnostic panel. A single call returns the current state of every tracked L1, L2, and bridge. The agent composes its own route client-side.
from invarians import InvariansClient
client = InvariansClient(api_key="inv_your_key_here")
panel = client.get_panel()
eth = panel.l1_by_chain("ethereum")
arb = panel.l2_by_chain("arbitrum")
bridge = panel.bridge_by_id("arbitrum-ethereum/native")
if eth.regime.startswith("S2") or (arb and arb.regime and arb.regime.startswith("S2")):
# Structural stress detected — L1, L2, or both
# Invisible to fee monitors
pause_agent_execution()
print(panel.oracle_status) # "OK" | "DEGRADED"
print(eth.regime, eth.status) # "S1D1" "OK"
print(bridge.state, bridge.status) # None "UNCALIBRATED" (P0, native calibration lands 2026-04-22)
Install
pip install invarians[requests] # default
pip install invarians[httpx] # async-friendly
Requires Python 3.9+. Get an API key at invarians.com.
What you can do with it
1. Pause execution when infrastructure degrades
panel = client.get_panel()
eth = panel.l1_by_chain("ethereum")
if eth.regime and eth.regime.startswith("S2"):
# Structural stress detected — hold until nominal
return {"action": "hold", "reason": eth.regime}
2. Detect silent failures (S2D1)
S2D1 is the critical regime: structural stress with no demand signature. A fee monitor reports normal while Invarians detects degradation.
eth = client.get_panel().l1_by_chain("ethereum")
if eth.regime == "S2D1":
# Chain slowing — no gas spike, no price move
# Nothing shows on any fee monitor
alert_ops("S2D1 detected on Ethereum")
3. Certify execution conditions
Every panel carries a signed attestation over its canonical JSON. Attach it to any agent action for audit or dispute resolution.
panel = client.get_panel()
if panel.is_fully_ok:
result = execute_trade(...)
sec = panel.signed_execution_context
audit_log.append({
"tx": result.hash,
"panel_version": panel.version, # "1.0.0"
"issued_at": panel.issued_at,
"payload_hash": sec.payload_hash, # "0x{sha256}"
"signature": sec.signature, # "hmac-sha256:{hex}"
"key_id": sec.key_id, # "invarians-v1"
"anchor": sec.anchor, # None in V1, on-chain anchor from May 2026
})
4. Route around bridge stress
Bridge IDs are canonical: {chainA}-{chainB}/{type} (e.g. arbitrum-ethereum/native). Three native bridges are exposed at launch; CCTP and CCIP lanes are added in the panel on 2026-04-24 (calibration lands ≥ 2026-05-23).
panel = client.get_panel()
bridge = panel.bridge_by_id("arbitrum-ethereum/native")
if bridge.state == "BS2":
# Bridge degraded — route via alternative path
use_fallback_bridge()
elif bridge.status == "UNCALIBRATED":
# Raw signal still available — use with care
age = bridge.last_batch_age_seconds
if age is not None and age > 300:
use_fallback_bridge()
5. Handle degraded data gracefully
oracle_status reports global health. Per-item status tells you exactly which signal is unreliable.
panel = client.get_panel()
if panel.oracle_status == "DEGRADED":
# At least one L1 / L2 / bridge is STALE or UNAVAILABLE
for entry in panel.l1 + panel.l2:
if entry.status != "OK":
log.warning(f"{entry.chain}: {entry.status}")
for bridge in panel.bridges:
if bridge.status in ("STALE", "UNAVAILABLE"):
log.warning(f"{bridge.id}: {bridge.status}")
fall_back_to_conservative_mode()
Per-item status values:
| Status | Meaning |
|---|---|
OK |
Signal fresh and calibrated |
STALE |
Last update older than the freshness window (1h for L1/L2, 10m for bridges) |
UNAVAILABLE |
Signal temporarily missing |
UNCALIBRATED |
Collector running, thresholds not yet published — does not trigger DEGRADED |
Regimes
| Code | Structure | Demand | What it means |
|---|---|---|---|
| S1D1 | nominal | nominal | Infrastructure within calibrated norms |
| S1D2 | nominal | elevated | Structurally sound, demand above baseline |
| S2D1 | stress | nominal | The only regime where the chain degrades silently — no gas spike, no price signal. Invisible to gas monitors. |
| S2D2 | stress | elevated | Structural stress and elevated demand simultaneously |
Bridge states:
| Code | Type | Meaning |
|---|---|---|
BS1 |
native | Batches posted to L1 within calibrated cadence |
BS2 |
native | Posting latency above P97/30d threshold |
null |
any | Not yet calibrated (raw last_batch_age_seconds still exposed) |
CCIP (CS1/CS2) and CCTP (TS1/TS2) states arrive in the panel on 2026-04-24 (UNCALIBRATED) and calibrate ≥ 2026-05-23.
Signal quality
Every L1 and L2 entry is enriched with explicit calibration metadata. The SDK never hides uncertainty.
sol = client.get_panel().l1_by_chain("solana")
print(sol.meta.m1_validated) # False — backtest not yet validated
print(sol.meta.calibration_confidence) # "LOW"
print(sol.meta.notes) # "π not calibrated. τ only."
Chain coverage
| Chain | Layer | Confidence | Ready |
|---|---|---|---|
| ethereum | L1 | MEDIUM | ✅ |
| polygon | L1 | MEDIUM | ✅ |
| arbitrum | L2 | LOW | ⏳ 25 Apr 2026 |
| base | L2 | LOW | ⏳ 25 Apr 2026 |
| optimism | L2 | LOW | ⏳ 25 Apr 2026 |
| solana | L1 | LOW | ⏳ July 2026 |
| avalanche | L1 | NONE | ⏳ July 2026 |
Native bridges exposed at launch:
| Bridge ID | Type | Calibrated | Calibration date |
|---|---|---|---|
arbitrum-ethereum/native |
native | ❌ | 2026-04-22 |
base-ethereum/native |
native | ❌ | 2026-04-22 |
optimism-ethereum/native |
native | ❌ | 2026-04-22 |
Verify a panel
panel = client.get_panel()
payload = panel_raw_dict # as returned by the API
signature = panel.signed_execution_context.signature
valid = client.verify_panel(payload, signature)
print(valid) # True
Error handling
from invarians.exceptions import AuthError, RateLimitError, ServerError
try:
panel = client.get_panel()
except AuthError:
print("Invalid API key")
except RateLimitError:
print("Quota exceeded — free tier: 20 req/day")
except ServerError as e:
print(f"Service unavailable: {e}")
Migrating from v0.1.x
The legacy endpoints (/attestation/{chain}, /attestation/l2/{chain}, /attestation/execution-context) return HTTP 410 Gone since 2026-04-20, and the matching SDK methods raise NotImplementedError:
# Before (v0.1.x)
ctx = client.get_execution_context(l1="ethereum", l2="arbitrum")
print(ctx.proof.l1_regime, ctx.proof.l2_regime, ctx.proof.bridge_state)
# After (v0.2.x)
panel = client.get_panel()
eth = panel.l1_by_chain("ethereum")
arb = panel.l2_by_chain("arbitrum")
br = panel.bridge_by_id("arbitrum-ethereum/native")
print(eth.regime, arb.regime, br.state) # agent composes the route itself
Documentation
API reference: invarians.com/developers.html
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file invarians-0.2.1.tar.gz.
File metadata
- Download URL: invarians-0.2.1.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ed233444965639f921247a5e595b2e031959c07e9b8cb1e103304373111ce4f
|
|
| MD5 |
34c560a2e910ae4e8ad667ee31ecc0ed
|
|
| BLAKE2b-256 |
ce049b916412bd11d93e01dec2d92a3e9d69cc35df2bc3054b3bef22ea4189b7
|
File details
Details for the file invarians-0.2.1-py3-none-any.whl.
File metadata
- Download URL: invarians-0.2.1-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
649229d9b6188361ee36907c9bdcdf0c1ef75530423ec09f20a8afee6d09de8f
|
|
| MD5 |
4952fc5ce3270ad84d9a7fc12cc62752
|
|
| BLAKE2b-256 |
6ce9d10fac50e9b3518252d2b925ea2958a348e3f190e6e092f9c5897256d51b
|