solidity实现HTLC合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HTLC{
struct LockHTLC {
address payable sender;
address payable receiver;
uint amount;
bytes32 hashlock; //即H=hash(s)
uint timelock; //锁定的时间
bool withdrawn;
bool refunded;
bytes preimage;
}
mapping (bytes32 => LockHTLC) contracts;
string public version="1.0";
event NewHTLCLog(bytes32 indexed htlcId,address indexed sender,address indexed receiver,uint amount,bytes32 hashlock,uint timelock);
event HTLCWithdrawLog(bytes32 indexed htlcId);
event HTLCRefundLog(bytes32 indexed htlcId);
//要求锁定资产大于0
modifier fundsSent() {
require(msg.value > 0, "msg.value must be > 0");
_;
}
//要求解锁时间必须大于目前
modifier futureTimelock(uint _time) {
require(_time > block.timestamp, "timelock time must be in the future");
_;
}
//要求合约必须存在
modifier contractExists(bytes32 _htlcId) {
require(haveContract(_htlcId), "htlcId does not exist");
_;
}
//要求密钥匹配哈希锁
modifier hashlockMatches(bytes32 _htlcId, bytes memory _x) {
require(
contracts[_htlcId].hashlock == sha256(abi.encodePacked(_x)),
"hashlock hash does not match"
);
_;
}
//判断是否可以取
modifier withdrawable(bytes32 _htlcId) {
require(contracts[_htlcId].receiver == msg.sender, "withdrawable: not receiver");
require(contracts[_htlcId].withdrawn == false, "withdrawable: already withdrawn");
require(contracts[_htlcId].timelock > block.timestamp, "withdrawable: timelock time must be in the future");
_;
}
//判断是否可以退回资产
modifier refundable(bytes32 _htlcId) {
require(contracts[_htlcId].sender == msg.sender, "refundable: not sender");
require(contracts[_htlcId].refunded == false, "refundable: already refunded");
require(contracts[_htlcId].withdrawn == false, "refundable: already withdrawn");
require(contracts[_htlcId].timelock <= block.timestamp, "refundable: timelock not yet passed");
_;
}
//新建一个HTLC实例,相当于资产锁定步骤(会传递接收人,哈希锁,时间锁,和转账金额msg.value)
function newHTLC(address payable _receiver,bytes32 _hashlock, uint _timelock) external payable fundsSent futureTimelock(_timelock) returns (bytes32 htlcId) {
//计算HTLC实例的ID
htlcId=sha256(abi.encodePacked(msg.sender,_receiver,msg.value,_hashlock,_timelock));
//如果ID存在
if(haveContract(htlcId)){
//revert()函数用于在合约中显式地回滚交易,并将状态恢复到调用该函数之前的状态。与require类型
revert("Contract already exists");
}
//创建并保存该HTLC实例
contracts[htlcId]=LockHTLC(payable(msg.sender), _receiver, msg.value, _hashlock, _timelock,false,false,'0x0');
emit NewHTLCLog(htlcId,msg.sender,_receiver,msg.value,_hashlock,_timelock);
}
//取钱,相当于解锁资产
function withdraw(bytes32 _htlcId,bytes calldata _preimage) external contractExists(_htlcId) hashlockMatches(_htlcId,_preimage) withdrawable(_htlcId) returns (bool){
//storage使得c是一个对存储在区块链上的数据进行直接引用的变量,而不是创建一个新的拷贝。这意味着对c的修改将直接影响到存储在区块链上的合约数据。
LockHTLC storage c = contracts[_htlcId];
c.preimage = _preimage;
c.withdrawn = true;
c.receiver.transfer(c.amount);
emit HTLCWithdrawLog(_htlcId);
return true;
}
//如果超时没有人解锁资产,资产锁定人可以将这些锁定的资产退回来
function refund(bytes32 _htlcId) external contractExists(_htlcId) refundable(_htlcId) returns (bool){
LockHTLC storage c = contracts[_htlcId];
c.refunded = true;
c.sender.transfer(c.amount);
emit HTLCRefundLog(_htlcId);
return true;
}
//获取一个HTLC实例的细节
function getContract(bytes32 _htlcId) public view returns(address sender,address receiver,uint amount,bytes32 hashlock,uint timelock,bool withdrawn,bool refunded,bytes memory preimage){
if (haveContract(_htlcId) == false){
bytes memory _preimage = '0x0';
return (address(0), address(0), 0, 0, 0, false, false, _preimage);
}
LockHTLC storage c = contracts[_htlcId];
return (
c.sender,
c.receiver,
c.amount,
c.hashlock,
c.timelock,
c.withdrawn,
c.refunded,
c.preimage
);
}
//查询htlcID是否已经存在
function haveContract(bytes32 _htlcId) internal view returns (bool exists){
exists = (contracts[_htlcId].sender != address(0));
}
}