Skip to content

Commit

Permalink
📖 Added basic documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
CaptainUnknown committed Aug 6, 2024
1 parent db9d572 commit 6e563c4
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 22 deletions.
75 changes: 69 additions & 6 deletions contracts/AccessManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,78 +22,124 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
event CompanyUserRoleRevoked(address indexed companyUser, uint256 timestamp);

/**
* @notice To check if the party is TODO documentation
*/
* @dev Throws `UnAuthorized` if called by any account other than the Admin or Default (Super) Admin.
*/
modifier onlyClearanceLevelA() {
if (!(hasRole(ADMIN_ROLE, msg.sender) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender)))
revert Errors.UnAuthorized("ADMIN_ROLE");
_;
}

/**
* @dev Throws `UnAuthorized` if called by any account other than company user, Admin or Default (Super) Admin.
*/
modifier onlyClearanceLevelB() {
if (!(hasRole(COMPANY_USER_ROLE, msg.sender) || hasRole(ADMIN_ROLE, msg.sender) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender)))
revert Errors.UnAuthorized("COMPANY_USER_ROLE");
_;
}

/**
* @dev Sets the Default (Super) Admin.
*/
constructor(address defaultAdmin) {
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
}

/// Authorized Contract Role
/**
* @dev grants the AUTHORIZED_CONTRACT_ROLE to the provided address.
* Necessary for all guarded external calls in between contracts.
*/
function grantAuthorizedContractRole(address contractAddress) public onlyClearanceLevelA {
_grantRole(AUTHORIZED_CONTRACT_ROLE, contractAddress);
emit AuthorizedContractRoleGranted(contractAddress, block.timestamp);
}

/**
* @dev revokes the AUTHORIZED_CONTRACT_ROLE from the provided address.
*/
function revokeAuthorizedContractRole(address contractAddress) public onlyClearanceLevelA {
_revokeRole(AUTHORIZED_CONTRACT_ROLE, contractAddress);
emit AuthorizedContractRoleRevoked(contractAddress, block.timestamp);
}

/// Admin Role
/**
* @dev grants the ADMIN_ROLE to the provided address.
* Admins can only be appointed by the Default (Super) Admin.
*/
function grantAdminRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
_grantRole(ADMIN_ROLE, account);
emit AdminRoleGranted(account, block.timestamp);
}

/**
* @dev revokes the ADMIN_ROLE from the provided address.
*/
function revokeAdminRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
_revokeRole(ADMIN_ROLE, account);
emit AdminRoleRevoked(account, block.timestamp);
}

/// Company User Role
/**
* @dev grants the COMPANY_USER_ROLE to the provided address.
* Company User can only be appointed by the by actors of clearance level A.
* Company User can perform management ops ('with write access' as specified in the specs).
*/
function grantCompanyUserRole(address account) public onlyClearanceLevelA {
_grantRole(COMPANY_USER_ROLE, account);
emit CompanyUserRoleGranted(account, block.timestamp);
}

/**
* @dev revokes the COMPANY_USER_ROLE from the provided address.
*/
function revokeCompanyUserRole(address account) public onlyClearanceLevelA {
_revokeRole(COMPANY_USER_ROLE, account);
emit CompanyUserRoleRevoked(account, block.timestamp);
}

/// Consumer Role
/**
* @dev grants the CONSUMER_ROLE to the provided address.
* Consumers gain read-only access, this role can be utilized in a permissioned chain.
*/
function grantConsumerRole(address account) public onlyClearanceLevelB {
_grantRole(CONSUMER_ROLE, account);
}

/**
* @dev revokes the CONSUMER_ROLE from the provided address.
*/
function revokeConsumerRole(address account) public onlyClearanceLevelB {
_revokeRole(CONSUMER_ROLE, account);
}

/// Super User | Default Admin role
/**
* @dev grants the DEFAULT_ADMIN_ROLE to the provided account.
* This is an irreversible step unless the given account agrees to transfer back the role.
*/
function transferDefaultAdminRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
_revokeRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(DEFAULT_ADMIN_ROLE, account);
emit DefaultAdminRoleTransferred(account, msg.sender, block.timestamp);
}

/**
* @dev To retrieve the current Default (Super) Admin.
* @return The address with the DEFAULT_ADMIN_ROLE.
*/
function getCurrentDefaultAdmin() public view returns (address) {
return getRoleMember(DEFAULT_ADMIN_ROLE, 0);
}

// Get All Authorized Contracts
/**
* @dev To get All Authorized Contracts.
* @return The addresses with the AUTHORIZED_CONTRACT_ROLE.
*/
function getCurrentContracts() public view returns (address[] memory) {
uint256 roleMemberCount = getRoleMemberCount(AUTHORIZED_CONTRACT_ROLE);
address[] memory contracts = new address[](roleMemberCount);
Expand All @@ -104,7 +150,10 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
return contracts;
}

// Get All Admins
/**
* @dev To get All Admins.
* @return The addresses with the ADMIN_ROLE.
*/
function getCurrentAdmins() public view returns (address[] memory) {
uint256 roleMemberCount = getRoleMemberCount(ADMIN_ROLE);
address[] memory admins = new address[](roleMemberCount);
Expand All @@ -115,7 +164,10 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
return admins;
}

// Get All Company Users
/**
* @dev To get All Company Users.
* @return The addresses with the COMPANY_USER_ROLE.
*/
function getCurrentCompanyUsers(uint256 query) public view returns (address[] memory) {
uint256 roleMemberCount = getRoleMemberCount(COMPANY_USER_ROLE);
if (roleMemberCount < query) query = roleMemberCount;
Expand All @@ -127,7 +179,10 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
return companyUsers;
}

// Get All Consumers
/**
* @dev To get All Consumers.
* @return The addresses with the CONSUMER_ROLE.
*/
function getCurrentConsumers(uint256 query) public view returns (address[] memory) {
uint256 roleMemberCount = getRoleMemberCount(CONSUMER_ROLE);
if (roleMemberCount < query) query = roleMemberCount;
Expand All @@ -140,6 +195,10 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
}

/// Necessary Overrides:
/**
* @dev To grant a custom role.
* @return success status.
*/
function _grantRole(bytes32 role, address account)
internal
override(AccessControl, AccessControlEnumerable)
Expand All @@ -148,6 +207,10 @@ contract AccessManager is AccessControl, AccessControlEnumerable {
return super._grantRole(role, account);
}

/**
* @dev To revoke a custom role.
* @return success status.
*/
function _revokeRole(bytes32 role, address account)
internal
override(AccessControl, AccessControlEnumerable)
Expand Down
31 changes: 30 additions & 1 deletion contracts/Actor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { ERC721URIStorage } from "@openzeppelin/contracts/token/ERC721/extension
import { AccessManager } from "./AccessManager.sol";
import { Errors } from "./Errors.sol";

/// @custom:security-contact @captainunknown7@gmail.com
/**
* @title An ERC721 collection of actors.
* @dev A soul-bound NFT for identity management.
* @custom:security-contact @captainunknown7@gmail.com
*/
contract Actor is ERC721, ERC721Enumerable, ERC721URIStorage {
uint256 private _nextActorId;
AccessManager public acl;
Expand All @@ -20,6 +24,9 @@ contract Actor is ERC721, ERC721Enumerable, ERC721URIStorage {
_;
}

/**
* @dev Sets the ACL and determines the hash AUTHORIZED_CONTRACT_ROLE.
*/
constructor(address aclAddress, string memory actorType, string memory prefix) ERC721(actorType, prefix) {
acl = AccessManager(aclAddress);
AUTHORIZED_CONTRACT_ROLE = acl.AUTHORIZED_CONTRACT_ROLE();
Expand All @@ -29,6 +36,13 @@ contract Actor is ERC721, ERC721Enumerable, ERC721URIStorage {
return "ipfs://";
}

/**
* @dev To register a new actor of any kind.
* Can only by called an external contract which would be `ActorsManager`.
* @param The receiver of the ID.
* @param The hash of the ID.
* @return The registered Actor ID.
*/
function registerActor(address account, string calldata hash)
external
onlyAuthorizedContract
Expand All @@ -41,21 +55,36 @@ contract Actor is ERC721, ERC721Enumerable, ERC721URIStorage {
return actorId;
}

/**
* @dev To update an actor of any kind.
* Can only by called an external contract which would be `ActorsManager`.
* @param Actor ID to update.
* @param The new hash.
*/
function updateActor(uint256 actorId, string memory newHash)
external
onlyAuthorizedContract
{
_setTokenURI(actorId, newHash);
}

/**
* @dev Reverts with `SoulBoundTransferNotAllowed`.
*/
function transferFrom(address /*from*/, address /*to*/, uint256 /*tokenId*/) public pure override(IERC721, ERC721) {
revert Errors.SoulBoundTransferNotAllowed();
}

/**
* @dev Reverts with `SoulBoundTransferNotAllowed`.
*/
function safeTransferFrom(address /*from*/, address /*to*/, uint256 /*tokenId*/, bytes memory /*data*/) public pure override(IERC721, ERC721) {
revert Errors.SoulBoundTransferNotAllowed();
}

/**
* @return Whether the id has been issued or not.
*/
function idExists(uint256 id) public view returns(bool) {
return id < totalSupply();
}
Expand Down
53 changes: 49 additions & 4 deletions contracts/ActorsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { Errors } from "./Errors.sol";
import { FunctionsClient } from "@chainlink/contracts@1.2.0/src/v0.8/functions/v1_0_0/FunctionsClient.sol";
import { FunctionsRequest } from "@chainlink/contracts@1.2.0/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol";

/// @custom:security-contact @captainunknown7@gmail.com
/**
* @title Actors Manager.
* @dev Aggregates the collections for all actor types & performs the necessary validation.
* @custom:security-contact @captainunknown7@gmail.com
*/
contract ActorsManager is FunctionsClient {
using FunctionsRequest for FunctionsRequest.Request;
AccessManager public acl;
Expand Down Expand Up @@ -41,6 +45,7 @@ contract ActorsManager is FunctionsClient {
string hash;
}
mapping(bytes32 => RequestInfo) private lastValidationRequest;

string validationSource =
"const actorType = args[0];"
"const hash = args[1];"
Expand All @@ -64,6 +69,10 @@ contract ActorsManager is FunctionsClient {
_;
}

/**
* @dev Sets the ACL and determines the hash AUTHORIZED_CONTRACT_ROLE.
* Along with the Chainlink Configuration.
*/
constructor(address aclAddress, bytes32 _donId, address _donRouter, uint64 _donSubscriptionId)
FunctionsClient(_donRouter)
{
Expand All @@ -82,6 +91,12 @@ contract ActorsManager is FunctionsClient {
AUTHORIZED_CONTRACT_ROLE = acl.AUTHORIZED_CONTRACT_ROLE();
}

/**
* @dev Creates the batch & updates the on-chain state if the metadata validation succeeds.
* @param The type of the actor to register.
* @param The account to receive the identification NFT.
* @param The hash of the metadata of the actor.
*/
function registerActor(uint8 actorType, address account, string calldata hash)
public
onlyValidActorType(actorType)
Expand All @@ -96,6 +111,13 @@ contract ActorsManager is FunctionsClient {
});
}

/**
* @dev Updates the metadata of the actor if the metadata validation succeeds.
* @param The actor type.
* @param The actor ID to replace the hash of.
* @param The hash of the actor.
* @param Callback selector, which calls a post validation function in SupplyChain to perform update.
*/
function updateActor(uint8 actorType, uint256 actorId, string calldata hash)
public
onlyValidActorType(actorType)
Expand All @@ -110,6 +132,12 @@ contract ActorsManager is FunctionsClient {
});
}

/**
* @dev To retrieve the actor URI.
* @param The type of the actor.
* @param The ID of the actor.
* @return The hash of the batch.
*/
function getActorURI(uint8 actorType, uint256 actorId)
public
view
Expand All @@ -119,6 +147,13 @@ contract ActorsManager is FunctionsClient {
return actors[actorType].tokenURI(actorId);
}

/**
* @dev To retrieve the batch URIs in a chunk, chunk size cannot exceed 100.
* @param The type of the actor.
* @param The starting index (ID) of the actors.
* @param Total request size.
* @return The hashes of the actors.
*/
function getActorsURIsInBatch(uint8 actorType, uint256 cursor, uint256 pageSize)
public
view
Expand All @@ -141,7 +176,11 @@ contract ActorsManager is FunctionsClient {
return actorURIs;
}

// Chainlink Metadata Validation Function
/**
* @dev An internal function to be called to send a validation request.
* @param The hash of the metadata to be validated.
* @return The DON Function request ID.
*/
function validateMetadata(uint8 actorType, string calldata hash) internal returns(bytes32) {
FunctionsRequest.Request memory req;
req.initializeRequestForInlineJavaScript(validationSource);
Expand All @@ -157,10 +196,16 @@ contract ActorsManager is FunctionsClient {
);
}

/**
* @dev An internal function to be called by the donRouter.
* @param The validation request ID.
* @param The response from the DON Function.
* @return The error from the DON Function (if any).
*/
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override {
// TODO: Request Id Check
// if (s_lastRequestId != requestId) revert UnexpectedRequestID(requestId);
RequestInfo memory info = lastValidationRequest[requestId];
if (bytes(info.hash).length == 0) revert Errors.UnexpectedRequestID(requestId);

uint256 actorId = info.actorId;
uint8 actorType = uint8(info.actorType);
string memory hash = info.hash;
Expand Down
Loading

0 comments on commit 6e563c4

Please sign in to comment.