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 on-chain check or the issuer's documented high-deviation path, and gives consumers an evidence-backed decision.
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.
Three targets today. svzchf, the Frankencoin savings vault: full recomputation, two independent model paths. midas, the 66 Midas customFeed contracts: the posting path of every round replayed, the result always carries INPUT_GAP for the NAV. mtbill, the original Midas mTBILL checks.
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 raw response is stored byte for byte with its sha256 in a manifest, and crossfoot verify <bundle> re-hashes every file and replays the verdict from the bundle alone, without the network; exit code 0 means the root hash on the page reproduces. Bundles download from every feed page of the explorer.
An unchecked post is an update sent through the setter without the on-chain deviation check. Midas documents that path as a higher-quorum process applied off chain; nothing on chain shows which process was followed. It says nothing about whether the value was wrong.
| Largest cases | Posts | Bound then | Largest move | Period |
|---|---|---|---|---|
| mBTC | 15 | 0.05 % | 0.105 % | 2024-11-21 to 2025-03-11, posted through a Safe; the most by count |
| mSL | 10 | 0.05 % | 5.727 % | 2025-05-07 to 2026-03-31, then the bound raised to 0.35 % |
| mevBTC | 5 | 0.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.
One worked case: on 2026-05-06 the mRE7 feed took the path without the on-chain check for a 2.22 percent move against a 0.36 percent bound; the consumer agent routes it to REVIEW. See the round on its timeline, with the bound step, the findings and the bundle that reproduces the page.
Binaries are attached to the latest release; the README covers install, targets and the verdict vocabulary.
--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 midas --block <B1> --config config/midas-mainnet.json crossfoot render --bundles bundles --out site # decide, then re-check any bundle offline crossfoot consume --subgraph $CROSSFOOT_SUBGRAPH_URL --timeline mRE7 crossfoot verify <bundle>.tar.gz # exit 0: root hash reproduces