pragma solidity ^0.8.13; contract ReusableHTLC { address public funder; address public recipient; bytes32 public hashLock; uint256 public timeout; uint256 public amount; bool public settled; constructor() { funder = msg.sender; } function fund() external payable { require(msg.sender == funder, "not funder"); require(recipient == address(0), "active lock"); amount += msg.value; } function lock(address _recipient, bytes32 _hashLock, uint256 _timeout) external payable { require(msg.sender == funder, "not funder"); require(recipient == address(0), "active lock"); require(_recipient != address(0), "bad recipient"); require(_timeout > block.timestamp, "bad timeout"); amount += msg.value; require(amount > 0, "zero amount"); recipient = _recipient; hashLock = _hashLock; timeout = _timeout; settled = false; } function claim(bytes32 preimage) external { require(!settled, "settled"); require(recipient != address(0), "no lock"); require(block.timestamp < timeout, "expired"); require(keccak256(abi.encodePacked(preimage)) == hashLock, "bad preimage"); settled = true; address payable payee = payable(recipient); uint256 value = amount; amount = 0; recipient = address(0); (bool ok, ) = payee.call{value: value}(""); require(ok, "transfer failed"); } function refund() external { require(msg.sender == funder, "not funder"); require(!settled, "settled"); require(recipient != address(0), "no lock"); require(block.timestamp >= timeout, "not expired"); settled = true; uint256 value = amount; amount = 0; recipient = address(0); (bool ok, ) = payable(funder).call{value: value}(""); require(ok, "transfer failed"); } function relock(bytes32 newHashLock, uint256 newTimeout) external { require(msg.sender == funder, "not funder"); require(!settled, "settled"); require(recipient != address(0), "no lock"); require(block.timestamp >= timeout, "not expired"); require(newTimeout > block.timestamp, "bad timeout"); hashLock = newHashLock; timeout = newTimeout; } }