# Treekipedia ResearchLogSchema https://base-sepolia.easscan.org/schema/view/0x879ed82d38bd26318e55e4803c5699f3191e3e9ca2ffbf75d0cdf16524e4d9d3 ``` import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk"; const easContractAddress = "0x4200000000000000000000000000000000000021"; const schemaUID = "0x879ed82d38bd26318e55e4803c5699f3191e3e9ca2ffbf75d0cdf16524e4d9d3"; const eas = new EAS(easContractAddress); // Signer must be an ethers-like signer. await eas.connect(signer); // Initialize SchemaEncoder with the schema string const schemaEncoder = new SchemaEncoder("uint256 researchLogID,address triggerWallet,string scientificName,string speciesUID,string[] speciesURL,string llmModel,string ipfsCID,uint16 numberInsights,uint16 numberCitations"); const encodedData = schemaEncoder.encodeData([ { name: "researchLogID", value: "0", type: "uint256" } { name: "triggerWallet", value: "0x0000000000000000000000000000000000000000", type: "address" } { name: "scientificName", value: "", type: "string" } { name: "speciesUID", value: "", type: "string" } { name: "speciesURL", value: [], type: "string[]" } { name: "llmModel", value: "", type: "string" } { name: "ipfsCID", value: "", type: "string" } { name: "numberInsights", value: "0", type: "uint16" } { name: "numberCitations", value: "0", type: "uint16" } ]); const tx = await eas.attest({ schema: schemaUID, data: { recipient: "0x0000000000000000000000000000000000000000", expirationTime: 0, revocable: true, // Be aware that if your schema is not revocable, this MUST be false data: encodedData, }, }); const newAttestationUID = await tx.wait(); console.log("New attestation UID:", newAttestationUID); ``` # Resolver Contracts ### Attester This resolver ensures that an attestation is created by a specific attester. It's like a VIP pass, where only a particular entity is allowed to attest. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title AttesterResolver /// @notice A sample schema resolver that checks whether the attestation is from a specific attester. contract AttesterResolver is SchemaResolver { address private immutable _targetAttester; constructor(IEAS eas, address targetAttester) SchemaResolver(eas) { _targetAttester = targetAttester; } function onAttest(Attestation calldata attestation, uint256 /*value*/) internal view override returns (bool) { return attestation.attester == _targetAttester; } function onRevoke(Attestation calldata /*attestation*/, uint256 /*value*/) internal pure override returns (bool) { return true; } } ``` ### Expiration Time This resolver checks if an attestation's expiration time meets a certain condition. Think of it as a "best before" date for attestations. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title ExpirationTimeResolver /// @notice A sample schema resolver that checks whether the expiration time is later than a specific timestamp. contract ExpirationTimeResolver is SchemaResolver { uint256 private immutable _validAfter; constructor(IEAS eas, uint256 validAfter) SchemaResolver(eas) { _validAfter = validAfter; } function onAttest(Attestation calldata attestation, uint256 /*value*/) internal view override returns (bool) { return attestation.expirationTime >= _validAfter; } function onRevoke(Attestation calldata /*attestation*/, uint256 /*value*/) internal pure override returns (bool) { return true; } } ``` ### Paying Resolver This resolver facilitates payments to attesters when they create an attestation. It's a way to incentivize or reward certain attestations. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title PayingResolver /// @notice A sample schema resolver that pays attesters (and expects the payment to be returned during revocations). contract PayingResolver is SchemaResolver { using Address for address payable; error InvalidValue(); uint256 private immutable _incentive; constructor(IEAS eas, uint256 incentive) SchemaResolver(eas) { _incentive = incentive; } function isPayable() public pure override returns (bool) { return true; } function onAttest(Attestation calldata attestation, uint256 value) internal override returns (bool) { if (value > 0) { return false; } payable(attestation.attester).transfer(_incentive); return true; } function onRevoke(Attestation calldata attestation, uint256 value) internal override returns (bool) { if (value < _incentive) { return false; } if (value > _incentive) { payable(address(attestation.attester)).sendValue(value - _incentive); } return true; } } ``` ### Recipient Resolver Ensures an attestation is made to a specific recipient. It's like sending a letter, where only the intended recipient should receive it. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title RecipientResolver /// @notice A sample schema resolver that checks whether the attestation is to a specific recipient. contract RecipientResolver is SchemaResolver { address private immutable _targetRecipient; constructor(IEAS eas, address targetRecipient) SchemaResolver(eas) { _targetRecipient = targetRecipient; } function onAttest(Attestation calldata attestation, uint256 /*value*/) internal view override returns (bool) { return attestation.recipient == _targetRecipient; } function onRevoke(Attestation calldata /*attestation*/, uint256 /*value*/) internal pure override returns (bool) { return true; } } ``` ### Token Resolver Checks if a specific amount of tokens has been approved for an attestation. It integrates token transactions into the attestation process. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title TokenResolver /// @notice A sample schema resolver that checks whether a specific amount of tokens was approved to be included in an attestation. contract TokenResolver is SchemaResolver { using SafeERC20 for IERC20; error InvalidAllowance(); IERC20 private immutable _targetToken; uint256 private immutable _targetAmount; constructor(IEAS eas, IERC20 targetToken, uint256 targetAmount) SchemaResolver(eas) { _targetToken = targetToken; _targetAmount = targetAmount; } function onAttest(Attestation calldata attestation, uint256 /*value*/) internal view override returns (bool) { if (_targetToken.allowance(attestation.attester, address(this)) < _targetAmount) { revert InvalidAllowance(); } return true; } function onRevoke(Attestation calldata /*attestation*/, uint256 /*value*/) internal pure override returns (bool) { return true; } } ``` ### Value Resolver Ensures that an attestation is accompanied by a specific amount of ETH. It's like paying a fee or deposit for the attestation. ``` // SPDX-License-Identifier: MIT pragma solidity 0.8.28; import { SchemaResolver } from "../SchemaResolver.sol"; import { IEAS, Attestation } from "../../IEAS.sol"; /// @title ValueResolver /// @notice A sample schema resolver that checks whether a specific amount of ETH was sent with an attestation. contract ValueResolver is SchemaResolver { uint256 private immutable _targetValue; constructor(IEAS eas, uint256 targetValue) SchemaResolver(eas) { _targetValue = targetValue; } function isPayable() public pure override returns (bool) { return true; } function onAttest(Attestation calldata /*attestation*/, uint256 value) internal view override returns (bool) { return value == _targetValue; } function onRevoke(Attestation calldata /*attestation*/, uint256 /*value*/) internal pure override returns (bool) { return true; } } ```