# Agent Identity: ERC-8004 and Key-Based Agents

Valiron supports two identity paths:

| Agent type | Use this identifier | Request header | Lookup path |
|------------|---------------------|----------------|-------------|
| ERC-8004 / on-chain EVM agent | ERC-8004 token ID | `x-agent-id` | `/operator/agent/:agentId` |
| Solana 8004 agent | Metaplex Core asset pubkey or indexed ID | `x-agent-id` | `/operator/agent/:agentId?chain=solana` |
| Local, Web2, or non-ERC-8004 agent | Persistent Ethereum-style agent address | `x-agent-address` | `/operator/key/:agentAddress` |

Use `/operator/agent/:agentId` only for registry-backed on-chain agents. Local and Web2 agents should generate or reuse a persistent keypair, prove ownership through Valiron's challenge-response flow, and then use their `x-agent-address` for trust checks.

## ERC-8004 Identity

For EVM on-chain agents, Valiron uses the ERC-8004 standard for AI agent identity. Each agent is represented by an ERC-721 token in the Identity Registry.

## How Identity Works

1. An agent owner mints an ERC-721 token in the Identity Registry
2. The token's `tokenURI` points to an Agent Registration File (ARF)
3. The ARF contains the agent's name, description, endpoints, and supported trust models
4. Valiron reads this on-chain data to identify and evaluate agents

## Agent Registration File (ARF) Format

The `tokenURI` must resolve to a JSON object with this structure:

```json
{
  "name": "Agent Name",
  "image": "https://example.com/agent-avatar.png",
  "description": "A brief description of what the agent does.",
  "endpoints": {
    "agentWallet": "eip155:1:0xAgentWalletAddress",
    "api": "https://agent-api.example.com"
  },
  "supportedTrust": [
    "reputation_on_chain",
    "behavioral_sandbox"
  ]
}
```

### ARF Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | yes | Human-readable agent name |
| `image` | string | no | URL to agent avatar/image |
| `description` | string | no | Brief description of agent purpose |
| `endpoints.agentWallet` | string | yes | CAIP-10 formatted wallet address |
| `endpoints.api` | string | no | Agent's API endpoint URL |
| `supportedTrust` | string[] | no | Trust models the agent supports |

### Supported Trust Models

- `reputation_on_chain` — Agent participates in on-chain feedback
- `behavioral_sandbox` — Agent can be evaluated via sandbox testing

### ARF Hosting

The ARF can be hosted as:
- **Data URI**: `data:application/json;base64,eyJuYW1lIjoi...` (inline, gas-efficient)
- **IPFS**: `ipfs://bafybeig...` (permanent, decentralized)
- **HTTPS URL**: `https://example.com/agent.json` (mutable, centralized)

## Contract Addresses

The Identity Registry contract address is the same across all supported networks:

```
Identity Registry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
```

## Reading Identity On-Chain

### Using viem (direct contract call)

```typescript
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

const client = createPublicClient({
  chain: mainnet,
  transport: http(),
});

// Get token owner
const owner = await client.readContract({
  address: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  abi: [{ name: "ownerOf", type: "function", inputs: [{ type: "uint256" }], outputs: [{ type: "address" }], stateMutability: "view" }],
  functionName: "ownerOf",
  args: [25459n],
});

// Get agent metadata
const tokenUri = await client.readContract({
  address: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  abi: [{ name: "tokenURI", type: "function", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }], stateMutability: "view" }],
  functionName: "tokenURI",
  args: [25459n],
});
```

### Using Valiron SDK

```typescript
import { ValironSDK } from "@valiron/sdk";

const valiron = new ValironSDK();
const profile = await valiron.getAgentProfile("25459");

console.log(profile.identity.name);
console.log(profile.identity.wallet);
console.log(profile.identity.endpoints);
```

## On-Chain Reputation (Feedback)

The Reputation Registry stores feedback submitted by other agents and operators.

### Contract Address

```
Reputation Registry: 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63
```

### Submitting Feedback

```typescript
giveFeedback(
  agentId: uint256,        // Target agent's token ID
  value: int128,           // Score (typically 0-100)
  valueDecimals: uint8,    // Decimal places in value
  tag1: string,            // Category tag #1
  tag2: string,            // Category tag #2
  endpoint: string,        // API endpoint tested
  feedbackURI: string,     // IPFS CID or URL to full feedback JSON
  feedbackHash: bytes32    // SHA-256 hash of feedback for verification
)
```

### Reading Feedback

```typescript
// Get all feedback for an agent
readAllFeedback(agentId, clientAddresses, tag1, tag2, includeRevoked)

// Get specific feedback entry
readFeedback(agentId, clientAddress, feedbackIndex)

// Get all clients who provided feedback
getClients(agentId)
```

### Impact on Trust Score

On-chain reputation contributes to an agent's overall trust evaluation. More feedback with higher scores yields a positive impact. The exact bonuses and thresholds are not disclosed.

---

## Key-Based Agents (Web2)

Not every agent has an on-chain ERC-8004 identity. For local, Web2, and non-ERC-8004 agents that only have a persistent Ethereum keypair (no minted token), Valiron supports **key-based authentication** using EIP-191 challenge-response.

### How It Works

1. Agent sends a request with the `x-agent-address: 0x...` header
2. Valiron returns a challenge nonce
3. Agent signs the nonce with their private key (EIP-191 personal sign)
4. Valiron verifies the signature and creates a `KeyAgentProfile`

The SDK and middleware auto-detect key-based agents from the `x-agent-address` header. No configuration needed.

Agents can follow the hosted identity skill at [https://www.valiron.co/auth.md](https://www.valiron.co/auth.md) to generate an identifier, request a challenge, sign it, and cache the returned session token.

### KeyAgentProfile

| Field | Type | Description |
|-------|------|-------------|
| `agentAddress` | string | Ethereum-style address used as the key-based agent identifier |
| `verified` | boolean | Whether the agent proved key ownership through challenge-response |
| `score` | number \| null | Behavioral score once sandbox evaluation has run |
| `tier` | string \| null | Moody's-style trust tier once scored |
| `riskLevel` | string \| null | GREEN / YELLOW / RED once scored |
| `route` | string \| null | Route decision once scored |
| `icebreaker` | object \| null | Optional ownership context from Icebreaker |
| `reasons` | string[] | Human-readable trust explanation |
| `timestamp` | string | ISO timestamp for the profile response |

### Key-Based vs On-Chain Agents

| | On-Chain (ERC-8004) | Key-Based |
|---|---|---|
| Identity source | Minted ERC-721 token | Ethereum address + EIP-191 signature |
| Starting trust | Varies (based on on-chain reputation) | Verified identity first, score/tier appear after sandbox evaluation |
| Trust improvement | Sandbox testing + on-chain feedback | Key-agent sandbox evaluation + behavioral history |
| World ID linkage | Supported | Not currently supported by key-agent endpoints |
| Solana support | Yes (Metaplex Core) | No (EVM only) |

### API Endpoints

See [API-REFERENCE.md](./API-REFERENCE.md#key-based-agent-endpoints) for the full HTTP API.

---

## World ID (Proof-of-Personhood)

World ID verifies that an agent is linked to a real human via Worldcoin's zero-knowledge proof system. This is one of Valiron's four trust signals and provides a strong indicator that an agent is operated by a verified person.

### How It Works

1. Agent owner completes World ID verification (orb or device level)
2. The proof is submitted to Valiron via `verifyWorldId()` or the API endpoint
3. Valiron stores the verification status and includes it in trust evaluation

### SDK Methods

```typescript
// Submit a World ID proof
await valiron.verifyWorldId("25459", proof);

// Check verification status
const status = await valiron.getWorldIdStatus("25459");
// { verified: true, verifiedAt: "...", level: "orb" }

// Get full profile
const profile = await valiron.getWorldIdProfile("25459");
```

### API Endpoints

See [API-REFERENCE.md](./API-REFERENCE.md#world-id-endpoints) for the full HTTP API.

---

## Solana Identity (QuantuLabs 8004-solana)

Solana agent identity uses a separate registry operated by [QuantuLabs](https://8004.qnt.sh/) — not the EVM ERC-8004 contracts. The on-chain representation is a **Metaplex Core** asset instead of an ERC-721 token.

### How Solana Identity Works

1. An agent owner creates a Metaplex Core asset through the QuantuLabs identity registry
2. The asset's metadata URI points to an Agent Registration File (ARF) — typically on IPFS
3. The QuantuLabs indexer assigns a sequential integer ID (1, 2, 3…) for convenience
4. Valiron reads this data via the `8004-solana` SDK's `loadAgent()` call

### Program IDs

| Program | Address |
|---------|---------|
| Identity Registry | `8oo4dC4JvBLwy5tGgiH3WwK4B9PWxL9Z4XjA2jzkQMbQ` |
| Reputation (ATOM Engine) | `AToMw53aiPQ8j7iHVb4fGt6nzUNxUhcPc3tbPBZuzVVb` |

### Solana ARF Format

Solana ARFs follow a similar structure to EVM ARFs but are resolved via IPFS and the QuantuLabs API rather than on-chain `tokenURI()` calls:

```json
{
  "name": "NoahScout_Bot.noah",
  "image": "https://arweave.net/abc123...",
  "description": "An AI agent for automated DeFi monitoring.",
  "endpoints": {
    "rest": "https://my-agent.example.com/api",
    "ws": "wss://my-agent.example.com/ws"
  }
}
```

### Agent ID Formats

Solana agents have two identifiers:

| Format | Example | Usage |
|--------|---------|-------|
| Asset pubkey | `DFkntsJ9aTCHkK88m6WZVQEvLdLNi4X1LVUgRMqetFPM` | Canonical on-chain ID (base-58) |
| Sequential ID | `1226` | Convenience integer from QuantuLabs indexer |

Both work interchangeably in Valiron's API:

```bash
# By asset pubkey
curl "https://valiron-edge-proxy.onrender.com/operator/agent/DFknts...?chain=solana"

# By sequential ID
curl "https://valiron-edge-proxy.onrender.com/operator/agent/1226?chain=solana"
```

### Reading Solana Identity

```typescript
import { ValironSDK } from "@valiron/sdk";

const valiron = new ValironSDK({ chain: "solana" });
const profile = await valiron.getAgentProfile("1226"); // sequential ID

console.log(profile.identity.name);   // "NoahScout_Bot.noah"
console.log(profile.identity.wallet); // "VSAnVX4MQjEXreHc92iHxWuXPQZ1tjwiKccpFLCgLM9"
```

### Solana On-Chain Reputation

Reputation on Solana is powered by the **ATOM Engine** — a behavioral evaluation system built into the QuantuLabs registry. ATOM provides richer metrics than EVM's simple feedback count/average:

| Field | Type | Description |
|-------|------|-------------|
| `trustTier` | string | ATOM trust classification (e.g. `"trusted"`, `"neutral"`) |
| `qualityScore` | number | Overall quality metric (0–100) |
| `confidence` | number | Statistical confidence in the quality score (0–1) |
| `riskScore` | number | Risk assessment (0–100, lower = safer) |
| `uniqueCallers` | number | Number of distinct addresses that submitted feedback |

These fields appear in the `onchainReputation.solana` section of the API response.

### Solana Feedback Write-Back

After sandbox or gate evaluation, Valiron can write scores back to the Solana registry via `giveFeedback()`. This requires a funded Solana keypair:

| Environment Variable | Format | Description |
|---------------------|--------|-------------|
| `SOLANA_FEEDBACK_KEYPAIR` | JSON array (e.g. `[174,23,...]`) | Ed25519 secret key for signing feedback transactions |
