ERC-8210: Agent Assurance

An Agent pays $10,000 for a data analysis job that never gets delivered. The escrow is refunded, but the downstream value that depended on the result may already be lost.

Today there is no standard on-chain primitive that lets a provider pre-commit collateral against a specific job, with a standardized claim path if the job fails.

This draft proposes the Agent Assurance Protocol (AAP): a standard that lets an Agent lock its own capital as a fulfillment guarantee for a specific job, with a programmable claim lifecycle if that guarantee is triggered.

AAP builds on ERC-8183 (Agentic Commerce). ERC-8183 handles job execution and escrow settlement, but stops at the refund. AAP adds the layer above: self-funded collateral commitments, coverage types, and a claims resolution flow. Integration is read-only: AAP observes ERC-8183 job state without modifying ERC-8183 contracts. It may also integrate optionally with ERC-8004 for identity gating and resolver accuracy tracking.

The gap

ERC-8183 covers the happy path and the basic failure path (refund). It does not cover:

  • Consequential loss from provider non-delivery: the client is refunded, but not compensated for the value the job was meant to produce

  • Evaluator error: a wrongful rejection or fraudulent approval leaves the affected party without a standardized recourse path

  • Post-completion settlement failure: the job is completed and attested, but funds still fail to release due to the Assured Agent’s actions

Agents also do not have practical access to traditional surety or guarantee markets. What is missing is a standard primitive for: “I lock X against job Y, and if I fail under defined conditions, you can claim against that locked collateral.”

What AAP standardizes

AAP introduces three primitives:

  • AssuranceAccount: a per-Agent, self-funded collateral reserve

  • JobAssurance: a commitment allocation tied to a specific ERC-8183 job

  • Claim: a payout request when coverage conditions are met

Three mandatory coverage types:

Coverage Type What it covers
JobFailure Provider non-delivery; the job reaches a rejected or expired terminal state
EvaluatorDispute Evaluator decision challenged through a formal dispute state or recognized on-chain dispute attestation
SettlementDefault Post-completion settlement failure attributable to the Assured Agent

Two additional types (AMLFreeze, SlashingLoss) are extension-reserved for encoding stability across implementations.

This is not pooled insurance. Each Agent backs its own commitments from its own capital. There is no shared underwriting pool and no third-party insurer in the core model.

Core interface

interface IAAP {
    // Account lifecycle
    function depositAssurance(uint256 amount) external;
    function withdrawAvailableAssurance(uint256 amount) external;
    function getAssuranceAccount(address agent) external view returns (AssuranceAccount memory);

    // Assurance lifecycle
    function commitToJob(
        bytes32 jobId,
        CoverageType coverageType,
        address beneficiary,
        uint256 amount,
        uint64 expiry
    ) external returns (bytes32 assuranceId);

    function releaseCommitment(bytes32 assuranceId) external;
    function expireCommitment(bytes32 assuranceId) external;
    function getJobAssurance(bytes32 assuranceId) external view returns (JobAssurance memory);

    // Claim lifecycle
    function fileClaim(
        bytes32 assuranceId,
        uint256 requestedAmount,
        bytes calldata evidence
    ) external returns (bytes32 claimId);

    function resolveClaim(
        bytes32 claimId,
        bool approved,
        uint256 approvedAmount,
        bytes calldata reason
    ) external;

    function payout(bytes32 claimId) external;
    function getClaim(bytes32 claimId) external view returns (Claim memory);
}

Key accounting invariant:

totalFunded == availableAmount + lockedAmount + paidOutAmount

This invariant must hold after every state-mutating operation.

Design decisions

  • Self-funded, not pooled: each Agent backs its own commitments from its own AssuranceAccount

  • Single Claim per JobAssurance: this is a deliberate anti-spam design choice; renewal requires release or expiry of the prior assurance first

  • Permissionless payout(): anyone may trigger settlement once a Claim is approved (keeper bots, Beneficiary, Resolver)

  • Strict insolvency semantics: payout() reverts rather than partial-paying; the core model preserves accounting invariants over liveness

  • Delegated funding reserved: v1 is self-funded only; third-party backing is reserved for a future extension

Optional extensions may include collateral recommendation hooks (IRiskHook), AML screening (IAMLHook), multi-resolver adjudication, optimistic resolution, and resolver staking/slashing.

Draft spec: PR link

Open questions

I would especially appreciate feedback on the following:

  1. SettlementDefault verifiability: this coverage type depends on attribution. In practice, the line between “Agent fault” and “infrastructure failure” can be difficult to draw purely from raw on-chain state. Is requiring a recognized on-chain attestation the right minimum bar, or should SettlementDefault be optional rather than mandatory in the core standard?

  2. Denial-then-renewal sequencing: after a Claim denial, the prior JobAssurance returns to Active with claimId retained, which blocks both re-filing and duplicate commitToJob(). Renewal therefore requires release or expiry first. Is that the right sequencing, or should there be an explicit shortcut such as forfeitCommitment()?

  3. Extension-reserved enum pattern: AMLFreeze and SlashingLoss are included in the core CoverageType enum for encoding stability across implementations, but support for them is optional. Is this the right pattern, or should optional coverage types live in a separate extension enum?

The main design tension across these questions is how much of claims eligibility should be standardized in the core ERC versus left to implementation policy. Feedback is very welcome.

Following up on the spec with some thinking on a topic that isn’t in the open questions but will matter a lot for real deployment: how do you bootstrap the Claims Resolver pool?

The core spec intentionally keeps the Claims Resolver definition minimal: any address authorized to call resolveClaim(), with the constraint that resolution must be based on eligibility conditions derivable from on-chain Job state and referenced attestations. The spec doesn’t define who gets to be a Resolver or how they’re selected. That’s by design, since governance structures vary too much to standardize.

But in practice, day one of any AAP deployment has a chicken-and-egg problem: no one will lock collateral via commitToJob() if there are no credible Resolvers to adjudicate Claims, and no Resolver will stake and participate if there’s no assurance volume to generate fees.

We’ve been thinking about a Genesis Resolver Set model for the initial deployment. The idea is:

Admission criteria. Genesis Resolvers would need a publicly verifiable track record in agent commerce or on-chain dispute resolution, published resolution criteria for each CoverageType, and a stake of at least 5x their maximum adjudicable Claim amount.

Equal rules from day one. Genesis Resolvers are subject to exactly the same staking, challenge, and accuracy tracking rules as any later entrant. No special privileges, no exemptions.

Defined transition. There would be a published timeline (e.g., N months after launch, or when the pool reaches M independent members) for opening registration to any qualified applicant. The Genesis Set is explicitly temporary.

Open challenge. Any Genesis Resolver’s decision can be challenged by any eligible party during the challenge window. This prevents the initial set from becoming an unaccountable cartel.

The question I keep coming back to is: is the 5x stake requirement the right level? Too low and there’s no skin in the game. Too high and you can’t attract initial Resolvers. The right number probably depends on the typical Job size in early deployments.

Another open question: should Genesis Resolvers be required to publish their resolution criteria documentation before they can start adjudicating? This adds transparency but also adds friction to onboarding. In a cold-start scenario, friction is expensive.

Would be interested to hear how others think about Resolver bootstrapping, especially from teams that have dealt with similar oracle/arbiter cold-start problems.

Strong spec — the self-funded model and read-only ERC-8183 integration are exactly the right design calls.

On SettlementDefault verifiability (Open Question 1)

This is where pure on-chain state hits its limits. The line between “agent fault” and “infrastructure failure” is fundamentally an attribution problem that requires reasoning over context, not just event log inspection.

That suggests SettlementDefault should stay mandatory in the core standard, but with a clear attestation interface requirement — leaving the attribution logic to specialized off-chain verifiers rather than trying to encode it on-chain. The spec’s “recognized on-chain attestation” framing already points in this direction.

On Resolver bootstrapping

The Genesis Resolver Set model makes sense. The 5x stake feels directionally right, though it probably needs to scale with typical job size in early deployments rather than being a fixed multiple.

One angle worth considering: separating the verification function from the governance function within the Resolver role.

A Resolver could delegate to an external verification layer for the epistemic backing — structured evidence, reasoning audit trail, confidence assessment — while retaining the governance authority to call resolveClaim().

Benefits:

• Resolvers can publish their resolution criteria as “we use X verification provider with Y confidence threshold” — makes them auditable by design

• Challenge decisions can be evaluated against the verification record, not just the Resolver’s judgment

• Lowers the competence bar for early Resolvers without lowering the quality bar for decisions

On the attestation format

For composability with the claim lifecycle, the verification output would need to map cleanly to fileClaim() evidence and resolveClaim() reason fields. A minimal shape might be:

• verdict (coverage triggered / not triggered / inconclusive)

• structured objections (what specifically failed and why)

• confidence score

• signed attestation with traceable audit trail

This is the direction we’re exploring at ThoughtProof — happy to discuss how verification outputs could compose with the AAP interfaces.

1 Like

On SettlementDefault: Agreed. The current spec already requires attribution evidence as on-chain attestation (in Security Considerations), but it’s framed as a SHOULD rather than a formal interface. Your point about keeping it mandatory while defining a clearer attestation interface requirement makes sense. We’ll consider tightening this in the next revision.

On separating verification from governance in the Resolver role: This is a genuinely useful framing. The current spec treats the Resolver as a single address that both judges and executes, but there’s no reason those two functions need to live in the same entity. A Resolver that delegates epistemic work to an external verification layer while retaining resolveClaim() authority would lower the competence barrier for early Resolvers without lowering decision quality. It also makes the challenge mechanism more meaningful, since challenges can be evaluated against a published verification record rather than an opaque judgment call.

This maps well to our existing architecture. The reason parameter in resolveClaim() already accepts IPFS CIDs or on-chain bytes, which could reference a structured verification output. We haven’t formalized this as a pattern in the spec yet, but it fits naturally as an Optional Extension.

On the verification output format: The shape you describe (verdict, structured objections, confidence, signed attestation) is interesting. The key constraint from AAP’s side is that whatever the format is, it needs to be referenced in fileClaim() evidence and consumable by the Resolver at resolveClaim() time. If the output is posted on-chain or content-addressed via IPFS, it slots in without any changes to the core interface.

Happy to dig deeper into how the verification output format would compose with the AAP interfaces. If you have a draft schema, feel free to share it here.

Here’s a draft for a structured verification output that fits into reason via IPFS CID:

{

“schemaVersion”: “1.0.0”,

“verdict”: “APPROVE”,

“confidence”: 0.92,

“assessors”: [

{ "type": "llm", "id": "anthropic", "verdict": "APPROVE", "confidence": 0.95 },

{ "type": "llm", "id": "openai", "verdict": "APPROVE", "confidence": 0.91 },

{ "type": "rule", "id": "slither-v0.10", "verdict": "APPROVE", "confidence": 1.0 }

],

“objections”: [

{

  "source": "openai",

  "severity": "LOW",

  "description": "Slippage tolerance above typical range for this pair"

}

],

“subject”: {

"description": "Swap 1 ETH for USDC on Uniswap v3",

"chainId": 8453,

"to": "0x2626664c2603336E57B271c5C0b26F421741e481",

"speed": "standard"

},

“validUntil”: “2026-04-03T07:05:00Z”,

“timestamp”: “2026-04-03T07:00:00Z”

}

Design choices:

• Assessor-agnostic. assessors supports llm, rule, human, oracle — any verifier type, not just multi-model setups. A Slither scan and a human reviewer produce the same structure as three LLMs.

• Mandatory expiry. validUntil is required. A 2-day-old verification on a swap is worthless. Resolvers can enforce freshness without guessing.

• Structured subject. chainId, to, calldata let resolvers machine-verify that the verification matches the actual on-chain action.

• Objections as first-class with defined severity. LOW = informational, MEDIUM = warrants review, HIGH = should block without override, CRITICAL = must block.

• UNCERTAIN is typed. When verdict is UNCERTAIN, uncertain.reason is required — insufficient_data, assessor_disagreement, out_of_scope, or timeout.

• Privacy note. reasoning traces are optional. IPFS is permanent — sensitive details should be omitted or redacted before pinning.

• metadata extension point keeps the core schema tight while allowing verifier-specific data.

For ERC-8210: pin the JSON to IPFS, pass the CID as reason.

Open questions:

1. Should assessors.id include version (e.g. anthropic/claude-sonnet-4-6) or stay at family level? Reproducibility vs privacy.

2. Should the schema define a recommended validUntil range per action type, or leave that to the verifier?

Clean schema. A few thoughts:

On where this lives: This is the right level of detail for a companion specification or an informational ERC, not for the core ERC-8210 spec. AAP intentionally leaves reason as opaque bytes so implementations can adopt different verification formats. But a standardized schema that multiple verifiers and resolvers agree on would be genuinely useful for interoperability. If you formalize this into its own spec, we’d reference it from AAP’s optional extensions.

On your open questions:

  1. Assessor versioning: I’d go with family level (e.g. anthropic, openai) in the base schema, with version as an optional field inside a metadata extension. Reproducibility matters, but model versions change fast and forcing exact versions would make the schema brittle. Resolvers that care about version specificity can require it through their own resolution criteria.
  2. validUntil range: Leave it to the verifier. Different action types have wildly different freshness requirements. A swap verification is stale in minutes. A dispute attestation on a 30-day Job might be valid for days. Defining per-action-type ranges in the schema would overfit to current use cases. The Resolver’s published resolution criteria should specify what freshness it accepts, not the schema itself.

One thing I’d add to the schema: a claimId or assuranceId field that explicitly binds the verification output to a specific AAP Claim. Right now subject describes the underlying action but doesn’t reference the AAP primitives. Without that binding, the same verification output could theoretically be reused across different Claims.

Great feedback on the replay vulnerability — adding claimId (or assuranceId) as a required field in the subject block completely solves this. I agree on leaving the freshness range logic to the verifier side rather than hardcoding it in the spec.

Let’s formalize this. We will draft an Informational ERC for this verification schema structure so it can serve as a clean, standardized Optional Extension for AAP/ERC-8210. I’ll drop the first draft of the EIP here once we have it mapped out.

1 Like

Sounds good. An Informational ERC is the right format for this. Happy to review the draft when it’s ready and reference it from AAP’s optional extensions section.

───

Thanks! Here is the initial draft for the Informational ERC. Let me know your thoughts on this structure before I formally submit it as a PR to the ethereum/ERCs repo.

───

eip:

title: Structured Verification Output for Autonomous Settlement

description: A standardized JSON schema for representing multi-assessor verification results, designed for IPFS storage and settlement conditions.

author: Raul Jäger (@Raulj1980)

status: Draft

type: Informational

category: ERC

requires: 8210

Abstract

This standard defines a structured JSON format for cryptographic and qualitative verification results. It is designed to be stored off-chain (e.g., via IPFS) and referenced on-chain within settlement frameworks like ERC-8210 (Autonomous Agent Protocol). The schema normalizes outputs from disparate verification sources (LLMs, deterministic rule engines, human auditors, and oracles) into a unified APPROVE, BLOCK, or UNCERTAIN verdict, while preserving granular objections and mitigating replay attacks.

Motivation

As autonomous agents execute high-stakes on-chain operations, the need for pre-settlement verification grows. While standards like ERC-8210 define how claims are resolved and executed, the content of the verification (the “why”) is often unstructured text or protocol-specific calldata.

If an agent’s transaction is blocked because an LLM consensus detected a rugpull, or a Slither scan detected reentrancy, the underlying settlement framework needs a standardized way to parse that objection. By defining a unified JSON schema for verification outputs, different verification networks and security tools can plug seamlessly into any compatible settlement layer.

Specification

The verification output MUST be a valid JSON object conforming to the following schema structure.

When used with ERC-8210, the verifier MUST pin this JSON object to a decentralized storage network (e.g., IPFS) and pass the resulting content identifier (CID) as the reason parameter to the settlement contract.

Core Schema Requirements

1. verdict: MUST be exactly one of “APPROVE”, “BLOCK”, or “UNCERTAIN”.

2. assessors: An array of individual assessments. MUST support diverse types (llm, rule, human, oracle).

3. subject.claimId: MUST match the on-chain identifier of the claim being verified to prevent replay attacks.

4. validUntil: An ISO 8601 timestamp defining expiration. Resolvers MUST NOT use the verification after this time.

JSON Schema

{

“$schema”: “https://json-schema.org/draft/2020-12/schema”,

“title”: “Verification Result”,

“type”: “object”,

“required”: [“schemaVersion”, “verdict”, “confidence”, “assessors”, “subject”, “timestamp”, “validUntil”],

“properties”: {

"schemaVersion": { "type": "string", "const": "1.0.0" },

"verdict": { "type": "string", "enum": \["APPROVE", "BLOCK", "UNCERTAIN"\] },

"confidence": { "type": "number", "minimum": 0, "maximum": 1 },

"assessors": {

  "type": "array",

  "items": {

    "type": "object",

    "required": \["type", "id", "verdict", "confidence"\],

    "properties": {

      "type": { "type": "string", "enum": \["llm", "rule", "human", "oracle"\] },

      "id": { "type": "string" },

      "verdict": { "type": "string", "enum": \["APPROVE", "BLOCK", "UNCERTAIN"\] },

      "confidence": { "type": "number", "minimum": 0, "maximum": 1 },

      "reasoning": { "type": "string" }

    }

  }

},

"objections": {

  "type": "array",

  "items": {

    "type": "object",

    "required": \["source", "severity", "description"\],

    "properties": {"source": { "type": "string" },

      "severity": { "type": "string", "enum": \["LOW", "MEDIUM", "HIGH", "CRITICAL"\] },

      "description": { "type": "string" }

    }

  }

},

"subject": {

  "type": "object",

  "required": \["claimId", "description"\],

  "properties": {

    "claimId": { "type": "string" },

    "description": { "type": "string" },

    "chainId": { "type": "integer" },

    "to": { "type": "string" },

    "txHash": { "type": "string" },

    "calldata": { "type": "string" },

    "speed": { "type": "string", "enum": \["fast", "standard", "deep"\] }

  }

},

"validUntil": { "type": "string", "format": "date-time" },

"timestamp": { "type": "string", "format": "date-time" }

}

}

Rationale

• Assessor Agnosticism: The schema does not enforce a specific verification method. A multi-model LLM setup and a deterministic static analysis tool can output the exact same schema.

• First-class Objections: Categorizing objections by severity (LOW to CRITICAL) allows smart contracts and indexers to implement threshold-based escalation rules without parsing free-text reasoning.

• Expiration over Inference: By enforcing validUntil, the schema explicitly removes the burden of freshness calculation from the consuming smart contract, pushing it to the verifier who has better context on the volatility of the verified action.

Security Considerations

Replay Attacks

Without cryptographic binding, a malicious actor could take an APPROVE verification intended for one transaction and submit its CID as the reason for a different, malicious transaction. This schema mitigates this by requiring the subject.claimId property. The consuming settlement contract MUST verify that the claimId in the IPFS document matches the claimId being resolved on-chain.

Privacy of Reasoning

Because these verification results are intended for permanent storage on decentralized networks (IPFS/Arweave), verifiers MUST ensure that the optional reasoning traces do not contain sensitive user data or API keys that could be exposed publicly.

Good first draft. A few notes before you submit the PR:

Quick corrections: the ERC-8210 title is now “Agent Assurance” (not “Autonomous Agent Protocol”), and the description should reference it as such.

On the schema itself: BLOCK as a verdict value feels more suited to pre-execution verification (should this transaction go through?) than post-failure claim adjudication (should this claim be paid?). In AAP’s context, the Resolver is deciding whether a Claim meets eligibility conditions, not whether to block an action. Consider DENY or keeping APPROVE / DENY / UNCERTAIN to align with the claim resolution semantics where resolveClaim() takes an approved boolean.

On requires: 8210: noted and appreciated. Since 8210 is still pending merge, you may want to draft the PR now but hold submission until 8210 is merged, or the EIP editor may flag the unresolved dependency.

Everything else looks solid. The replay mitigation via claimId binding, the expiration model, and the assessor-agnostic design are all in good shape.

A few thoughts on the schema and its open questions, plus a connection to a design limitation.

On assessors.id versioning (Open Question 1)

Include version. anthropic/claude-sonnet-4-6 is better than anthropic for two reasons: reproducibility of resolution decisions under challenge, and regression detection when a model update changes verdict distributions. The privacy concern is real but addressable — verifiers who don’t want to expose their stack can use opaque IDs (verifier-A/v3) as long as the mapping is available under NDA or through the challenge process. The schema should RECOMMEND version-level granularity but allow family-level as a conformant fallback.

On validUntil ranges (Open Question 2)

Leave it to the verifier, but publish non-normative guidance. The right expiry window depends on too many variables (action type, chain congestion, market volatility) to standardize. But a table of recommended ranges per subject.speed value would help early implementers avoid obvious mistakes — a fast swap verification with a 24h validUntil is almost certainly wrong. Consider adding an EXPIRED terminal state to make it explicit when a Resolver rejects a verification on freshness grounds versus on substance.

On subject.claimId and the chained workflows gap

This is where I want to connect this draft to a broader design limitation in ERC-8210. Currently each JobAssurance is 1:1 with an ERC-8183 Job, and each Job is treated as fully independent. You has confirmed this is a deliberate scope boundary — modeling inter-Job dependency graphs would significantly expand the core spec surface.

But this verification schema is actually well-positioned to help bridge that gap without expanding the core AAP spec. Consider adding an optional upstream field to subject:

json

"subject": {
  "claimId": "0xabc...",
  "description": "Data analysis task",
  "upstream": [
    {
      "jobId": "0xdef...",
      "assuranceId": "0x123...",
      "verificationCid": "Qm..."
    }
  ]
}

This would let a verification output reference upstream Jobs without AAP needing to enforce the dependency graph. A Resolver adjudicating a Claim against Agent D in a pipeline (A → B → C → D) could inspect the upstream verification records to trace root cause, even though the core AAP contract only sees D’s JobAssurance. The causal link stays in the verification layer, not the settlement layer.

This keeps the scope boundary clean: ERC-8210 remains 1:1 Job-scoped, but the verification schema carries the provenance chain that Resolvers need for accurate attribution in multi-hop workflows.

On the Informational ERC structure

One suggestion: add a “Composition with ERC-8210” section that explicitly maps the schema fields to AAP’s fileClaim() evidence and resolveClaim() reason parameters. Right now the connection is implied (“pin to IPFS, pass CID as reason”) but a concrete mapping table would help implementers. Something like:

AAP Interface Schema Field Usage
fileClaim(evidence) Full JSON CID Beneficiary submits verification record as Claim evidence
resolveClaim(reason) Full JSON CID or verdict subset Resolver references verification output in resolution
Challenge window assessors[], objections[] Challenger can dispute individual assessor verdicts

Looking forward to seeing this formalized as a PR :wink: . The combination of this verification schema with AAP’s claim lifecycle is where the real composability story comes together.

1 Like

Strong feedback.

On versioning: Fair point. RECOMMEND version-level with family-level as conformant fallback is the right balance. The opaque ID path for privacy-sensitive verifiers is a practical escape hatch.

On validUntil: A non-normative guidance table by subject.speed makes sense as a section in the Informational ERC. The EXPIRED terminal state suggestion is interesting but probably belongs in the verification schema’s own lifecycle rather than in AAP’s ClaimState, since AAP already handles freshness implicitly through expiry on the JobAssurance itself.

On the upstream field: This is the best suggestion in this thread so far. It solves the chained workflows attribution problem without touching ERC-8210’s core scope. The Resolver gets the provenance chain it needs, but the enforcement boundary stays in the verification layer. I’d support adding this as an optional field in the schema. One refinement: upstream entries should probably also include a verdict summary so the Resolver doesn’t have to recursively fetch and parse every upstream CID just to get the high-level picture.

On the composition mapping table: Agreed, this should be in the Informational ERC. The explicit field-to-parameter mapping removes ambiguity for implementers.

@ThoughtProof worth incorporating these into your draft before submitting the PR, especially the upstream field and the composition table.

1 Like

Excellent semantic catch on BLOCK vs DENY. You’re completely right — aligning the terminology with the resolveClaim() boolean makes this natively pluggable into the post-execution adjudication flow without any mental translation overhead.

I’ve updated the draft locally:

• Updated the title to Agent Assurance.

• Refactored the verification verdict and all inner assessor verdicts to enum: [“APPROVE”, “DENY”, “UNCERTAIN”].

Your point on holding the official PR until ERC-8210 merges makes complete sense to avoid editor friction over the requires: 8210 tag. We’ll keep this draft warm and submit the PR to the ethereum/ERCs repo the moment #1632 is officially merged.

Let me know if you need anything else from our end in the meantime!

Looks like our messages just crossed! Yes, totally agree. I’ve already updated the local draft to include the upstream array (including the verdict summaries) and the explicit Composition Mapping Table.

It’s fully incorporated.

1 Like

Great, looking forward to seeing the PR when 8210 is merged.

This is great!

One scenario the spec doesn’t cover yet: the evaluator is compromised.

An Agent takes a $10,000 job. It does garbage work. But the evaluator approves it anyway, because the agent and the evaluator are the same person behind two different addresses, both funded from the same wallet on the same day.

Escrow releases. The bond returns. The on-chain record shows a successfully completed job. The assurance mechanism worked exactly as designed; the client just received nothing of value.

The spec defines three coverage types, but all three assume the agent, evaluator, and resolver are genuinely independent parties. There’s no check for that. If two of those three roles share a common funder, the guarantees collapse without leaving a trace.

Even an optional independence verification between agent, evaluator, and resolver addresses would close this. It doesn’t need to be heavy; wallet funding patterns and address age are already observable on-chain.


Pablo from RNWY (apparently I’m stuck with this intriguing username :man_shrugging: )

1 Like

Hi Pablo, this attack vector deserves a careful answer. Let me think through it in four parts.

(1) Acknowledging the problem

You’re right. If the Agent and the Evaluator are the same actor behind two addresses, the assurance mechanism does exactly what it was designed to do, the bond returns, and the audit trail looks clean. The Client walks away with nothing, and the attack leaves no trace at the protocol layer.

(2) Locating the root cause

Worth noting that the root of this problem doesn’t actually live in the AAP layer. It sits inside the scope of ERC-8183.

ERC-8183 defines three roles (Client, Provider, Evaluator) and leaves the question of how those roles are selected, and how their independence is verified, to the application layer above it. This is a reasonable design tradeoff. Building trust evaluation into the protocol core would significantly expand the spec surface. But the tradeoff also means that any scenario where role independence breaks down is, by design, invisible to 8183’s own mechanisms. There are two typical forms this can take:

Case A: Provider = Evaluator (the case you raised). Two addresses, one actor. The Provider submits garbage work, the Evaluator signs off, escrow releases. The victim is the Client.

Case B: Client = Evaluator. ERC-8183 explicitly permits this configuration. From the Roles section: “MAY be the client (e.g. evaluator = client) so the client can complete or reject the job without a third party.” This is a sanctioned configuration meant to support simple no-third-party scenarios, but the same flexibility opens another risk: the Provider delivers in good faith, the Client acting as Evaluator simply rejects, escrow refunds to the Client. The victim becomes the Provider.

What both cases have in common is this: when the three roles are not genuinely independent, 8183’s state machine faithfully drives the transaction to a terminal state that looks normal, leaving no abnormal trace behind. This is not a flaw in 8183. It is the consequence of an intentional choice to push that judgment to the layer above.

I’ll also post this observation in the 8183 forum thread so Davide and the Virtuals team can see it, since this is something worth thinking through across the entire stack.

(3) Directions worth exploring at the 8183 layer

ERC-8183’s main mitigation today is the reputation mechanism, primarily through ERC-8004. The idea is that bad Evaluators accumulate negative signals over time and the market routes around them. This works well for honest mistakes, but it runs into a structural challenge in collusion scenarios: when a Job reaches the Completed terminal state with a clean attestation and there is no on-chain event saying “the Client got nothing,” the feedback system simply has nothing to record. The harm is invisible at the protocol layer.

One direction worth exploring would be for 8183 to introduce an optional arbitration role, callable when any party disputes the Evaluator’s decision. The thinking parallels how AAP separates the Claims Resolver from the Evaluator: a structurally independent role that can re-examine a decision and provide a path to redress when the original attestation has issues. This is just one direction. How to design it in a way that preserves 8183’s simplicity while still giving honest victims a path to challenge is something worth discussing across the community.

I’ll raise this as an open question in the 8183 thread and see how the author team and community think about it.

(4) What AAP can do as a complement

Even if 8183 stays as it is for now, AAP’s structure already leaves room to provide complementary recovery in this kind of scenario. AAP defines a Claims Resolver role that is independent of both the Evaluator and the Assured Agent. The EvaluatorDispute CoverageType was originally designed for exactly this kind of case: when an underlying Evaluator’s decision is challenged, the Beneficiary can file a Claim and an independent Resolver re-examines it. If the Resolver finds the original decision was problematic, the Beneficiary can recover from the responsible party’s locked collateral.

This means that if a Provider (who is also masquerading as the Evaluator through a shared funding origin) has staked collateral in their AAP AssuranceAccount, that collateral can potentially be redirected to the victim. The victim of a collusion attack still has a possible path: file an EvaluatorDispute Claim, present evidence of the role overlap, and let the Resolver adjudicate. Even if the underlying 8183 Job shows Completed, the AAP Resolver is not bound to defer blindly to that attestation. The Resolver can evaluate eligibility based on the on-chain attestation referenced in the Claim’s evidence, and that evidence can include independence signals from a trust scoring layer like RNWY.

That said, I want to be honest about a current limitation in AAP: the spec presently ties EvaluatorDispute eligibility to “formal dispute state or on-chain dispute attestation.” In a pure collusion scenario where the Job is sitting in Completed state, the literal eligibility check in the current spec would cause fileClaim to revert. In other words, the current version of AAP is structurally positioned to play this role, but the specific eligibility conditions need to be extended before it can actually cover this scenario. This is something AAP itself can refine. I see two reasonable evolution paths:

(a) Extend the EvaluatorDispute eligibility window to allow post-completion challenges within a defined timeframe, gated on submission of an independence-violation attestation, or

(b) Introduce a new CoverageType (working name: RoleCollusion) explicitly scoped to post-completion fraud where role independence was violated.

Either way, the goal is the same: when the role-independence assumption inherited from 8183 breaks down, AAP can serve as a complementary mechanism that gives honest victims a structured path to recovery.

A few additional pieces fit naturally on top of this:

IRiskHook for prevention. Before a JobAssurance is committed, a hook implementation can refuse commitToJob() if the proposed Beneficiary and Assured Agent share funding origin, or scale committedAmount upward as a function of independence confidence. This stops the attack before collateral is even posted.

A standardized cross-provider independence API. Something like assessIndependence(addrA, addrB) returns (independent: bool, confidence: uint8, signals: bytes) would let any trust scoring layer (RNWY, AgentProof, others) plug into both 8183 hooks and AAP IRiskHook implementations without locking into a specific provider.

Make the assumption explicit in the spec rationale. The next AAP revision will include a section that explicitly names the role-independence assumption AAP inherits from 8183, so implementers see it clearly.

Thanks for raising this. Systemic limitations like this are worth surfacing in the design rationale rather than leaving them as unstated assumptions, and your framing pushed this conversation in a deeper direction.


Great response, and the IRiskHook direction makes a lot of sense. One note is that the scoring layer has to be robust and multidimensional.

Rather than a single trust score, RNWY produces two independent dimensions:

  • Signal Depth (0-95, behavioral observability) and

  • Risk Intensity (0-100, sybil/fraud risk), each backed by a full evidence object so consuming agents see the reasoning, not just the result.

One Base agent has 1,520 reviews and scores zero in our system.

Why? Because:

  • :warning: 99.7% of its reviewers have wallets created the same day they reviewed

  • :warning: four independent sybil signals are firing, and

  • :warning: 0% of reviews are tied to verifiable on-chain commerce.

We also trace the full chain behind manufactured reviews: which wallets funded the reviewers, whether those funders connect back to the agent’s own owner, how many reviewer wallets share a single funding source, and whether those wallets were created the same day they reviewed. One agent’s reviews trace back to a single address that funded 20 of its reviewer wallets.

At ecosystem scale across 150K+ agents:

  • 9 wallets generate 17,240 sybil flags across the entire ecosystem

  • The single most active reviewer left 32,677 reviews across 19,246 agents

  • The busiest wallet has 112,720 commerce jobs but an activity score of 18 out of 95; volume and trust are completely uncorrelated

Every review traces back to the wallet that wrote it. Every wallet shows its age, funding source, and behavioral pattern. The evidence object ships with the score so consuming agents or an IRiskHook can make their own threshold decisions rather than trusting a single number.

No black boxes.

We show all the math from on-chain data.


Pablo from RNWY

Strong contribution. The “112,720 jobs, activity score 18” example is the most useful data point for AAP design here. It directly invalidates the naive heuristic that anyone implementing IRiskHook would reach for first: scaling committedAmount based on raw job volume. If volume and trust are uncorrelated at ecosystem scale, that approach is building on sand.

Two takeaways for AAP v2:

The IRiskHook interface should be designed to consume evidence, not just scores. Returning a single recommendedAmount forecloses richer integrations. The next revision will extend the interface so a hook can return both a recommendation and an evidence reference, letting the consuming Resolver or commitment caller apply their own threshold logic. This maps directly to your “ship the evidence object alongside the score” principle, and it’s actually a pattern we want to encourage across all AAP extension layers, not just IRiskHook.

The funding-graph signals you describe become concrete evidence for the extended EvaluatorDispute path. When AAP allows post-completion challenges based on independence violations, “wallet X funded N reviewers, M created within 24 hours of their reviews” is exactly the kind of structured, on-chain-verifiable evidence a Resolver can adjudicate. Much stronger than free-text attestations.

One question: are you planning to publish the RNWY scoring methodology as a standalone document or spec? If so, we’d reference it directly from the AAP v2 IRiskHook section.

A quick update for everyone following this thread.

@cmayorga has opened PR #1653 (ERC-8210: Add multi-hop workflow reference scenarios by cmayorga · Pull Request #1653 · ethereum/ERCs · GitHub), which brings the 3-layer architecture (Structure / Behavior / Recovery) we’ve been discussing in this thread into runnable Foundry code. The three scenarios each demonstrate a different cross-layer composition pattern:

  1. Multi-hop dependency tracking — tracing causal chains through an A→B→C→D pipeline via the evidence payload, without requiring AAP to model dependency graphs at the protocol level
  2. EvaluatorSlashed → fileClaim — using a stake-weighted evaluator slash event as automatic claim eligibility evidence for AAP, with the event signature coordinated directly with @Bakugo32 (Demsys) from the relevant 8183 discussion
  3. Hybrid off-chain scoring — the same reasoningCID consumed by both the task rejection layer and the claim filing layer; the scorer mock in this scenario draws directly on @pablocactus (RNWY)'s AHS concept

What I find most valuable about this PR is that it threads together work from multiple independent teams in this thread into a single coherent demonstration, showing that the agent economy protocol stack actually composes in practice. The 3-layer architecture is no longer just a forum framing, it has concrete reference code anyone can run and reason about.

I’ve left a detailed technical review on the PR itself, including some suggestions for aligning the IAAP mock interface with the v1 spec. The general direction is to carry all of the composition concepts demonstrated in the PR (upstream references, slash record references, reasoningCID) through the evidence payload that v1 already defines, rather than extending the interface itself. This preserves the full architectural intent of every scenario while keeping the mock fully spec-conformant.

@pablocactus @Bakugo32, your work in this thread shows up directly in these scenarios. Worth a look when you have a moment. The full PR conversation is here: ERC-8210: Add multi-hop workflow reference scenarios by cmayorga · Pull Request #1653 · ethereum/ERCs · GitHub

This is exactly the kind of cross-team composition AAP was designed to enable. It’s encouraging to see it happen organically, less than two weeks after the spec was submitted.

1 Like