Liveliness Bond

liveliness-bond · conditional-settlement · 2086 B runtime · funds-movement

scores

source

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract LivelinessBond {
    uint256 public immutable interval;
    uint256 public immutable bounty;
    uint256 public immutable withdrawDelay;
    uint256 public nextAgentId = 1;

    struct Agent {
        address payable owner;
        uint256 balance;
        uint256 lastPing;
    }

    mapping(uint256 => Agent) public agents;

    event Registered(uint256 indexed id, address indexed owner, uint256 amount);
    event Pinged(uint256 indexed id, address indexed owner, uint256 timestamp);
    event Claimed(uint256 indexed id, address indexed collector, uint256 amount);
    event Withdrawn(uint256 indexed id, address indexed owner, uint256 amount);

    constructor(uint256 _interval, uint256 _bounty, uint256 _withdrawDelay) {
        require(_bounty > 0, 'zero bounty');
        require(_withdrawDelay > 0 && _withdrawDelay < _interval, 'bad delay');
        interval = _interval;
        bounty = _bounty;
        withdrawDelay = _withdrawDelay;
    }

    function register() external payable returns (uint256 id) {
        require(msg.value == bounty, 'wrong bond');
        id = nextAgentId++;
        Agent storage a = agents[id];
        a.owner = payable(msg.sender);
        a.balance = msg.value;
        a.lastPing = block.timestamp;
        emit Registered(id, msg.sender, msg.value);
    }

    modifier onlyOwner(uint256 id) {
        require(msg.sender == agents[id].owner, 'not owner');
        _;
    }

    function ping(uint256 id) external onlyOwner(id) {
        Agent storage a = agents[id];
        require(a.balance > 0, 'dead');
        require(block.timestamp < a.lastPing + interval, 'missed');
        a.lastPing = block.timestamp;
        emit Pinged(id, msg.sender, block.timestamp);
    }

    function claim(uint256 id) external {
        Agent storage a = agents[id];
        require(a.balance > 0, 'dead');
        require(block.timestamp >= a.lastPing + interval, 'too early');
        uint256 reward = a.balance;
        delete agents[id];
        payable(msg.sender).transfer(reward);
        emit Claimed(id, msg.sender, reward);
    }

    function withdraw(uint256 id) external onlyOwner(id) {
        Agent storage a = agents[id];
        require(a.balance > 0, 'dead');
        require(block.timestamp >= a.lastPing + withdrawDelay, 'wait');
        require(block.timestamp < a.lastPing + interval, 'missed');
        address payable owner = a.owner;
        uint256 amount = a.balance;
        delete agents[id];
        owner.transfer(amount);
        emit Withdrawn(id, owner, amount);
    }
}