---
# System prepended metadata

title: 哈希时间锁实现跨链交易
tags: [Smart Contract, EVM]

---

## 0x00: 背景：

不同区块链的状态是相互隔离的，当想要把A区块链的资产换成B区块链的资产，可以怎么做呢？简单的就是中心化交易所啦，但是体现不出**去中心化**的精神。而在本文章，会介绍一种去中心化的方法——基于**哈希时间锁**实现跨链交易。
<br>

## 0x01: 具体场景：

Alice想将以太坊的ETH换成BSC上的BNB，而恰巧Bob想把BNB换成ETH，他们一拍即合。在谈妥兑换率后，却遇到了问题：他们都不愿意**先**转账。这时候哈希时间锁就可以派上用场了。

整个过程：
![image-20241113185922981](https://hackmd.io/_uploads/S1eOqmFoye.png)
<br>
**步骤1**：Alice设定一个secret，并生成secret的hash；
**步骤2**：Alice部署HTLC-A合约，存入1 ETH，并设定只有Bob在时间timeA内输入secrect才能提款;
**步骤3**：Bob也获得该hash，接着部署HTLC-B合约和存入5 BNB，并设定只有Alice在时间timeB内输入secrect才能提款；
**步骤4**：Alice与HTLC-B合约交互，输入secret，提出Bob存入的5 BNB；
**步骤5**：在上一步中已经暴露了secrect，所以Bob可以与HTLC-A交互，输入secrect，提出1 ETH;

> 大概的过程是这样，具体细节可以看下面的代码

<br>

## 0x02: 代码实现：

HTLC合约：

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.18;

contract HTLC {
    uint public startTime;
    uint public lockTime = 1 hours;
    string public secret;  // SecretOfAlice
    bytes32 public hash = 0x7a1737ec6bb58706b3b2d9ccd17ebd3701d3fe55bfc71fba515df41512b63dc8;
    address public recipient;
    address public owner;
    uint public amount;
	
    constructor(address _recipient) {
    	recipient = _recipient;
    	owner = msg.sender;
    }
	
    function deposit() external {
    	startTime = block.timestamp;
    	amount = msg.value;
    }
	
    function withdraw(string memory _secret) external {
	require(keccak256(abi.encodePacked(_secret)) == hash, "wrong secret");
	secret = _secret;
	(bool sent, ) = recipient.call{value: amount}("");
	require(sent, "Failed to send ETH");
    }
	
    function refund() external {
	require(block.timestamp > startTime + lockTime, "too early");
	(bool sent, ) = owner.call{value: amount}("");
	require(sent, "Failed to send ETH");
    }
}
```

HTLC-A和HTLC-B合约可以都部署成这样。注意拥有secret的一方的锁定时间应该比另一方的长，防止Alice在锁定时间快结束时领取了HTLC-B的钱，但Bob可能会来不及调用领取HTLC-A的钱，而Alice却可以提回之前存入HTLC-A的钱。

<br>

另外，一开始哈希的计算，可以部署个合约，执行相同的代码进行计算：

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.18;

contract Hash {
    function calculateHash(string memory _key) external pure returns(bytes32){
	return keccak256(abi.encodePacked(_key));
    }
}
```