--- eip: 8275 title: Agent Service Discovery and Escrow Payments description: AI agent marketplace — service discovery, escrow payments, reputation, and mesh-node compensation via commit-reveal settlement. author: Panini (@Brooks1003), Tiago Merlini (@TMerlini), Damon Zwicker (@damonzwicker), Jimmy Shi (@JimmyShi22), Vincent Wu (@TruthAnchor-AI), babyblueviper1 (@babyblueviper1), Pocket Network VNI Group (@traciecmyers) discussions-to: https://ethereum-magicians.org/t/erc-8275-agent-service-discovery-and-escrow-payments/28622 status: Draft type: Standards Track category: ERC created: 2026-05-26 requires: 712, 8004 --- ## Abstract This ERC defines a converged standard covering two economic axes of the AI agent marketplace: (1) **service-layer interfaces** for agent discovery, escrow payment, and event-derived reputation; and (2) **mesh-settlement interfaces** for contribution accounting, signed snapshots, commit-reveal settlement, and proportional compensation of Origin, Router, and Hybrid nodes. The four-layer settlement protocol — off-chain attribution, signed contribution snapshots with deterministic freeze, on-chain commit-reveal with bond-backed fraud proofs, and a generic challenge interface — layers on top of [ERC-8004](./eip-8004.md) node identity and [ERC-3668](./eip-3668.md) (CCIP Read) record exchange. All interfaces are independently deployable and communicate exclusively through standardized on-chain events. It does not redefine how records are produced or signed; that is the domain of ERC-8004. ## Motivation The AI agent standard ecosystem has seen rapid growth — [ERC-8004](./eip-8004.md) (agent identity), [ERC-8273](./eip-8273.md) (attestation framing), and [ERC-8183](./eip-8183.md) (agentic commerce) — each address critical layers of the agent stack. However, two gaps remain. **Gap 1 — Service discovery and payment:** No existing standard covers how users discover the right agent and pay for services safely. Every application requires bespoke integration, resulting in fragmented UX. **Gap 2 — Mesh node compensation:** CCIP Read (ERC-3668) gateways today operate without any standard mechanism for accounting or compensating node contributions. A gateway operator who serves thousands of lookups receives no protocol-level economic attribution. Three failure modes follow: 1. **Infrastructure centralisation**: without compensation, only operators with external business incentives run gateways. The mesh collapses to a small set of trusted parties. 2. **No accountability surface**: without signed contribution records, there is no basis for challenging fabricated attribution. 3. **No separation of roles**: a monolithic gateway model conflates record production with record aggregation, making it impossible to reward each activity independently. [ERC-8275](./eip-8275.md) addresses both gaps by defining service discovery + escrow interfaces for consumers, and a four-layer mesh settlement protocol for operators. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. --- # Part I: Service-Layer Interfaces ### IAgentRegistry — Service Discovery and Node Registration Agents register with metadata (IPFS CID or arbitrary URI). Discovery is event-driven: clients listen to `AgentRegistered` events and build their own indices. No search API is defined — global discovery behavior emerges from local indexing of global events. **ERC-8004 identity linking:** Agents SHOULD reference their ERC-8004 token ID in the metadata field. When an agent has a canonical ERC-8004 identity, the `agentId` in this registry SHOULD be the ERC-8004 token ID to enable cross-standard identity resolution. **Metadata schema:** Agents SHOULD expose metadata conforming to the schema defined in ERC-8004 (tokenURI identity anchor). ```solidity interface IAgentRegistry { function registerAgent(bytes calldata metadata) external returns (bytes32 agentId); function updateAgent(bytes32 agentId, bytes calldata metadata) external; function deregisterAgent(bytes32 agentId) external; function getAgent(bytes32 agentId) external view returns ( address owner, bytes memory metadata, uint64 registeredAt, bool active ); function supportsInterface(bytes4 interfaceId) external view returns (bool); } ``` **Events:** `AgentRegistered`, `AgentUpdated`, `AgentDeregistered`. ### INodeRegistry — Node Role Registration ```solidity enum NodeType { Origin, Router, Hybrid } interface INodeRegistry { function registerNode(string calldata url, NodeType nodeType) external returns (bytes32 nodeId); function getNode(bytes32 nodeId) external view returns ( address owner, string memory url, NodeType nodeType, uint64 registeredAt, bool active ); function getContributionCount(bytes32 nodeId) external view returns (uint64 count); } ``` **Node Type Semantics:** | NodeType | Description | Reward Pool | |----------|-------------|-------------| | **Origin** | Record producers — generate attestations at the edge; expose `GET /records` and `GET /contributions`. Beneficiaries of settlement, not quorum signers. | Pool A — per-attestation | | **Router** | Aggregators/settlers — run full peer-sync stack, maintain `sourcePeer → count` attribution, produce signed snapshots, participate in commit-reveal quorum. | Pool B — per-settlement | | **Hybrid** | Both originate and route. Earn from both pools; Origin/Router split MUST be 50/50 at V1. MUST NOT count own records in routing reward. | Pro rata A + B | **Why enum, not bitmask:** A bitmask implies arbitrary role combinations are valid. `Hybrid` already encodes the one meaningful combined role. New valid combinations warrant new enum values with defined semantics. **Contribution accounting:** Router nodes MUST aggregate across all known peers, grouping by the `sourcePeer` field. Origin nodes report only their own production. Implementations SHOULD expose: ``` GET /contributions → { namespace, contributions: [{ source: , records: }] } ``` ### IAgentEscrow — Escrow Payment Layer ```solidity interface IAgentEscrow { function createOrder(bytes32 agentId, address paymentToken, uint256 amount, uint64 deadline, bytes calldata metadata) external payable returns (bytes32 orderId); function confirmOrder(bytes32 orderId) external; function disputeOrder(bytes32 orderId, bytes calldata reason) external; function resolveDispute(bytes32 orderId, uint8 resolution) external; function refundExpiredOrder(bytes32 orderId) external; function getOrder(bytes32 orderId) external view returns ( bytes32 agentId, address client, address agent, address paymentToken, uint256 amount, uint64 deadline, uint8 status, bytes memory metadata ); function distributeReward(bytes32 orderId, bytes32[] calldata nodeIds, uint16[] calldata contributionWeights) external; } ``` **Events:** `OrderCreated`, `OrderConfirmed`, `OrderDisputed`, `OrderResolved`, `OrderRefunded`, `RewardDistributed`. ### IAgentReputation — Reputation Layer Reputation is derived entirely from Escrow events and optionally from verified attestation history. **Derived-not-stored**: every value is recomputable from public data, with no scorer to trust. ```solidity interface IAgentReputation { function getReputation(bytes32 agentId) external view returns ( uint64 completedOrders, uint64 disputedOrders, uint64 totalVolume, uint64 lastActiveAt, uint16 score ); function getDecayWeight(bytes32 agentId) external view returns (uint16 weight); function verifyOutcome(bytes32 orderId, bytes calldata proof) external view returns (bool); } ``` **Reputation function shape (RECOMMENDED):** `f(attestationCount, counterpartyDiversity, winRate, volumeCap)` — losses remain in the record, weighting favours distinct at-stake counterparties over call volume. `volumeCap` ceilings the volume weight by `(winRate × settled-count)` so the volume axis cannot dominate the outcome axis. **ValidatorType Enum (for attestation-gated scoring):** ```solidity enum ValidatorType { ReExecution, Attestation, Judgment } enum ClaimType { ReExecution = 0, Attestation = 1, Judgment = 2 } ``` **Dual discriminator:** [EIP-712](./eip-712.md) type string (on-chain schema discrimination) + explicit `claimType` enum (off-chain indexer readability). --- # Part II: Mesh Settlement Protocol The settlement protocol compensates node infrastructure per period — who produced and relayed how many validated records — and pays out against a commit-reveal snapshot. It reads none of the WYRIWE attestation fields. ### Layer 1 — Off-chain Attribution Each node exposes `GET /contributions` as defined in INodeRegistry. Router nodes aggregate across all known peers. The `/contributions` response is the accounting primitive that higher layers settle against. ### Layer 2 — Signed Contribution Snapshots with Freeze Requirement #### Snapshot Cutoff Each settlement period is identified by a `periodId` (uint256, monotonically increasing). `EPOCH_CLOSE` is the Unix timestamp at which the period's data collection window ends. ``` snapshotCutoff = EPOCH_CLOSE - FREEZE_BUFFER ``` `FREEZE_BUFFER` MUST be protocol-defined. RECOMMENDED default: 600 seconds. #### Freeze Invariant The commitment hash submitted to `CommitRevealSettler.submitCommit()` MUST be derived exclusively from frozen snapshot data for the relevant period. A router that has not produced a frozen snapshot for the current period MUST NOT submit a commit. The freeze MUST be triggered automatically at `snapshotCutoff`. A node MUST NOT begin hashing before `snapshotCutoff`. Once frozen, the snapshot is immutable — records arriving after `snapshotCutoff` belong to the next period. #### Canonicalization Contribution rows MUST be sorted by `contributor_address` (lowercase hex) in ascending lexicographic order before hashing. Duplicate source rows MUST be deterministically aggregated (sum scores, keep earliest timestamp). Empty snapshots are valid; `snapshotRoot` is `keccak256("")`. #### Commitment Hash Derivation ``` row = abi.encode(address contributor, uint256 score, uint256 timestamp) snapshotRoot = keccak256(abi.encode(row_0, row_1, ..., row_n)) commitmentHash = keccak256(abi.encode(snapshotRoot, periodId, nodeAddress, salt)) ``` `salt` is a per-reveal random `bytes32` chosen by the router at freeze time and kept secret until `submitReveal`. `snapshotRoot` is what peers can independently verify. `commitmentHash` binds the snapshot to the period, the node, and a secret salt — preventing cross-period, cross-node, and preimage replay. **V1 challenge scope:** `snapshotRoot` is a flat hash of all rows. `EscrowV1.challenge()` therefore requires the challenger to supply the full row set. Row-level Merkle inclusion proofs are the V2 direction. #### Snapshot Endpoints Router nodes MUST expose: ```http POST /contributions/snapshot/freeze { "periodId": "42" } ``` Triggers the freeze if `now >= snapshotCutoff` and no freeze exists yet. Idempotent. ```http GET /contributions/snapshot?period=42 ``` Returns current snapshot state without triggering a freeze. Response MUST include: `periodId`, `snapshotCutoff`, `frozenAt`, `rowCount`, `snapshotRoot`, `commitmentHash`, `nodeAddress`, and `status` (pending/frozen/committed/revealed). ### Layer 3 — CommitRevealSettler ```solidity interface ICommitRevealSettler { /// @notice Submit a commitment during the COMMIT_WINDOW. /// @param periodId The settlement period identifier. /// @param commitmentHash keccak256(abi.encode(snapshotRoot, periodId, nodeAddress, salt)) function submitCommit(uint256 periodId, bytes32 commitmentHash) external; /// @notice Reveal the snapshot after COMMIT_WINDOW closes. /// @dev Must reproduce commitmentHash. Requires msg.value >= BOND_AMOUNT. /// @param anchorProof Merkle inclusion proof against the AnchorProof log. function submitReveal( uint256 periodId, bytes32 snapshotRoot, address nodeAddress, bytes32 salt, bytes calldata anchorProof ) external payable; } ``` **COMMIT_WINDOW** opens at `EPOCH_CLOSE` and closes after a protocol-defined number of blocks (RECOMMENDED: 32). `submitReveal` is accepted only after `COMMIT_WINDOW` closes and before `REVEAL_DEADLINE`. The bond posted at reveal time is held per reporter per period and released only after the challenge window closes without a successful fraud proof. **Bond sizing (V1):** per-period fixed `BOND_AMOUNT`, separate from `NodeType` registration. **Bond token requirements (non-normative):** The escrow bond denomination is implementation-defined. Implementations MAY bond in native value (e.g., ETH posted as `msg.value`) or in a conforming [ERC-20](./eip-20.md) token. ERC-20 bonds MUST support standard decimals and transferability, and SHOULD NOT implement rebase mechanics. The bond denomination applies exclusively to the settler/compensation axis (mesh settlement and escrow payments). The **reputation axis is token-free** — it bonds nothing and references no settlement token. Every reputation input derives from signed verdicts and settled outcomes, recomputable from public fields. Implementers MUST NOT require a bond token for reputation computation. The two axes are cleanly separable: changing the bond token or switching between native-value and ERC-20 bonds does not affect reputation conformance, and reputation inputs can be recomputed without touching any bond token. **Fraud proof anchor:** at reveal time, the revealer submits anchor fields plus an event-inclusion Merkle proof against the `AnchorProof` log. `CommitRevealSettler` verifies the proof and records the anchored root into `EscrowV1`'s period-keyed attestation index. **Small-N collusion resistance:** with 3–5 routers the Nash equilibrium holds — any individual router's dominant strategy is to report truthfully. The bond makes coordination cost explicit. Operators are independent (different keys, infrastructure, operators). ### Layer 4 — EscrowV1 ```solidity interface IEscrowV1 { /// @notice Submit a fraud proof against a revealed report. /// @param proofType bytes4 discriminator (see proofType Registry below). function challenge(uint256 periodId, bytes4 proofType, bytes calldata proofData) external; /// @notice Distribute rewards after CHALLENGE_PERIOD with no unresolved challenges. function settle(uint256 periodId) external; } ``` `EscrowV1` reads `NodeRegistry` to resolve `nodeUrl → signerAddress` and `nodeType`. It maintains a period-keyed attestation index populated by `CommitRevealSettler` at reveal. Quorum requires ≥ M-of-N routers to agree on the same distribution. #### proofType Registry | Value | Name | Description | Status | |---|---|---|---| | `0x00000001` | `SIG_CONTRADICTION` | Signature contradiction — challenger supplies a signed `/records` pull from the accused router that contradicts their revealed report | V1 | | `0x00000002` | `ZK_VM` | zkVM execution proof — for coordinated majority collusion requiring off-chain re-execution | Future | | `0x00000003` | `MIPS_BISECTION` | MIPS bisection trace — interactive fault proof for disputed execution | Future | Values `0x00000004` and above reserved for future allocation via ERC update. Implementations MUST revert on unknown `proofType` values. #### Distribution at `settle(periodId)` - **Origin pool:** proportional to `sourcePeer` counts - **Router pool:** proportional to router uptime and sync score - **Hybrid nodes:** 50/50 split across both pools - **Bonds** of non-challenged reporters released - **Reserve:** slashed bonds from successful challenges accrue to `EscrowV1.reserve()` and supplement future settlement pools **Value flow separation:** Reward distribution and bond slashing are distinct value flows. Pool rewards (`distributeReward`) compensate honest contribution — origin records relayed, router uptime, sync scores. Slashed bonds route to `EscrowV1`'s reserve via a separate event path (`challenge → slash → reserve`), not into the distribution pools. Implementations MUST NOT recycle slashed bonds back into pool distribution — this would blur the incentive structure by mixing penalty proceeds with participation rewards. ### Two-Axis Separation The converged ERC-8275 carries two economic axes keyed off different commitments: | | Commitment | Period | Binds | Feeds | |---|---|---|---|---| | **WYRIWE (8299)** | `commitmentHash` | per-action | `agentId · modelHash · inputHash · outputHash · timestamp` | **agent** reputation | | **Settler (8275)** | snapshot commitment | per-period | `snapshotRoot · periodId · nodeAddress` | **node-infra** compensation | The reputation loop closes via the WYRIWE attestation, NOT by embedding the settler's snapshot hash into it. Keeping the two on separate axes prevents infra-economics (who relayed how many records) from leaking into agent scoring (the quality of an agent's outcomes). A node earning more by relaying more records cannot move any agent's score, and a high-reputation agent earns its operator nothing on the compensation axis. The two are joined only by the shared `inputHash` spine upstream, never by a settlement value. **Recompute-grade guarantee:** Every value on both axes is recomputable from public data — `attestationCount` from signed verdicts whose signatures verify against published keys, `winRate` from settled digests on the public non-editable account, `snapshotRoot` from revealed rows that must match the committed hash on-chain. No scorer or settler to trust. **Token-free reputation axis:** The reputation axis carries zero token dependency. Bond tokens, escrow currencies, and settlement denominations are settler-axis concerns only (§Layer 3 — Bond token requirements). Reputation inputs derive entirely from signed verdicts and settled on-chain digests — a verifier can independently recompute an agent's reputation without access to or knowledge of any bond token. This separation ensures that bond token changes, upgrades, or multi-token settlement configurations do not affect reputation conformance in any way. **V1 settler decisions (snapshotRoot and FREEZE_BUFFER):** - **snapshotRoot:** V1 uses a flat `keccak256(abi.encode(row_0, ..., row_n))` of sorted contribution rows (§Layer 2). A Merkle root construction is noted for consideration in future versions — Merkle roots enable partial-row challenges and reduce challenge data payloads, but add complexity to the freeze-time hashing protocol. V1 intentionally keeps the hashing scheme simple and verifiable with a single on-chain hash comparison. - **FREEZE_BUFFER:** V1 sets `FREEZE_BUFFER = 600` seconds (10 minutes). This value balances two constraints: (a) late-arriving records from origin nodes that operate at the edge, and (b) the need for a deterministic freeze deadline that honest routers can converge on. Future versions MAY adjust this value based on observed mesh latency distributions. These decisions are settler-axis only and do not affect the reputation axis, which is token-free and settles independently (§Two-Axis Separation). --- ### Architecture ``` ┌─────────────┐ events ┌─────────────┐ events ┌──────────────┐ │ Registry │◄──────────►│ Escrow │◄──────────►│ Reputation │ │ (Discovery) │ │ (Payment) │ │ (Scoring) │ │ INodeReg. │ │ distribute │ │ verifyOutcome│ └─────────────┘ └─────────────┘ └──────────────┘ │ │ │ ▼ ▼ ▼ AgentRegistered OrderCreated getReputation NodeRegistered OrderConfirmed Read-only OrderDisputed OrderResolved RewardDistributed ┌──────────────────────────────────────────────┐ │ Mesh Settlement Protocol (Layers 1–4) │ │ L1: Off-chain attribution (GET /contributions)│ │ L2: Signed snapshots with freeze requirement │ │ L3: CommitRevealSettler (commit→reveal) │ │ L4: EscrowV1 (challenge→settle) │ │ │ │ Node Taxonomy → Reward Pool Mapping │ │ Origin → Pool A (per-attestation) │ │ Router → Pool B (per-settlement) │ │ Hybrid → Pro rata A + B (50/50 at V1) │ └──────────────────────────────────────────────┘ ``` - Service-layer interfaces are **independently deployable** and independently upgradeable. - The mesh settlement protocol layers on top without modifying service interfaces. - Communication is exclusively through **standardized events**. **ERC pipeline:** 8273 (attestation) → 8274 (proof) → **8275 (settlement)** → 8183 (commerce) --- ## Rationale ### Why event-driven discovery? On-chain search is expensive and creates centralization pressure. Event-driven discovery is permissionless and scalable — analogous to ant pheromone trails. ### Why three decoupled interfaces? Decoupling allows each layer to evolve independently. An escrow implementation MAY be upgraded without breaking existing registrations. ### Why three node types? Origin-only nodes would be excluded from routing rewards despite contributing to mesh resilience. A monolithic model conflates record production with aggregation. The three-way taxonomy ensures each operator is rewarded for what they actually contribute. ### Why freeze at snapshotCutoff? Without a deterministic freeze step, honest routers independently hashing live contribution data at slightly different wall-clock moments produce divergent commitment hashes. The issue is not bad faith — it is nondeterminism. ### Why include nodeAddress in commitmentHash? Without `nodeAddress`, a node could copy a peer's commitment without having the corresponding snapshot data. Including `nodeAddress` makes cross-node replay detectable at reveal time. ### Why two-axis separation? Infra-economics (who relayed how many records) must not leak into agent scoring (the quality of an agent's outcomes). Compensation cadence MUST NOT become a reputation signal. Keeping the two on separate commitment axes — WYRIWE per-action vs settler per-period — enforces this boundary. ### Why ValidatorType-gated reputation scores? Different verification paradigms provide different levels of assurance. Collapsing ReExecution, Attestation, and Judgment into a single score without type information misleads consumers. ### Why passive, recompute-grade reputation? Manual reputation is vulnerable to Sybil attacks. Every value being recomputable from public data — no scorer to trust — is the implementation counterpart to the settler's on-chain fraud proofs. --- ## Backwards Compatibility No backward compatibility issues. All interfaces are new. The settlement protocol layers on existing ERC-8004 + ERC-3668 infrastructure without modification. --- ## Reference Implementation - **ERC-8275 Reference Implementation:** Foundry-based implementation at `Brooks1003/erc8275-reference`. Deployed on Sepolia testnet. - **ENS Boiler Gateway (TMerlini):** Live credit-based escrow at `dinamic.eth.limo/top-up`. Full L1-L4 attestation stack with 46+ live proofs. - **ccip-router (TMerlini / dinamic.eth):** Production peer-sync + attestation coordination layer. 4-node production mesh: `gateway.ensub.org` + 3 routers. npm `v0.5.24`. - **CommitRevealSettlerV2 (TMerlini / Damon Zwicker):** On-chain commit-reveal settlement with bond/slash. Deployed on Sepolia at `0x3001a91418c6aA75daD4093AC9e57277e2c81eDC`. Fraud-proof validated end-to-end on-chain — a fabricated snapshot root was submitted, revealed, detected as mismatch, and slashed in the same transaction. - **BountySettlement (TMerlini):** OCP proof-of-concept using EIP-712 InferenceAttestation. Deployed on Base Sepolia at `0x57fe09a6Eb8d5741b24fF640AA8Bc4D2010B93D7`. `gist.github.com/TMerlini/bf3abd30c332cccb257d0e5bdff1ff95`. - **WYRIWE (TMerlini):** Input-provenance specification at `github.com/TMerlini/wyriwe`. Triple-hash scheme, IDENTITY_SENTINEL invariant, EIP-712 attestation profile. - **Reputation reference feed (babyblueviper1):** Live recomputable verdict ledger at `api.babyblueviper.com/ledger`. Every reputation input is derived from this feed's public fields. ### Live Contract Addresses | Contract | Network | Address | |----------|---------|---------| | NodeRegistry | Ethereum Mainnet | `0x95a1e10D1508EF5CD11e3F4d296359c93f15e48D` | | OffchainResolver v2 | Ethereum Mainnet | `0xB300e09e6C4f901409B809e7924CF68A2A429014` | | AttestationIndex | Ethereum Mainnet | `0xc7BCCD785Fb994e570d0ca10D0F7899d87C82210` | | WyriweProofVerifier | Ethereum Mainnet | `0xd8a09d830b27697e1b24e8c9800e562d20318a09` | | CommitRevealSettlerV2 | Sepolia | `0x3001a91418c6aA75daD4093AC9e57277e2c81eDC` | | NodeRegistryV2 (NodeType) | Sepolia | `0xeFae266aE0a74518da320a029dD76F4d47e2a87b` | | EscrowV1 | Sepolia | `0x18165265aDBA40054792929D89c6C487Ae2242E9` | | BountySettlement | Base Sepolia | `0x57fe09a6Eb8d5741b24fF640AA8Bc4D2010B93D7` | ### Fraud-proof Validation (Sepolia) The bond/slash path was exercised end-to-end on-chain on `CommitRevealSettlerV2`: - **register** (Router): `0xffc2a1e8...` - **submitCommit** (fabricated root + 0.01 ETH bond): `0x11b0eebd...` - **submitReveal** (rows mismatch → `RevealMismatch` + slash): `0xe89bea20...` `EscrowV1`'s balance moved `0 → 0.01 ETH` in the reveal transaction — the slashed bond. The fraud-proof is enforced on-chain, not only specified. --- ### Acknowledgements This converged ERC merges two workstreams — Panini's filed PR #1774 (service discovery + escrow + reputation) and the mesh economic-compensation spec drafted by the full team below. All authors contributed across both axes. **Tiago Merlini** (TMerlini, `dinamic.eth`) — three-tier node taxonomy, ccip-router production mesh, four-layer settlement protocol (L1–L4), CommitRevealSettler + EscrowV1 reference implementation, fraud-proof validation, ERC-8004 identity linking, OCP proof anchoring, WYRIWE spec. **Damon Zwicker** (@damonzwicker) — OCP integration, CommitRevealSettler fraud proof model, commit-reveal bond/slash mechanics, small-N collusion resistance analysis. **Jimmy Shi** (@JimmyShi22) — `IAgentVerifier`, `claimType` / `proofProfile()` integration, `snapshotRoot` canonicalization and V1/V2 upgrade path. **Vincent Wu** (@vincent-wu-eth) — composition framework connecting ERC-8273 → ERC-8275 → ERC-8183, AnchorProof log integration. **babyblueviper1** (@babyblueviper1) — Reputation function `f(attestationCount, counterpartyDiversity, winRate, volumeCap)`, recompute-grade guarantee, `api.babyblueviper.com/ledger` reference feed, `committed_at` gate, dual-axis separation framing. **Panini** (@panini-eth) — Service-layer interfaces (IAgentRegistry, IAgentEscrow, IAgentReputation), event-driven architecture, INodeRegistry extension, ValidatorType enum + dual discriminator, attestation-weighted scoring formula. **Pocket Network VNI Group** (@traciecmyers) — `validatorAddress` role in ERC-8004, VNI challenge kind alignment. --- ## Security Considerations ### Escrow fund safety Implementations MUST ensure funds can only be released via `confirmOrder` or `resolveDispute`. Reentrancy protection MUST be applied. ### Quorum collusion (mesh settlement) A colluding majority of routers could agree on a fabricated attribution distribution. The bond + challenge window provides economic enforcement: fabricated reports can be falsified using the routers' own signed `/records` pulls. Fabricating a report requires also fabricating signed mesh records, which is computationally infeasible without key compromise. ### Freeze timing manipulation A router that delays its freeze past `snapshotCutoff` to observe late-arriving records gains an informational advantage. The MUST-be-automatic freeze requirement eliminates this. ### Bond griefing A challenger who submits spurious fraud proofs forces routers to defend valid reveals. `challenge()` SHOULD require a challenge bond, forfeited if the challenge fails. ### Cross-node replay Without `nodeAddress` in `commitmentHash`, a node could copy a peer's commitment. Including `nodeAddress` makes cross-node replay detectable at reveal time. ### Hybrid node self-attribution A hybrid node that counts its own records in its routing reward receives double compensation. Origin pool payouts for hybrid nodes MUST derive from `sourcePeer` counts as attributed by other routers. ### Reputation Sybil resistance Since reputation is derived from economic activity, Sybil attacks require capital commitment. Attestation-weighted scoring further raises the bar — an attacker must produce verifiable attestations. On the attester side, the independence-adjusted effective count (A.3.5) prevents an operator from inflating a score by splitting its signers across multiple co-controlled keys. ### Event spamming `AgentRegistered` and `NodeRegistered` events are permissionless. Client indexers SHOULD implement spam filtering. --- ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).