Arcveil
Verification

Five checks. Two local, three against Arc, and a third verdict that matters.

Verification answers one question in five parts: is this receipt the one that was issued, was it issued by the policy signer, was the mandate it names live, does it join the receipt before it, and did the action really settle. The overall verdict is the worst of the five.

What each one asks

  • 01integrityLocalpass · fail

    Does the body still hash to the id it claims?

    Recomputes sha256 over the canonical body. Editing one character of a receipt fails here, which is why this check has no unknown: the answer never depends on anything outside the file.

  • 02signatureLocalpass · fail · unknown

    Did the policy signer sign these exact bytes?

    ECDSA P-256 over the same canonical bytes the id covers. A receipt carrying a zk proof returns unknown: the in-browser verifier for those ships with v1.

  • 03mandateArc mainnetpass · fail

    Was that mandate commitment live at that epoch?

    Reads MandateRegistry.mandateOf(account, epoch). Fails if nothing is registered, if the epoch was revoked, or if the commitment on chain differs from the one the receipt was checked against. The terms behind the commitment stay sealed either way.

  • 04linkageArc mainnetpass · fail · unknown

    Does the budget chain join to its predecessor?

    With a predecessor in the bundle, the previous receipt's counter.next must equal this one's counter.prev — a gap means a receipt was dropped or reordered. With no predecessor, the starting commitment has to be anchored in AnchorRegistry; if it is not, the answer is unknown, not fail.

  • 05settlementArc mainnetpass · fail · unknown

    Did the transaction it points at succeed?

    An eth_getTransactionReceipt for action.settledTx. A reverted transaction fails. A transaction that is not visible yet, or a receipt for a different chain than the verifier is pointed at, returns unknown.

Three verdicts

The three verdicts a check can return.
passThe check ran and the answer was yes.
failThe check ran and the answer was no. This receipt is not what it claims.
unknownThe check could not decide. Never reported as a pass, and never as a fail — which would read as an accusation the evidence does not support.

The report

Verification returns every verdict, not a boolean — the detail line on a failing check is usually the whole answer. Receipts are checked in the order given, so a bundle verifies its own linkage.

report shape
const report = await verifyReceipts(parsed.receipts, { chain }); report.status; // worst verdict across every receiptreport.receipts[0].status; // worst across this receipt's five checksreport.receipts[0].checks; // [{ id, status, detail }, ...] in CHECK_ORDER

Checking against fixed state

The RPC reader is one implementation of a small interface. Tests use the in-memory one, which answers from a state you supply.

chain.test.ts
// In tests, hand the verifier the chain state you want to check against.import { createMemoryChainReader } from "@arcveildev/sdk"; const chain = createMemoryChainReader({  mandates: [{ account, commitment, epoch: 1, revoked: false }],  transactions: { [settledTx.toLowerCase()]: { status: "success" } },  anchors: [head],});

Or just try one

The verifier on this site runs exactly these checks against Arc mainnet. Load a sample, change one character, and watch which check catches you.