pragma solidity ^0.8.13; contract AckOrTimeoutReceipt { struct Receipt { address recipient; uint48 deadline; bool acked; bool finalized; bytes32 ackHash; } mapping(bytes32 => Receipt) private receipts; event ReceiptCreated(bytes32 indexed id, address indexed recipient, uint256 deadline); event Acked(bytes32 indexed id, bytes32 ackHash, address indexed recipient); event MissFinalized(bytes32 indexed id); function create(bytes32 id, address recipient, uint256 deadline) external { require(recipient != address(0)); require(deadline > block.timestamp); require(deadline <= type(uint48).max); Receipt storage r = receipts[id]; require(r.recipient == address(0)); r.recipient = recipient; r.deadline = uint48(deadline); emit ReceiptCreated(id, recipient, deadline); } function ack(bytes32 id, bytes32 ackHash) external { Receipt storage r = receipts[id]; require(r.recipient == msg.sender); require(!r.acked); require(block.timestamp < uint256(r.deadline)); r.acked = true; r.ackHash = ackHash; emit Acked(id, ackHash, msg.sender); } function finalizeMiss(bytes32 id) external { Receipt storage r = receipts[id]; require(r.recipient != address(0)); require(!r.acked); require(block.timestamp >= uint256(r.deadline)); require(!r.finalized); r.finalized = true; emit MissFinalized(id); } }