EAS Resolvers unlock location-based smart contracts. They allow you to execute arbitrary logic whenever an attestation is created — turning geospatial policy attestations into triggers for onchain actions.
For background on the Ethereum Attestation Service, see the EAS documentation.
In the Ethereum Attestation Service, a resolver is a smart contract that gets called whenever an attestation is made against a specific schema. This enables:
Validation: Accept or reject attestations based on custom logic
Side Effects: Execute actions atomically with attestation creation
Composability: Combine attestations with any onchain logic
Code snippets need testing — Verify against actual implementation before use.
About the Astral signer: The astralSigner address is the key that signs policy attestations inside the TEE. Signer management (multisig, key rotation, etc.) is on the roadmap. See Security for more details.
Copy
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;import "@eas/contracts/resolver/SchemaResolver.sol";import "@openzeppelin/contracts/access/Ownable.sol";contract LocationGatedAction is SchemaResolver, Ownable { address public astralSigner; constructor(IEAS eas, address _astralSigner) SchemaResolver(eas) { astralSigner = _astralSigner; } function onAttest( Attestation calldata attestation, uint256 /* value */ ) internal override returns (bool) { // 1. Verify from Astral require(attestation.attester == astralSigner, "Not from Astral"); // 2. Decode policy result (BooleanPolicyAttestation) ( bool result, bytes32[] memory inputRefs, uint64 timestamp, string memory operation ) = abi.decode( attestation.data, (bool, bytes32[], uint64, string) ); // 3. Execute business logic require(result, "Policy check failed"); _executeAction(attestation.recipient); return true; } function onRevoke(Attestation calldata, uint256) internal pure override returns (bool) { return false; // Don't allow revocation } function _executeAction(address recipient) internal virtual { // Override in child contracts } // Owner-controlled signer update for key rotation function updateAstralSigner(address newSigner) external onlyOwner { astralSigner = newSigner; }}
contract LocationAirdrop is LocationGatedAction { IERC20 public token; uint256 public amount; function _executeAction(address recipient) internal override { token.transfer(recipient, amount); }}
Use numeric policy attestations (distance, area, length) for more sophisticated logic like spatial demurrage — where transfer fees vary based on distance from a target location.