This repository contains a system for creating, managing, and verifying two-party agreements on top of the Ethereum Attestation Service (EAS). It provides a standardized and secure way for a primary entity (such as a DAO, protocol, or individual) to enter into on-chain agreements with various counterparties.
The core of the system is the AgreementAnchor contract, which serves as an immutable, on-chain record of an agreement about some off-chain content, identified by a bytes32 content hash.
The EAS-Anchor system is designed to solve the problem of creating formal, bilateral agreements on-chain. While EAS provides a primitive for making attestations, this system builds a higher-level abstraction for agreements where two signers are required.
The primary use case is for a single, canonical Signer (e.g., a DAO) that needs to enter into many standardized agreements with different Counter-Signers. The system ensures that:
- All agreements associated with the primary Signer are created through a single, controlled factory.
- The content of the agreement is set before attestations are made.
- The consent of each party is explicitly tracked via individual attestations.
- The agreement's lifecycle (attestation and revocation) is governed by a strict set of rules defined in a central resolver.
The system is composed of three main contracts that work together to manage the agreement lifecycle.
AgreementResolver.sol: This is the logic layer of the system. It is deployed once for a canonicalsigner. It serves as a custom EAS Schema Resolver, meaning its hooks (onAttest,onRevoke) are automatically called by the EAS contract whenever an attestation or revocation is made using its schema. It is responsible for enforcing most business rules.AgreementAnchorFactory.sol: EachAgreementResolverdeploys its own private factory. This factory is responsible for creating allAgreementAnchorcontracts associated with the resolver's primarysigner. This ensures that the resolver only ever acts upon anchors that it has created, preventing unauthorized contracts from interacting with the system.AgreementAnchor.sol: This contract is the stateful representation of a single agreement. It stores the immutable details of the agreement (contentHash,partyA,partyB) and the state of each party's consent (their latest attestation UID and whether the agreement has been revoked). AnAgreementAnchor's address is used in therecipientfield of an EAS attestation.
- Deployment: The primary
signerdeploys a singleAgreementResolvercontract. The resolver's constructor automatically deploys its ownAgreementAnchorFactory. - Schema Registration: A schema is registered on EAS (e.g.,
bytes32 contentHash) with the deployedAgreementResolveras its official resolver. - Agreement Creation: When the
signerand acounterSigneragree on some off-chain content (e.g., a legal document), they calculate its 32 byte hash. They then callcreateAgreementAnchoron the resolver's factory, creating a newAgreementAnchorcontract for this specific agreement. - Attestation (Signing): Both parties "sign" the agreement by making an EAS attestation.
- Recipient: The address of the newly created
AgreementAnchor. - Schema: The UID of the registered schema.
- Data: The
contentHashof the agreement.
- Recipient: The address of the newly created
- Validation: The
onAttesthook in theAgreementResolveris triggered. It validates that the attester is a party to the agreement, the anchor is legitimate, and the content hash matches. If valid, it updates the state of theAgreementAnchor. - Revocation: If a party wishes to revoke their consent, they revoke their attestation through EAS. The
onRevokehook is triggered, and if the revocation corresponds to the latest attestation for that party, theAgreementAnchoris marked as revoked.
To install dependencies, run:
forge installThis project uses Foundry for testing. To run the full test suite:
forge testTo see test coverage:
forge coverageThe repository includes scripts for deploying the AgreementResolver and registering its schema on EAS. These can be found in the script/ directory.
To deploy to a network (e.g., Sepolia), first set the required environment variables in a .env file (see .env.example). Then, run the deployment script:
forge script script/sepolia/DeployAndRegisterSchema.s.sol --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY --broadcast --verify -vvvvThe security of the system relies on a few key principles:
- Single Authority: The
AgreementResolveris the single source of truth and authority for the business logic of all agreements created under its schema. - Factory-Controlled Anchors: The resolver will only process attestations and revocations for
AgreementAnchorcontracts that were deployed by its own internal factory. This prevents malicious actors from creating their own anchors and having the resolver interact with them. - EAS as the State Layer: The system leverages the security and immutability of the core EAS contracts for all other management of attestations. The resolver acts as a "guard" layer on top of EAS.