# Vaultfire — V2 Behavior Test Suite (PR1)

**Repo HEAD:** `a80144d1acbbbbf24b9eca7cd91e61daad0c0ad6`
**Purpose:** Lock down current V2 behavior with executable tests so any V3 change that would break an existing partner integration fails CI before merge.

Assignment rules being enforced:
- "For every deployed V2 contract, write a foundry test that runs against a mainnet fork and asserts current behavior. These tests must pass before and after V3."
- "For every current API route write a schema and behavior test using recorded HTTP fixtures."
- "For every current SDK method write a test that runs against a mainnet fork or replay fixture."

Nothing here executes live transactions. Everything runs against forked state.

---

## 1. Contract fork-tests (Foundry)

**Layout (to be materialized under `test/fork/` in PR2):**

```
test/
  fork/
    base/
      AIAccountabilityBondsV2.t.sol
      AIPartnershipBondsV2.t.sol
      VaultfireTeleporterBridge.t.sol
      VaultfireBIPVault.t.sol
      VaultfireStreetCred.t.sol
      VaultfireTaskEscrow.t.sol
      ...
    avalanche/
      AIAccountabilityBondsV2.t.sol
      AIPartnershipBondsV2.t.sol
      ...
    arbitrum/
      ...
    polygon/
      ...
```

Foundry `foundry.toml` fork profiles (excerpt):

```toml
[fork.base]
rpc_url = "$BASE_RPC_URL"
block_number = "$BASE_FORK_BLOCK"

[fork.avalanche]
rpc_url = "$AVAX_RPC_URL"
block_number = "$AVAX_FORK_BLOCK"

# ...
```

### Standard test cases per V2 star bond

Each `AIAccountabilityBondsV2` and `AIPartnershipBondsV2` per-chain test must assert:

1. **Address exists** at the canonical `deployments.json` value with non-zero code.
2. **`owner()` returns the expected owner** per matrix (`ghostkey.base.eth` on 53 instances, `bpow20.cb.id` on 16 documented-inert instances, revert on the 65 that have no `owner()` selector).
3. **ABI compatibility:** every ABI function in the checked-in `abi/v2/AIAccountabilityBondsV2.json` must be present at the deployed address. This is verified with `staticcall(abi.encodeWithSelector(selector))` for every selector and asserting the call does not revert with "function selector not found".
4. **Event topics unchanged:** every V2 event topic in the checked-in `topics/v2.json` must resolve to a `LogTopic` that appears in historical logs for that address (recovered from a small window near `$FORK_BLOCK`).
5. **State reads reproducible:** `getBond(bondId)` for a fixed set of `bondId`s returns bit-identical struct data pre and post any local V3 build.
6. **No admin call succeeds from a random signer:** every `onlyOwner` function reverts when called from `vm.prank(0xdead)`.
7. **Pausable state:** on `Pausable` contracts, `paused()` returns the expected value, and a mutating call reverts when paused.

### Standard cases for auxiliary contracts

For each of the 15+ un-audited contracts (`AgentInsurancePool`, `VaultfireBIPVault`, `VaultfireTaskEscrow`, etc.):

1. Address exists and has code.
2. Basic view functions do not revert.
3. Any known admin function reverts from non-admin.

### ERC-4626 property tests (VaultfireBIPVault)

Uses OpenZeppelin's `IERC4626` reference test set:

- `deposit(assets, receiver)` mints exactly `previewDeposit(assets)` shares.
- `mint(shares, receiver)` deposits at least `previewMint(shares)` assets.
- `withdraw(assets, receiver, owner)` burns at most `previewWithdraw(assets)` shares.
- `redeem(shares, receiver, owner)` returns at least `previewRedeem(shares)` assets.
- Share-inflation resistance: donating assets directly to the vault does not let a follower attacker steal a subsequent depositor's principal.
- Reentrancy: every state-changing entry point is `nonReentrant` or provably reentrancy-safe.

### Cross-chain bridge fork tests

For each `VaultfireTeleporterBridge` instance:

- `remoteBridgeSigner` matches the expected mainnet value.
- Message ID mixes `chainId`, `blockHash`, `sender`, `nonce` (prevents replay per HIGH-19 fix).
- A synthetic `MessageReceived` cannot be re-executed (replay protection).

---

## 2. API behavior tests (Vitest + HTTP fixtures)

**Layout (materialized in PR7):**

```
apps/theloopbreaker-site/test/
  routes/
    contracts.test.ts
    hub-stats.test.ts
    hub-activity.test.ts
    x402/
      well-known.test.ts
      trust/
        bonds.test.ts
        street-cred.test.ts
        vns-resolve.test.ts
        ...
      actions/
        create-partnership-bond.test.ts
        ...
    agent/
      register.test.ts
      status.test.ts
      ...
  fixtures/
    https/
      <method>__<path>.http.json
```

### Per-route tests

For every one of the **132 V2 route files** enumerated in `baseline/extracted/v2_api_routes.txt`:

1. **Schema snapshot** — response conforms to a checked-in JSON schema (`baseline/schemas/v2/`). Adding a new optional field is allowed; removing or repurposing is not.
2. **Status codes preserved** — same HTTP status codes for equivalent inputs.
3. **Priced-endpoint 402 behavior** — for every `/api/x402/*` route that is priced, calling without payment returns `402 Payment Required` with correct headers per x402 spec.
4. **`dataSourceErrors` on failure** — mocked RPC failure must set `dataSourceErrors` non-empty and return HTTP 503 for read routes that would otherwise return zero-defaults.
5. **CORS + rate-limit headers** unchanged.
6. **`/.well-known/x402.json` byte-identical** to the CI-generated version from `baseline/x402-route-registry.json` (canonical source).

### x402 test list (assignment §Payments and x402, non-negotiable)

Priced endpoint contract:

1. Correct 402 payload: `method`, `path`, `price`, `asset`, `network`, `payee`, `x402Version`.
2. Signature validation — malformed signature ⇒ reject.
3. Amount check — under-payment ⇒ reject.
4. Asset check — wrong token ⇒ reject.
5. Network check — wrong `network` value ⇒ reject.
6. Payee check — payment sent to wrong address ⇒ reject.
7. Expiration check — expired quote ⇒ reject.
8. Replay protection — same payment used twice ⇒ second call rejected.
9. Request binding — payment for `/a` cannot pay for `/b`.
10. Double fulfillment — server crash after settlement, retry ⇒ idempotent, returns receipt of first settlement.
11. Idempotency key on writes — same key ⇒ same effect and receipt.
12. Settlement finality — response reports finality state.
13. Facilitator timeout — bounded retry, then error surface.
14. HTTP timeout post-settle — recorded, retry safe.
15. Receipt correctness — includes `chainId`, `txHash`, `blockNumber`, `network`, `asset`, `amount`, `payer`, `payee`, `x402Version`.

---

## 3. SDK behavior tests

**Layout (materialized in PR7):**

```
packages/sdk/test/
  vaultfire.test.ts        (VaultfireSDK / createVaultfireSDK)
  safe.test.ts             (VaultfireSafeSDK)
  bonds.test.ts            (BondsModule)
  trust.test.ts            (TrustModule)
  tasks.test.ts            (TasksModule)
  x402/
    client.test.ts
    replay.fixtures.ts
```

### Per-method tests

For every published V2 SDK method:

1. **Signature preservation** — TypeScript type test asserts function signature is unchanged (arg names, arg types, return type).
2. **Round-trip against fork** — call the method against a Base mainnet fork; assert response matches recorded fixture.
3. **Chain switching** — every method that accepts `chainId` behaves identically on all deployed chains for the method.
4. **Error surface unchanged** — same error class hierarchy, same error codes.
5. **Version routing** — passing `version: "v2"` returns V2 reads; passing `version: "v3"` (once V3 lands) returns V3 reads; default is `"v2"` for the pilot window.

### x402 SDK tests

For `@vaultfire/x402` client:
- Priced request without payment ⇒ 402.
- Priced request with valid signed payment ⇒ 200 + receipt.
- Replay of same payment ⇒ 402 or explicit error.
- Facilitator down ⇒ documented bounded retry + explicit failure.

---

## 4. Indexer replay tests

**Layout (materialized in PR7):**

```
apps/indexer/test/
  reorg.test.ts
  duplicate-log.test.ts
  removed-log.test.ts
  partial-rpc-failure.test.ts
  v2-v3-coexistence.test.ts
```

Cases:
1. Reorg — same `(chainId, txHash, logIndex)` reported twice with different blockHash; only latest is kept.
2. Duplicate log — same event decoded twice from redundant RPC providers; idempotent.
3. Removed log — `removed: true` log removes the event from the read model.
4. Partial RPC failure — one chain down; other three still index; API returns `dataSourceErrors` for the affected chain instead of zeros.
5. V2/V3 coexistence — same participant with a V2 bond and a V3 bond appears in `/api/v3/agent/status` as `{ v2: {...}, v3: {...} }`, no fields lost.

---

## 5. Website/UI compatibility tests

**Layout (materialized in PR7):**

```
apps/site/test/
  labels.spec.tsx      (asserts Legacy V2 / V3 test / V3 audited pilot labels render)
  feature-flag.spec.tsx (asserts V3 UI hidden when NEXT_PUBLIC_ENABLE_V3=false)
  address-source.spec.ts (asserts every rendered address flows from deployments.json)
```

---

## 6. Continuous evidence

CI job `pr1-compat` runs the above tests and produces an artifact bundle:

```
artifacts/pr1-compat/
  fork-test-results.json
  api-schema-diff.json
  sdk-signature-diff.json
  indexer-replay-report.json
  ui-label-audit.json
```

The job must be green before any V3 PR (PR3+) can be merged. This is the "V2 preservation gate."

---

## PR1 exit checklist for tests

- [x] Test taxonomy defined (contract / API / SDK / indexer / UI)
- [x] Per-chain fork-test layout defined
- [x] Complete x402 15-item test list documented
- [x] ERC-4626 property test list documented
- [ ] Foundry `foundry.toml` fork profiles committed (PR2)
- [ ] First fork test file committed (PR2 — see `test/invariants/Inv00_ChainSanity.t.sol`)
- [ ] Full 132-route schema snapshot commit (PR7)
- [ ] SDK signature-diff CI job (PR7)
