Two-Party Handshake Receipt
two-party-handshake-receipt · receipt-attestation · 2386 B runtime · funds-movement
scores
- usefulness: 78
- safety: 58
- liveness: 62
- authenticity: 82
- extensibility: 70
- bytecodeDiscipline: 88
- practical: 71
source
pragma solidity ^0.8.13;
contract TwoPartyHandshake {
struct Receipt {
address sender;
address recipient;
uint256 deadline;
uint256 senderDeposit;
bool completed;
}
mapping(bytes32 => Receipt) public receipts;
event Initiated(bytes32 indexed receiptHash, address indexed sender, address indexed recipient, uint256 deadline);
event Echoed(bytes32 indexed receiptHash, address indexed sender, address indexed recipient);
event Withdrawn(bytes32 indexed receiptHash, address indexed sender);
function initiate(
bytes32 receiptHash,
address recipient,
uint256 timeoutBlocks
) external payable returns (uint256 deadline) {
require(msg.value > 0, 'deposit required');
require(recipient != address(0), 'recipient required');
require(timeoutBlocks > 0, 'timeout required');
require(receipts[receiptHash].sender == address(0), 'receipt exists');
deadline = block.number + timeoutBlocks;
receipts[receiptHash] = Receipt({
sender: msg.sender,
recipient: recipient,
deadline: deadline,
senderDeposit: msg.value,
completed: false
});
emit Initiated(receiptHash, msg.sender, recipient, deadline);
}
function echo(bytes32 receiptHash) external payable {
Receipt storage r = receipts[receiptHash];
require(r.sender != address(0), 'receipt missing');
require(!r.completed, 'receipt completed');
require(msg.sender == r.recipient, 'not recipient');
require(block.number <= r.deadline, 'timeout passed');
require(msg.value == r.senderDeposit, 'deposit mismatch');
r.completed = true;
address sender = r.sender;
address recipient = r.recipient;
uint256 amount = msg.value;
(bool s, ) = payable(sender).call{value: amount}('');
require(s, 'sender refund failed');
(bool t, ) = payable(recipient).call{value: amount}('');
require(t, 'recipient refund failed');
emit Echoed(receiptHash, sender, recipient);
}
function withdraw(bytes32 receiptHash) external {
Receipt storage r = receipts[receiptHash];
require(r.sender != address(0), 'receipt missing');
require(!r.completed, 'receipt completed');
require(msg.sender == r.sender, 'not sender');
require(block.number > r.deadline, 'timeout pending');
uint256 amount = r.senderDeposit;
address sender = r.sender;
delete receipts[receiptHash];
(bool s, ) = payable(sender).call{value: amount}('');
require(s, 'refund failed');
emit Withdrawn(receiptHash, sender);
}
}