ReceiptDuel
receiptduel · receipt-attestation · 2459 B runtime · funds-movement
scores
- usefulness: 70
- safety: 30
- liveness: 30
- authenticity: 95
- extensibility: 25
- bytecodeDiscipline: 85
- practical: 51
source
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract ReceiptDuel {
uint256 constant CHALLENGE_WINDOW = 7 days;
uint256 constant REVEAL_WINDOW = 1 days;
struct Duel {
address submitter;
bytes32 receiptHash;
uint256 submitTime;
uint256 bond;
address challenger;
uint256 challengeTime;
uint256 challengeBond;
}
Duel private duel;
event Submit(address indexed submitter, bytes32 receiptHash, uint256 bond);
event Challenge(address indexed challenger, uint256 bond);
event Reveal(address indexed winner, bytes32 preimage);
event Claim(address indexed challenger, uint256 amount);
event Finalize(address indexed submitter, uint256 amount);
function submitReceipt(bytes32 receiptHash) external payable {
require(duel.submitter == address(0), "ACTIVE");
require(msg.value > 0, "BOND");
duel.submitter = msg.sender;
duel.receiptHash = receiptHash;
duel.submitTime = block.timestamp;
duel.bond = msg.value;
emit Submit(msg.sender, receiptHash, msg.value);
}
function challengeReceipt() external payable {
require(duel.submitter != address(0), "NO_ACTIVE");
require(duel.challenger == address(0), "CHALLENGED");
require(block.timestamp <= duel.submitTime + CHALLENGE_WINDOW, "TOO_LATE");
require(msg.value > duel.bond, "BOND_TOO_SMALL");
duel.challenger = msg.sender;
duel.challengeTime = block.timestamp;
duel.challengeBond = msg.value;
emit Challenge(msg.sender, msg.value);
}
function revealReceipt(bytes32 preimage) external {
require(duel.challenger != address(0), "NOT_CHALLENGED");
require(msg.sender == duel.submitter, "NOT_SUBMITTER");
require(block.timestamp <= duel.challengeTime + REVEAL_WINDOW, "REVEAL_ENDED");
require(keccak256(abi.encodePacked(preimage)) == duel.receiptHash, "BAD_PREIMAGE");
address winner = duel.submitter;
uint256 amount = duel.bond + duel.challengeBond;
delete duel;
(bool sent,) = payable(winner).call{value: amount}("");
require(sent, "SEND_FAILED");
emit Reveal(winner, preimage);
}
function claimChallenge() external {
require(duel.challenger != address(0), "NOT_CHALLENGED");
require(msg.sender == duel.challenger, "NOT_CHALLENGER");
require(block.timestamp > duel.challengeTime + REVEAL_WINDOW, "REVEAL_NOT_ENDED");
address winner = duel.challenger;
uint256 amount = duel.bond + duel.challengeBond;
delete duel;
(bool sent,) = payable(winner).call{value: amount}("");
require(sent, "SEND_FAILED");
emit Claim(winner, amount);
}
function finalize() external {
require(duel.submitter != address(0), "NO_ACTIVE");
require(duel.challenger == address(0), "CHALLENGED");
require(block.timestamp > duel.submitTime + CHALLENGE_WINDOW, "EARLY");
address submitter = duel.submitter;
uint256 amount = duel.bond;
delete duel;
(bool sent,) = payable(submitter).call{value: amount}("");
require(sent, "SEND_FAILED");
emit Finalize(submitter, amount);
}
}