EAS (Attestation Service)
The Ethereum Attestation Service is where Green Goods records its claims about work. Work submitted, work approved, and an assessment authored are all EAS attestations, and that's a deliberate choice: attestations are portable, signed, inspectable records that outlive any app Green Goods ships. Commitments are the exception: they are records in the commitment pooling module, never attestations, because their state keeps changing. A commitment can point to an assessment attestation, and a testimony can name a commitment, but EAS never holds the commitment itself.

What makes the integration more than "we write attestations" is the resolver pattern. Each Green Goods schema is bound to a resolver contract that validates authorization at write time. An approval, for example, can only be recorded by one of the garden's stewards or its owner, and never by the person who submitted the work. Meaning is enforced, not implied.
The records
- A Work attestation records submitted evidence for a garden and action.
- A separate Work Approval attestation records the steward's decision, referencing the work it judges.
- An Assessment attestation records evaluation strategy and its content reference. EAS schemas are immutable, so assessment v3 was registered as a new schema beside the still-readable v2 one, on the same resolver. A commitment that requires an assessment accepts either version, as long as it was recorded for the commitment's provider garden and has not been revoked.
- A Community Testimony attestation records what a community member says about a garden or a commitment. Only a wearer of the garden's community hat can write one, and it is append-only. The resolver and schema are recorded for Arbitrum One; no app surface writes testimony yet.
The Anatomy of a Work Submission follows one record through the whole stack, and the Data Model shows how they relate.
How it flows
Here's the path one record takes, from a signature to the pages that show it. The resolver can refuse the write, so any record you can read has already passed its role check. Apps read attestations from EAS GraphQL directly; the Green Goods indexer never reads EAS.
Where it lives in the code
| Layer | Source |
|---|---|
| Resolvers | packages/contracts/src/resolvers/ (Work, WorkApproval, Assessment, Testimony) |
| Schema definitions | packages/contracts/src/Schemas.sol and packages/contracts/config/schemas.json |
| Encode a record | packages/shared/src/utils/eas/encoders.ts (encodeWorkData, encodeWorkApprovalData) |
| Build and send the attestation | packages/shared/src/utils/eas/transaction-builder.ts, sent by the queue executors in packages/shared/src/modules/job-queue/ (work-executor.ts, approval-executor.ts) |
| Query and parse records | packages/shared/src/modules/data/eas.ts |
The write side and the read side are separate modules on purpose: a change to how a record is encoded or sent never touches the query layer, and the reverse.
Schema UIDs and EAS endpoints are different on every chain, so read them from their source
instead of copying them into code or prose. Each chain's deployment artifact lists its schema UIDs
under schemas (for Arbitrum One, packages/contracts/deployments/42161-latest.json), and the EAS
GraphQL endpoints the apps query live in packages/shared/src/config/blockchain.ts. The projection
below lists the networks whose artifacts record the four Green Goods resolvers and the schemas
they guard, so a network that has only some of them reads Partial; the EAS contracts
themselves are the official per-chain deployments linked under upstream docs.
Checked-in deployment projection
| Network | Status | Recorded components |
|---|---|---|
Sepolia Testnet (11155111) | Partial | assessmentResolver, workApprovalResolver, workResolver, schemas.assessmentSchemaUID, schemas.workApprovalSchemaUID, schemas.workSchemaUID |
Arbitrum One (42161) | Deployed | assessmentResolver, testimonyResolver, workApprovalResolver, workResolver, schemas.assessmentSchemaUID, schemas.assessmentV3SchemaUID, schemas.communityTestimonySchemaUID, schemas.workApprovalSchemaUID, schemas.workSchemaUID |
Celo (42220) | Partial | assessmentResolver, workApprovalResolver, workResolver, schemas.workSchemaUID |
Networks without recorded components are omitted; per-network state lives in the deployment status projection.
Indexer boundary
Configured indexer contracts: WorkApprovalResolver.
A deployment artifact does not by itself prove product activation, live indexing, or partner-service health. This projection regenerates from checked-in artifacts via node scripts/docs/generate.mjs.
Working with it locally
The fork mode (bun run dev -- fork) runs a local fork of
Arbitrum One, so the EAS contracts and Green Goods resolvers are present with real state and no
real gas cost. A successful query with no records is different from an unavailable source;
preserve that distinction in anything you build.
Canonical upstream docs
- EAS welcome for the mental model.
- Schemas for UIDs, resolvers, and revocability.
- The EAS SDK, which the shared data layer builds on.
- Per-chain contracts for official EAS addresses.
- arbitrum.easscan.org to browse Green Goods records live.
Next steps
- Anatomy of a Work Submission follows one attestation from a phone to the chain.
- Hats Protocol explains the roles the resolvers check.
- Data Model & Ontology shows how work, approvals, and assessments relate.