pragma solidity ^0.8.13; contract ReceiptNullifier { mapping(bytes32 => bytes32) private commitments; bytes32 private constant SPENT = bytes32(uint256(1)); event Committed(bytes32 indexed taskId, bytes32 commitment); event Revealed(bytes32 indexed taskId, bytes32 outputHash, bytes32 secret); function _key(bytes32 taskId) private view returns (bytes32) { return keccak256(abi.encodePacked(taskId, block.chainid, address(this))); } function commit(bytes32 taskId, bytes32 outputHash, bytes32 secret) external { bytes32 commitment = keccak256(abi.encodePacked(taskId, outputHash, secret)); bytes32 key = _key(taskId); require(commitment != bytes32(0) && commitment != SPENT && commitments[key] == bytes32(0)); commitments[key] = commitment; emit Committed(taskId, commitment); } function reveal(bytes32 taskId, bytes32 outputHash, bytes32 secret) external { bytes32 commitment = keccak256(abi.encodePacked(taskId, outputHash, secret)); bytes32 key = _key(taskId); require(commitments[key] == commitment); commitments[key] = SPENT; emit Revealed(taskId, outputHash, secret); } }