2. 基于哈希时间锁的跨链原子交换

任务说明

本案例实现一个基于哈希时间锁(HTLC)的跨链原子交换合约。目标是在两条独立链(链A与链B)上分别部署HTLC合约,使Alice与Bob能够安全交换各自链上的代币,且保证整个过程要么双方都获得对方资产,要么双方都保留自己资产,不存在中间状态导致一方受损。

HTLC核心机制

HTLC通过哈希锁与时间锁两个条件约束资金提取:

  • 哈希锁:资金提取方需提供与锁定哈希值匹配的原像(preimage)。该原像由发起方Alice生成,并作为两条链上合约共用的解锁密钥。
  • 时间锁:若超时未提取,资金自动退还至原锁定人。两条链上的时间锁需设置不同时长,确保退款路径安全(链A先到期,链B后到期)。

合约实现(Solidity)

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

contract HTLC {
    enum State { ACTIVE, COMPLETED, REFUNDED }
    
    address public sender;
    address public receiver;
    bytes32 public hashLock;
    uint256 public timeLock;
    uint256 public amount;
    State public state;
    
    event Locked(address indexed sender, address indexed receiver, uint256 amount, bytes32 hashLock);
    event Claimed(address indexed claimer, bytes32 preimage);
    event Refunded(address indexed sender);
    
    constructor(address _receiver, bytes32 _hashLock, uint256 _timeLock) payable {
        require(msg.value > 0, "Amount must be > 0");
        require(_receiver != address(0), "Invalid receiver");
        
        sender = msg.sender;
        receiver = _receiver;
        hashLock = _hashLock;
        timeLock = _timeLock;
        amount = msg.value;
        state = State.ACTIVE;
        
        emit Locked(sender, receiver, amount, hashLock);
    }
    
    // 接收方凭原像提取资金
    function claim(bytes32 _preimage) external {
        require(state == State.ACTIVE, "Not active");
        require(msg.sender == receiver, "Only receiver can claim");
        require(sha256(abi.encodePacked(_preimage)) == hashLock, "Invalid preimage");
        
        state = State.COMPLETED;
        emit Claimed(msg.sender, _preimage);
        
        (bool sent, ) = receiver.call{value: amount}("");
        require(sent, "Transfer failed");
    }
    
    // 超时后原锁定人取回资金
    function refund() external {
        require(state == State.ACTIVE, "Not active");
        require(msg.sender == sender, "Only sender can refund");
        require(block.timestamp > timeLock, "Timelock not expired");
        
        state = State.REFUNDED;
        emit Refunded(sender);
        
        (bool sent, ) = sender.call{value: amount}("");
        require(sent, "Transfer failed");
    }
    
    // 查询当前时间锁剩余时间(用于链下监控)
    function getRemainingTime() external view returns (uint256) {
        if (block.timestamp >= timeLock) return 0;
        return timeLock - block.timestamp;
    }
}

原子交换流程

以下时序图展示两条链上HTLC合约的完整交互过程:

Alice 链A HTLC 链B HTLC Bob 1. 生成随机原像s 2. 部署HTLC(receiver=Bob, hash=H(s), timelock=T1) 3. 转入10 ETH(锁定) 4. 验证链A合约 5. 部署HTLC(receiver=Alice, hash=H(s), timelock=T2) 6. 转入10 BTC(锁定) 7. Alice调用链B合约claim(s),获得10 BTC 8. Bob从链B交易中提取原像s 9. Bob调用链A合约claim(s),获得10 ETH 时间锁约束:T1 < T2(链A先到期) 若Alice在T2前未claim链B,Bob可在T1后从链A退款;若Alice已claim链B,Bob必能从链A提取

部署与验证

前置条件:需要两条独立链环境(如以太坊测试链与比特币测试网,或两条EVM兼容链)。本案例以Solidity合约演示HTLC逻辑,实际跨链部署时需在两条链上分别执行。

// 部署脚本(使用ethers.js)
// 链A:Alice部署,锁定10 ETH给Bob,时间锁T1 = 当前时间 + 24小时
// 链B:Bob部署,锁定10 BTC给Alice,时间锁T2 = 当前时间 + 48小时

// 1. Alice生成原像
const preimage = crypto.randomBytes(32);
const hashLock = ethers.utils.sha256(preimage);

// 2. Alice在链A部署
const contractA = await HTLC.deploy(bobAddress, hashLock, T1, { value: parseEther("10") });

// 3. Bob验证链A合约参数后,在链B部署
const contractB = await HTLC.deploy(aliceAddress, hashLock, T2, { value: parseEther("10") });

// 4. Alice在链B上claim
await contractB.claim(preimage);

// 5. Bob从链B交易中获取preimage,在链A上claim
await contractA.claim(preimage);

验证方法:

  1. 部署后检查两条链上合约的state均为ACTIVE,锁定金额正确;
  2. Alice调用链B合约的claim(preimage),交易成功后检查链B合约状态为COMPLETED,Alice余额增加;
  3. Bob从链B的claim交易中提取preimage,调用链A合约的claim(preimage),交易成功后检查链A合约状态为COMPLETED,Bob余额增加;
  4. 若在T1后、T2前Bob未claim,Alice可调用链A合约的refund()取回资金;若T2后Alice未claim,Bob可调用链B合约的refund()取回资金。

判定标准:两条链上的合约最终状态均为COMPLETED(正常交换)或均为REFUNDED(超时退款),不存在一条链COMPLETED而另一条链REFUNDED的不一致状态,即满足原子性。