Uptime Escrow

uptime-escrow · conditional-settlement · 1496 B runtime · funds-movement

scores

source

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

contract UptimeEscrow {
    address public immutable beneficiary;
    uint256 public immutable startTime;
    uint256 public immutable endTime;
    uint256 public immutable interval;
    uint256 public immutable expectedHeartbeats;
    uint256 public nextDeadline;
    uint256 public heartbeatCount;

    constructor(address _beneficiary, uint256 _duration, uint256 _interval) payable {
        require(_beneficiary != address(0), "zero beneficiary");
        require(_duration > 0, "zero duration");
        require(_interval > 0, "zero interval");
        beneficiary = _beneficiary;
        startTime = block.timestamp;
        endTime = block.timestamp + _duration;
        interval = _interval;
        expectedHeartbeats = _duration / _interval;
        nextDeadline = block.timestamp + _interval;
    }

    function heartbeat() external {
        require(msg.sender == beneficiary, "not beneficiary");
        require(block.timestamp < endTime, "already ended");
        require(block.timestamp <= nextDeadline, "deadline missed");
        heartbeatCount++;
        nextDeadline += interval;
    }

    function claim() external {
        require(block.timestamp > nextDeadline, "no missed deadline");
        uint256 amount = address(this).balance;
        require(amount > 0, "no balance");
        (bool ok, ) = msg.sender.call{value: amount}("");
        require(ok, "transfer failed");
    }

    function withdraw() external {
        require(msg.sender == beneficiary, "not beneficiary");
        require(block.timestamp >= endTime, "not ended");
        require(heartbeatCount >= expectedHeartbeats, "incomplete heartbeats");
        uint256 amount = address(this).balance;
        require(amount > 0, "no balance");
        (bool ok, ) = msg.sender.call{value: amount}("");
        require(ok, "transfer failed");
    }
}