# Vaultfire V3 — Draft State (existing code vs assignment requirements)

**Prepared:** 2026-08-20
**Repo HEAD:** `a80144d1acbbbbf24b9eca7cd91e61daad0c0ad6` at `gitlawb://z6MkryiNsYdFEMHv95wxzSQ1vtFXPyVQQrxXdPw3tE5HpfxV/vaultfire`
**Prior audits (all V3.3 branch):** V3.2 → V3.3-R1 → V3.3-R2 → V3.3-R3 (Coinbase-grade, 2026-03-27)
**Purpose:** Ground the PR2+ work in what already exists rather than starting V3 from zero. The V3.3-R3 audit verified 34/34 prior CRIT+HIGH fixes as correct — the code is real and mature. The gap between it and the assignment is a *smaller-than-expected* additive scope, not a rewrite.

---

## Inventory of existing V3 draft files (in `v2-repo/contracts-root/`)

Two variants coexist: canonical `.sol` and `push_contracts_v3_*.sol` copies staged for release. Where both exist they should be diffed and one dropped.

| # | File | LoC | Layer | R3 status |
|---|---|---|---|---|
| 1 | `AIAccountabilityBondsV3.sol` | 1,111 | Bond (star) | 11 prior CRIT+HIGH fixed · 1 R3 HIGH (nonReentrant) · 1 R3 HIGH indirect (partnership solvency next door) · 5 R3 MED |
| 2 | `AIPartnershipBondsV3_to_push.sol` | 903 | Bond (star) | ✅ prior fixes verified · **1 R3 HIGH-R3-02 solvency** · 5 R3 MED |
| 3 | `file_05_contracts_v3_BaseYieldPoolBondV3.sol.txt` / `push_contracts_v3_BaseYieldPoolBondV3.sol` | 535 | Bond | Included in R3 scope, no HIGH found |
| 4 | `file_04_contracts_v3_BaseDignityBond.sol.txt` | ~200 | Bond | Not in R3 scope — see gap list |
| 5 | `VaultfireTeleporterBridgeV3.sol` | ~700 | Bridge | ✅ prior fixes verified · 3 R3 HIGH (sender field, destination chainId, interface gap) · 7 R3 MED |
| 6 | `TrustPortabilityExtensionV3.sol` | 720 | Bridge | R2 fix verified · 1 R3 HIGH (stale-overwrite guards) · 3 R3 MED |
| 7 | `file_15_contracts_v3_MultisigGovernanceV3.sol.txt` / `push_contracts_v3_MultisigGovernanceV3.sol` | ~350 | Governance | Threshold, guardians, timelock present · 3 R3 MED (signer removal, threshold immutable, guardian rotation) |
| 8 | `file_07_contracts_v3_DilithiumAttestorV3.sol.txt` / `push_contracts_v3_DilithiumAttestorV3.sol` | ~200 | ZK/Governance | **1 R3 CRITICAL (timestamp)** |
| 9 | `file_11_contracts_v3_FlourishingMetricsOracleV3.sol.txt` / `push_contracts_v3_FlourishingMetricsOracleV3.sol` | 201 | Oracle | 2 R3 MED (stale source data, unbounded sourceList) |
| 10 | `file_14_contracts_v3_MultiOracleConsensusV3.sol.txt` / `push_contracts_v3_MultiOracleConsensusV3.sol` | 307 | Oracle | 1 R3 HIGH (slashed-stake), 2 R3 MED |
| 11 | `file_06_contracts_v3_BeliefOracleV3.sol.txt` / `push_contracts_v3_BeliefOracleV3.sol` | 247 | Oracle | 1 R3 HIGH (queryBelief no rate limit) |
| 12 | `file_08_contracts_v3_ERC8004IdentityRegistryV3.sol.txt` | 304 | Identity | 1 R3 MED (free registration → Sybil concern) |
| 13 | `file_09_contracts_v3_ERC8004ReputationRegistryV3.sol.txt` | 805 | Identity | ✅ prior fixes verified · 1 R3 MED (hashed feedback not revocable) |
| 14 | `file_10_contracts_v3_ERC8004ValidationRegistryV3.sol.txt` | 700 | Identity | ✅ prior fixes verified · 1 R3 MED (slashed ETH locked) |
| 15 | `file_17_contracts_v3_VaultfireERC8004AdapterV3.sol.txt` / `VaultfireERC8004AdapterV3_decoded.sol` / `_fix.sol` | 580 | Identity | 1 R3 HIGH (2-step ownership missing) |
| 16 | `file_16_contracts_v3_ProductionBeliefAttestationVerifierV3.sol.txt` / `push_contracts_v3_ProductionBeliefAttestationVerifierV3.sol` | 532 | ZK | 1 R3 HIGH (2-step ownership missing) |
| 17 | `file_13_contracts_v3_MissionEnforcement.sol.txt` | ~200 | Bond helper | Not in R3 scope |
| 18 | `push_contracts_v3_TrustPortabilityExtensionV3.sol` | 720 | Bridge | Duplicate of #6 — reconcile before push |
| 19 | `file_12_contracts_v3_IERC20Minimal.sol.txt` | 15 | Interface | ✅ minimal |
| 20 | `VaultfireTaskEscrow.sol` (V2 draft in root) | ? | Escrow | Not in R3 scope — see gap list |

**Total V3-tagged Solidity in draft:** ≈ 8,644 lines across 21 contracts (R3 confirmed).

Duplicates to resolve (`push_contracts_v3_*` vs canonical) before PR3:
- AIAccountabilityBondsV3, AIPartnershipBondsV3, BaseYieldPoolBondV3, BeliefOracleV3, DilithiumAttestorV3, FlourishingMetricsOracleV3, MultiOracleConsensusV3, MultisigGovernanceV3, ProductionBeliefAttestationVerifierV3, TrustPortabilityExtensionV3.

---

## Mapping — assignment requirement × existing V3 draft × gap

Legend: **PRESENT** (draft implements it) · **PARTIAL** (draft implements part) · **MISSING** (must be added in PR2/PR3) · **N/A**.

### §1 Identity adapter

| Assignment field | V3 draft status | Gap |
|---|---|---|
| Identity-registry namespace + chainId + registry address | PARTIAL | `ERC8004IdentityRegistryV3` uses address+agentId; namespace/chainId not part of struct — must add for cross-chain identity fingerprint |
| agentId, verified agent wallet, principal, operator, beneficiary | PARTIAL | Present: agentId, agent wallet. **Missing:** principal (human/org), operator, beneficiary/refund address as distinct fields |
| EIP-712 for EOA signatures | **MISSING** | Direct-call model used everywhere; no `EIP712` base contract, no domain separator per V3 contract, no typed structs |
| ERC-1271 for smart-contract wallets | **MISSING** | No `isValidSignature(bytes32,bytes)` fallback path |
| ERC-8004 conformance test coverage | PARTIAL | Adapter exists; **no conformance test** in `test/` that proves interface compliance |
| Legacy KYA queryable through labeled adapter | **MISSING** | V2 KYA registrations exist in V2 contracts; no `LegacyKYAAdapter` yet |

### §2 Mandate Registry

| Field | Draft status | Gap |
|---|---|---|
| Full 16-field mandate struct (principal, agent, operator, allowed/prohibited actions, allowed contracts/methods, asset caps, rate limits, times, evidence/dispute policy, nonce, chainId, version, mandateHash) | **MISSING** | Bond terms exist implicitly; no dedicated `MandateRegistryV3` contract. Assignment §2 is essentially a new deliverable |
| Multi-party signature activation | **MISSING** | |
| Consent enforced (no wallet can bind another without signature) | PARTIAL | Partnership V3 has proposal + acceptance model but not cryptographic bilateral EIP-712 |

### §3 Partnership Bonds V3

| Requirement | Draft status | Gap |
|---|---|---|
| Proposal + explicit acceptance | PRESENT | `AIPartnershipBondsV3.createBond` creates unilaterally; assignment requires **both parties sign** — must add a `proposePartnership → acceptPartnership` flow (currently the human creates and the AI is named without signature) |
| Signed terms | **MISSING** | `partnershipType` is a string, not a signed EIP-712 typed structure |
| Duration, breach, flourishing conditions | PARTIAL | Present as bond fields; not explicitly signed |
| Separate beneficiary + operator | **MISSING** | |
| Challenge period, cancel/expire paths | PARTIAL | `deactivateBond` exists; not all state-machine transitions have deadlines |
| Principal redemption path | PARTIAL | Pull-payment pattern present (HIGH-02 fix); needs formal state |
| **HIGH-R3-02 solvency bug** | OPEN | Must fix in PR4 |
| Assignment: "If only one party stakes, call it sponsored/unilateral — not mutual" | **DOC MISSING** | Draft calls the current model a "partnership bond" regardless of who staked. Rename or split types |

### §4 Accountability Bonds V3

| Requirement | Draft status | Gap |
|---|---|---|
| Objective vs subjective separation | PARTIAL | `_capToOracle` prevents self-report inflation but bond still slashes on measurement, not on signed mandate breach |
| Only accepted objective breaches can slash principal | **MISSING** | Slashing today is metric-driven, not mandate-breach-driven. This is the deepest structural gap vs assignment |
| Self-report cannot alone determine payout | PRESENT | `_capToOracle` fix (CRIT-03) does this |
| Global stats treated as context, not causation | PARTIAL | Not explicitly labeled in the contract or in indexer output |

### §5 Flourishing Reward Programs

| Requirement | Draft status | Gap |
|---|---|---|
| Sponsor-funded reward mechanism | **MISSING** as separate contract | Rewards are wired into bond math and paid from bond principal/fund. Assignment requires a **separate `RewardProgramV3`** with own funding, own max liability, own duration |
| Fixed funding, max liability, duration | **MISSING** | |
| Independent verifier policy per program | **MISSING** | |
| "Never call reserves 'yield' unless documented revenue" | **DOC** | Base yield pool naming needs review |
| "Program cannot promise more than funded reserve" | **MISSING** invariant | |

### §6 Bond state machine

| Requirement | Draft status | Gap |
|---|---|---|
| Explicit `Proposed → Accepted → Funded → Active → SettlementRequested → Finalizable/Challenged → Settled` | **MISSING** as enum | State is implicit across booleans (`active`, `distributionPending`, `oracleConfirmedMetrics`, `challenged`) — must be an explicit `enum BondState` |
| Every non-terminal state has deadline + safe permissionless path | PARTIAL | Some deadlines exist (`distributionDelay`); no universal permissionless `ForceExit(bondId)` |
| `Proposed → Expired`, `Accepted/Funded → Cancelled`, `Active → Expired → ForceExit` | **MISSING** | |

### §7 Asset accounting

| Requirement | Draft status | Gap |
|---|---|---|
| Separate accounting buckets (Party A principal, Party B, sponsor reward reserve, pending distributions, challenge stakes, protocol fees, mutual-aid reserves, surplus) | PARTIAL | Bond contracts track `remainingStake`, `totalPendingDistributions`, `partnershipFundNative`, `protocolFundsNative`. Sponsor reward reserve doesn't exist because reward programs aren't separate |
| Invariant: `controlled ≥ redeemable + reserved + pending + fees + reserves` | **MISSING** as invariant test | Assignment invariant #1; no fuzz test exists |
| Pull-payment withdrawals | PRESENT (HIGH-02) | |
| Governance cannot withdraw pending liabilities | PARTIAL | Assignment invariant #7; needs explicit `withdrawSurplus()` accounting check |

### §8 Evidence and disputes

| Requirement | Draft status | Gap |
|---|---|---|
| 12-field attestation (attester, authority, subject, bond/mandate, schema, commitment, observation period, timestamp, nonce, signature, expiration, **independence classification**) | PARTIAL | `ERC8004ReputationRegistryV3` has most fields; **independence classification** missing |
| Duplicate attestation prevention | PRESENT | Cycle counter (R2 fix NEW-03) |
| Full dispute config (authorized challengers, proportional stakes, deadlines, adjudicator threshold, default outcome, persistent history, payout source cap) | PARTIAL | `MetricsChallenged/ChallengeResolved` exists on bonds; `VaultfireDisputeResolution` is a separate contract (deployed, un-audited); no timeout defaults to permissionless outcome |
| Threshold governance + timelocks for admin | PRESENT (`MultisigGovernanceV3`) | Not yet wired as owner of bridges/adapters — see P0-6 |
| Emergency pause preserves safe withdrawals | PARTIAL | `whenNotPaused` on most paths but withdraw paths aren't consistently exempt |

### §9 Privacy

| Requirement | Draft status | Gap |
|---|---|---|
| No freeform PII in permanent onchain strings | PARTIAL | `partnershipType` string, `reason` strings on events — need bounded URI or content hash pattern |
| Salted commitments / hashes | PRESENT | `HumanVerificationSubmittedHashed` events use `relationshipHash`, `notesHash` |
| Don't claim onchain records deletable | **DOC** | Website/docs may claim removable; needs public wording audit |
| Same authorization on public + private evidence paths | PARTIAL | Assignment invariant #13; no fuzz test yet |

### §Backward compatibility, migration, x402, reputation, insurance/escrow/vaults

All covered in the accompanying baseline documents:
- `V2_COMPATIBILITY_MATRIX.md` — V2 preservation contract
- `V2_X402_MATRIX.md` — priced route registry
- `MIGRATION_PLAN.md` — opt-in migration procedure
- `ASSET_AND_LIABILITY_LEDGER.md` — solvency snapshot

Gaps flagged for those areas:
- `VaultfireBIPVault` claims ERC-4626 → no property test suite yet (assignment §Insurance/vaults)
- `VaultfireTaskEscrow` — needs assignee-timeout + permissionless-refund audit
- `AgentInsurancePool` / `VaultfireBondInsurancePool` — must be renamed **Mutual Aid Pool** unless full insurance semantics exist (assignment §Insurance)
- `VaultfireStreetCred` (Base-only) — must be redesigned as versioned, explainable risk signal (assignment §Reputation)

---

## What the existing V3 drafts already do well

1. **Oracle-capped self-report** (`_capToOracle`) directly satisfies "self-report alone cannot determine payout."
2. **Quorum-retroactive confirmation** (R2 NEW-01 fix) blocks the "raise quorum but keep old confirmation" attack.
3. **ECDSA signer-authenticated cross-chain relay** on both bridge and TPE (post-R2).
4. **Commit-reveal + zero-reveal round voiding** on `MultiOracleConsensusV3`.
5. **Rate-limited authorized feedback callers** on `ERC8004ReputationRegistryV3`.
6. **Fee-on-transfer safe accounting** via balance-delta.
7. **Two-step ownership + guardian transfer** on most (not all) contracts.
8. **8,644 lines of Solidity with 564 passing tests** (as of R3, 2026-03-27).

These wins reduce PR3–PR8 to *additive* work, not rewrite.

---

## PR2 gate — what must exist before writing new V3 contracts

The following invariant tests must be written and **must fail against the existing V3 drafts before we start fixing them**. This is the assignment's "PR2: V3 specification and failing safety tests" gate.

1. **Solvency fuzz** — For every state transition on `AIPartnershipBondsV3`, assert `partnershipFundNative + sum(remainingStake) + sum(pendingChallengeStakes) + protocolFundsNative == contract.balance`. Expected: **fails on HIGH-R3-02 today.**
2. **Reentrancy fuzz** — Malicious-oracle harness re-entering `AIAccountabilityBondsV3.requestDistribution`. Expected: **fails on HIGH-R3-01.**
3. **Consent invariant** — Try `createBond(otherWallet, ...)` from an unauthorized signer; assert bond is not `Active`. Expected: **fails today** — bond is created with only the human's tx, no AI signature.
4. **Force-exit reachability** — For every non-terminal state, assert there exists a call sequence (no admin) reachable within `MAX_STATE_TIMEOUT` that reaches a terminal state. Expected: **fails on multiple states.**
5. **Reward-cap invariant** — `sum(scheduled reward payouts) ≤ funded reserve`. Expected: **fails because no separate reserve exists yet.**
6. **Signature domain** — EIP-712 signatures from one contract cannot be replayed on another. Expected: **fails because no EIP-712 anywhere.**
7. **ZK proof timestamp** — Present a real STARK proof to `DilithiumAttestorV3.verifyZKProof`. Expected: **fails on CRIT-R3-01.**
8. **Contract size** — Compile both star bond contracts under default Hardhat config (no `allowUnlimitedContractSize`) and assert `bytecode.length < 24576`. Expected: **fails on both.**

Six of eight tests exist to be written; **all eight are expected to fail today**. That is the PR2 deliverable.

---

## Priority for PR3–PR8

- **PR3 (identity/mandate/consent)** — highest leverage. Introduces `MandateRegistryV3`, EIP-712 base library, ERC-1271 adapter, proposePartnership/acceptPartnership flow. Does **not** touch existing V3 draft bond bodies; instead provides a `SafeBondFactoryV3` that wraps them with signed terms.
- **PR4 (bonds V3 fixes)** — closes HIGH-R3-01, HIGH-R3-02, ForceExit path, adds explicit `BondState` enum, splits mutual vs unilateral bond naming, extracts `BondMathLib` to fix P0-2 contract size.
- **PR5 (reputation/validation)** — closes MED-R3-17 (slashed ETH treasury), MED-R3-18 (hashed feedback revocation), MED-R3-19 (Sybil), rewrites `StreetCred` as versioned + explainable.
- **PR6 (escrow/mutual aid/vaults)** — renames insurance pool → `MutualAidPool` unless policies exist, adds `TaskEscrow` timeout/refund audit, writes ERC-4626 property tests on `VaultfireBIPVault`.
- **PR7 (APIs/SDK/x402/indexer)** — implements `/api/v3/*` alongside `/api/*`, generates all public artifacts from `deployments.json` + `x402-route-registry.json`, adds finality + block + errors to every onchain response.
- **PR8 (pilot package)** — MultisigGovernanceV3 as bridge owner, monitoring, incident runbook, capped Base pilot, independent audit scope.

The R3 audit's own remediation priority tiers map 1:1 onto PR4 (Tier 1+2), PR4/PR5 (Tier 3), PR5+PR6 (Tier 4+5).

---

## Non-goals

- **Do not rebuild V2.** V2 stays untouched. `deployments.json` marks each of the 134 as active/legacy/read-only.
- **Do not deploy V3 yet.** All work is source + tests + simulation on forks.
- **Do not touch keys.** Owner transfers happen from ghostkey.base.eth *after* multisig deployment, gated by explicit user approval per-tx.
