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.
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.
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.
Before making attestations, get your agent onchain. Use Coinbase’s AgentKit to create an agent that holds a wallet, initiates transactions, and can make attestations.
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. EAS is natively integrated into the OP Stack, so these contracts are the same throughout the Superchain.
With the EAS SDK you can easily make, revoke, delegate, and batch your attestations or register schemas.
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);
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.
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.
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
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.”
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
Encode subscription data: Use EAS’s SchemaEncoder
to define your fields.
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
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.
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.
Trustless, composable data
Costs gas but is globally verifiable and easy for smart contracts to consume
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.
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.
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 Use the GraphQL API at 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.
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.
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!