Skip to main content
An invariant is a property that must hold no matter what a malicious or careless client does. Ward compiles each one into a self-contained, executable test: build a real payment, optionally tamper with it in one specific way, submit it to a real facilitator, and assert the response is correct. Every invariant’s source field — visible in ward test / ward fuzz output and in the JSON report — cites exactly what it’s checking against, so a PASS or FAIL is always traceable back to either the x402 protocol spec, the USENIX Security ‘26 facilitator study, or a specific Algorand protocol primitive.

The full set

Must-have vs. stretch

ward test exits non-zero if any must-have invariant fails (U1, U2, U3, U4, A1 — see MUST_HAVE_IDS in src/cli/setup.ts), making it safe to gate a CI pipeline or a release process on. Stretch invariants (U5, A2, A3) still run and report every time, but a failure there doesn’t fail the overall run — they cover real but narrower correctness properties (bounded rejection cost, early opt-in detection, post-rekey authorization) that matter less universally than the five must-haves.

Universal vs. Algorand-specific

Universal (U1–U5)

Import only core/types.ts and invariants/shared.ts. They express properties every x402 facilitator must satisfy regardless of settlement chain — verify/settle consistency, retry safety, concurrency safety, allowlist enforcement, and bounded rejection cost.

Algorand (A1–A3)

The only invariants allowed to import chain-adapters/algorand/*. They express properties specific to Algorand’s transaction model — atomic transaction groups, ASA opt-in semantics, and account rekeying.

Reading a result

Every invariant produces an InvariantResult:
evidence is never a black box — it’s the literal request bodies sent and response bodies received for every sub-case an invariant runs, collected via util/evidence.ts’s EvidenceCollector. ward fuzz <id> prints this in full; ward test’s table shows a compact evidenceSummary, with the full trail available in the written JSON report.

Start with the headline invariant

A1 is the sharpest, most Algorand-specific test in the suite — read it first to see what “adversarial” actually means in Ward’s context.