// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/AccessControl.sol"; import "../RWAStorage.sol"; import "../libraries/RWAUriCodec.sol"; import "../interfaces/IRWADocumentFacet.sol"; /** * @title RWADocumentFacet * @notice Anchor document URIs (IPFS, Filecoin, Arweave, HTTPS, internal) with content hashes. */ contract RWADocumentFacet is AccessControl, IRWADocumentFacet { bytes32 public constant DOCUMENT_ADMIN_ROLE = keccak256("DOCUMENT_ADMIN_ROLE"); constructor(address admin) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(DOCUMENT_ADMIN_ROLE, admin); RWAStorage.layout().documentAdmin = admin; } function anchorDocument(bytes32 assetId, string calldata uri, bytes32 contentHash) external onlyRole(DOCUMENT_ADMIN_ROLE) returns (uint256 docIndex) { require(contentHash != bytes32(0), "RWADocument: hash"); RWAStorage.UriScheme scheme = RWAUriCodec.detectScheme(uri); require(scheme != RWAStorage.UriScheme.None, "RWADocument: scheme"); RWAStorage.DocumentRef memory doc = RWAStorage.DocumentRef({ contentHash: contentHash, uriHash: RWAUriCodec.uriHash(uri), scheme: scheme, updatedAt: uint64(block.timestamp) }); RWAStorage.Layout storage l = RWAStorage.layout(); l.assets[assetId].documents.push(doc); docIndex = l.assets[assetId].documents.length - 1; emit DocumentAnchored(assetId, contentHash, doc.uriHash, scheme, docIndex); } function setPrimaryContentHash(bytes32 assetId, bytes32 contentHash) external onlyRole(DOCUMENT_ADMIN_ROLE) { require(contentHash != bytes32(0), "RWADocument: hash"); RWAStorage.layout().assets[assetId].primaryContentHash = contentHash; emit PrimaryContentHashSet(assetId, contentHash); } function documentCount(bytes32 assetId) external view returns (uint256) { return RWAStorage.layout().assets[assetId].documents.length; } function getDocument(bytes32 assetId, uint256 index) external view returns (bytes32 contentHash, bytes32 uriHash, RWAStorage.UriScheme scheme, uint64 updatedAt) { RWAStorage.DocumentRef storage doc = RWAStorage.layout().assets[assetId].documents[index]; return (doc.contentHash, doc.uriHash, doc.scheme, doc.updatedAt); } }