Skip to content

Commit

Permalink
Refactor SFT Roles Registry Interface (#23)
Browse files Browse the repository at this point in the history
refactor SftRolesRegistrySingleRole.sol
  • Loading branch information
ernanirst authored Dec 20, 2023
1 parent 8a77c49 commit 2aaff2c
Show file tree
Hide file tree
Showing 5 changed files with 605 additions and 685 deletions.
220 changes: 75 additions & 145 deletions contracts/RolesRegistry/SftRolesRegistrySingleRole.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,16 @@ import { ERC165Checker } from '@openzeppelin/contracts/utils/introspection/ERC16
contract SftRolesRegistrySingleRole is ISftRolesRegistry, ERC1155Holder {
bytes32 public constant UNIQUE_ROLE = keccak256('UNIQUE_ROLE');

uint256 public recordCount;

// grantor => tokenAddress => operator => isApproved
mapping(address => mapping(address => mapping(address => bool))) public roleApprovals;

// grantor => nonce => DepositInfo
mapping(address => mapping(uint256 => DepositInfo)) public deposits;
// recordId => Record
mapping(uint256 => Record) public records;

// grantor => nonce => role => RoleAssignment
mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))) internal roleAssignments;

modifier validGrantRoleData(
uint256 _nonce,
address _grantee,
uint64 _expirationDate,
uint256 _tokenAmount,
bytes32 _role
) {
require(_nonce > 0, 'SftRolesRegistry: nonce must be greater than zero');
require(_expirationDate > block.timestamp, 'SftRolesRegistry: expiration date must be in the future');
require(_tokenAmount > 0, 'SftRolesRegistry: tokenAmount must be greater than zero');
require(_role == UNIQUE_ROLE, 'SftRolesRegistry: role not supported');
require(_grantee != address(0), 'SftRolesRegistry: grantee must not be zero address');
_;
}
// recordId => role => RoleAssignment
mapping(uint256 => mapping(bytes32 => RoleAssignment)) internal roleAssignments;

modifier onlyOwnerOrApproved(address _account, address _tokenAddress) {
require(
Expand All @@ -45,118 +32,77 @@ contract SftRolesRegistrySingleRole is ISftRolesRegistry, ERC1155Holder {
_;
}

modifier validRoleAndGrantee(
address _grantor,
modifier sameGrantee(
uint256 _recordId,
bytes32 _role,
address _grantee,
uint256 _nonce
address _grantee
) {
require(_role == UNIQUE_ROLE, 'SftRolesRegistry: role not supported');
require(
_grantee != address(0) && _grantee == roleAssignments[_grantor][_nonce][_role].grantee,
_grantee != address(0) && _grantee == roleAssignments[_recordId][_role].grantee,
'SftRolesRegistry: grantee mismatch'
);
_;
}

/** External Functions **/

function grantRoleFrom(
RoleAssignment calldata _grantRoleData
)
external
override
validGrantRoleData(
_grantRoleData.nonce,
_grantRoleData.grantee,
_grantRoleData.expirationDate,
_grantRoleData.tokenAmount,
_grantRoleData.role
)
onlyOwnerOrApproved(_grantRoleData.grantor, _grantRoleData.tokenAddress)
{
if (deposits[_grantRoleData.grantor][_grantRoleData.nonce].tokenAmount == 0) {
// nonce does not exist, transfer tokens
_deposit(_grantRoleData);
} else {
// nonce exists
require(
deposits[_grantRoleData.grantor][_grantRoleData.nonce].tokenAddress == _grantRoleData.tokenAddress,
'SftRolesRegistry: tokenAddress mismatch'
);
require(
deposits[_grantRoleData.grantor][_grantRoleData.nonce].tokenId == _grantRoleData.tokenId,
'SftRolesRegistry: tokenId mismatch'
);
require(
deposits[_grantRoleData.grantor][_grantRoleData.nonce].tokenAmount == _grantRoleData.tokenAmount,
'SftRolesRegistry: tokenAmount mismatch'
);

RoleData storage _roleData = roleAssignments[_grantRoleData.grantor][_grantRoleData.nonce][
_grantRoleData.role
];
require(
_roleData.expirationDate < block.timestamp || _roleData.revocable,
'SftRolesRegistry: nonce is not expired or is not revocable'
);
}
_grantOrUpdateRole(_grantRoleData);
function createRecordFrom(
address _grantor,
address _tokenAddress,
uint256 _tokenId,
uint256 _tokenAmount
) external override onlyOwnerOrApproved(_grantor, _tokenAddress) returns (uint256 recordId_) {
require(_tokenAmount > 0, 'SftRolesRegistry: tokenAmount must be greater than zero');
recordId_ = _createRecord(_grantor, _tokenAddress, _tokenId, _tokenAmount);
}

function revokeRoleFrom(
address _grantor,
uint256 _nonce,
function grantRole(
uint256 _recordId,
bytes32 _role,
address _grantee
) external override {
RoleData memory _roleData = roleAssignments[_grantor][_nonce][_role];
require(_roleData.expirationDate != 0, 'SftRolesRegistry: role does not exist');
require(_grantee == _roleData.grantee, 'SftRolesRegistry: grantee mismatch');
address _grantee,
uint64 _expirationDate,
bool _revocable,
bytes calldata _data
) external override onlyOwnerOrApproved(records[_recordId].grantor, records[_recordId].tokenAddress) {
require(_role == UNIQUE_ROLE, 'SftRolesRegistry: role not supported');
require(_expirationDate > block.timestamp, 'SftRolesRegistry: expiration date must be in the future');
_grantOrUpdateRole(_recordId, _role, _grantee, _expirationDate, _revocable, _data);
}

DepositInfo storage _depositInfo = deposits[_grantor][_nonce];
address caller = _findCaller(_grantor, _roleData.grantee, _depositInfo.tokenAddress);
if (_roleData.expirationDate > block.timestamp && !_roleData.revocable) {
function revokeRoleFrom(
uint256 _recordId, bytes32 _role, address _grantee
) external override sameGrantee(_recordId, _role, _grantee) {
RoleAssignment storage roleAssignment = roleAssignments[_recordId][_role];
Record storage record = records[_recordId];
address caller = _findCaller(record.grantor, roleAssignment.grantee, record.tokenAddress);
if (roleAssignment.expirationDate > block.timestamp && !roleAssignment.revocable) {
// if role is not expired and is not revocable, only the grantee can revoke it
require(caller == _roleData.grantee, 'SftRolesRegistry: nonce is not expired or is not revocable');
require(caller == roleAssignment.grantee, 'SftRolesRegistry: role is not expired and is not revocable');
}

delete roleAssignments[_grantor][_nonce][_role];

emit RoleRevoked(
_grantor,
_nonce,
UNIQUE_ROLE,
_depositInfo.tokenAddress,
_depositInfo.tokenId,
_depositInfo.tokenAmount,
_roleData.grantee
);
emit RoleRevoked(_recordId, _role, roleAssignment.grantee);
delete roleAssignments[_recordId][_role];
}

function withdrawFrom(
address _grantor,
uint256 _nonce
) public onlyOwnerOrApproved(_grantor, deposits[_grantor][_nonce].tokenAddress) {
require(deposits[_grantor][_nonce].tokenAmount != 0, 'SftRolesRegistry: nonce does not exist');
uint256 _recordId
) external onlyOwnerOrApproved(records[_recordId].grantor, records[_recordId].tokenAddress) {
require(
roleAssignments[_grantor][_nonce][UNIQUE_ROLE].expirationDate < block.timestamp ||
roleAssignments[_grantor][_nonce][UNIQUE_ROLE].revocable,
roleAssignments[_recordId][UNIQUE_ROLE].expirationDate < block.timestamp,
'SftRolesRegistry: token has an active role'
);

delete roleAssignments[_grantor][_nonce][UNIQUE_ROLE];
delete roleAssignments[_recordId][UNIQUE_ROLE];

_transferFrom(
address(this),
_grantor,
deposits[_grantor][_nonce].tokenAddress,
deposits[_grantor][_nonce].tokenId,
deposits[_grantor][_nonce].tokenAmount
records[_recordId].grantor,
records[_recordId].tokenAddress,
records[_recordId].tokenId,
records[_recordId].tokenAmount
);

delete deposits[_grantor][_nonce];
emit Withdrew(_grantor, _nonce);
delete records[_recordId];
emit Withdrew(_recordId);
}

function setRoleApprovalForAll(address _tokenAddress, address _operator, bool _isApproved) external override {
Expand All @@ -167,21 +113,19 @@ contract SftRolesRegistrySingleRole is ISftRolesRegistry, ERC1155Holder {
/** View Functions **/

function roleData(
address _grantor,
uint256 _nonce,
uint256 _recordId,
bytes32 _role,
address _grantee
) external view validRoleAndGrantee(_grantor, _role, _grantee, _nonce) returns (RoleData memory) {
return roleAssignments[_grantor][_nonce][_role];
) external view sameGrantee(_recordId, _role, _grantee) returns (RoleAssignment memory) {
return roleAssignments[_recordId][_role];
}

function roleExpirationDate(
address _grantor,
uint256 _nonce,
uint256 _recordId,
bytes32 _role,
address _grantee
) external view validRoleAndGrantee(_grantor, _role, _grantee, _nonce) returns (uint64 expirationDate_) {
return roleAssignments[_grantor][_nonce][_role].expirationDate;
) external view sameGrantee(_recordId, _role, _grantee) returns (uint64 expirationDate_) {
return roleAssignments[_recordId][_role].expirationDate;
}

function isRoleApprovedForAll(
Expand All @@ -200,42 +144,28 @@ contract SftRolesRegistrySingleRole is ISftRolesRegistry, ERC1155Holder {

/** Helper Functions **/

function _deposit(RoleAssignment calldata _grantRoleData) internal {
deposits[_grantRoleData.grantor][_grantRoleData.nonce] = DepositInfo(
_grantRoleData.tokenAddress,
_grantRoleData.tokenId,
_grantRoleData.tokenAmount
);

_transferFrom(
_grantRoleData.grantor,
address(this),
_grantRoleData.tokenAddress,
_grantRoleData.tokenId,
_grantRoleData.tokenAmount
);
function _createRecord(
address _grantor,
address _tokenAddress,
uint256 _tokenId,
uint256 _tokenAmount
) internal returns (uint256 recordId_) {
recordId_ = ++recordCount;
records[recordId_] = Record(_grantor, _tokenAddress, _tokenId, _tokenAmount);
_transferFrom(_grantor, address(this), _tokenAddress, _tokenId, _tokenAmount);
emit RecordCreated(_grantor, recordId_, _tokenAddress, _tokenId, _tokenAmount);
}

function _grantOrUpdateRole(RoleAssignment calldata _grantRoleData) internal {
roleAssignments[_grantRoleData.grantor][_grantRoleData.nonce][_grantRoleData.role] = RoleData(
_grantRoleData.grantee,
_grantRoleData.expirationDate,
_grantRoleData.revocable,
_grantRoleData.data
);

emit RoleGranted(
_grantRoleData.grantor,
_grantRoleData.nonce,
UNIQUE_ROLE,
_grantRoleData.tokenAddress,
_grantRoleData.tokenId,
_grantRoleData.tokenAmount,
_grantRoleData.grantee,
_grantRoleData.expirationDate,
_grantRoleData.revocable,
_grantRoleData.data
);
function _grantOrUpdateRole(
uint256 _recordId,
bytes32 _role,
address _grantee,
uint64 _expirationDate,
bool _revocable,
bytes calldata _data
) internal {
roleAssignments[_recordId][_role] = RoleAssignment(_grantee, _expirationDate, _revocable, _data);
emit RoleGranted(_recordId, _role, _grantee, _expirationDate, _revocable, _data);
}

function _transferFrom(
Expand Down
Loading

0 comments on commit 2aaff2c

Please sign in to comment.