Skip to content

Commit

Permalink
ON-483: Remove grantors from mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Lima committed Sep 25, 2023
1 parent be4293f commit 131bdb3
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 103 deletions.
68 changes: 48 additions & 20 deletions contracts/RolesRegistry/RolesRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
pragma solidity 0.8.9;

import { IERC7432 } from "./interfaces/IERC7432.sol";
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

contract RolesRegistry is IERC7432 {
// grantor => grantee => tokenAddress => tokenId => role => struct(expirationDate, data)
mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData)))))
public roleAssignments;
// grantee => tokenAddress => tokenId => role => struct(expirationDate, data)
mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData)))) public roleAssignments;

// grantor => tokenAddress => tokenId => role => grantee
mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees;
// tokenAddress => tokenId => role => grantee
mapping(address => mapping(uint256 => mapping(bytes32 => address))) public latestGrantees;

// grantor => tokenAddress => tokenId => operator => isApproved
mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) public tokenIdApprovals;
Expand All @@ -31,6 +33,23 @@ contract RolesRegistry is IERC7432 {
_;
}

modifier onlyTokenOwner(address _tokenAddress, uint256 _tokenId) {
if (isERC1155(_tokenAddress)) {
require(
IERC1155(_tokenAddress).balanceOf(msg.sender, _tokenId) > 0,
"OriumMarketplace: only token owner can call this function"
);
} else if(isERC721(_tokenAddress)) {
require(
msg.sender == IERC721(_tokenAddress).ownerOf(_tokenId),
"OriumMarketplace: only token owner can call this function"
);
} else {
revert("OriumMarketplace: token address is not ERC1155 or ERC721");
}
_;
}

function grantRole(
bytes32 _role,
address _tokenAddress,
Expand All @@ -39,7 +58,7 @@ contract RolesRegistry is IERC7432 {
uint64 _expirationDate,
bool _revocable,
bytes calldata _data
) external {
) external onlyTokenOwner(_tokenAddress, _tokenId) {
_grantRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, _expirationDate, _revocable, _data);
}

Expand All @@ -66,12 +85,13 @@ contract RolesRegistry is IERC7432 {
bool _revocable,
bytes calldata _data
) internal validExpirationDate(_expirationDate) {
roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _revocable, _data);
latestGrantees[_grantor][_tokenAddress][_tokenId][_role] = _grantee;
// TODO: How to handle the case where the role is already granted and not expired?
roleAssignments[_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _revocable, _data);
latestGrantees[_tokenAddress][_tokenId][_role] = _grantee;
emit RoleGranted(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _revocable, _data);
}

function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external {
function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external onlyTokenOwner(_tokenAddress, _tokenId) {
_revokeRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, msg.sender);
}

Expand Down Expand Up @@ -104,52 +124,52 @@ contract RolesRegistry is IERC7432 {
address _grantee,
address _caller
) internal {
bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable;
bool _isRevocable = roleAssignments[_grantee][_tokenAddress][_tokenId][_role].revocable;
require(_isRevocable || _caller == _grantee, "RolesRegistry: Role is not revocable or caller is not the grantee");
delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role];
delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role];
delete roleAssignments[_grantee][_tokenAddress][_tokenId][_role];
delete latestGrantees[_tokenAddress][_tokenId][_role];
emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee);
}

function hasRole(
bytes32 _role,
address _tokenAddress,
uint256 _tokenId,
address _grantor,
address _grantor, // not used, but needed for compatibility with ERC7432
address _grantee
) external view returns (bool) {
return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
return roleAssignments[_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
}

function hasUniqueRole(
bytes32 _role,
address _tokenAddress,
uint256 _tokenId,
address _grantor,
address _grantor, // not used, but needed for compatibility with ERC7432
address _grantee
) external view returns (bool) {
return latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
return latestGrantees[_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
}

function roleData(
bytes32 _role,
address _tokenAddress,
uint256 _tokenId,
address _grantor,
address _grantor, // not used, but needed for compatibility with ERC7432
address _grantee
) external view returns (bytes memory data_) {
RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role];
RoleData memory _roleData = roleAssignments[_grantee][_tokenAddress][_tokenId][_role];
return (_roleData.data);
}

function roleExpirationDate(
bytes32 _role,
address _tokenAddress,
uint256 _tokenId,
address _grantor,
address _grantor, // not used, but needed for compatibility with ERC7432
address _grantee
) external view returns (uint64 expirationDate_) {
RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role];
RoleData memory _roleData = roleAssignments[_grantee][_tokenAddress][_tokenId][_role];
return (_roleData.expirationDate);
}

Expand Down Expand Up @@ -201,4 +221,12 @@ contract RolesRegistry is IERC7432 {
) internal view returns (bool) {
return isRoleApprovedForAll(_tokenAddress, _grantor, _operator) || getApprovedRole(_tokenAddress, _tokenId, _grantor, _operator);
}

function isERC1155(address _tokenAddress) public view returns (bool) {
return ERC165Checker.supportsInterface(_tokenAddress, type(IERC1155).interfaceId);
}

function isERC721(address _tokenAddress) public view returns (bool) {
return ERC165Checker.supportsInterface(_tokenAddress, type(IERC721).interfaceId);
}
}
13 changes: 13 additions & 0 deletions contracts/mocks/MockERC1155.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

import { ERC1155 } from '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';

contract MockERC1155 is ERC1155 {
constructor() ERC1155('https://example.com/{id}') {}

function mint(address to, uint256 tokenId, uint256 amount, bytes memory data) external {
_mint(to, tokenId, amount, data);
}
}
4 changes: 2 additions & 2 deletions contracts/mocks/Nft.sol → contracts/mocks/MockERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ pragma solidity 0.8.9;
import { ERC721 } from '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';

contract Nft is ERC721 {
contract MockERC721 is ERC721 {
using Strings for uint256;

constructor() ERC721('Nft', 'NFT') {}
constructor() ERC721('MockERC721', 'MockERC721') {}

function mint(address to, uint256 tokenId) external {
_mint(to, tokenId);
Expand Down
Loading

0 comments on commit 131bdb3

Please sign in to comment.