Skip to main content

Python SDK for the Invarians panel API v2.0 — three primitives (Attestation + Regime + Drift Signal) plus per-message CCTP attestation retrieval with Circle ECDSA crypto-grounding

Project description

invarians-py

Cross-chain infrastructure context for autonomous agents. Three primitives in one signed payload: Attestation, Regime, Drift Signal.

L2 activity no longer shows up in L1 gas fees. Sequencer slowdowns and bridge delays leave no economic trace. Fee monitors stay silent. Invarians detects them.

v0.8.0 (2026-05-11) — Per-message CCTP attestation retrieval with Circle ECDSA crypto-grounding. Each CCTP message now exposes its independently verifiable ECDSA signature from Circle's attester. Bridge entries carry a capability_level semantic (per_message_attested for CCTP routes, aggregate for CCIP lanes) plus structured metrics and crypto objects.

Since v0.7.0 (2026-05-04), the SDK targets the production endpoint at https://api.invarians.com and exposes the v2.0 panel: a single direction-agnostic payload with axis-grouped metric blocks, drift signals, and 12 signed regime codes per chain. Bridge classification scope is variable-latency surfaces only (Chainlink CCIP, Circle CCTP).

from invarians import InvariansClient

client = InvariansClient(api_key="inv_your_key_here")
panel  = client.get_panel_v2(include="diagnostic")

eth = panel.l1_by_chain("ethereum")
arb = panel.l2_by_chain("arbitrum")
br  = panel.bridge_by_id("arbitrum-ethereum/cctp")

# Regime: 12 signed codes (S1D1, S1D2+, S1D2-, S1D2±, S2+D1, S2-D1, S2+D2+, ...)
if eth.regime and (eth.regime.startswith("S2") or eth.regime.endswith("D2-")):
    pause_agent_execution()

# Drift: per-axis composite trend, plus per-metric shift
if eth.drift.demand_magnitude_delta is not None and eth.drift.demand_magnitude_delta > 0:
    log.info("Demand axis deviation amplifying on ethereum")

print(panel.oracle_status)        # "OK" | "DEGRADED"
print(eth.regime, eth.status)     # e.g. "S1D1" "OK"
print(br.state, br.calibrated)    # e.g. "BS1" True (CCTP preliminary)

Install

pip install invarians[requests]  # default
pip install invarians[httpx]     # async-friendly

Requires Python 3.9+. Get an API key at invarians.com.


The three primitives

The v2.0 panel separates three independent concerns. Every panel response carries all three.

1. Attestation (HMAC integrity)

Every panel response carries a signed_execution_context with payload_hash, signature, key_id, and an optional on-chain anchor. Independently verifiable.

panel = client.get_panel_v2()
sec   = panel.signed_execution_context

ok = client.verify_panel_v2(panel_raw_dict, sec.signature)
# True if HMAC matches the canonical JSON of the payload

2. Regime (12 signed codes per chain)

Per-chain regime is a 2-axis tuple on the SxDx grid. Structure axis: S1 nominal, S2+ structural high, S2- structural low. Demand axis: D1 nominal, D2+ demand high, D2- demand low, D2± composition split. Twelve codes total per chain on both L1 and L2.

eth = panel.l1_by_chain("ethereum")

if eth.regime == "S2+D1":
    # Structural high stress, demand nominal
    return {"action": "hold", "reason": eth.regime}
elif eth.regime and eth.regime.startswith("S1") and not eth.regime.endswith("D1"):
    # Nominal infrastructure, asymmetric or elevated demand
    proceed_with_caution()

3. Drift Signal (substrate-only)

Applies to L1 and L2 substrate entries. Bridges, being operational pipelines rather than substrates, expose their fitness-for-action directly via current state, metrics, and crypto pointer — without a drift block.

Each metric block exposes ratio (current state vs short EMA), ratio_long (current vs long EMA), shift (deviation magnitude), shift_delta (raw direction), shift_magnitude_delta (deviation amplifying or shrinking). Plus a per-axis composite drift on every chain entry.

eth = panel.l1_by_chain("ethereum")

# Per-axis composite drift
print(eth.drift.demand)                     # composite drift magnitude on demand axis
print(eth.drift.demand_magnitude_delta)     # > 0 amplifying, < 0 reverting

# Per-metric shift (diagnostic mode only)
print(eth.demand.tx.shift)                  # per-metric tx-count shift
print(eth.structural.rhythm.shift)          # per-metric rhythm shift

Trend reading rule for an agent in an active regime:

shift_magnitude_delta Interpretation
> 0 Deviation amplifying. Regime persists or worsens.
< 0 Deviation shrinking. Regime exit toward nominal likely.
≈ 0 Regime stable.

Common patterns

Hold on structural stress

panel = client.get_panel_v2()
eth   = panel.l1_by_chain("ethereum")

if eth.regime and eth.regime.startswith("S2"):
    # Structural stress, regardless of polarity (S2+ or S2-)
    return {"action": "hold", "reason": eth.regime}

Detect silent slowdown (no fee signal)

S2+D1 and S2-D1 are the codes where infrastructure degrades without any demand signature. Fee monitors stay silent.

eth = client.get_panel_v2().l1_by_chain("ethereum")

if eth.regime in ("S2+D1", "S2-D1"):
    # No gas spike, no price move, but the chain is structurally stressed
    alert_ops(f"Silent stress on ethereum: {eth.regime}")

Certify execution conditions on chain

panel = client.get_panel_v2()
sec   = panel.signed_execution_context

if panel.oracle_status == "OK":
    result = execute_trade(...)
    audit_log.append({
        "tx":            result.hash,
        "panel_version": panel.version,           # "2.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,
        "anchor":        sec.anchor,              # on-chain anchor slot when available
    })

Route around bridge stress

Bridge IDs are canonical: {chainA}-{chainB}/{type} with type ∈ {ccip, cctp}. Bridge classification scope is variable-latency surfaces only.

panel = client.get_panel_v2(bridges=["ccip", "cctp"])

# CCTP: per-message capture since 2026-05-11
#   capability_level = "per_message_attested", crypto.anchor = "circle_ecdsa"
#   metrics.latency_p90_s / latency_p99_s / success_rate_1h are computed on per-message latencies
br = panel.bridge_by_id("arbitrum-ethereum/cctp")
if br and br.state == "BS2":
    use_fallback_route()
if br and br.metrics and br.metrics.latency_p90_s and br.metrics.latency_p90_s > 1200:
    log.warning(f"{br.id}: attestation P90 {br.metrics.latency_p90_s:.0f}s above 20-min threshold")

# CCIP: capability_level = "aggregate" today (per-message capture upgrade scheduled May 2026)
#   metrics.commit_latency_p90_s and metrics.total_latency_p90_s remain None until upgrade
ccip = next((b for b in panel.bridges if b.type == "ccip"), None)
if ccip and ccip.metrics and ccip.metrics.last_sequence_advance_s and ccip.metrics.last_sequence_advance_s > 600:
    log.warning(f"{ccip.id}: lane idle for {ccip.metrics.last_sequence_advance_s:.0f}s")

# RMN cursed override (CCIP only) — absolute binary, lane is frozen
if ccip and ccip.is_frozen:
    block_ccip_route()

Retrieve a CCTP per-message ECDSA attestation

Each attested CCTP message exposes a Circle ECDSA signature (65-byte secp256k1), independently verifiable against Circle's published attester public key.

# Lookup by message hash (32-byte keccak256, 0x prefix optional)
att = client.get_cctp_attestation("0x654c0c87fb7895ec703d200469e8ef2b57876e06ad88b65e74e6e515f0ee510e")

print(att["status"])                              # "attested" or "pending"
print(att["source_chain"], "→", att["dest_chain"])
print(att["attestation"]["signature"])            # "0x..." 65-byte ECDSA secp256k1
print(att["attestation"]["latency_ms"])           # observed source_block → Iris attestation latency
print(att["attestation"]["verification_url"])     # https://iris-api.circle.com/attestations/...

Handle degraded data gracefully

panel = client.get_panel_v2()

if panel.oracle_status == "DEGRADED":
    for entry in panel.l1 + panel.l2:
        if entry.status != "OK":
            log.warning(f"{entry.chain}: {entry.status}")
    for br in panel.bridges:
        if br.status in ("STALE", "UNAVAILABLE"):
            log.warning(f"{br.id}: {br.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)
UNAVAILABLE Signal temporarily missing
UNCALIBRATED Collector running, thresholds not yet published. Does not trigger DEGRADED.

Regime grid

12 signed codes per chain on both L1 and L2.

Code Structure Demand What it captures
S1D1 nominal nominal Within calibrated norms
S1D2+ nominal high Demand surge, infrastructure healthy
S1D2- nominal low Demand depressed, infrastructure healthy
S1D2± nominal split Asymmetric demand composition
S2+D1 high stress nominal Silent structural slowdown. No fee signal.
S2-D1 low stress nominal Silent structural underrun. No fee signal.
S2+D2+ high stress high Combined upward stress
S2+D2- high stress low Stress with depressed demand
S2+D2± high stress split Stress with asymmetric demand
S2-D2+ low stress high Underrun with elevated demand
S2-D2- low stress low Underrun with depressed demand
S2-D2± low stress split Underrun with asymmetric demand

Bridge states (variable-latency surfaces only):

Code Type Meaning
BS1 ccip / cctp Within calibrated latency threshold
BS2 ccip / cctp Above calibrated latency threshold
null any Not yet calibrated. Raw signals still exposed on the entry.

Calibration status:

  • CCTP: per-message capture since 2026-05-11 (capability_level: per_message_attested). Each message exposes a Circle ECDSA signature (crypto.anchor: "circle_ecdsa"), retrievable via client.get_cctp_attestation(message_hash) and independently verifiable against Circle's published attester public key. metrics.latency_p90_s / latency_p99_s / success_rate_1h computed on per-message latencies. Confidence MEDIUM (EVM only; Solana routes scheduled 2026-Q3).
  • CCIP: capability_level: aggregate today. metrics.messages_confirmed_1h, metrics.last_sequence_advance_s, and metrics.rmn_cursed exposed; per-message latency P90/P99 not yet computed (upgrade to per_message_attested scheduled May 2026). RMN cursed override remains absolute.

Chain coverage

Chain Layer Confidence Status
ethereum L1 HIGH live
polygon L1 MEDIUM live
arbitrum L2 MEDIUM live
base L2 MEDIUM live
optimism L2 MEDIUM live
avalanche L1 LOW observation
solana L1 LOW calibration target Q3 2026

Bridges live (variable-latency scope, 20 lanes total): 10 CCTP routes (per-message ECDSA capture since 2026-05-11, capability_level: per_message_attested) and 10 CCIP lanes (capability_level: aggregate today; per-message capture upgrade scheduled May 2026).


Migrating from v0.6.x

v0.7.0 narrows the bridge scope to variable-latency surfaces (CCIP, CCTP). Native L2-to-L1 bridges operate on protocol-defined timeframes outside any observability lever and are removed from the panel. Several types and fields are removed accordingly.

# Removed types
# from invarians import CcipState, CctpState, AnyBridgeState  # gone — use BridgeState

# Removed fields on BridgeEntry
# br.last_batch_age_seconds                                   # gone (native-only signal)

# Removed fields on Coverage / V2Coverage
# coverage.bridges_native                                     # gone

# BridgeType is now Literal["ccip", "cctp"]  (was: "native" | "ccip" | "cctp")
# State codes CS1 / CS2 (CCIP) and TS1 / TS2 (CCTP) are unified as BS1 / BS2

If you previously did bridge_by_id("arbitrum-ethereum/native"), switch to a CCTP route ("...-ethereum/cctp") or a CCIP lane ("...-ethereum/ccip").


Error handling

from invarians.exceptions import AuthError, RateLimitError, ServerError

try:
    panel = client.get_panel_v2()
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}")

Documentation

API reference: invarians.com/developers.html


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

invarians-0.8.0.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

invarians-0.8.0-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file invarians-0.8.0.tar.gz.

File metadata

  • Download URL: invarians-0.8.0.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for invarians-0.8.0.tar.gz
Algorithm Hash digest
SHA256 dc8d9384de5b01b8c7c9cd88651ab19a805e17ca535b47108a803886ac36d9f8
MD5 579399a2b2561382ef62df3b9f6bf163
BLAKE2b-256 8382bdda9dd5d3040a5503b09040c009b26a6d9d29452e06a5822ad03766eef1

See more details on using hashes here.

File details

Details for the file invarians-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: invarians-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for invarians-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3284fb7755d66e4359d0050e85b00b1e0ff0f5a499bc066f3f2cd8acc58f2912
MD5 b71e47b54f7dd0ae99b939fed5ea3728
BLAKE2b-256 675feadfebfb8c4a90e8a1d15dc7b724dc2d0a08ca31d0b591fc9a13741cee77

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page