Recant Bond
recant-bond · receipt-attestation · 1777 B runtime · registry-info
scores
- usefulness: 68
- safety: 78
- liveness: 80
- authenticity: 72
- extensibility: 45
- bytecodeDiscipline: 80
- practical: 71
source
pragma solidity ^0.8.13;
contract RecantBond {
struct Oath {
uint256 deadline; // block number before which breakOath() must not be called
bytes4 selector; // the designated target selector
bool broken; // set when the oath is violated
uint256 bond; // ETH at stake
}
mapping(address => Oath) public oaths;
event Pledged(address indexed agent, bytes4 indexed selector, uint256 deadline, uint256 bond);
event Broken(address indexed agent);
event Claimed(address indexed agent, uint256 amount);
event Refunded(address indexed agent, uint256 amount);
function pledge(uint256 deadline) external payable {
require(msg.value > 0, "zero bond");
require(deadline > block.number, "bad deadline");
Oath storage o = oaths[msg.sender];
require(o.deadline == 0 && o.bond == 0, "active oath");
o.deadline = deadline;
o.selector = this.breakOath.selector;
o.broken = false;
o.bond = msg.value;
emit Pledged(msg.sender, o.selector, deadline, msg.value);
}
// Designated public target: if the agent calls this while the oath is active,
// the broken flag is flipped and the bond becomes claimable.
function breakOath() external {
Oath storage o = oaths[msg.sender];
require(o.deadline != 0, "no oath");
require(block.number <= o.deadline, "too late");
require(o.selector == msg.sig, "wrong target");
require(!o.broken, "already broken");
o.broken = true;
emit Broken(msg.sender);
}
// Anyone may burn a forfeited bond.
function claim(address agent) external {
Oath storage o = oaths[agent];
require(o.broken, "not broken");
require(o.bond != 0, "already burned");
uint256 amount = o.bond;
o.bond = 0;
o.deadline = 0;
o.broken = false;
payable(address(0)).transfer(amount);
emit Claimed(agent, amount);
}
// Refund after the deadline if the oath was kept.
function refund() external {
Oath storage o = oaths[msg.sender];
require(o.deadline != 0, "no oath");
require(!o.broken, "broken");
require(block.number > o.deadline, "still active");
uint256 amount = o.bond;
o.bond = 0;
o.deadline = 0;
payable(msg.sender).transfer(amount);
emit Refunded(msg.sender, amount);
}
}