marc
DOC-06 · SECURITY

Audit Readiness

PRE-ENGAGEMENT PACK · TWO AUDITS · CODE FREEZE HASH PENDING

Two independent audits stand between this code and the MARC launch gate. This pack gives each engagement its scope, its invariants, and its threat models up front — so auditors spend their weeks breaking the protocol, not reading it.

01Engagements

#SCOPECONTRACTSEST. LOCRISK TIERWEEKS
ACapital contractsEscrow · SettlementBatcher · MARC token + VestingVault≈ 1,080CRITICAL3 + 2 remediation
BConsensus contractsVerifierRegistry · QuorumElection · SlashExecutor · EmissionsDistributor≈ 1,200CRITICAL3 + 2 remediation

Both engagements audit against commit freeze — no scope drift mid-review. Frozen hash recorded on-chain at engagement start; any post-freeze change reopens that contract's review.

02Escrow — invariants & threat model

Holds every task's USDC until proof or ruling. Immutable, no upgrade path, no admin withdrawal. This is the contract users actually trust with capital, so its invariant list is short and absolute:

INVARIANTMUST HOLDTEST
I-E1Funds move only on matched quorum proof, or signed ruling inside fraud windowinvariant test: no code path bypasses both
I-E2Σ escrowed per-task balances == contract USDC balance at all timesstateful fuzz: random op sequences
I-E3settle() is idempotent — double-settle pays oncereplay fuzz
I-E4No role, key, or pause can freeze escrow beyond one ruler signature + windowadmin-key simulation: zero authority paths
ATTACKPRECONDITIONIMPACTMITIGATIONSTATUS
Reentrancy on settle hookattacker-controlled token callbackdouble-releaseCEI order + nonReentrant; USDC has no hooksCOVERED
Ruling replay across railssame domain on two chainsdouble refund on second railchainId in EIP-712 domain; per-rail nullifiersCOVERED
Fraud-window timestamp squeezeminer-aligned block timesruling after honest windowwindow measured in blocks, not secondsCOVERED
Commit griefingbond-free commitsescrow lock DoScommit bond forfeited on TTLOPEN — bond rate under calib.
Fee rounding accumulationmany tiny tasksdust accounting drift vs I-E2floor-fee minimum 0.01 USDCCOVERED

03Settlement batcher

Posts Merkle roots every 30s; receipts carry inclusion proofs. Batching exists to amortize L1 fees, not to custody anything — the failure mode is withholding, not theft:

ATTACKPRECONDITIONIMPACTMITIGATIONSTATUS
Root forgery by compromised batcherbatcher hot key leakedfalse receipts anchored2-of-3 multisig + epoch key rotation; slashable bondCOVERED
Withholding / liveness failurebatcher offlineanchoring stallsanyone may force-batch after 2 missed windows (permissionless)COVERED
MEV on batch inclusionpublic mempoolroot front-runningprivate relay; anchor is append-only so front-run gains nothingCOVERED
EXCLUSION
The USDC token contract itself is out of scope — including its own upgradeability risk, which the threat register tracks separately as an external dependency assumption.

04MARC token & vesting

Fixed supply, no mint authority, vesting locked to network epochs — not wall clocks — per the tokenomics design:

INVARIANTTEST
I-T1 totalSupply == 1e9 forever; mint() does not exist in bytecodebytecode grep + symbolic exec
I-T2 vested(t) is monotone non-decreasing; epochs never tick backwardsepoch oracle fuzz
I-T3 paused network ⇒ paused vesting; no insider accrues stalled timeepoch-freeze state machine test
ATTACKIMPACTMITIGATIONSTATUS
Epoch oracle manipulation to fast-forward cliffsearly insider unlockoracle = epoch counter on settlement rail, not gov-settableCOVERED
approve/transferFrom race (ERC-20 classic)allowance double-spendOZ ERC20 with increaseAllowance guidance in SDKCOVERED
Snapshot timing at epoch boundaryclaim twice on boundary reorgclaims settle at epoch+1 stateOPEN — formal boundary proof pending

05Quorum election

The election decides who verifies — bias here is bias everywhere. Determinism is the defense: the same seed must yield the same quorum on every recompute:

ELECTION — DETERMINISM SPEC (AUDITOR-REPRODUCIBLE)UTF-8
seed = keccak(blockhash(epoch_start - 2)) // past, not future
score(i) = bond_i × acc_i² × (0.75 + u_i × 0.5) // u_i from seed
quorum = top-3 by score, bond ≥ 25,000, not jailed
 
caps: weight_ratio(quorum) ≤ 67% // whale capture bound
jail: open challenge ⇒ cannot unbond or re-elect
 
fixtures: 40 election scenarios w/ expected quorums
shipped in /test/fixtures/elections.json
ATTACKPRECONDITIONIMPACTMITIGATIONSTATUS
Validator blockhash biasrail validator manipulates seed blocksteer quorum selectionpast-block seed + commit-reveal fallbackCOVERED
Sybil grinding pre-epochcheap identities in candidate poolcrowd out honest seatsbond floor + accuracy decays to 0 on new identityCOVERED
Weight overflow / rounding steerhuge bond inputelection capture via arithmeticmulDiv 512-bit math; weight cap 67%OPEN — formal check pending

06Slash executor

ATTACKIMPACTMITIGATIONSTATUS
Evidence replay — same proof, double slashverifier bled twicenullifier per evidence hash; consumed on first useCOVERED
Challenge griefingchallenges spam-locked to stall unbondschallenger posts bond, slashed on frivolous proofCOVERED
Escalating slash DoSepoch where many proofs arriveslash cap per epoch; FIFO challenge queue with timeoutsOPEN — cap value under calib.
False-evidence by compromised verifierhonest voter burnedchallenged vote re-executed in fresh quorum before burningCOVERED
KNOWN RESIDUAL RISK
Collusion detection is heuristic (linked stake signatures + voting correlation). A perfect colluder leaves no trace; the mitigation is economic (100% bond at risk) plus challenges by any watcher. Auditors should attack this explicitly — it is the protocol's hardest problem.

07Cross-contract systemic threats

SURFACEEXPOSUREPOSITION
Multi-rail replaytasks and rulings replicated across railsdomain-separated chainIds in every signature
USDC upgradeabilityproxy changes under escrowexternal dependency in threat register; custody never relies on USDC internals
MEV on verdict transactionsruling params visible pre-inclusionsigned rulings are payload-bound; front-running gains nothing
Governance floor captureMARC holders steer fee/quorum paramsphase gates: foundation till V1.0, bounded vote, timelock 7d
Deterministic-sandbox divergencespec executes differently in verify than in worksame WASM runtime, pinned version hash, frozen syscall table

08Process, rubric & remediation SLA

SEVERITYDEFINITIONEXAMPLE HERESLA
CRITICALloss of user funds or escrow invariants brokenI-E1/I-E2 violationfix + re-audit before any deployment
HIGHnetwork-wide liveness or trust compromiseelection capture, slash-grieffix before gate #3 completes
MEDIUMbounded loss or degraded correctnessrounding drift, boundary snapshotfix before V0.3
LOW / INFOhardening, clarity, gasevent indexing, natspecrolling backlog

Coverage targets: 100% line coverage on Escrow and SlashExecutor (invariant-driven Foundry suite), ≥ 95% on all other contracts, plus 40 deterministic election fixtures and 12 slashing scenarios shipped as reproducible fixtures inside each engagement's repo.

ENGAGEMENT TIMELINEUTF-8
W1 ENG-A kickoff — capital contracts, freeze hash anchored
W3 ENG-A report — triage within 48h
W4 remediation window A (+ re-audit of patches)
W6 ENG-B kickoff — consensus contracts
W8 ENG-B report — triage within 48h
W9 remediation window B → launch gate #3 evaluation
rule: no gate #3 until every CRITICAL and HIGH is closed
AUDIT CONTACT: HELLO@MACHINARC.COM · REPORTS PUBLISHED IN FULL — VERIFIERS DESERVE TO READ WHAT THEY BOND AGAINST.
MACHINARC LABS · DOCS V0.2 · ERRATA VIA GITHUB