// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @notice Timestamped prediction commitments. No stakes, payouts or custody. contract RealityCommit { struct Commitment { uint256 committedAt; uint256 targetTime; bool revealed; } mapping(address => mapping(bytes32 => Commitment)) public commitments; event PredictionCommitted(address indexed contributor, bytes32 indexed commitment, uint256 targetTime); event PredictionRevealed(address indexed contributor, bytes32 indexed commitment, bytes predictionData); function commitPrediction(bytes32 commitment, uint256 targetTime) external { require(commitment != bytes32(0), 'EMPTY_HASH'); require(targetTime > block.timestamp, 'TARGET_NOT_FUTURE'); require(targetTime <= block.timestamp + 30 days, 'TARGET_TOO_FAR'); require(commitments[msg.sender][commitment].committedAt == 0, 'DUPLICATE_COMMIT'); commitments[msg.sender][commitment] = Commitment(block.timestamp, targetTime, false); emit PredictionCommitted(msg.sender, commitment, targetTime); } function revealPrediction(bytes calldata predictionData, bytes32 salt) external { require(predictionData.length <= 1024, 'DATA_TOO_LARGE'); bytes32 digest = keccak256(abi.encode(predictionData, salt)); Commitment storage entry = commitments[msg.sender][digest]; require(entry.committedAt != 0, 'COMMIT_NOT_FOUND'); require(!entry.revealed, 'ALREADY_REVEALED'); require(block.timestamp >= entry.targetTime, 'TOO_EARLY'); (address author, string memory asset, bool up, uint16 confidence, uint256 targetTime, uint256 generation) = abi.decode(predictionData, (address, string, bool, uint16, uint256, uint256)); require(author == msg.sender && targetTime == entry.targetTime, 'METADATA_MISMATCH'); require(bytes(asset).length > 0 && bytes(asset).length <= 16 && confidence <= 10000, 'INVALID_PREDICTION'); up; generation; entry.revealed = true; emit PredictionRevealed(msg.sender, digest, predictionData); } }