160 lines
5.8 KiB
Solidity
160 lines
5.8 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.8.7;
|
|
|
|
import "@openzeppelin/contracts/utils/Counters.sol";
|
|
|
|
contract FleekAccessControl {
|
|
using Counters for Counters.Counter;
|
|
|
|
enum Roles {
|
|
Owner,
|
|
Controller
|
|
}
|
|
|
|
event TokenRoleGranted(uint256 indexed tokenId, Roles indexed role, address indexed toAddress, address byAddress);
|
|
event TokenRoleRevoked(uint256 indexed tokenId, Roles indexed role, address indexed toAddress, address byAddress);
|
|
event CollectionRoleGranted(Roles indexed role, address indexed toAddress, address byAddress);
|
|
event CollectionRoleRevoked(Roles indexed role, address indexed toAddress, address byAddress);
|
|
|
|
struct Role {
|
|
mapping(address => uint256) indexes;
|
|
address[] members;
|
|
}
|
|
|
|
Counters.Counter private _collectionRolesVersion;
|
|
// _collectionRoles[version][role]
|
|
mapping(uint256 => mapping(Roles => Role)) private _collectionRoles;
|
|
|
|
mapping(uint256 => Counters.Counter) private _tokenRolesVersion;
|
|
// _tokenRoles[tokenId][version][role]
|
|
mapping(uint256 => mapping(uint256 => mapping(Roles => Role))) private _tokenRoles;
|
|
|
|
constructor() {
|
|
_grantCollectionRole(Roles.Owner, msg.sender);
|
|
}
|
|
|
|
modifier requireCollectionRole(Roles role) {
|
|
require(
|
|
hasCollectionRole(role, msg.sender) || hasCollectionRole(Roles.Owner, msg.sender),
|
|
"FleekAccessControl: must have collection role"
|
|
);
|
|
_;
|
|
}
|
|
|
|
modifier requireTokenRole(uint256 tokenId, Roles role) {
|
|
require(
|
|
hasTokenRole(tokenId, role, msg.sender) || hasTokenRole(tokenId, Roles.Owner, msg.sender),
|
|
"FleekAccessControl: must have token role"
|
|
);
|
|
_;
|
|
}
|
|
|
|
function grantCollectionRole(Roles role, address account) public requireCollectionRole(Roles.Owner) {
|
|
_grantCollectionRole(role, account);
|
|
}
|
|
|
|
function grantTokenRole(
|
|
uint256 tokenId,
|
|
Roles role,
|
|
address account
|
|
) public requireTokenRole(tokenId, Roles.Owner) {
|
|
_grantTokenRole(tokenId, role, account);
|
|
}
|
|
|
|
function revokeCollectionRole(Roles role, address account) public requireCollectionRole(Roles.Owner) {
|
|
_revokeCollectionRole(role, account);
|
|
}
|
|
|
|
function revokeTokenRole(
|
|
uint256 tokenId,
|
|
Roles role,
|
|
address account
|
|
) public requireTokenRole(tokenId, Roles.Owner) {
|
|
_revokeTokenRole(tokenId, role, account);
|
|
}
|
|
|
|
function hasCollectionRole(Roles role, address account) public view returns (bool) {
|
|
uint256 currentVersion = _collectionRolesVersion.current();
|
|
|
|
return _collectionRoles[currentVersion][role].indexes[account] != 0;
|
|
}
|
|
|
|
function hasTokenRole(uint256 tokenId, Roles role, address account) public view returns (bool) {
|
|
uint256 currentVersion = _tokenRolesVersion[tokenId].current();
|
|
return _tokenRoles[tokenId][currentVersion][role].indexes[account] != 0;
|
|
}
|
|
|
|
function getCollectionRoleMembers(Roles role) public view returns (address[] memory) {
|
|
uint256 currentVersion = _collectionRolesVersion.current();
|
|
return _collectionRoles[currentVersion][role].members;
|
|
}
|
|
|
|
function getTokenRoleMembers(uint256 tokenId, Roles role) public view returns (address[] memory) {
|
|
uint256 currentVersion = _tokenRolesVersion[tokenId].current();
|
|
return _tokenRoles[tokenId][currentVersion][role].members;
|
|
}
|
|
|
|
function _grantCollectionRole(Roles role, address account) internal {
|
|
uint256 currentVersion = _collectionRolesVersion.current();
|
|
_grantRole(_collectionRoles[currentVersion][role], account);
|
|
emit CollectionRoleGranted(role, account, msg.sender);
|
|
}
|
|
|
|
function _revokeCollectionRole(Roles role, address account) internal {
|
|
uint256 currentVersion = _collectionRolesVersion.current();
|
|
_revokeRole(_collectionRoles[currentVersion][role], account);
|
|
emit CollectionRoleRevoked(role, account, msg.sender);
|
|
}
|
|
|
|
function _grantTokenRole(uint256 tokenId, Roles role, address account) internal {
|
|
uint256 currentVersion = _tokenRolesVersion[tokenId].current();
|
|
_grantRole(_tokenRoles[tokenId][currentVersion][role], account);
|
|
emit TokenRoleGranted(tokenId, role, account, msg.sender);
|
|
}
|
|
|
|
function _revokeTokenRole(uint256 tokenId, Roles role, address account) internal {
|
|
uint256 currentVersion = _tokenRolesVersion[tokenId].current();
|
|
_revokeRole(_tokenRoles[tokenId][currentVersion][role], account);
|
|
emit TokenRoleRevoked(tokenId, role, account, msg.sender);
|
|
}
|
|
|
|
function _grantRole(Role storage role, address account) internal {
|
|
if (role.indexes[account] == 0) {
|
|
role.members.push(account);
|
|
role.indexes[account] = role.members.length;
|
|
}
|
|
}
|
|
|
|
function _revokeRole(Role storage role, address account) internal {
|
|
if (role.indexes[account] != 0) {
|
|
uint256 index = role.indexes[account] - 1;
|
|
uint256 lastIndex = role.members.length - 1;
|
|
address lastAccount = role.members[lastIndex];
|
|
|
|
role.members[index] = lastAccount;
|
|
role.indexes[lastAccount] = index + 1;
|
|
|
|
role.members.pop();
|
|
delete role.indexes[account];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Clears all token roles and not garants an owner role.
|
|
* Should be used when burns the token.
|
|
*/
|
|
function _clearAllTokenRoles(uint256 tokenId) internal {
|
|
_tokenRolesVersion[tokenId].increment();
|
|
}
|
|
|
|
/**
|
|
* @dev Clears all token roles and garants an owner role.
|
|
* Should be used when transfers the token.
|
|
*/
|
|
function _clearAllTokenRoles(uint256 tokenId, address newOwner) internal {
|
|
_clearAllTokenRoles(tokenId);
|
|
_grantTokenRole(tokenId, Roles.Owner, newOwner);
|
|
}
|
|
}
|