// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; contract MiniMeRightsRegistry { struct Grant { address owner; address grantee; bytes32 commitment; bytes32 rightsHash; bytes32 scopeHash; uint64 expiresAt; bool revoked; } struct JobReceipt { bytes32 grantId; address worker; bytes32 inputCommitment; bytes32 resultCommitment; bytes32 attestationHash; uint64 completedAt; } struct ComputeJob { address requester; address worker; bytes32 grantId; bytes32 inputCommitment; bytes32 modelRefHash; bytes32 privacyTierHash; uint256 maxPriceWei; uint64 leaseExpiresAt; bool completed; } struct WorkerProfile { bytes32 capabilitiesHash; bytes32 endpointHash; uint64 registeredAt; uint64 lastSeenAt; bool active; } mapping(bytes32 => address) public ownerOf; mapping(bytes32 => Grant) public grants; mapping(bytes32 => JobReceipt) public jobReceipts; mapping(bytes32 => ComputeJob) public computeJobs; mapping(address => WorkerProfile) public workers; event MemoryRegistered(bytes32 indexed commitment, address indexed owner); event GrantCreated(bytes32 indexed grantId, bytes32 indexed commitment, address indexed owner, address grantee); event GrantRevoked(bytes32 indexed grantId); event JobReceiptRecorded( bytes32 indexed jobId, bytes32 indexed grantId, address indexed worker, bytes32 resultCommitment, bytes32 attestationHash ); event ComputeJobSubmitted(bytes32 indexed jobId, bytes32 indexed grantId, address indexed requester); event ComputeJobClaimed(bytes32 indexed jobId, address indexed worker, uint64 leaseExpiresAt); event ComputeJobCompleted(bytes32 indexed jobId, address indexed worker, bytes32 resultCommitment); event WorkerRegistered(address indexed worker, bytes32 capabilitiesHash, bytes32 endpointHash); event WorkerHeartbeat(address indexed worker, uint64 lastSeenAt); function registerMemory(bytes32 commitment) external { require(commitment != bytes32(0), "commitment required"); require(ownerOf[commitment] == address(0), "already registered"); ownerOf[commitment] = msg.sender; emit MemoryRegistered(commitment, msg.sender); } function createGrant( bytes32 commitment, address grantee, bytes32 rightsHash, bytes32 scopeHash, uint64 expiresAt ) external returns (bytes32 grantId) { require(ownerOf[commitment] == msg.sender, "not owner"); require(grantee != address(0), "grantee required"); grantId = keccak256(abi.encode(msg.sender, grantee, commitment, rightsHash, scopeHash, expiresAt)); require(grants[grantId].owner == address(0), "grant exists"); grants[grantId] = Grant(msg.sender, grantee, commitment, rightsHash, scopeHash, expiresAt, false); emit GrantCreated(grantId, commitment, msg.sender, grantee); } function revokeGrant(bytes32 grantId) external { Grant storage grant = grants[grantId]; require(grant.owner == msg.sender, "not owner"); grant.revoked = true; emit GrantRevoked(grantId); } function isGrantActive(bytes32 grantId) external view returns (bool) { Grant memory grant = grants[grantId]; if (grant.owner == address(0) || grant.revoked) return false; return grant.expiresAt == 0 || block.timestamp < grant.expiresAt; } function recordJobReceipt( bytes32 jobId, bytes32 grantId, bytes32 resultCommitment, bytes32 attestationHash ) external { require(jobId != bytes32(0), "jobId required"); require(resultCommitment != bytes32(0), "result required"); require(attestationHash != bytes32(0), "attestation required"); require(jobReceipts[jobId].completedAt == 0, "job exists"); Grant memory grant = grants[grantId]; require(grant.owner != address(0), "grant not found"); require(!grant.revoked, "grant revoked"); require(grant.expiresAt == 0 || block.timestamp < grant.expiresAt, "grant expired"); jobReceipts[jobId] = JobReceipt({ grantId: grantId, worker: msg.sender, inputCommitment: grant.commitment, resultCommitment: resultCommitment, attestationHash: attestationHash, completedAt: uint64(block.timestamp) }); emit JobReceiptRecorded(jobId, grantId, msg.sender, resultCommitment, attestationHash); } function submitComputeJob( bytes32 grantId, bytes32 modelRefHash, bytes32 privacyTierHash, uint256 maxPriceWei, bytes32 jobSalt ) external returns (bytes32 jobId) { Grant memory grant = grants[grantId]; require(grant.owner != address(0), "grant not found"); require(!grant.revoked, "grant revoked"); require(grant.expiresAt == 0 || block.timestamp < grant.expiresAt, "grant expired"); require(modelRefHash != bytes32(0), "model required"); require(privacyTierHash != bytes32(0), "privacy required"); require(jobSalt != bytes32(0), "salt required"); jobId = keccak256(abi.encode(msg.sender, grantId, modelRefHash, privacyTierHash, maxPriceWei, jobSalt)); require(computeJobs[jobId].requester == address(0), "job exists"); computeJobs[jobId] = ComputeJob({ requester: msg.sender, worker: address(0), grantId: grantId, inputCommitment: grant.commitment, modelRefHash: modelRefHash, privacyTierHash: privacyTierHash, maxPriceWei: maxPriceWei, leaseExpiresAt: 0, completed: false }); emit ComputeJobSubmitted(jobId, grantId, msg.sender); } function claimComputeJob(bytes32 jobId, uint64 leaseSeconds) external { ComputeJob storage job = computeJobs[jobId]; require(job.requester != address(0), "job not found"); require(!job.completed, "job completed"); require(job.worker == address(0) || block.timestamp >= job.leaseExpiresAt, "job leased"); require(leaseSeconds > 0, "lease required"); job.worker = msg.sender; job.leaseExpiresAt = uint64(block.timestamp) + leaseSeconds; emit ComputeJobClaimed(jobId, msg.sender, job.leaseExpiresAt); } function completeComputeJob( bytes32 jobId, bytes32 resultCommitment, bytes32 attestationHash ) external { ComputeJob storage job = computeJobs[jobId]; require(job.requester != address(0), "job not found"); require(job.worker == msg.sender, "not worker"); require(!job.completed, "job completed"); require(block.timestamp < job.leaseExpiresAt, "lease expired"); job.completed = true; jobReceipts[jobId] = JobReceipt({ grantId: job.grantId, worker: msg.sender, inputCommitment: job.inputCommitment, resultCommitment: resultCommitment, attestationHash: attestationHash, completedAt: uint64(block.timestamp) }); emit JobReceiptRecorded(jobId, job.grantId, msg.sender, resultCommitment, attestationHash); emit ComputeJobCompleted(jobId, msg.sender, resultCommitment); } function registerWorker(bytes32 capabilitiesHash, bytes32 endpointHash) external { require(capabilitiesHash != bytes32(0), "capabilities required"); WorkerProfile storage profile = workers[msg.sender]; uint64 timestamp = uint64(block.timestamp); if (profile.registeredAt == 0) { profile.registeredAt = timestamp; } profile.capabilitiesHash = capabilitiesHash; profile.endpointHash = endpointHash; profile.lastSeenAt = timestamp; profile.active = true; emit WorkerRegistered(msg.sender, capabilitiesHash, endpointHash); } function heartbeatWorker() external { WorkerProfile storage profile = workers[msg.sender]; require(profile.registeredAt != 0, "worker not registered"); profile.lastSeenAt = uint64(block.timestamp); profile.active = true; emit WorkerHeartbeat(msg.sender, profile.lastSeenAt); } }