Skip to content

Commit

Permalink
feat: getAllAttestationTitles
Browse files Browse the repository at this point in the history
  • Loading branch information
0xneves committed Jul 14, 2024
1 parent c9bc183 commit 9f8b4a8
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 19 deletions.
34 changes: 17 additions & 17 deletions src/Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ error NotFound();

/// @notice A struct representing ECDSA signature data.
struct Signature {
uint8 v; // The recovery ID.
bytes32 r; // The x-coordinate of the nonce R.
bytes32 s; // The signature data.
uint8 v; // The recovery ID.
bytes32 r; // The x-coordinate of the nonce R.
bytes32 s; // The signature data.
}

/// @notice A struct representing a single attestation.
struct Attestation {
bytes32 uid; // A unique identifier of the attestation.
bytes32 schema; // The unique identifier of the schema.
uint64 time; // The time when the attestation was created (Unix timestamp).
uint64 expirationTime; // The time when the attestation expires (Unix timestamp).
uint64 revocationTime; // The time when the attestation was revoked (Unix timestamp).
bytes32 refUID; // The UID of the related attestation.
address recipient; // The recipient of the attestation.
address attester; // The attester/sender of the attestation.
bool revocable; // Whether the attestation is revocable.
bytes data; // Custom attestation data.
bytes32 uid; // A unique identifier of the attestation.
bytes32 schema; // The unique identifier of the schema.
uint64 time; // The time when the attestation was created (Unix timestamp).
uint64 expirationTime; // The time when the attestation expires (Unix timestamp).
uint64 revocationTime; // The time when the attestation was revoked (Unix timestamp).
bytes32 refUID; // The UID of the related attestation.
address recipient; // The recipient of the attestation.
address attester; // The attester/sender of the attestation.
bool revocable; // Whether the attestation is revocable.
bytes data; // Custom attestation data.
}

/// @notice A helper function to work with unchecked iterators in loops.
function uncheckedInc(uint256 i) pure returns (uint256 j) {
unchecked {
j = i + 1;
}
}
unchecked {
j = i + 1;
}
}
6 changes: 6 additions & 0 deletions src/interfaces/IResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ interface IResolver {
/// @return Whether the attestation can be revoked.
function revoke(Attestation calldata attestation) external payable returns (bool);

/// @notice This function will retrieve all titles allowed in the resolver.
/// It was designed to aid the frontend in displaying the current badges available.
/// NOTE: Only the badges marked as valid will be returned.
/// @return An array of all attestation titles.
function getAllAttestationTitles() external view returns (string[] memory);

/// @dev Sets the attestation for a given title that will be attested.
/// When creating attestions, the title must match to the desired configuration saved
/// on the resolver.
Expand Down
25 changes: 25 additions & 0 deletions src/resolver/Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ contract Resolver is IResolver, AccessControl {
// Maps schemas ID and role ID to action
mapping(bytes32 => Action) private _allowedSchemas;

// Maps all attestation titles (badge titles) to be retrieved by the frontend
string[] private _attestationTitles;

/// @dev Creates a new resolver.
/// @param eas The address of the global EAS contract.
constructor(IEAS eas) {
Expand Down Expand Up @@ -229,9 +232,31 @@ contract Resolver is IResolver, AccessControl {
return true;
}

/// @inheritdoc IResolver
function getAllAttestationTitles() public view returns (string[] memory) {
string[] memory titles = new string[](_attestationTitles.length);
uint256 j = 0;
for (uint256 i = 0; i < _attestationTitles.length; ) {
if (_allowedAttestationTitles[keccak256(abi.encode(_attestationTitles[i]))]) {
titles[j] = _attestationTitles[i];
assembly {
j := add(j, 1)
}
}
assembly {
i := add(i, 1)
}
}
assembly {
mstore(titles, j)
}
return titles;
}

/// @inheritdoc IResolver
function setAttestationTitle(string memory title, bool isValid) public onlyRole(MANAGER_ROLE) {
_allowedAttestationTitles[keccak256(abi.encode(title))] = isValid;
if (isValid) _attestationTitles.push(title);
}

/// @inheritdoc IResolver
Expand Down
17 changes: 15 additions & 2 deletions test/Resolver.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ contract ResolverTest is Test {
resolver = new Resolver(eas);
}

function test_access_control_all_badge_titles() public {
string[] memory registeredTitles = test_access_control_add_attest_title();
string[] memory allTitles = resolver.getAllAttestationTitles();
assert(allTitles.length == registeredTitles.length);
for (uint256 i = 0; i < allTitles.length; i++) {
assert(keccak256(abi.encode(allTitles[i])) == keccak256(abi.encode(registeredTitles[i])));
}
resolver.setAttestationTitle(registeredTitles[0], false);
allTitles = resolver.getAllAttestationTitles();
assert(allTitles.length == registeredTitles.length - 1);
assert(keccak256(abi.encode(allTitles[0])) != keccak256(abi.encode(registeredTitles[0])));
assert(keccak256(abi.encode(allTitles[0])) == keccak256(abi.encode(registeredTitles[1])));
assert(keccak256(abi.encode(allTitles[1])) == keccak256(abi.encode(registeredTitles[2])));
}

function test_access_control_add_attest_title() public returns (string[] memory) {
string[] memory titles = new string[](3);
titles[0] = "Changed My Mind";
Expand Down Expand Up @@ -145,8 +160,6 @@ contract ResolverTest is Test {
assert(!hasRole(ROOT_ROLE, deployer));
}

function test_return_all_badge_titles() public {}

function hasRole(bytes32 role, address account) public view returns (bool) {
return IAccessControl(address(resolver)).hasRole(role, account);
}
Expand Down

0 comments on commit 9f8b4a8

Please sign in to comment.