Querying EAS Data

integration beginner

How to read attestations from Maroo's EAS — via Solidity contract calls (the canonical surface), via the EAS Indexer for reverse lookups, and via the JS/TS SDKs.

EAS on Maroo is just a Solidity contract preinstall — you read attestations the same way you'd read any contract, over JSON-RPC. The Indexer is a separate preinstall that exposes reverse lookups ("all attestations issued to address X under schema Y"). Pick the path that fits your stack: contract call for one-shot reads, Indexer for reverse lookups, eas-sdk if you want a JS-first API.

Prerequisites

  • Maroo testnet RPC URL
  • EAS / EAS Indexer addresses (preinstalls or resolved via the EAS precompile's getParams())

Resolve EAS / Indexer addresses

Two options. Hard-code the canonical preinstall addresses (EAS = 0x1000…0007, Indexer = 0x1000…0008) — fine for known networks. Or call the EAS precompile's getParams() so the same code works against any Maroo network without modification.
import { createPublicClient, http } from "viem";
import { iEasAbi as easPrecompileAbi } from "@maroo-chain/contracts/abi/precompiles/eas/IEas";

const publicClient = createPublicClient({ transport: http(process.env.MAROO_RPC_URL) });

const EAS_PRECOMPILE = "0x1000000000000000000000000000000000000009";
const { eas: EAS, indexer: INDEXER } = await publicClient.readContract({
  address: EAS_PRECOMPILE,
  abi: easPrecompileAbi,
  functionName: "getParams",
});

Method 1 — Direct contract call (viem / ethers)

The default path for frontend dApps and most backend code. Use getAttestation(uid) against the EAS contract; it returns the full Attestation struct (schema, recipient, attester, time, expirationTime, revocationTime, refUID, data).
import { parseAbi } from "viem";

const easAbi = parseAbi([
  "struct Attestation { bytes32 uid; bytes32 schema; uint64 time; uint64 expirationTime; uint64 revocationTime; bytes32 refUID; address recipient; address attester; bool revocable; bytes data; }",
  "function getAttestation(bytes32 uid) view returns (Attestation)",
]);

const attestation = await publicClient.readContract({
  address: EAS,
  abi: easAbi,
  functionName: "getAttestation",
  args: [uid],
});
// attestation.recipient, attestation.revocationTime, attestation.expirationTime, ...

Method 2 — Reverse lookups via the Indexer

"Has user X been attested under schema Y?" — that's the Indexer. Two methods you'll use:

  • getReceivedAttestationUIDCount(recipient, schemaUid) → cheap existence check
  • getReceivedAttestationUIDs(recipient, schemaUid, start, length, reverseOrder) → paginated list


Then feed each UID into Method 1 to fetch the actual attestation.
const indexerAbi = parseAbi([
  "function getReceivedAttestationUIDCount(address recipient, bytes32 schemaUID) view returns (uint256)",
  "function getReceivedAttestationUIDs(address recipient, bytes32 schemaUID, uint256 start, uint256 length, bool reverseOrder) view returns (bytes32[])",
]);

// 1) count check
const count = await publicClient.readContract({
  address: INDEXER,
  abi: indexerAbi,
  functionName: "getReceivedAttestationUIDCount",
  args: [recipient, schemaUid],
});

// 2) most recent 5
const uids = await publicClient.readContract({
  address: INDEXER,
  abi: indexerAbi,
  functionName: "getReceivedAttestationUIDs",
  args: [recipient, schemaUid, 0n, 5n, true /* reverseOrder */],
});
Note: The Indexer lists only attestations someone has indexed with indexAttestation(uid) (any account may call it; a schema's resolver may do it on attest). A plain attest does not appear here until then, and PCL's EAS_POLICY, which finds attestations only through the Indexer, rejects that sender with EasNoAttestationReceived. The Indexer tracks indexing, not validity: filter out revoked/expired attestations after fetching. EAS_POLICY runs the same revocation/expiration checks against getAttestation, on the most recently indexed one.

Method 3 — eas-sdk (JS)

If you already use the official @ethereum-attestation-service/eas-sdk in your stack, point it at the Maroo EAS address and use it normally. The SDK wraps getAttestation and the schema registry calls.
const { EAS: EasSdk } = require("@ethereum-attestation-service/eas-sdk");

async function main() {
  const eas = new EasSdk(EAS); // EAS: the address the precompile's getParams returned above
  await eas.connect(provider);
  const attestation = await eas.getAttestation(uid);
  console.log(attestation);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
Note: The eas-sdk doesn't ship Indexer bindings — for reverse lookups you'll still call the Indexer directly via viem/ethers as in Method 2.

Method 4 — cast for ad-hoc terminal queries

When you just want to confirm a value from the shell.
# fetch one attestation
cast call $EAS "getAttestation(bytes32)" $ATTESTATION_UID --rpc-url $MAROO_RPC_URL

# count attestations a user has under a schema
cast call $INDEXER \
  "getReceivedAttestationUIDCount(address,bytes32)(uint256)" \
  $RECIPIENT $SCHEMA_UID --rpc-url $MAROO_RPC_URL

Conclusion

All four paths read the same on-chain state. Use viem/ethers for app code, eas-sdk if you already depend on it, the Indexer for reverse lookups, and cast for one-off shell checks.
ESC
Type to search