aere-docs/AERE-FORMAL-EXTENSION-MONEY-CONTRACTS.md
Aere Network e4cead319d Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:01:36 +03:00

11 KiB

Formal-verification extension: new fund-flow contracts (z3 SMT + full regression)

Date: 2026-07-19 Scope: three new money contracts for Aere Network, modelled in z3 in the exact style of the existing consensus/contract SMT corpus, plus a full regression of the new-contract test suite to confirm the recent security fixes (M1 giveFeedback gate, L1 codeless-gateway guards, L2 VectorStore receipt binding) broke nothing.

Honesty posture (same caveat as the rest of the corpus): each SMT script checks the DESIGN-level accounting/guard logic over the modelled transitions with unbounded Ints, NOT the compiled EVM bytecode. A model counts as non-vacuous only because a NEGATIVE CONTROL (one guard removed) fires a real counterexample. Trusted external primitives (SP1 gateway proof soundness, the Falcon-512 precompile at 0x0AE1, SafeERC20 whole-tx revert) are marked [VERIFY] and are not re-proved here.

All verdicts below are the REAL z3 output and the REAL mocha output, reproduced verbatim from the runs.


PART 1: new z3 SMT models

All three scripts live in aerenew/formal-consensus/ (they join the existing corpus next to spokepool_smt.py, settlementhub_smt.py, threshold_account_smt.py). Run each with python <script>.py (z3-solver 4.16.0, confirmed installed). Each exits 0 only if every PROOF is PROVED and every NEGATIVE CONTROL fired.

A. computemarket_smt.py -> AereComputeMarketV3, ESCROW SOLVENCY

Contract: aerenew/contracts/contracts/depin/AereComputeMarketV3.sol Invariant (the contract's own isSolvent): per asset T, bal[T] >= totalLiabilities[T] and totalLiabilities[T] >= 0, where a reward is escrowed in its own token and EVERY provider/challenger bond is native AERE (address(0)). So native liabilities carry native-token rewards PLUS all bonds; an ERC-20 asset carries only its own rewards. No fee, no owner, no sweep in this contract, so each op's balance delta equals its liability delta on the same asset.

VERDICT: PROVED (16 proofs UNSAT), 3 NEGATIVE CONTROLS fired (SAT). Script exit 0.

Proofs (all z3=unsat, inductive across the real transitions):

  • base case (empty contract) satisfies INV
  • postJob(native) / postJob(ERC20, received==reward guard) preserve INV
  • claimJob (bond escrowed to native), cancelJob (refund + uncommit) preserve INV
  • submitResult (status-only, no fund move) preserves INV
  • settle (acceptResult / finalize / submitResultZK): reward leg on token asset, bond-return leg on native, AND the combined leg when token==native, all preserve INV
  • reclaimExpired (reward + bond leave together) preserves INV
  • dispute (challenger bond escrowed) preserves INV
  • resolveDispute BOTH branches (providerWon / not) preserve INV on token and native legs
  • no double-count: an ERC20-reward + native-bond settle keeps BOTH assets solvent, reward touched only on its asset, bond only on native
  • double-pay: a second payout after the terminal status is set is guard-infeasible
  • ZK_VERIFIED: paying without a valid proof is impossible (settlement sits strictly behind the ZK_VERIFIER.verifyProof gate, which reverts on an invalid proof)

Negative controls (all z3=sat, load-bearing):

  • BUGGY postJob (commit full reward but receive less, i.e. no received==reward check) CAN under-back the escrow [witness: reward=1, received=0]
  • BUGGY claim (native bond mis-posted to the ERC-20 reward asset) CAN under-back that asset [witness: bond=1, balE=0, liabE=0]
  • BUGGY ZK settle (no verifyProof gate) CAN pay without a valid proof [witness: pay_zk=1, proofValid=0]

[VERIFY] SP1 gateway proof soundness and the Falcon-512 precompile at 0x0AE1 are trusted primitives, not re-proved by this SMT model.

B. destinationsettler_smt.py -> AereDestinationSettler, NO-ARBITRARY-RECIPIENT + ATOMICITY

Contract: aerenew/contracts/contracts/intents/AereDestinationSettler.sol Guards modelled from the real fill(): G1 declOrderId==orderId, G2 declRecipient!=0, G3 declOutputToken!=0, G4 declOutputAmount!=0, G5 fills[orderId].filler==0 (unfilled), G6 delivered token == declared token AND delivered recipient == declared recipient AND delivered amount >= declared amount.

VERDICT: PROVED (5 proofs UNSAT), 4 NEGATIVE CONTROLS fired (SAT). Script exit 0.

Proofs:

  • P1 a successful fill can deliver ONLY to the order's declared recipient (an attacker address is impossible)
  • P1b the transfer target equals the declared recipient AND is non-zero
  • P2 a second fill of an already-filled order is guard-infeasible (AlreadyFilled), so a solver is repaid at most once per intent
  • P2b the fill is bound to the arg orderId (G1), so no cross-slot record can dodge the duplicate check
  • P3 an output that mismatches the declared token OR is short is rejected (OutputMismatch)

Negative controls:

  • no-recipient-check settler CAN deliver to an arbitrary attacker [witness: declRecipient=1, attacker=2, deliveredRecipient=2]
  • no-AlreadyFilled settler CAN double-fill one order (double repayment)
  • no-ZeroRecipient settler CAN record a delivery to address(0)
  • no-OutputMismatch settler CAN record a wrong-token delivery [witness: declOutputToken=1, deliveredToken=2]

[VERIFY] Delivery ATOMICITY (effects-before-interaction record, then a single SafeERC20 pull solver->recipient that reverts the whole tx on failure, under nonReentrant) is an EVM-revert property asserted structurally, not by this arithmetic model. [MEASURE] Origin-chain repayment is gated by the validator-set-anchored finality+inclusion proof and is out of scope here.

C. migrator_smt.py -> AereAccountMigrator, ONLY-DESTINATION + ATOMICITY

Contract: aerenew/contracts/contracts/pqc/AereAccountMigrator.sol Guards modelled from the real _migrate(): H1 destination!=0, H2 length match, H3 each token/amount !=0, H4 moveNative => msg.value!=0, H5 !moveNative => msg.value==0 (StrayNative, the no-strand guard), H6 every ERC-20 leg is safeTransferFrom(caller, destination, amount), H7 native leg forwards the full msg.value to destination and reverts on failure.

VERDICT: PROVED (5 proofs UNSAT), 4 NEGATIVE CONTROLS fired (SAT). Script exit 0.

Proofs:

  • P1 every ERC-20 leg delivers ONLY to the caller's non-zero destination (no third-party target)
  • P2 no custody: sum(pulled from caller) == sum(delivered to destination), migrator ERC-20 delta == 0
  • P3 atomicity: no partial move, all legs commit or none (whole-tx revert)
  • P4 no stranded native: migrator native delta == 0 (StrayNative guard + full forward)
  • P5 migrateToPqcAccount honors a pinned expectedDestination (AddressMismatch guard)

Negative controls:

  • BUGGY skim (a fee f>0 diverted to a third party) CAN leak funds off destination [witness: amount0=2, fee=1, destGets=1, feeCollectorGets=1]
  • BUGGY per-leg try/catch (continue past a failed leg instead of whole-tx revert) CAN leave a PARTIAL move, i.e. a half-drained old account [witness: leg_ok_0=true, leg_ok_1=false]
  • BUGGY no-StrayNative migrator CAN strand native value unrecoverably (no sweep exists) [witness: msgValue=1]
  • BUGGY no-ZeroDestination migrator CAN sweep to address(0) (burn) [witness: destination=0]

[VERIFY] Whole-tx atomicity rests on SafeERC20 reverting on a false/failing ERC-20 and on nonReentrant; P3 models its consequence (all-or-nothing) rather than the opcode semantics.

Part 1 summary table

Model File Proofs (UNSAT) Neg-controls (SAT) Control fired? Exit
AereComputeMarketV3 escrow solvency computemarket_smt.py 16 / 16 PROVED 3 / 3 YES 0
AereDestinationSettler no-arb-recipient + atomicity destinationsettler_smt.py 5 / 5 PROVED 4 / 4 YES 0
AereAccountMigrator only-destination + atomicity migrator_smt.py 5 / 5 PROVED 4 / 4 YES 0

Every model is non-vacuous: each has at least one firing negative control. No z3 timeouts, no FAILED lines. The out-of-decidable-scope pieces (EVM whole-tx revert atomicity, SP1/Falcon primitive soundness, origin-chain repayment) are marked [VERIFY]/[MEASURE] honestly and are not claimed as proved.


PART 2: full regression of the new-contract test suite

npx hardhat compile -> GREEN ("Nothing to compile", cache valid, exit 0).

Per-file npx hardhat test test/<file>.test.js (RandomnessBeacon run with --config hardhat.config.prague.js so the EIP-2537 BLS12-381 pairing path actually executes):

# Test file Result Exit
1 AereRecoveryRegistry.test.js 10 passing 0
2 erc8004-adapters.test.js 19 passing 0
3 AerePQAggregate.test.js 18 passing 0
4 aere-pq-screen.test.js 13 passing 0
5 destination-settler.test.js 4 passing 0
6 AereRandomnessBeaconV2.test.js (prague config) 15 passing, 1 pending 0
7 AereComputeMarketV3.test.js 14 passing 0
8 aere-vector-store.test.js 8 passing 0
9 account-migrator.test.js 9 passing 0
10 AerePQFinalityCertificate.test.js 12 passing 0

GRAND TOTAL: 122 passing, 0 failing, 1 pending (all 10 files exit 0).

Notes:

  • 0 failing across all 10 logs (verified by a grep for "failing": NONE).
  • The 1 pending is intentional and honest: under the prague config EIP-2537 IS present, so the "without EIP-2537, a genuine sig is also rejected" fail-closed-ABSENCE check is not applicable and is skipped. The 15 passing include the real on-chain BLS12-381 pairing verification of genuine drand quicknet vectors.
  • destination-settler.test.js legitimately has 4 tests (valid fill, duplicate reverts, output mismatch reverts, zero recipient reverts), the complete run, matching the properties modelled in Part 1.

The recent security fixes (M1 giveFeedback gate in the ERC-8004 adapters, L1 codeless-gateway guards, L2 VectorStore receipt binding) introduced NO regression: erc8004-adapters (19), aere-vector-store (8), and the whole suite stay green.


Flags / honest caveats

  • SMT models check DESIGN-level math/guards over the modelled transitions with unbounded Ints, NOT the compiled EVM bytecode. Same boundary as the existing corpus.
  • [VERIFY] items not proved by SMT: SP1 gateway proof soundness, Falcon-512 precompile (0x0AE1) soundness, SafeERC20 whole-tx revert / nonReentrant atomicity.
  • [MEASURE] AereDestinationSettler origin-chain repayment (off-chain SP1 prover + second chain) is out of scope for both the SMT model and the unit test.
  • 1 pending test in the regression is a deliberately-skipped not-applicable fail-closed-absence check under the prague EVM, not a masked failure.
  • No contract was modified. Only the three new SMT scripts were added.

Files added:
  aerenew/formal-consensus/computemarket_smt.py
  aerenew/formal-consensus/destinationsettler_smt.py
  aerenew/formal-consensus/migrator_smt.py