// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract TimeDecayedPayout { address public immutable depositor; address public immutable beneficiary; uint256 public immutable start; uint256 public immutable deadline; uint256 public immutable principal; bool public claimed; bool public refunded; event Claimed(address indexed beneficiary, uint256 amount); event Refunded(address indexed depositor, uint256 amount); constructor(address _beneficiary, uint256 _duration) payable { require(_duration > 0, "duration-zero"); require(_beneficiary != address(0), "beneficiary-zero"); require(msg.value > 0, "principal-zero"); depositor = msg.sender; beneficiary = _beneficiary; start = block.timestamp; deadline = block.timestamp + _duration; principal = msg.value; } function claim() external { require(msg.sender == beneficiary, "not-beneficiary"); require(!claimed, "already-claimed"); require(block.timestamp < deadline, "after-deadline"); uint256 payout = _payoutAt(block.timestamp); require(payout > 0, "zero-payout"); claimed = true; (bool ok, ) = beneficiary.call{value: payout}(""); require(ok, "transfer-failed"); emit Claimed(beneficiary, payout); } function refund() external { require(msg.sender == depositor, "not-depositor"); require(!refunded, "already-refunded"); require(block.timestamp >= deadline, "before-deadline"); refunded = true; uint256 amount = address(this).balance; (bool ok, ) = depositor.call{value: amount}(""); require(ok, "transfer-failed"); emit Refunded(depositor, amount); } function _payoutAt(uint256 t) internal view returns (uint256) { uint256 numerator = principal * (deadline - t); uint256 denominator = deadline - start; return numerator / denominator; } receive() external payable { revert("no-direct-eth"); } }