Predicate-Locked Escrow with Timeout Refund
predicate-locked-escrow-with-timeout-refund · conditional-settlement · 1605 B runtime · funds-movement
scores
- usefulness: 20
- safety: 10
- liveness: 30
- authenticity: 10
- extensibility: 30
- bytecodeDiscipline: 80
- practical: 26
source
pragma solidity ^0.8.13;
contract PredicateEscrow {
struct Escrow {
address payable opener;
uint256 createdAt;
uint256 timeout;
uint256 amount;
}
mapping(bytes32 => Escrow) private escrows;
function open(bytes32 id, uint256 timeout) external payable {
require(escrows[id].opener == address(0), "exists");
escrows[id] = Escrow(payable(msg.sender), block.timestamp, timeout, msg.value);
}
function claim(bytes32 id, address predicate, bytes calldata data) external {
Escrow storage esc = escrows[id];
require(esc.opener != address(0), "not found");
require(block.timestamp <= esc.createdAt + esc.timeout, "expired");
(bool ok, bytes memory ret) = predicate.staticcall(data);
require(ok && ret.length >= 32 && abi.decode(ret, (bool)), "predicate false");
uint256 amount = esc.amount;
delete escrows[id];
(bool sent,) = msg.sender.call{value: amount}("");
require(sent, "transfer failed");
}
function refund(bytes32 id) external {
Escrow storage esc = escrows[id];
require(esc.opener == msg.sender, "not opener");
require(block.timestamp > esc.createdAt + esc.timeout, "too early");
uint256 amount = esc.amount;
delete escrows[id];
(bool sent,) = msg.sender.call{value: amount}("");
require(sent, "transfer failed");
}
}