// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract Receipt { bytes32 private immutable _payloadHash; constructor(bytes32 payloadHash_) { _payloadHash = payloadHash_; } function payloadHash() external view returns (bytes32) { return _payloadHash; } } contract ReceiptFactory { event ReceiptMinted( address indexed issuer, address indexed recipient, bytes32 payloadHash, uint256 nonce, address receipt ); function mint(address recipient, bytes32 payloadHash, uint256 nonce) external returns (address receipt) { require(recipient != address(0)); bytes32 salt = keccak256(abi.encodePacked(msg.sender, recipient, payloadHash, nonce)); receipt = address(new Receipt{salt: salt}(payloadHash)); emit ReceiptMinted(msg.sender, recipient, payloadHash, nonce, receipt); } function _computeReceipt(address issuer, address recipient, bytes32 payloadHash, uint256 nonce) private view returns (address) { bytes32 salt = keccak256(abi.encodePacked(issuer, recipient, payloadHash, nonce)); bytes32 initCodeHash = keccak256(abi.encodePacked(type(Receipt).creationCode, abi.encode(payloadHash))); return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, initCodeHash))))); } function verify(address issuer, address recipient, bytes32 payloadHash, uint256 nonce) external view returns (bool) { return _computeReceipt(issuer, recipient, payloadHash, nonce).code.length > 0; } }