// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; contract EasyTokenDocument is ERC721URIStorage, ERC721Burnable, ERC721Pausable, AccessControl { bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant COMPLIANCE_ROLE = keccak256("COMPLIANCE_ROLE"); bytes32 public constant METADATA_ROLE = keccak256("METADATA_ROLE"); bytes32 public constant APPRAISER_ROLE = keccak256("APPRAISER_ROLE"); mapping(address => bool) private _blacklist; mapping(uint256 => bytes32) private _documentHash; mapping(uint256 => uint256) private _appraisalValue; mapping(uint256 => string) private _tokenContent; uint256 private _tokenIdCounter; event BlacklistUpdated(address indexed account, bool isBlacklisted); event DocumentMinted(uint256 indexed tokenId, address indexed to, string uri, bytes32 documentHash, uint256 appraisalValue); event ContentMinted(uint256 indexed tokenId, address indexed to, string content); event AppraisalUpdated(uint256 indexed tokenId, uint256 oldValue, uint256 newValue); event TokenURIUpdated(uint256 indexed tokenId, string uri); constructor(address admin, string memory name_, string memory symbol_) ERC721(name_, symbol_) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(PAUSER_ROLE, admin); _grantRole(MINTER_ROLE, admin); _grantRole(METADATA_ROLE, admin); _grantRole(APPRAISER_ROLE, admin); _grantRole(COMPLIANCE_ROLE, admin); } function valueDecimals() public pure returns (uint8) { return 6; } function pause() external onlyRole(PAUSER_ROLE) { _pause(); } function unpause() external onlyRole(PAUSER_ROLE) { _unpause(); } function setBlacklist(address account, bool status) external onlyRole(COMPLIANCE_ROLE) { _blacklist[account] = status; emit BlacklistUpdated(account, status); } function isBlacklisted(address account) external view returns (bool) { return _blacklist[account]; } function documentHashOf(uint256 tokenId) external view returns (bytes32) { return _documentHash[tokenId]; } function appraisalOf(uint256 tokenId) external view returns (uint256) { return _appraisalValue[tokenId]; } function contentOf(uint256 tokenId) external view returns (string memory) { require(_ownerOf(tokenId) != address(0), "Invalid token"); return _tokenContent[tokenId]; } function safeMint(address to, string memory uri, bytes32 documentHash, uint256 appraisalValue) external onlyRole(MINTER_ROLE) returns (uint256) { require(!_blacklist[to], "Blacklisted"); uint256 tokenId = ++_tokenIdCounter; _safeMint(to, tokenId); _setTokenURI(tokenId, uri); _documentHash[tokenId] = documentHash; _appraisalValue[tokenId] = appraisalValue; emit DocumentMinted(tokenId, to, uri, documentHash, appraisalValue); return tokenId; } function mintContent(address to, string calldata content) external onlyRole(MINTER_ROLE) returns (uint256) { require(to != address(0), "Invalid recipient"); require(!_blacklist[to], "Blacklisted"); bytes memory raw = bytes(content); require(raw.length > 0, "Content required"); require(raw.length <= 20, "Content too long"); uint256 tokenId = ++_tokenIdCounter; _safeMint(to, tokenId); _tokenContent[tokenId] = content; emit ContentMinted(tokenId, to, content); return tokenId; } function setTokenURI(uint256 tokenId, string memory uri) external onlyRole(METADATA_ROLE) { require(_ownerOf(tokenId) != address(0), "Invalid token"); _setTokenURI(tokenId, uri); emit TokenURIUpdated(tokenId, uri); } function setAppraisal(uint256 tokenId, uint256 newValue) external onlyRole(APPRAISER_ROLE) { require(_ownerOf(tokenId) != address(0), "Invalid token"); uint256 old = _appraisalValue[tokenId]; _appraisalValue[tokenId] = newValue; emit AppraisalUpdated(tokenId, old, newValue); } function approve(address to, uint256 tokenId) public override(ERC721, IERC721) { require(!_blacklist[_msgSender()], "Blacklisted"); if (to != address(0)) { require(!_blacklist[to], "Blacklisted"); } super.approve(to, tokenId); } function setApprovalForAll(address operator, bool approved) public override(ERC721, IERC721) { require(!_blacklist[_msgSender()], "Blacklisted"); if (approved) { require(!_blacklist[operator], "Blacklisted"); } super.setApprovalForAll(operator, approved); } function _update(address to, uint256 tokenId, address auth) internal override(ERC721, ERC721Pausable) returns (address) { address from = _ownerOf(tokenId); if (from != address(0)) { require(!_blacklist[from], "Blacklisted"); } if (to != address(0)) { require(!_blacklist[to], "Blacklisted"); } require(!_blacklist[auth], "Blacklisted"); address previousOwner = super._update(to, tokenId, auth); if (to == address(0)) { delete _documentHash[tokenId]; delete _appraisalValue[tokenId]; delete _tokenContent[tokenId]; } return previousOwner; } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721URIStorage, AccessControl) returns (bool) { return super.supportsInterface(interfaceId); } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } function grantComplianceRole(address account) external onlyRole(DEFAULT_ADMIN_ROLE) { _grantRole(COMPLIANCE_ROLE, account); } }