Crossfoot Source on GitHub

crossfoot

Crossfoot audits tokenized-asset feeds from the outside: it replays the feed's public rules at exact blocks, shows whether each update went through the guarded path or the admin bypass, and gives consumers an evidence-backed decision.

What it does

Recomputes value from the contractual terms, compares it with the chain

A vendored ACTUS PAM engine in Rust models what a tokenized instrument should be worth from its contract terms, in exact decimal arithmetic with no floats and no clock reads, and compares the result with what the contract stored on chain at pinned blocks.

Where the underlying portfolio is not observable, the value is never recomputed. The tool replays the oracle's own posting rules per implementation era instead: deviation bound, spacing, min and max, stored rounds against emitted events.

Two targets today. svzchf, the Frankencoin savings vault: full recomputation, two independent model paths. mtbill, Midas mTBILL: consistency checks, no recomputation, the result always carries INPUT_GAP for the NAV.

Read-only by construction

The binary issues chain reads and keyless HTTP GETs. It holds no key and has no code path that can sign or send a transaction. Every read is pinned to an explicit block; nothing is read at latest.

Every run writes evidence

Every raw response is stored byte for byte with its sha256 in a manifest, and a run can be replayed offline from the local cache. Bundles are not yet self-contained; crossfoot verify, which re-hashes and replays from the bundle alone, is planned, not shipped.

One verdict vocabulary for both targets

MODEL_MATCH / CONSISTENT
all values equal, or all rules satisfied on enough data
OBSERVED_DEVIATION
a nonzero residual or a rule violation
MODEL_INCONSISTENT
the two model paths disagree; the chain is not judged
INSUFFICIENT_WINDOW
a check lacked rounds or days to run. Not a pass.
SOURCE_STALE
an input could not be read at the pinned block
INPUT_GAP
a required series is unobtainable; outranks the others

The Midas survey

44 bounded feeds, no unchecked post over the bound
16 feeds with at least one unchecked post over the bound in force
10 of them with such a post since 2026-03-01
6 derived wrapper feeds without a bound, excluded from the replay
66 Midas customFeed contracts on Ethereum mainnet, replayed on 2026-09-01 from external transaction lists and, on the six oldest feeds, from the AnswerUpdated logs of rounds posted through Safes. The order of the squares is arbitrary.
66feeds replayed, every setter call decoded
57unchecked posts over the bound, on 16 feeds; 29 on 14 from transaction lists alone
12of them since 2026-03-01, on 10 feeds

An unchecked post is a posting-path finding: the poster key used the setter that skips the deviation guard, and the move exceeded the bound in force at that block. It says nothing about whether the value was wrong.

The three largest cases
Largest casesPostsBound thenLargest movePeriod
mBTC150.05 %0.105 %2024-11-21 to 2025-03-11, posted through a Safe; the most by count
mSL100.05 %5.727 %2025-05-07 to 2026-03-31, then the bound raised to 0.35 %
mevBTC50.4 %19.312 %2026-02-13 to 2026-03-18, five weeks; the largest move

The bound is a governance parameter changed by timelocked upgrades that never show in the feed's own transaction list, so Crossfoot reads it from archive state at the block, never from head. Rounds posted through a Safe are invisible there too: on the six oldest feeds, 215 such rounds came from AnswerUpdated logs, 28 of them over the bound.

Run it

Rust, one binary, no key

--offline serves every read from the cache and fails on a miss, which proves a replay made no network call.

--verify-root is where cache/ and bundles/ live. Live cross-checks are ignored by default and need the network once.

# build and test (offline)
cargo build --release
cargo test
cargo test -p crossfoot -- --ignored   # live cross-checks

# fetch, run, render
crossfoot fetch svzchf --block <B1> [--baseline-block <B0>]
crossfoot run svzchf --baseline-block <B0> --block <B1>
crossfoot run mtbill --baseline-block <B0> --block <B1>
crossfoot render --bundles bundles --out site