Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiAttest and multiRevoke examples #4

Merged
merged 4 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 74 additions & 2 deletions contracts/Attester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

pragma solidity 0.8.26;

import { IEAS, AttestationRequest, AttestationRequestData, RevocationRequest, RevocationRequestData } from "@ethereum-attestation-service/eas-contracts/contracts/IEAS.sol";
import { IEAS, AttestationRequest, AttestationRequestData, RevocationRequest, RevocationRequestData, MultiAttestationRequest, MultiRevocationRequest } from "@ethereum-attestation-service/eas-contracts/contracts/IEAS.sol";
import { NO_EXPIRATION_TIME, EMPTY_UID } from "@ethereum-attestation-service/eas-contracts/contracts/Common.sol";

/// @title Attester
/// @notice Ethereum Attestation Service - Example
contract Attester {
error InvalidEAS();
error InvalidInput();

// The address of the global EAS contract.
IEAS private immutable _eas;
Expand Down Expand Up @@ -36,7 +37,7 @@ contract Attester {
recipient: address(0), // No recipient
expirationTime: NO_EXPIRATION_TIME, // No expiration time
revocable: true,
refUID: EMPTY_UID, // No references UI
refUID: EMPTY_UID, // No referenced UID
data: abi.encode(input), // Encode a single uint256 as a parameter to the schema
value: 0 // No value/ETH
})
Expand All @@ -50,4 +51,75 @@ contract Attester {
function revoke(bytes32 schema, bytes32 uid) external {
_eas.revoke(RevocationRequest({ schema: schema, data: RevocationRequestData({ uid: uid, value: 0 }) }));
}

/// @notice Multi-attests to a schemas which receive a uint256 parameter.
/// @param schemas The schema UIDs to attest to.
/// @param schemaInputs The uint256 values to pass to to the resolver for each schema.
/// @return The UIDs of new attestations.
function multiAttest(
bytes32[] calldata schemas,
uint256[][] calldata schemaInputs
) external returns (bytes32[] memory) {
uint256 schemaLength = schemas.length;
if (schemaLength == 0 || schemaLength != schemaInputs.length) {
revert InvalidInput();
}

MultiAttestationRequest[] memory multiRequests = new MultiAttestationRequest[](schemaLength);

for (uint256 i = 0; i < schemaLength; ++i) {
uint256[] calldata inputs = schemaInputs[i];

uint256 inputLength = inputs.length;
if (inputLength == 0) {
revert InvalidInput();
}

AttestationRequestData[] memory data = new AttestationRequestData[](inputLength);
for (uint256 j = 0; j < inputLength; ++j) {
data[j] = AttestationRequestData({
recipient: address(0), // No recipient
expirationTime: NO_EXPIRATION_TIME, // No expiration time
revocable: true,
refUID: EMPTY_UID, // No referenced UID
data: abi.encode(inputs[j]), // Encode a single uint256 as a parameter to the schema
value: 0 // No value/ETH
});
}

multiRequests[i] = MultiAttestationRequest({ schema: schemas[i], data: data });
}

return _eas.multiAttest(multiRequests);
}

/// @notice Multi-revokes an attestation of a schema that receives a uint256 parameter.
/// @param schemas The schema UIDs to attest to.
/// @param schemaUids The UIDs of the attestations to revoke for each schema.
function multiRevoke(bytes32[] calldata schemas, bytes32[][] calldata schemaUids) external {
uint256 schemaLength = schemas.length;
if (schemaLength == 0 || schemaLength != schemaUids.length) {
revert InvalidInput();
}

MultiRevocationRequest[] memory multiRequests = new MultiRevocationRequest[](schemaLength);

for (uint256 i = 0; i < schemaLength; ++i) {
bytes32[] calldata uids = schemaUids[i];

uint256 uidLength = uids.length;
if (uidLength == 0) {
revert InvalidInput();
}

RevocationRequestData[] memory data = new RevocationRequestData[](uidLength);
for (uint256 j = 0; j < uidLength; ++j) {
data[j] = RevocationRequestData({ uid: uids[j], value: 0 });
}

multiRequests[i] = MultiRevocationRequest({ schema: schemas[i], data: data });
}

_eas.multiRevoke(multiRequests);
}
}
8 changes: 4 additions & 4 deletions contracts/LogResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import { SchemaResolver } from "@ethereum-attestation-service/eas-contracts/cont
contract LogResolver is SchemaResolver {
/// @notice Emitted to log a uint256 value.
/// @param value The attested value.
event Attested(uint256 value);
event Attested(bytes32 schemaUID, uint256 value);

/// @notice Emitted to log a uint256 value.
/// @param value The attested value.
event Revoked(uint256 value);
event Revoked(bytes32 schemaUID, uint256 value);

/// @notice Creates a new LogResolver instance.
constructor(IEAS eas) SchemaResolver(eas) {}
Expand All @@ -25,7 +25,7 @@ contract LogResolver is SchemaResolver {
function onAttest(Attestation calldata attestation, uint256 /*value*/) internal override returns (bool) {
uint256 value = abi.decode(attestation.data, (uint256));

emit Attested(value);
emit Attested({ schemaUID: attestation.schema, value: value });

return true;
}
Expand All @@ -35,7 +35,7 @@ contract LogResolver is SchemaResolver {
function onRevoke(Attestation calldata attestation, uint256 /*value*/) internal override returns (bool) {
uint256 value = abi.decode(attestation.data, (uint256));

emit Revoked(value);
emit Revoked({ schemaUID: attestation.schema, value: value });

return true;
}
Expand Down
28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,32 @@
},
"dependencies": {
"@ethereum-attestation-service/eas-contracts": "^1.7.1",
"hardhat": "2.22.9"
"hardhat": "2.22.13"
},
"devDependencies": {
"@ethereum-attestation-service/eas-sdk": "2.6.0",
"@ethereum-attestation-service/eas-sdk": "2.7.0",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@nomicfoundation/hardhat-ethers": "^3.0.7",
"@nomicfoundation/hardhat-ethers": "^3.0.8",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomiclabs/hardhat-solhint": "^4.0.0",
"@nomiclabs/hardhat-solhint": "^4.0.1",
"@openzeppelin/contracts": "5.0.2",
"@typechain/ethers-v6": "^0.5.1",
"@types/chai": "^4.3.19",
"@types/chai": "^5.0.0",
"@types/chance": "^1.1.6",
"@types/mocha": "^10.0.7",
"@types/node": "^22.5.1",
"@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0",
"@types/mocha": "^10.0.9",
"@types/node": "^22.7.5",
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"chai": "4.3.7",
"chai-bigint": "^0.2.0",
"decimal.js": "^10.4.3",
"eslint": "^9.9.1",
"eslint": "^9.12.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-chai-friendly": "^1.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-promise": "^7.1.0",
"ethers": "^6.13.2",
"ethers": "^6.13.3",
"hardhat-dependency-compiler": "^1.2.1",
"mocha": "^10.7.3",
"prettier": "^3.3.3",
Expand All @@ -59,7 +59,7 @@
"solc": "0.8.26",
"solhint": "^5.0.3",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"typescript-eslint": "^8.0.1"
"typescript": "^5.6.3",
"typescript-eslint": "^8.8.1"
}
}
Loading
Loading