diff --git a/contracts/Project.sol b/contracts/Project.sol index 1fa6748..da848bd 100644 --- a/contracts/Project.sol +++ b/contracts/Project.sol @@ -10,6 +10,8 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { event SetMinter(address indexed minter); event SetName(uint256 indexed projectId, string name); event AddMetadata(uint256 indexed projectId, string name, bytes32 key, bytes value); + event AddOperator(uint256 indexed projectId, address operator); + event RemoveOperator(uint256 indexed projectId, address operator); address public minter; uint256 nextProjectId; @@ -18,6 +20,22 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { mapping(uint256 => string) names; mapping(uint256 => uint8) types; mapping(uint256 => mapping(bytes32 => bytes)) _metadata; + mapping(uint256 => mapping(address => bool)) operators; + + modifier onlyMinter() { + require(msg.sender == minter, "not minter"); + _; + } + + modifier onlyProjectOwner(uint256 projectId) { + require(msg.sender == ownerOf(projectId), "invalid owner"); + _; + } + + modifier onlyProjectOperator(uint256 projectId) { + require(msg.sender == ownerOf(projectId) || operators[projectId][msg.sender], "invalid operator"); + _; + } function initialize(string calldata _name, string calldata _symbol) public initializer { __Ownable_init(); @@ -26,9 +44,7 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { } // @deprecated - function mint(address _owner) external returns (uint256 projectId_) { - require(msg.sender == minter, "not minter"); - + function mint(address _owner) external onlyMinter returns (uint256 projectId_) { projectId_ = ++nextProjectId; _mint(_owner, projectId_); } @@ -41,8 +57,11 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { return _mintProject(_owner, _name, _type); } - function _mintProject(address _owner, string calldata _name, uint8 _type) internal returns (uint256 projectId_) { - require(msg.sender == minter, "not minter"); + function _mintProject( + address _owner, + string calldata _name, + uint8 _type + ) internal onlyMinter returns (uint256 projectId_) { bytes32 _nameHash = keccak256(abi.encodePacked(_name)); require(_nameHash != EMPTY_NAME_HASH, "empty name"); require(!nameHashes[_nameHash], "exist name"); @@ -72,15 +91,18 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { return _metadata[_projectId][_key]; } - function setMetadata(uint256 _projectId, string calldata _name, bytes calldata _value) external { - require(msg.sender == ownerOf(_projectId), "invalid owner"); + function setMetadata( + uint256 _projectId, + string calldata _name, + bytes calldata _value + ) external onlyProjectOperator(_projectId) { bytes32 _key = keccak256(abi.encodePacked(_name)); _metadata[_projectId][_key] = _value; emit AddMetadata(_projectId, _name, _key, _value); } - function setName(uint256 _projectId, string calldata _name) external { + function setName(uint256 _projectId, string calldata _name) external onlyProjectOwner(_projectId) { require(msg.sender == ownerOf(_projectId), "invalid owner"); bytes32 _nameHash = keccak256(abi.encodePacked(_name)); require(_nameHash != EMPTY_NAME_HASH, "empty name"); @@ -95,6 +117,20 @@ contract Project is IProject, OwnableUpgradeable, ERC721Upgradeable { emit SetName(_projectId, _name); } + function addOperator(uint256 _projectId, address _operator) external onlyProjectOwner(_projectId) { + require(!operators[_projectId][_operator], "already operator"); + + operators[_projectId][_operator] = true; + emit AddOperator(_projectId, _operator); + } + + function removeOperator(uint256 _projectId, address _operator) external onlyProjectOwner(_projectId) { + require(operators[_projectId][_operator], "not operator"); + + operators[_projectId][_operator] = false; + emit RemoveOperator(_projectId, _operator); + } + function setMinter(address _minter) public onlyOwner { minter = _minter;