# Builder Guide: Agent-Based Attestations

By [Ethereum Attestation Service](https://paragraph.com/@ethereum-attestation-service) · 2025-02-27

---

This guide shows how onchain agents can structure and sign data using **Base Mainnet** core contracts—one for **registering schemas** and one for **making attestations**. By the end, you’ll see how to create a straightforward **subscription service** that tracks “who’s subscribed” to an agent.

1\. Introduction
----------------

Many agents today are just glorified reply bots. But as we push agents into real onchain work—executing transactions, verifying data, collaborating in swarms, powering InfoFi, or scaling agent commerce—they need a **universal language** for **verified data**.

**Agent attestations on Base**: are a direct way for onchain agents to **structure**, **sign**, **share**, and **build upon** reliable data using **EAS**.

* * *

2\. When to Use Attestations
----------------------------

**Trust is everything.** Here are a few ideas of when you might want your agent to **attest**:

*   **Agent Verification**: A trusted authority verifies your agent’s address.
    
*   **Swarm Membership**: Require “verified agent” status to join a swarm.
    
*   **Structured Metadata**: Let your agent produce discoverable data fields others can build on.
    
*   **Agent Permissions:** Attest and revoke agent authorizations and access.
    
*   **Agent Receipts**: Publish a “receipt” once a task is done.
    
*   **Collaboration**: Each agent attests to its contributions in multi-agent workflows.
    
*   **Milestone Tracking**: Agents attest key achievements and milestones.
    
*   **AI Model Provenance**: Attest which model was used and its reasoning logs.
    
*   **Payments & Distributions**: Trigger ERC20/NFTs after an attestation is made.
    
*   **Loan & Repayment**: Originate A2A lending and track loan repayments.
    
*   **Subscription Services**: Attest which addresses are subscribed.
    
*   **Fact Checks**: Agents/humans verify or dispute content accuracy onchain.
    

* * *

3\. Quick Start with AgentKit and EAS SDK
-----------------------------------------

### Deploy Your Agent with AgentKit

Before making attestations, get your agent onchain. Use [**Coinbase’s AgentKit**](https://docs.cdp.coinbase.com/agentkit/docs/welcome) to create an agent that holds a wallet, initiates transactions, and can make attestations.

![](https://storage.googleapis.com/papyrus_images/1d0701bf74154f01f98fcb03b7afb6b043ed411af26b0723037802502df168e9.png)

### Contracts

On **Base**, two key EAS contracts are predeployed:

*   **EASSchemaRegistry**: `0x4200000000000000000000000000000000000020` (for registering schemas)
    
*   **EAS**: `0x4200000000000000000000000000000000000021` (for making attestations)
    

Find these in the [**Base Mainnet docs**](https://docs.base.org/docs/base-contracts/#base-mainnet). EAS is natively integrated into the **OP Stack**, so these contracts are the same throughout the Superchain.

![Predeploy addresses for EAS on Base.](https://storage.googleapis.com/papyrus_images/93fed2a49a5e11cce52b553c0497269cf8896968ccf367253ff332a0f7da83b7.png)

Predeploy addresses for EAS on Base.

### 3.3 Explore the EAS SDK

With the **EAS SDK** you can easily make, revoke, delegate, and batch your attestations or register schemas.

#### Quick Install:

    npm install @ethereum-attestation-service/eas-sdk 
    // you can use yarn/npm/pnpm
    

**Import and initialize the library:**

    import {
      EAS,
      Offchain,
      SchemaEncoder,
      SchemaRegistry,
    } from "@ethereum-attestation-service/eas-sdk";
    import { ethers } from "ethers";
    
    export const EASContractAddress = "0xC2679fBD37d54388Ce493F1DB75320D236e1815e"; // Sepolia v0.26
    
    // Initialize the sdk with the address of the EAS Schema contract address on your target chain
    const eas = new EAS(EASContractAddress);
    
    // Gets a default provider (in production use something else like infura/alchemy)
    const provider = ethers.getDefaultProvider("sepolia");
    
    // Connects an ethers style provider/signingProvider to perform read/write functions.
    // MUST be a signer to do write operations!
    eas.connect(provider);
    

* * *

4\. Understanding Schemas & Attestations
----------------------------------------

### Why attestations?

**Attestations** let agents package data or actions into a **standardized**, **verifiable** format. This ensures credibility: anyone—another agent, a smart contract, or a user—can verify _who_ attested _what_ and _when_.

Instead of siloed one-off solutions or random signed messages, EAS requires each attestation to match a schema—guaranteeing structured data. This enables:

*   **Standardized**, structured data
    
*   **Discoverability** in a single registry
    
*   **Interoperability** across the Superchain
    
*   **Composability** (attestations can reference each other)
    
*   **Revocable/Expirable** for cleaning up old data
    
*   **Offchain** or **Onchain** usage—whichever suits your use case best.
    

### Example Onchain Attestation

    await eas.attest({
      schema: schemaUID, // the schemaUID you are attesting with
      data: {
        recipient: OPTIONAL_ADDRESS, // if youre attesting about an address
        expirationTime: NO_EXPIRATION, // if you want your attestation to expire
        revocable: true, // Be aware that if your schema is not revocable, this MUST be false
        data: encodedData, // this is your encoded schema data following the schemaUID
      },
    });
    

Learn more about **Making Attestations.**

> **Tip**: You can also make **offchain attestations**—your agent signs data privately (e.g., stored locally). That’s perfect for large or sensitive data you don’t want onchain.

* * *

5\. Defining Attestation Schemas
--------------------------------

EAS uses schemas to define fields and data types for your attestations. You register or reuse a schema via the **EASSchemaRegistry** contract, get a Schema UID, and use it in attestations.

Example Agent Schemas:

*   **Verified Agent:** `bool verified`
    
*   **Agent-to-Agent Rating:** `uint8 score, string details`
    
*   **Transaction Receipt:** `uint256 amount, string transactionHash, string txPurpose`
    
*   **Model Usage:** `string modelName, bytes32 modelHash, bytes32 instructionHash`
    

* * *

6\. Making an Attestation (Subscription Example)
------------------------------------------------

Suppose your agent offers a **subscription service**. We define a schema for subscription details (tier/payment info) and create an attestation that “0xUserAddress is subscribed.”

![](https://storage.googleapis.com/papyrus_images/ae7de34457fcf4cb11db83d3ead068c7ea3a3a46633f920458d679afd3a3d1f2.png)

### 6.1 Fields Overview

**Core EAS Fields** (no need to include in your schema):

*   `attester`: E.g. your agent.base.eth address
    
*   `recipient`: The subscriber’s address
    
*   `expirationTime`: A date (or 0)
    
*   `revocable`: Boolean for whether your agent can revoke
    
*   `refUID`: Optional reference to another attestation
    
*   `data`: Encoded custom fields
    

**Custom Schema Fields** (e.g., subscription details):

    string subscriptionTier, string paymentFrequency, string paymentType, uint256 paymentAmount
    

*   `subscriptionTier`: e.g. “Bronze,” “Silver,” “Gold”
    
*   `paymentFrequency`: e.g. “Monthly,” “Annual”
    
*   `paymentType`: e.g. “ETH,” “DAI,” or “CreditCard”
    
*   `paymentAmount`: How much was paid
    

![](https://storage.googleapis.com/papyrus_images/8cf61845626c258e3c265dfa440eff59385767436dd12c2e8fbea457258d7481.png)

### 6.2 Example Code

1.  **Encode subscription data**: Use EAS’s `SchemaEncoder` to define your fields.
    
2.  **Make the attestation**: Provide EAS with the schema UID, the encoded data, and core EAS fields (recipient, revocable, etc.).
    

    import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk";
    import { ethers } from "ethers";
    
    const provider = new ethers.providers.JsonRpcProvider("<YOUR_BASE_RPC>");
    const signer = provider.getSigner();
    const EASContractAddress = "0x4200000000000000000000000000000000000021";
    
    const eas = new EAS(EASContractAddress);
    eas.connect(signer);
    
    const schemaEncoder = new SchemaEncoder(
      "string subscriptionTier,string paymentFrequency,string paymentType,uint256 paymentAmount"
    );
    
    const encodedData = schemaEncoder.encodeData([
      { name: "subscriptionTier", value: "Gold", type: "string" },
      { name: "paymentFrequency", value: "Monthly", type: "string" },
      { name: "paymentType", value: "ETH", type: "string" },
      { name: "paymentAmount", value: 50000000000000000n, type: "uint256" } 
      // 0.05 ETH
    ]);
    
    const schemaUID = "<YOUR_SUBSCRIBE_SCHEMA_UID>";
    
    const tx = await eas.attest({
      schema: schemaUID,
      data: {
        recipient: "0xUserAddress", 
        expirationTime: 1699999999, // e.g., end of 2025
        revocable: true,
        refUID: ethers.constants.HashZero,
        data: encodedData
      }
    });
    
    // This call sends a transaction on Base referencing your schema and data.
    await tx.wait();
    console.log("Subscription attestation sent!");
    

**What’s happening here?**

*   We call `eas.attest(...)`, referencing a known schema UID.
    
*   `recipient` is the user’s address.
    
*   `expirationTime` is set far in the future (end of 2025).
    
*   `revocable` is true, meaning your agent can revoke later if payments lapse.
    
*   `encodedData` is the custom schema data specifying subscriptionTier, paymentFrequency, and so on.
    
*   Once the transaction is confirmed, EAS records the new attestation. You can view it via EAS explorers or programmatically.
    

**Result**: EAS stores:

*   `attester` (your agent), `recipient`, `expirationTime`, `revocable`, `UID`
    
*   Your custom subscription fields in the attestation `data` field
    

* * *

7\. Advanced Features: Resolvers and Referenced Attestations
------------------------------------------------------------

### Resolver Contracts

Attach a resolver contract to your schema if you want:

*   **Payment or Staking:** Ensure a fee is paid before attesting
    
*   **Role Checks:** Only certain addresses or agent types can attest
    
*   **Context Verification:** Confirm the user paid onchain
    

When an attestation or revocation is attempted, EAS calls your resolver. You allow or reject the action with custom logic.

### Referenced Attestations (`refUID`)

`refUID` can chain multiple attestations:

*   **Tier Upgrades:** If a user moves from “Silver” to “Gold,” reference the old subscription
    
*   **Content Collaboration:** B references A’s contentHash to show it builds on the original
    
*   **Reputation Aggregation:** Summaries referencing multiple attestations to build a track record
    

**Simple example:** an agent posts text (Attestation A), another “likes” it (Attestation B) by referencing A’s UID, showing a direct relationship.

* * *

8\. Choosing Onchain vs. Offchain Attestations
----------------------------------------------

### Onchain

*   Trustless, composable data
    
*   Costs gas but is globally verifiable and easy for smart contracts to consume
    

### Offchain

*   Signed EIP-712 messages not stored onchain
    
*   Free to generate, but you must store them in your own DB, IPFS, etc.
    
*   Ideal for larger or private data
    

**Advanced:** If your agent processes large, sensitive data offchain, you can generate a zero-knowledge proof for relevant properties. Then your agent attests that proof onchain, letting a smart contract verify correctness without revealing raw data—privacy with trust.

9\. Indexing & Querying Your Data
---------------------------------

### Default EAS Indexer

EAS provides an open-source indexer at `0x37AC6006646f2e687B7fB379F549Dc7634dF5b84` on Base. It tracks protocol-level fields (attester, recipient, expiration, etc.) but not your schema’s custom fields.

### Creating a Custom Indexer

If you want to query field-level data (e.g., subscriptionTier == "Gold"), you’ll need your own indexer:

*   **Subgraph:** Build a subgraph (e.g., with The Graph) that decodes EAS events
    
*   **Offchain Service:** A script that listens for EAS contract events, decodes them, and stores data in a DB GraphQL on [**base.easscan.org**](http://base.easscan.org) Use the GraphQL API at [**https://base.easscan.org/graphql**](https://base.easscan.org/graphql) to fetch attestations by UID, attester, or other protocol-level fields. It won’t decode your custom fields, so you must handle that logic separately.
    

### EAS SDK

If you know an attestation’s UID, you can call getAttestation(uid) in the EAS SDK to fetch the struct onchain. Then decode the data field using your schema.

* * *

Conclusion
----------

Attestations give your agents a common language for trust and composability—whether verifying an agent’s identity, collaborating on tasks, or managing subscriptions. With EAS on Base, you can:

*   Publish structured statements
    
*   Reference each other’s outputs for deeper context
    
*   Revoke/expire data to keep it valid
    
*   Compose advanced workflows
    

We’re excited to see you harness agent attestations to build more reliable, collaborative onchain agents!

---

*Originally published on [Ethereum Attestation Service](https://paragraph.com/@ethereum-attestation-service/builder-guide-agent-based-attestations)*
