---
# System prepended metadata

title: Oyster CVM + ERC-8004 Validation Registry Integration

---

# Oyster CVM + ERC-8004 Validation Registry Integration

> **TL;DR** — An Oyster CVM agent (running inside a TEE) publishes verifiable computation artifacts to an ERC-8004 validation registry so downstream agents can trust results without re-running the workload.

## Table of Contents

1. [Actors & Components](#1-actors--components)
2. [End-to-End Lifecycle](#2-end-to-end-lifecycle)
3. [Sequence Diagram](#3-sequence-diagram)
4. [Contract Interfaces](#4-contract-interfaces)
5. [Data Model](#5-data-model)
6. [Validation Decision Logic](#6-validation-decision-logic)

## 1. Actors & Components

**`Client`**
Sends compute requests and submits returned artifacts to the verifier.

**`oyster-validation-gateway`** *(Nitro enclave)*
Public ingress and signing/publishing layer. Handles request routing, auth/rate limits, IPFS upload, response signing, and `validationRequest` calls.

**`oyster-agent-service`** *(Nitro enclave)*
Runs the compute job and returns output to the gateway.

> [!IMPORTANT]
> `oyster-validation-gateway` and `oyster-agent-service` run in the **same Nitro enclave** (same attested boundary).

**`AttestationVerifier`** *(Marlin-deployed root of trust)*
Verifies the attestation verifier enclave on-chain once. All other enclaves are verified cheaply through its chain of trust. ([source](https://github.com/marlinprotocol/oyster-monorepo/blob/master/contracts/contracts-foundry/src/attestation/AttestationVerifier.sol))

**`AttestationAuther`** *(base contract — inherited by app contracts)*
Tracks verified enclave keys for a specific application. Your app contracts inherit this to gate access to verified enclaves only. ([source](https://github.com/marlinprotocol/oyster-monorepo/blob/master/contracts/contracts-foundry/src/attestation/AttestationAuther.sol))

**`Verifier Service`** *(TEE)*
Validates data integrity, signature, and enclave key binding. Calls `validationResponse` on the registry.

**`ValidationRegistry`** *(ERC-8004 contract)*
Stores canonical validation lifecycle state.

**Consumer Agents**
Query final validation state and retrieve request/verification artifacts from IPFS.

## 2. End-to-End Lifecycle

### 2.1 Setup *(one-time per environment)*


1. Deploy `AttestationAuther` contract on-chain
2. Verify the attestation verifier enclave's own attestation on-chain (expensive — done once via ZK proof or NitroProver)
3. Verifier enclave's key is now the root of trust — all other enclaves can be verified cheaply through it.
4. Ensure `ValidationRegistry` (ERC-8004) is deployed/available
5. Deploy verifier service in Oyster CVM and fund its EOA for gas.
6. Enclave boots → attestation server exposes Nitro attestation at `/attestation/raw`.
7. Attestation is sent to Marlin's verifier enclave (`POST /verify/raw`) → verifier checks cert chain, PCRs, freshness → returns a signed EIP-712 receipt.
8. Receipt submitted on-chain via `AttestationAuther.verifyEnclaveSignature(signature, attestation)` → enclave key registered.

### 2.2 Runtime Flow

```
Client ─► Gateway ─► Agent ─► IPFS ─► Registry ─► Verifier ─► Registry (final)
```

1. **Client** sends compute request to `oyster-validation-gateway`
2. **Gateway** forwards request to `oyster-agent-service` (intra-enclave call)
3. **Agent** executes request in TEE, returns output
4. **Gateway** writes `{input, output}` to IPFS → gets `requestURI`
5. **Gateway** computes `requestHash = keccak256(canonical_request_payload)`
6. **Gateway** signs response payload with KMS-derived key
7. **Gateway** submits `validationRequest(...)` to ValidationRegistry
8. **Gateway** returns `{response, signature, requestURI, requestHash}` to client
9. **Client** calls verifier `POST /verify` with returned artifacts
10. **Verifier** fetches `requestURI` content and re-computes hash
11. **Verifier** recovers signer address from response signature
12. **Verifier** calls `AttestationAuther._ensureKeyVerified(signerAddress)` → confirms key was registered via chain-of-trust
13. **Verifier** derives KMS public key for `(imageId, signingPath)` off-chain, compares to recovered key
14. **Verifier** writes proof object to IPFS → `responseURI`, computes `responseHash`
15. **Verifier** submits `validationResponse(...)` → **APPROVED** or **REJECTED**
16. **Consumer** queries registry and fetches evidence URIs

## 3. Sequence Diagram

```mermaid
sequenceDiagram
    autonumber
    participant C as Client
    participant P as oyster-validation-gateway
    participant A as oyster-agent-service
    participant I as IPFS
    participant VR as ValidationRegistry (ERC-8004)
    participant V as Verifier (TEE)
    participant AV as AttestationAuther
    participant O as Consumer Agents

    note right of C: Request & Compute Phase
    C->>P: Compute request
    P->>A: Forward request (intra-enclave)
    A->>A: Execute workload in TEE
    A-->>P: response payload

    note right of P: Publish & Register Phase
    P->>I: Put {input, output}
    I-->>P: requestURI
    P->>P: requestHash + response signature
    P->>VR: validationRequest(validator, agentId, requestURI, requestHash)
    VR-->>P: tx receipt (PENDING)
    P-->>C: response, signature, requestURI, requestHash

    note right of C: Verification Phase
    C->>V: POST /verify(payload)
    V->>I: GET requestURI
    I-->>V: request payload
    V->>V: Verify requestHash and recover signer address
    V->>AV: _ensureKeyVerified(signerAddress)
    AV-->>V: confirmed (reverts if not registered)
    V->>V: kms-derive(imageId, signingPath) → compare keys
    V->>I: Put verification proof
    I-->>V: responseURI
    V->>VR: validationResponse(requestHash, status, responseURI, responseHash, tag)
    VR-->>V: tx receipt (final)

    note right of O: Consumption Phase
    O->>VR: Query by requestHash
    VR-->>O: status + URIs
    O->>I: Fetch requestURI/responseURI
    I-->>O: evidence artifacts
```

## 4. Contract Interfaces

### 4.1 `validationRequest` *(ERC-8004)*

```solidity
// validatorAddress — address of the designated verifier
// agentId         — numeric identifier of the registered agent
// requestURI      — IPFS URI pointing to {input, output} payload
// requestHash     — keccak256 of the canonical request payload
function validationRequest(
    address validatorAddress,
    uint256 agentId,
    string  requestURI,
    bytes32 requestHash
) external;
```

### 4.2 `validationResponse` *(ERC-8004)*

```solidity
// requestHash  — links this response to the original request
// response     — validation outcome (1=APPROVED, 2=PENDING, 3=REJECTED)
// responseURI  — IPFS URI pointing to verifier's proof object
// responseHash — hash of the response payload for integrity
// tag          — application-specific metadata tag
function validationResponse(
    bytes32 requestHash,
    uint8   response,
    string  responseURI,
    bytes32 responseHash,
    bytes32 tag
) external;
```

## 5. Data Model

### 5.1 `requestURI` Payload *(produced by agent)*

```json
{
  "input":  { "...": "arbitrary request data" },
  "output": { "...": "arbitrary response data" }
}
```

### 5.2 `responseURI` Payload *(produced by verifier)*

```json
{
  "signature":      "0x...",
  "agentPublicKey": "0x...",
  "imageId":        "0x...",
  "verifiedBy":     "0xVerifier...",
  "verifiedAt":     1704067300,
  "checks": {
    "hashMatch":          true,
    "signatureValid":     true,
    "enclaveKeyVerified": true,
    "kmsKeyMatch":        true
  }
}
```

### 5.3 Enclave Boot Registration Flow

```
Enclave boots
  └─► GET /attestation/raw        (attestation server inside enclave)
  └─► POST /verify/raw            (Marlin's verifier enclave)
        └─► returns { signature, imageId, timestampMs, publicKey, userData }
  └─► AttestationAuther.verifyEnclaveSignature(signature, attestation)
        └─► AttestationVerifier.verify() — confirms receipt is from trusted verifier
        └─► _setKeyVerified(publicKey, imageId) — key is now registered on-chain
```

## 6. Validation Decision Logic

The verifier marks a request as **REJECTED** if any of the following checks fail:

1. **IPFS Fetch** - `requestURI` content cannot be retrieved
2. **Hash Validation** - re-computed `keccak256(fetched_payload)` ≠ submitted `requestHash`
3. **Signature Recovery** - ECDSA recover fails or returns an unexpected address
4. **Enclave Key Verified** - `AttestationAuther._ensureKeyVerified(signerAddr)` reverts — enclave never completed chain-of-trust registration
5. **KMS Key Binding** - KMS-derived public key for `(imageId, signingPath)` ≠ recovered signer key
