Silence Receipt
silence-receipt · receipt-attestation · 2314 B runtime · funds-movement
scores
- usefulness: 30
- safety: 30
- liveness: 30
- authenticity: 20
- extensibility: 40
- bytecodeDiscipline: 70
- practical: 35
source
pragma solidity ^0.8.13;
contract SilenceReceipt {
event Committed(bytes32 indexed commitmentHash, address indexed deliverer, uint64 nonce, uint32 deadline);
event Disputed(bytes32 indexed commitmentHash, address indexed disputer, bytes32 reasonHash);
event ReceiptMinted(bytes32 indexed commitmentHash, address indexed deliverer, uint256 tokenId);
struct Commitment {
uint64 nonce;
uint32 deadline;
bool disputed;
}
mapping(bytes32 => Commitment) private _commitments;
mapping(uint256 => address) public ownerOf;
mapping(address => uint256) private _balances;
function commit(bytes32 deliveryHash, uint32 deadline, uint64 nonce) external returns (bytes32 commitmentHash) {
require(deadline > block.number, 'deadline must be in future');
commitmentHash = keccak256(abi.encodePacked(msg.sender, deliveryHash, nonce));
require(_commitments[commitmentHash].deadline == 0, 'commitment already exists');
_commitments[commitmentHash] = Commitment(nonce, deadline, false);
emit Committed(commitmentHash, msg.sender, nonce, deadline);
}
function dispute(bytes32 commitmentHash, bytes32 reasonHash) external payable {
require(msg.value >= 1 wei, 'dispute bond too low');
Commitment storage c = _commitments[commitmentHash];
require(c.deadline != 0, 'commitment not found');
require(block.number <= c.deadline, 'deadline passed');
require(!c.disputed, 'already disputed');
c.disputed = true;
emit Disputed(commitmentHash, msg.sender, reasonHash);
}
function claim(bytes32 commitmentHash, bytes32 deliveryHash, uint64 nonce) external {
Commitment storage c = _commitments[commitmentHash];
require(c.deadline != 0, 'commitment not found');
require(block.number > c.deadline, 'deadline not passed');
require(!c.disputed, 'commitment disputed');
require(c.nonce == nonce, 'nonce mismatch');
bytes32 expected = keccak256(abi.encodePacked(msg.sender, deliveryHash, nonce));
require(expected == commitmentHash, 'not the deliverer');
uint256 tokenId = uint256(commitmentHash);
require(ownerOf[tokenId] == address(0), 'receipt already minted');
ownerOf[tokenId] = msg.sender;
_balances[msg.sender]++;
emit ReceiptMinted(commitmentHash, msg.sender, tokenId);
}
function balanceOf(address account) external view returns (uint256) {
require(account != address(0), 'zero address');
return _balances[account];
}
}