---
eip: 8107
title: ENS Trust Registry for Agent Coordination
description: Web of trust validation using ENS names for ERC-8001 multi-party coordination
author: Kwame Bryan (@KBryan)
discussions-to: https://ethereum-magicians.org/t/erc-ens-trust-registry-for-agent-coordination/27200
status: Draft
type: Standards Track
category: ERC
created: 2025-12-16
requires: 137, 712, 1271, 8001
---

## Abstract

This ERC defines a **Trust Registry** that enables agents to establish and query transitive trust relationships using ENS names as identifiers. Trust is expressed at four levels (Unknown, None, Marginal, Full) and propagates through signature chains following the GNU Privacy Guard (GnuPG) web of trust model.

The registry serves as the **trust and delegation module** anticipated by [ERC-8001](./eip-8001.md), enabling coordinators to gate participation based on trust graph proximity. An agent is considered valid from a coordinator's perspective if sufficient trust paths exist between them.

This standard specifies trust attestation structures, the path verification algorithm, ENS integration semantics, and [ERC-8001](./eip-8001.md) coordination hooks.

## Motivation

[ERC-8001](./eip-8001.md) defines minimal primitives for multi-party agent coordination but explicitly defers trust to modules:

> "Privacy, thresholds, bonding, and cross-chain are left to modules."

And in Security Considerations:

> "Equivocation: A participant can sign conflicting intents. Mitigate with module-level slashing or reputation."

This ERC provides that trust and delegation module. Before coordinating, agents need answers to:

1. **"Should I include this agent in my coordination?"** — Participant selection
2. **"Can I trust this agent's judgment about other agents?"** — Transitive trust
3. **"How do I update trust based on coordination outcomes?"** — Trust maintenance

### Why Web of Trust?

The web of trust model, proven over 25+ years in GnuPG, solves the bootstrap problem: how do you establish trust with unknown agents without a centralised registrar?

| GnuPG Concept | This Standard |
|---------------|---------------|
| Public key | ENS name |
| Key signing | Trust attestation |
| Owner trust levels | `TrustLevel` enum |
| Key validity | Agent validity for coordination |
| Certification path | Trust chain through agents |

### Why ENS?

ENS provides a battle-tested, finalized identity layer:

- **Stable identifiers** that survive key rotation
- **Ownership semantics** via `owner()` and `isApprovedForAll()`
- **Human readable** names (`alice.agents.eth` not `0x742d...`)
- **Subdomain delegation** for protocol-issued agent identities

Using ENS avoids dependency on draft identity standards while remaining compatible with future standards through adapter patterns.

**Deployment note**: This standard requires access to an ENS registry. On Ethereum mainnet, use the canonical ENS deployment. On other networks, use network-specific ENS deployments or bridges. CCIP-Read is a client-side mechanism and cannot be used for on-chain validation.

### Identity Continuity

ENS names are the identity. When an ENS name is transferred, the new owner inherits existing trust relationships where that name is the trustee. The new owner can manage trust where they are the trustor.

Implementations SHOULD use short expiries (RECOMMENDED: 90 days maximum) for high-stakes scopes to limit exposure from name transfers. Agents SHOULD monitor `Transfer` events on ENS names they trust and re-evaluate trust accordingly.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

### Overview

This ERC specifies:

* Trust levels and their semantics
* ENS-indexed trust attestation structures with scope as key
* [EIP-712](./eip-712.md) typed data for signing attestations
* [EIP-1271](./eip-1271.md) support for contract controllers
* The `ITrustRegistry` interface
* Path verification algorithm
* [ERC-8001](./eip-8001.md) integration hooks

### Trust Levels

Implementations MUST use the canonical enum:

```solidity
enum TrustLevel {
   Unknown,   // 0: No trust relationship established
   None,      // 1: Explicitly distrusted
   Marginal,  // 2: Partial trust — multiple required for validation
   Full       // 3: Complete trust — single attestation sufficient
}
```

**Semantic definitions:**

| Level | Meaning | Validation Contribution |
|-------|---------|------------------------|
| `Unknown` | Default state; no data about agent | Cannot contribute to validation |
| `None` | Agent known to behave improperly | Explicitly excluded; voids trust paths containing this agent |
| `Marginal` | Agent generally trustworthy | Contributes to validation when `minEdgeTrust <= Marginal` |
| `Full` | Agent's judgment equals own verification | Always contributes to validation |

**Level transitions:**

* Any level MAY transition to any other level via a valid attestation with a higher nonce
* Transitioning from `None` to `Marginal` or `Full` requires a new attestation (revocation is not permanent)

### ENS Integration

The Trust Registry uses ENS namehashes as agent identifiers.

```solidity
// ENS namehash computation (per ERC-137)
bytes32 node = keccak256(abi.encodePacked(
   keccak256(abi.encodePacked(bytes32(0), keccak256("eth"))),
   keccak256("alice")
));
// node = namehash("alice.eth")
```

### Signature Authority

Trust attestations MUST be signed by an address with signing authority for the ENS name.

**Signing authority** is limited to:

* The ENS name owner (`ens.owner(node)`), OR
* For contract owners: any signer the contract validates via [EIP-1271](./eip-1271.md)

**Transaction submission** (calling `setTrust`, `revokeTrust`, etc.) MAY be performed by:

* Any address holding a valid signature
* An approved operator (`ens.isApprovedForAll(owner, operator)`) for `revokeTrust` only

This separation ensures:

* Attestations are cryptographically bound to the ENS owner/controller
* Transaction submission can be delegated (relayers, operators)
* Approvals cannot be used to forge signatures

```solidity
/// @dev Verify signature - signing authority is ENS owner only
   function verifySignature(
      bytes32 node,
      bytes32 digest,
      bytes calldata signature
   ) internal view returns (bool) {
      address owner = ens.owner(node);
      if (owner == address(0)) return false;

      // EOA owner
      if (owner.code.length == 0) {
         return ECDSA.recover(digest, signature) == owner;
      }

      // Contract owner - delegate to EIP-1271
      try IERC1271(owner).isValidSignature(digest, signature) returns (bytes4 magic) {
         return magic == IERC1271.isValidSignature.selector;
      } catch {
         return false;
      }
   }

/// @dev Check if caller can submit revokeTrust transaction
   function canSubmitRevocation(bytes32 node, address caller) internal view returns (bool) {
      address owner = ens.owner(node);
      return caller == owner || ens.isApprovedForAll(owner, caller);
   }
```

### EIP-712 Domain

Implementations MUST use the following [EIP-712](./eip-712.md) domain:

```solidity
EIP712Domain({
   name: "TrustRegistry",
   version: "1",
   chainId: block.chainid,
   verifyingContract: address(this)
})
```

Implementations SHOULD expose the domain via [EIP-5267](./eip-5267.md).

### Primary Types

```solidity
struct TrustAttestation {
   bytes32 trustorNode;       // ENS namehash of trustor
   bytes32 trusteeNode;       // ENS namehash of trustee
   TrustLevel level;          // Trust level assigned
   bytes32 scope;             // Scope restriction; bytes32(0) = universal
   uint64 expiry;             // Unix timestamp; 0 = no expiry
   uint64 nonce;              // Per-trustor monotonic nonce
}

   struct ValidationParams {
      uint8 maxPathLength;       // Maximum trust chain depth (1-10)
      TrustLevel minEdgeTrust;   // Minimum trust level required on each edge
      bytes32 scope;             // Required scope; bytes32(0) = any
      bool enforceExpiry;        // Check expiry on all chain elements
      bytes32[] requiredAnchors; // Path MUST traverse at least one anchor; empty = no requirement
   }

   struct TrustPath {
      bytes32[] nodes;           // [validator, ...intermediaries..., target]
   }
```

**Path length definition**: Path length is the number of edges (trust relationships) in the path. A direct trust relationship has path length 1. A path `[A, B, C]` has length 2.

#### Default Validation Parameters

When not specified, implementations SHOULD use:

```solidity
ValidationParams({
   maxPathLength: 5,
   minEdgeTrust: TrustLevel.Marginal,
   scope: bytes32(0),
   enforceExpiry: true,
   requiredAnchors: new bytes32[](0)
})
```

#### Validation Parameters Constraints

Implementations MUST reject `ValidationParams` where:

* `maxPathLength == 0` or `maxPathLength > 10`
* `minEdgeTrust == TrustLevel.Unknown` or `minEdgeTrust == TrustLevel.None`
* `requiredAnchors.length > 10`

### Typed Data Hashes

```solidity
bytes32 constant TRUST_ATTESTATION_TYPEHASH = keccak256(
   "TrustAttestation(bytes32 trustorNode,bytes32 trusteeNode,uint8 level,bytes32 scope,uint64 expiry,uint64 nonce)"
);

   function hashAttestation(TrustAttestation calldata att) internal pure returns (bytes32) {
      return keccak256(abi.encode(
         TRUST_ATTESTATION_TYPEHASH,
         att.trustorNode,
         att.trusteeNode,
         uint8(att.level),
         att.scope,
         att.expiry,
         att.nonce
      ));
   }
```

### Interface

Implementations MUST expose the following interface:

```solidity
interface ITrustRegistry {
   // ═══════════════════════════════════════════════════════════════════
   // Events
   // ═══════════════════════════════════════════════════════════════════

   /// @notice Emitted when trust is set or updated
   event TrustSet(
      bytes32 indexed trustorNode,
      bytes32 indexed trusteeNode,
      TrustLevel level,
      bytes32 indexed scope,
      uint64 expiry
   );

   /// @notice Emitted when trust is explicitly revoked
   event TrustRevoked(
      bytes32 indexed trustorNode,
      bytes32 indexed trusteeNode,
      bytes32 indexed scope,
      bytes32 reasonCode
   );

   /// @notice Emitted when an identity gate is configured
   event IdentityGateSet(
      bytes32 indexed coordinationType,
      bytes32 indexed gatekeeperNode,
      uint8 maxPathLength,
      TrustLevel minEdgeTrust
   );

   /// @notice Emitted when an identity gate is removed
   event IdentityGateRemoved(bytes32 indexed coordinationType);

   // ═══════════════════════════════════════════════════════════════════
   // Trust Management
   // ═══════════════════════════════════════════════════════════════════

   /// @notice Set trust level for another agent in a specific scope
   /// @dev Signature MUST be from ENS owner (EOA) or validate via EIP-1271 (contract)
   /// @param attestation The trust attestation
   /// @param signature EIP-712 signature from trustor's ENS owner
   function setTrust(
      TrustAttestation calldata attestation,
      bytes calldata signature
   ) external;

   /// @notice Batch set multiple trust relationships
   /// @dev All attestations MUST share the same trustorNode
   /// @param attestations Array of trust attestations
   /// @param signatures Corresponding signatures
   function setTrustBatch(
      TrustAttestation[] calldata attestations,
      bytes[] calldata signatures
   ) external;

   /// @notice Revoke trust (sets level to None)
   /// @dev Caller MUST be ENS owner or approved operator
   /// @param trustorNode The trustor's ENS namehash
   /// @param trusteeNode The agent to revoke trust from
   /// @param scope The scope to revoke trust in
   /// @param reasonCode Reason code for revocation
   function revokeTrust(
      bytes32 trustorNode,
      bytes32 trusteeNode,
      bytes32 scope,
      bytes32 reasonCode
   ) external;

   /// @notice Get trust record between two agents in a specific scope
   /// @param trustorNode The trusting agent
   /// @param trusteeNode The trusted agent
   /// @param scope The trust scope (bytes32(0) for universal)
   /// @return level Current trust level
   /// @return expiry Expiration timestamp (0 = never)
   function getTrust(
      bytes32 trustorNode,
      bytes32 trusteeNode,
      bytes32 scope
   ) external view returns (TrustLevel level, uint64 expiry);

   /// @notice Get current nonce for a trustor
   /// @param trustorNode The agent's ENS namehash
   /// @return Current nonce value
   function getNonce(bytes32 trustorNode) external view returns (uint64);

   // ═══════════════════════════════════════════════════════════════════
   // Path Verification
   // ═══════════════════════════════════════════════════════════════════

   /// @notice Verify a pre-computed trust path
   /// @param path The trust path to verify
   /// @param params Validation parameters
   /// @return valid Whether the path satisfies validation requirements
   /// @return anchorSatisfied Whether requiredAnchors constraint is met
   function verifyPath(
      TrustPath calldata path,
      ValidationParams calldata params
   ) external view returns (bool valid, bool anchorSatisfied);

   // ═══════════════════════════════════════════════════════════════════
   // ERC-8001 Integration
   // ═══════════════════════════════════════════════════════════════════

   /// @notice Set identity gate for a coordination type
   /// @param coordinationType The ERC-8001 coordination type
   /// @param gatekeeperNode Agent whose trust graph gates entry
   /// @param params Validation parameters for the gate
   function setIdentityGate(
      bytes32 coordinationType,
      bytes32 gatekeeperNode,
      ValidationParams calldata params
   ) external;

   /// @notice Remove identity gate for a coordination type
   /// @param coordinationType The ERC-8001 coordination type
   function removeIdentityGate(bytes32 coordinationType) external;

   /// @notice Get identity gate configuration
   /// @param coordinationType The ERC-8001 coordination type
   /// @return gatekeeperNode The gatekeeper agent
   /// @return params Validation parameters
   /// @return enabled Whether the gate is active
   function getIdentityGate(
      bytes32 coordinationType
   ) external view returns (
      bytes32 gatekeeperNode,
      ValidationParams memory params,
      bool enabled
   );

   /// @notice Validate participant using pre-computed path
   /// @param coordinationType The ERC-8001 coordination type
   /// @param path Pre-computed trust path from gatekeeper to participant
   /// @return isValid Whether participant passes the gate
   function validateParticipantWithPath(
      bytes32 coordinationType,
      TrustPath calldata path
   ) external view returns (bool isValid);
}
```

### OPTIONAL Interface Extensions

The following functions are OPTIONAL. Implementations MAY include them but they are not required for compliance:

```solidity
interface ITrustRegistryExtended is ITrustRegistry {
   /// @notice Get agents trusted by a given agent (paginated)
   /// @dev OPTIONAL - useful for indexing but not required
   function getTrustees(
      bytes32 trustorNode,
      TrustLevel minLevel,
      bytes32 scope,
      uint256 offset,
      uint256 limit
   ) external view returns (bytes32[] memory trustees, uint256 total);

   /// @notice Get agents that trust a given agent (paginated)
   /// @dev OPTIONAL - useful for indexing but not required
   function getTrustors(
      bytes32 trusteeNode,
      TrustLevel minLevel,
      bytes32 scope,
      uint256 offset,
      uint256 limit
   ) external view returns (bytes32[] memory trustors, uint256 total);

   /// @notice Validate an agent through on-chain graph traversal
   /// @dev OPTIONAL - expensive, prefer off-chain computation with verifyPath
   /// @param validatorNode The validating agent's perspective
   /// @param targetNode The agent to validate
   /// @param params Validation parameters
   /// @param marginalThreshold Number of marginal attestations required (for accumulation)
   /// @param fullThreshold Number of full attestations required
   function validateAgent(
      bytes32 validatorNode,
      bytes32 targetNode,
      ValidationParams calldata params,
      uint8 marginalThreshold,
      uint8 fullThreshold
   ) external view returns (
      bool isValid,
      uint8 pathLength,
      uint8 marginalCount,
      uint8 fullCount
   );

   /// @notice Check if any trust path exists
   /// @dev OPTIONAL - expensive, prefer off-chain computation
   function pathExists(
      bytes32 fromNode,
      bytes32 toNode,
      uint8 maxDepth
   ) external view returns (bool exists, uint8 depth);

   /// @notice Validate participant without pre-computed path
   /// @dev OPTIONAL - expensive, prefer validateParticipantWithPath
   function validateParticipant(
      bytes32 coordinationType,
      bytes32 participantNode,
      uint8 marginalThreshold,
      uint8 fullThreshold
   ) external view returns (bool isValid);
}
```

### Semantics

#### `setTrust`

`setTrust` MUST revert if:

* `attestation.trustorNode == attestation.trusteeNode` (self-trust prohibited)
* `attestation.nonce <= getNonce(attestation.trustorNode)`
* `attestation.expiry != 0 && attestation.expiry <= block.timestamp`
* The signature does not verify per the Signature Authority section
* The ENS name for `trustorNode` does not exist (owner is zero address)

If valid:

* The trust record MUST be stored, keyed by `(trustorNode, trusteeNode, scope)`
* `getNonce(trustorNode)` MUST return the attestation's nonce
* `TrustSet` MUST be emitted

#### `setTrustBatch`

`setTrustBatch` MUST revert if:

* `attestations.length != signatures.length`
* Any attestation has a different `trustorNode` than the first attestation
* Any individual attestation would fail `setTrust` validation

Nonces within the batch MUST be strictly increasing.

#### `revokeTrust`

`revokeTrust` MUST revert if:

* Caller is not the ENS owner or an approved operator for `trustorNode`
* No existing trust relationship exists for `(trustorNode, trusteeNode, scope)` (level is `Unknown`)

If valid:

* Trust level MUST be set to `None`
* `TrustRevoked` MUST be emitted
* The relationship MUST remain in storage (not deleted) to preserve the explicit distrust

#### `verifyPath` — Path Verification Algorithm

`verifyPath` validates a pre-computed trust path.

**Algorithm:**

```solidity
function verifyPath(
   TrustPath calldata path,
   ValidationParams calldata params
) external view returns (bool valid, bool anchorSatisfied) {
   // Path must have at least 2 nodes (validator and target)
   if (path.nodes.length < 2) return (false, false);

   // Path length constraint (edges = nodes - 1)
   if (path.nodes.length - 1 > params.maxPathLength) return (false, false);

   // Track anchor satisfaction
   bool foundAnchor = params.requiredAnchors.length == 0;

   // Verify each edge
   for (uint256 i = 0; i < path.nodes.length - 1; i++) {
      // Try scoped trust first, fall back to universal
      (TrustLevel level, uint64 expiry) = getTrust(
         path.nodes[i],
         path.nodes[i + 1],
         params.scope
      );

      // Fall back to universal scope if scoped trust not found
      if (level == TrustLevel.Unknown && params.scope != bytes32(0)) {
         (level, expiry) = getTrust(
            path.nodes[i],
            path.nodes[i + 1],
            bytes32(0)
         );
      }

      // Edge must meet minimum trust level
      if (level < params.minEdgeTrust) return (false, foundAnchor);

      // None explicitly voids (even if minEdgeTrust is somehow None)
      if (level == TrustLevel.None) return (false, foundAnchor);

      // Expiry check
      if (params.enforceExpiry && expiry != 0 && expiry <= block.timestamp) {
         return (false, foundAnchor);
      }

      // Anchor check (intermediate nodes only, not first or last)
      if (!foundAnchor && i > 0) {
         for (uint256 j = 0; j < params.requiredAnchors.length; j++) {
            if (path.nodes[i] == params.requiredAnchors[j]) {
               foundAnchor = true;
               break;
            }
         }
      }
   }

   return (true, foundAnchor);
}
```

**Scope fallback semantics:**

When validating an edge, implementations MUST:

1. First check for trust at the specified `params.scope`
2. If not found and `params.scope != bytes32(0)`, check for trust at universal scope `bytes32(0)`
3. Universal trust applies to all scopes

#### `validateParticipantWithPath`

This function gates [ERC-8001](./eip-8001.md) coordination participation.

```solidity
function validateParticipantWithPath(
   bytes32 coordinationType,
   TrustPath calldata path
) external view returns (bool isValid) {
   (bytes32 gatekeeperNode, ValidationParams memory params, bool enabled) =
               getIdentityGate(coordinationType);

   if (!enabled) return true; // No gate = open participation

   // Verify path starts at gatekeeper and ends at participant
   if (path.nodes.length < 2) return false;
   if (path.nodes[0] != gatekeeperNode) return false;

   (bool valid, bool anchorOk) = verifyPath(path, params);
   return valid && anchorOk;
}
```

### Errors

Implementations MUST revert with these errors:

```solidity
error SelfTrustProhibited();
   error NonceTooLow(uint64 provided, uint64 required);
   error AttestationExpired(uint64 expiry, uint64 currentTime);
   error InvalidSignature();
   error NotAuthorized(bytes32 node, address actor);
   error ENSNameNotFound(bytes32 node);
   error TrustNotFound(bytes32 trustorNode, bytes32 trusteeNode, bytes32 scope);
   error GateNotFound(bytes32 coordinationType);
   error InvalidValidationParams(string reason);
   error BatchTrustorMismatch();
   error BatchNonceNotIncreasing();
```

### Recommended Reason Codes

For `TrustRevoked` events, the following reason codes are RECOMMENDED:

| Reason Code | Value | Meaning |
|-------------|-------|---------|
| Unspecified | `bytes32(0)` | No specific reason |
| Misbehavior | `keccak256("MISBEHAVIOR")` | Agent acted improperly |
| Compromised | `keccak256("COMPROMISED")` | Key or account compromised |
| Inactive | `keccak256("INACTIVE")` | Agent no longer active |
| Transfer | `keccak256("TRANSFER")` | ENS name transferred |

### Recommended Scopes

For interoperability, the following scope values are RECOMMENDED:

| Scope | Value | Use Case |
|-------|-------|----------|
| Universal | `bytes32(0)` | Trust applies to all contexts |
| DeFi | `keccak256("DEFI")` | DeFi coordination |
| Gaming | `keccak256("GAMING")` | Gaming/metaverse |
| MEV | `keccak256("MEV")` | MEV protection |
| Commerce | `keccak256("COMMERCE")` | Agentic commerce |

### Recommended Coordination Types

For [ERC-8001](./eip-8001.md) identity gates:

| Coordination Type | Value |
|-------------------|-------|
| MEV Coordination | `keccak256("MEV_COORDINATION")` |
| DeFi Yield | `keccak256("DEFI_YIELD")` |
| Gaming Match | `keccak256("GAMING_MATCH")` |
| Commerce Escrow | `keccak256("COMMERCE_ESCROW")` |

## Rationale

### Why ENS Instead of a New Identity System?

ENS is finalised [EIP-137](./eip-137.md), battle-tested, and widely adopted. Creating a new identity system would:

* Add dependency on draft standards
* Fragment the identity ecosystem
* Require new adoption efforts

ENS provides everything needed: stable identifiers, ownership semantics, and extensibility.

### Why Scope as Storage Key?

A trustor may have different trust levels for the same trustee in different contexts. For example:

* Trust `bob.eth` fully for DeFi coordination
* Trust `bob.eth` marginally for gaming

Making scope part of the storage key `(trustorNode, trusteeNode, scope)` enables this naturally. Universal trust `bytes32(0)` serves as a fallback when scoped trust is not specified.

### Why minEdgeTrust Instead of Marginal/Full Thresholds?

The `marginalThreshold` and `fullThreshold` parameters were designed for on-chain graph traversal with marginal accumulation logic. Since on-chain traversal is OPTIONAL (expensive, DoS-prone), and the core primitive is `verifyPath`, we need only specify the minimum trust level each edge must have.

This simplification:

* Reduces parameter complexity
* Makes path verification straightforward
* Leaves accumulation semantics to OPTIONAL extensions

For use cases requiring marginal accumulation, the OPTIONAL `validateAgent` extension accepts threshold parameters.

### Why Separate Signing Authority from Transaction Submission?

ENS approvals (`isApprovedForAll`) are designed for operators to manage names on behalf of owners. However, allowing approved operators to forge attestation signatures would break the cryptographic binding between attestations and ENS owners.

By restricting signing authority to the ENS owner (or EIP-1271 for contract owners) while allowing operators to submit transactions like `revokeTrust`, we preserve:

* Cryptographic integrity of attestations
* Operational flexibility for name management
* Clear security boundaries

### Why verifyPath Only (No On-Chain Search)?

On-chain graph traversal is expensive and creates DoS vectors:

* Branching factor can explode with user-controlled adjacency lists
* Gas costs are unpredictable
* Attackers can bloat trustee lists

By requiring pre-computed paths, this standard:

* Keeps on-chain verification O(path length)
* Pushes search complexity to off-chain indexers where it belongs
* Enables predictable gas costs

Implementations MAY add `validateAgent` and `pathExists` as OPTIONAL extensions, but these are not required for compliance.

### Why Four Trust Levels?

The four-level model (Unknown, None, Marginal, Full) is proven by GnuPG's 25+ years of use. Finer granularity adds complexity without clear benefit; coarser granularity loses important distinctions.

With `minEdgeTrust`, applications can choose their security posture:

* `minEdgeTrust: Full` — Only fully trusted paths
* `minEdgeTrust: Marginal` — Accept marginal trust (default)

### Why Required Anchors?

Sybil attacks are the primary threat to web of trust systems. Required anchors force trust paths to traverse established community nodes (DAOs, protocols, auditors), transforming Sybil resistance from application-layer advice into protocol-level enforcement.

## Backwards Compatibility

This ERC introduces new functionality and does not modify existing standards.

**ENS Compatibility**: Uses standard ENS interfaces (`owner`, `isApprovedForAll`). Works with any ENS deployment. Does not rely on CCIP-Read or other off-chain mechanisms.

**ERC-8001 Compatibility**: Designed as a module. ERC-8001 coordinators can optionally integrate identity gates.

**Wallet Compatibility**: Uses [EIP-712](./eip-712.md) signatures, compatible with all major wallets. Supports [EIP-1271](./eip-1271.md) for contract wallets and smart accounts.

## Reference Implementation

See [`contracts/TrustRegistry.sol`](../assets/eip-8107/contracts/TrustRegistry.sol) for the complete implementation.

## Security Considerations

### Sybil Attacks

An attacker can create many ENS names and establish mutual trust between them.

**Protocol-level mitigations:**

* **Required anchors**: `ValidationParams.requiredAnchors` forces paths through established community nodes
* **Short path limits**: `maxPathLength: 2` requires close proximity to validators
* **High trust requirement**: `minEdgeTrust: Full` rejects marginal trust paths

**Application-level mitigations:**

* Weight trust by ENS name age or registration cost
* Implement additional stake requirements
* Monitor trust graphs for anomalous patterns off-chain

### Trust Graph Manipulation

Attackers may attempt to position themselves in many trust paths.

**Mitigations:**

* Monitor trust graphs for anomalous patterns off-chain
* Use `minEdgeTrust: Full` for high-value coordination
* Require multiple independent paths via OPTIONAL extensions

### Key Compromise

If an ENS name's controller is compromised:

**Mitigations:**

* Agents SHOULD monitor for unexpected trust changes via `TrustSet` events
* Use short expiries (90 days maximum recommended for high-stakes)
* ENS name owners can rotate controllers
* Affected agents can issue `TrustRevoked` to quarantine compromised nodes

### ENS Name Transfer

When an ENS name is transferred:

* New owner inherits trust where they are the trustee
* New owner can manage trust where they are the trustor
* Old attestations signed by old owner remain valid until expiry

**Mitigations:**

* Use short expiries for high-stakes trust
* Monitor ENS `Transfer` events
* Re-evaluate trust after transfers

### Replay Protection

[EIP-712](./eip-712.md) domain binding prevents cross-contract replay. Monotonic nonces prevent replay within the same contract. The `chainId` in the domain prevents cross-chain replay.

### Stale Trust

Trust relationships may become stale if agents don't update them.

**Mitigations:**

* Use `enforceExpiry: true` in validation parameters
* Set reasonable `expiry` values on attestations (RECOMMENDED: 90 days maximum for high-stakes)
* Monitor `TrustSet` event timestamps off-chain

### Off-Chain Path Computation

This standard assumes off-chain indexers compute trust paths. Malicious indexers could:

* Return suboptimal paths
* Omit valid paths
* Return invalid paths (caught by `verifyPath`)

**Mitigations:**

* Users can run their own indexers
* Multiple independent indexers provide redundancy
* Invalid paths are always rejected on-chain

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
