区块链跨链技术深度解析:从原子交换到轻客户端验证

引言 跨链技术是WEB3生态实现互操作性的关键。随着多条公链并存,资产和数据的跨链转移变得日益重要。本文将深入探讨从原子交换到轻客户端验证的各种跨链技术原理和实现。 跨链基础 为什么需要跨链 多链生态的现实: ├── Ethereum: DeFi、NFT主要生态 ├── Solana: 高性能应用 ├── Polygon: 低成本交易 ├── BSC: 中心化交易所公链 └── Cosmos/Polkadot: 跨链生态 问题: - 资产孤立:各链资产无法互通 - 流动性分散:DeFi流动性被分割 - 用户体验差:需要跨链桥,步骤繁琐 - 安全风险:中心化桥是黑客主要目标 跨链方案分类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 interface CrossChainSolutions { centralized: { name: "中心化跨链桥", examples: ["Binance Bridge", "Core DAO Bridge"], pros: ["速度快", "用户体验好"], cons: ["需要信任", "单点故障风险"] }, liquidity: { name: "流动性跨链桥", examples: ["Hop Protocol", "Across"], pros: ["去中心化", "速度快"], cons: ["依赖流动性提供者", "资金效率低"] }, lightClient: { name: "轻客户端验证", examples: ["IBC (Cosmos)", "XCM (Polkadot)"], pros: ["安全性高", "真正的去中心化"], cons: ["实现复杂", "跨链速度慢"] }, atomic: { name: "原子交换", examples: ["THORChain", "LIOS"], pros: ["无需信任", "点对点"], cons: ["只支持资产交换", "限制多"] } } 哈希时间锁定合约(HTLC) HTLC原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract HTLC { struct Swap { address payable sender; address payable receiver; uint256 amount; bytes32 hashLock; // 哈希锁 uint256 timeLock; // 时间锁 bytes32 preimage; // 原像(秘密) bool claimed; // 是否已提取 bool refunded; // 是否已退款 } mapping(bytes32 => Swap) public swaps; event SwapCreated( bytes32 indexed swapId, address indexed sender, address indexed receiver, uint256 amount, bytes32 hashLock, uint256 timeLock ); event SwapClaimed(bytes32 indexed swapId, bytes32 preimage); event SwapRefunded(bytes32 indexed swapId); // 创建HTLC function createSwap( address payable _receiver, bytes32 _hashLock, uint256 _timeLock ) external payable returns (bytes32) { require(msg.value > 0, "Amount must be greater than 0"); require(_timeLock > block.timestamp, "Time lock must be in future"); bytes32 swapId = keccak256( abi.encodePacked( msg.sender, _receiver, msg.value, _hashLock, _timeLock, block.number ) ); swaps[swapId] = Swap({ sender: payable(msg.sender), receiver: payable(_receiver), amount: msg.value, hashLock: _hashLock, timeLock: _timeLock, preimage: bytes32(0), claimed: false, refunded: false }); emit SwapCreated( swapId, msg.sender, _receiver, msg.value, _hashLock, _timeLock ); return swapId; } // 提取资金(需要知道preimage) function claimSwap(bytes32 _swapId, bytes32 _preimage) external { Swap storage swap = swaps[_swapId]; require(swap.amount > 0, "Swap does not exist"); require(!swap.claimed, "Already claimed"); require(!swap.refunded, "Already refunded"); require(swap.receiver == msg.sender, "Not the receiver"); // 验证preimage require( keccak256(abi.encodePacked(_preimage)) == swap.hashLock, "Invalid preimage" ); swap.preimage = _preimage; swap.claimed = true; emit SwapClaimed(_swapId, _preimage); // 转移资金 swap.receiver.transfer(swap.amount); } // 退款(时间锁过期后) function refundSwap(bytes32 _swapId) external { Swap storage swap = swaps[_swapId]; require(swap.amount > 0, "Swap does not exist"); require(!swap.claimed, "Already claimed"); require(!swap.refunded, "Already refunded"); require(swap.sender == msg.sender, "Not the sender"); require(block.timestamp >= swap.timeLock, "Time lock not expired"); swap.refunded = true; emit SwapRefunded(_swapId); // 退还资金 swap.sender.transfer(swap.amount); } } // 使用示例 // Alice想和Bob跨链交换1 ETH换100 USDT // 1. Alice生成随机数secret,计算hashLock = keccak256(secret) // 2. Alice在以太坊上创建HTLC,发送1 ETH,设置hashLock和时间锁 // 3. Bob在BSC上创建HTLC,发送100 USDT,使用相同的hashLock和时间锁 // 4. Bob在以太坊上调用claimSwap,提供secret,获得1 ETH // 5. Alice从Bob的交易中获得secret // 6. Alice在BSC上调用claimSwap,提供secret,获得100 USDT 跨链原子交换流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 interface AtomicSwapFlow { step1: "Alice生成随机数secret", step2: "Alice计算hashLock = H(secret)", step3: "Alice在Chain A创建HTLC(hashLock, 时间锁24小时)", step4: "Bob在Chain B创建HTLC(hashLock, 时间锁23小时)", step5: "Bob在Chain A调用claim(secret)提取资金", step6: "Alice从Chain A的交易中读取secret", step7: "Alice在Chain B调用claim(secret)提取资金", timeout: "如果24小时内Bob未提取,Alice可以退款" } // 实现原子交换 class AtomicSwap { async initiateSwap( fromChain: string, toChain: string, fromToken: string, toToken: string, amount: bigint, counterparty: string ): Promise<string> { // 1. 生成secret const secret = this.generateSecret() const hashLock = this.hashFunction(secret) // 2. 在源链创建HTLC const swapId = await this.createHTLC( fromChain, amount, hashLock, 24 * 60 * 60 // 24小时时间锁 ) // 3. 发送hashLock给对方 await this.notifyCounterparty(counterparty, { swapId, hashLock, toChain, toToken, amount }) return swapId } async participateSwap( hashLock: string, toChain: string, toToken: string, amount: bigint ): Promise<string> { // 在目标链创建HTLC // 使用稍短的时间锁(23小时) const swapId = await this.createHTLC( toChain, amount, hashLock, 23 * 60 * 60 ) return swapId } async claimSwap( chain: string, swapId: string, secret: string ): Promise<void> { // 调用claim合约方法 const tx = await this.executeContract( chain, swapId, 'claimSwap', [secret] ) await tx.wait() } } 轻客户端验证 SPV (Simple Payment Verification) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 // SPV证明 interface MerkleProof { txId: string blockHash: string merkleProof: string[] blockHeader: BlockHeader } class SPVVerifier { /** * 验证交易是否在区块中 */ verifyTransaction(proof: MerkleProof): boolean { // 1. 验证区块头工作量证明 const isValidPOW = this.verifyProofOfWork(proof.blockHeader) if (!isValidPOW) return false // 2. 计算Merkle根 const calculatedRoot = this.calculateMerkleRoot( proof.txId, proof.merkleProof ) // 3. 比较Merkle根 return calculatedRoot === proof.blockHeader.merkleRoot } /** * 计算Merkle根 */ private calculateMerkleRoot( txId: string, proof: string[] ): string { let hash = txId for (const sibling of proof) { // 根据位置确定hash顺序 if (this.isLeftChild(hash)) { hash = this.hashPair(hash, sibling) } else { hash = this.hashPair(sibling, hash) } } return hash } /** * 验证工作量证明 */ private verifyProofOfWork(header: BlockHeader): boolean { const target = this.calculateTarget(header.bits) const headerHash = this.hashHeader(header) return BigInt('0x' + headerHash) < target } /** * 双SHA256哈希 */ private sha256(data: string): string { return crypto.createHash('sha256') .update(data) .digest('hex') } private hashPair(a: string, b: string): string { return this.sha256(this.sha256(a + b)) } } 轻客户端实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import { ethers } from 'ethers' class LightClient { private headers: Map<number, BlockHeader> = new Map() private currentHeight: number = 0 /** * 添加新的区块头 */ async addHeader(header: BlockHeader): Promise<boolean> { // 验证区块头 if (!this.verifyHeader(header)) { throw new Error('Invalid block header') } // 如果是第一个区块头 if (this.headers.size === 0) { this.headers.set(header.number, header) this.currentHeight = header.number return true } // 验证区块连接 const parentHeader = this.headers.get(header.number - 1) if (parentHeader && header.parentHash !== parentHeader.hash) { throw new Error('Block does not connect to known chain') } // 存储区块头 this.headers.set(header.number, header) this.currentHeight = Math.max(this.currentHeight, header.number) // 限制存储大小 if (this.headers.size > 1000) { const oldest = Math.min(...this.headers.keys()) this.headers.delete(oldest) } return true } /** * 验证默克尔证明 */ verifyMerkleProof( blockNumber: number, txHash: string, proof: MerkleProof ): boolean { const header = this.headers.get(blockNumber) if (!header) { throw new Error('Unknown block') } // 计算根哈希 let hash = txHash for (const sibling of proof.siblings) { if (proof.path % 2 === 0) { hash = ethers.utils.keccak256( ethers.utils.concat([hash, sibling]) ) } else { hash = ethers.utils.keccak256( ethers.utils.concat([sibling, hash]) ) ) proof.path = Math.floor(proof.path / 2) } // 验证根哈希匹配 return hash === header.transactionsRoot } } Cosmos IBC协议 IBC架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 // IBC核心组件 package ibc // Channel握手状态 type ChannelState string const ( INIT ChannelState = "INIT" TRYOPEN ChannelState = "TRYOPEN" OPEN ChannelState = "OPEN" CLOSED ChannelState = "CLOSED" ) // Channel结构 type Channel struct { State ChannelState Ordering Order Counterparty Counterparty ConnectionHops []string Version string } // IBC消息 type Message interface { Type() string ValidateBasic() error } // ChannelOpenInit消息 type MsgChannelOpenInit struct { PortId string ChannelId string Ordering Order Counterparty Counterparty Version string Signer string } func (msg MsgChannelOpenInit) ValidateBasic() error { if msg.PortId == "" { return fmt.Errorf("port ID cannot be empty") } if msg.ChannelId != "" { return fmt.Errorf("channel ID must be empty for Init") } return nil } // Packet数据结构 type Packet struct { Data []byte TimeoutHeight uint64 TimeoutTimestamp uint64 Sequence uint64 SourcePort string SourceChannel string DestPort string DestChannel string } // IBC Handler type IBCModule interface { OnChanOpenInit( ctx sdk.Context, order ChannelOrder, connectionHops []string, portId string, channelId string, counterparty Counterparty, version string, ) (string, error) OnChanOpenTry( ctx sdk.Context, order ChannelOrder, connectionHops []string, portId string, channelId string, counterparty Counterparty, counterpartyVersion string, ) error OnChanOpenAck( ctx sdk.Context, portId string, channelId string, counterpartyChannelId string, counterpartyVersion string, ) error OnChanOpenConfirm( ctx sdk.Context, portId string, channelId string, ) error OnRecvPacket( ctx sdk.Context, packet Packet, relayer sdk.AccAddress, ) exported.Acknowledgement OnAcknowledgePacket( ctx sdk.Context, packet Packet, acknowledgement []byte, relayer sdk.AccAddress, ) error OnTimeoutPacket( ctx sdk.Context, packet Packet, relayer sdk.AccAddress, ) error } IBC跨链转账 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 // ICS-20: 跨链代币转账标准 package ics20 type TransferData struct { Sender string Receiver string Amount sdk.Int Denom string Memo string } type MsgTransfer struct { SourcePort string SourceChannel string Token sdk.Coin Sender string Receiver string TimeoutHeight uint64 TimeoutTimestamp uint64 Memo string } func (msg MsgTransfer) ValidateBasic() error { if msg.Token.Amount.IsZero() || msg.Token.Amount.IsNegative() { return fmt.Errorf("amount must be positive") } if msg.Sender == "" || msg.Receiver == "" { return fmt.Errorf("sender and receiver cannot be empty") } return nil } // 转账逻辑 func (k Keeper) Transfer( ctx sdk.Context, msg MsgTransfer, ) error { // 1. 锁定或销毁代币 sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return err } if err := k.SendCoins(ctx, sender, msg.Token); err != nil { return err } // 2. 创建IBC Packet packet := channeltypes.Packet{ Data: modulecdc.MustMarshalJSON(&TransferData{ Sender: msg.Sender, Receiver: msg.Receiver, Amount: msg.Token.Amount, Denom: msg.Token.Denom, Memo: msg.Memo, }), TimeoutHeight: clienttypes.Height{ RevisionNumber: 0, RevisionHeight: msg.TimeoutHeight, }, TimeoutTimestamp: msg.TimeoutTimestamp, } // 3. 发送Packet _, err = k.channelKeeper.SendPacket(ctx, packet) if err != nil { return err } return nil } // 接收跨链代币 func (k Keeper) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, ) exported.Acknowledgement { var data TransferData if err := modulecdc.UnmarshalJSON(packet.Data, &data); err != nil { return channeltypes.NewErrorAcknowledgement(err) } // 铸造代币给接收者 receiver, err := sdk.AccAddressFromBech32(data.Receiver) if err != nil { return channeltypes.NewErrorAcknowledgement(err) } coins := sdk.NewCoins(sdk.NewCoin(data.Denom, data.Amount)) if err := k.bankKeeper.MintCoins(ctx, coins); err != nil { return channeltypes.NewErrorAcknowledgement(err) } if err := k.bankKeeper.SendCoins(ctx, k.GetAccount(ctx), receiver, coins); err != nil { return channeltypes.NewErrorAcknowledgement(err) } return channeltypes.NewResultAcknowledgement([]byte{byte(1)}) } Polkadot XCM XCM消息格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 // XCM (Cross-Consensus Message) 类型定义 use xcm::v3::{ Xcm, Junction, Junctions::X1, MultiAsset, MultiLocation, Instruction, WeightLimit, }; // 构建跨链转账XCM fn create_transfer_xcm( dest: MultiLocation, amount: u128, ) -> Xcm<()> { Xcm(vec![ // 1. 提取资产 WithdrawAsset(MultiAsset::from((dest, amount))), // 2. 初始化资产 InitiateReserveWithdraw( X1([Parachain(2000)]), // 中继链 MultiAsset::from((dest, amount)), ), // 3. 跨链传输 TransferReserveAsset( X1([Parachain(2000)]), X1([AccountId32 { network: None, id: [/* 目标账户 */], }]), MultiAsset::from((dest, amount)), ), ]) } // XCM执行器 pub struct XcmExecutor; impl XcmExecutor { pub fn execute_xcm( origin: MultiLocation, xcm: Xcm<()>, ) -> Result<XcmOutcome, XcmError> { match xcm { Xcm::TransferReserveAsset { assets, dest, xcm, } => { // 处理资产转移 Self::handle_reserve_transfer(assets, dest, xcm) } Xcm::Transact { origin_kind, require_weight_at_most, call, } => { // 处理跨链调用 Self::handle_transact(origin_kind, require_weight_at_most, call) } _ => Ok(XcmOutcome::Complete) } } } 跨链智能合约调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 use xcm::v3::{Instruction, WeightLimit}; // 构建跨链合约调用XCM fn create_cross_chain_call( target_chain: u32, contract_address: [u8; 32], call_data: Vec<u8>, ) -> Xcm<()> { Xcm(vec![ // 设置权重限制 SetAppendix(Xcm(vec![ SetTopic([0u8; 32]), ])), // 执行远程调用 Transact { origin_kind: OriginKind::SovereignAccount, require_weight_at_most: WeightLimit::Limited(3_000_000_000), call: { let encoded_call = Encode::encode(&Call::EVM(evm::Call::call( contract_address.into(), call_data, ))); // 编码为XCM格式 (/* 调用编码 */) }, }, ]) } 跨链桥安全 常见攻击向量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 interface CrossChainAttackVectors { fakeDeposits: { name: "虚假存款攻击", description: "攻击者在源链存款后,在目标链欺骗性地铸造包装代币", mitigation: "使用轻客户端验证,等待足够的确认数" }, dataAvailability: { name: "数据可用性攻击", description: "中继器提交虚假或无效的数据", mitigation: "多个独立中继器,欺诈证明机制" }, doubleSpend: { name: "双花攻击", description: "利用跨链延迟在多条链上花费同一笔资产", mitigation: "适当的锁定期和确认数" }, bridgeCompromise: { name: "桥合约被攻破", description: "智能合约漏洞导致资产被盗", mitigation: "多重签名、时间锁、渐进式去中心化" } } 安全跨链桥实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; contract SecureBridge is ReentrancyGuard, Pausable, AccessControl { bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); bytes32 public constant RELAYER_ROLE = keccak256("RELAYER_ROLE"); // 映射:源链交易哈希 -> 是否已处理 mapping(bytes32 => bool) public processedTransactions; // 桥接配置 uint256 public minConfirmations = 6; uint256 public maxDailyTransfer = 1000000 * 1e18; uint256 public dailyTransferLimit = 100000 * 1e18; mapping(address => uint256) public userDailyTransfer; mapping(uint256 => uint256) public dailyTotalTransfer; event Deposit( address indexed user, uint256 amount, bytes32 indexed destTxHash ); event Withdraw( address indexed user, uint256 amount, bytes32 indexed srcTxHash ); modifier onlyRelayer() { require( hasRole(RELAYER_ROLE, msg.sender), "Not a relayer" ); _; } constructor() { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(GUARDIAN_ROLE, msg.sender); } // 存款(源链) function deposit( bytes32 destTxHash, address recipient, uint256 amount ) external whenNotPaused nonReentrant { require(amount > 0, "Amount must be greater than 0"); // 检查每日限额 uint256 currentDay = block.timestamp / 1 days; uint256 userDaily = userDailyTransfer[recipient]; uint256 dailyTotal = dailyTotalTransfer[currentDay]; require( userDaily + amount <= dailyTransferLimit, "User daily limit exceeded" ); require( dailyTotal + amount <= maxDailyTransfer, "Bridge daily limit exceeded" ); // 更新限额 userDailyTransfer[recipient] = userDaily + amount; dailyTotalTransfer[currentDay] = dailyTotal + amount; // 转入资金 IERC20(USDT).transferFrom(msg.sender, address(this), amount); emit Deposit(msg.sender, amount, destTxHash); } // 取款(目标链,由中继器触发) function withdraw( bytes32 srcTxHash, address recipient, uint256 amount, uint256 confirmations, bytes memory proof ) external onlyRelayer whenNotPaused nonReentrant { // 检查是否已处理 require( !processedTransactions[srcTxHash], "Transaction already processed" ); // 验证证明 require( verifyWithdrawProof(srcTxHash, recipient, amount, confirmations, proof), "Invalid proof" ); // 检查确认数 require(confirmations >= minConfirmations, "Not enough confirmations"); // 标记为已处理 processedTransactions[srcTxHash] = true; // 转出资金 uint256 balance = IERC20(USDT).balanceOf(address(this)); uint256 amountToTransfer = amount > balance ? balance : amount; if (amountToTransfer > 0) { IERC20(USDT).transfer(recipient, amountToTransfer); } emit Withdraw(recipient, amountToTransfer, srcTxHash); } // 验证取款证明(使用轻客户端验证) function verifyWithdrawProof( bytes32 srcTxHash, address recipient, uint256 amount, uint256 confirmations, bytes memory proof ) internal view returns (bool) { // 这里实现轻客户端验证逻辑 // 验证: // 1. 交易确实存在于源链 // 2. 有足够的确认数 // 3. 证明由多个独立的中继器签名 // 简化实现,实际应用中需要完整的SPV验证 return true; } // 紧急暂停 function pause() external onlyRole(GUARDIAN_ROLE) { _pause(); } function unpause() external onlyRole(GUARDIAN_ROLE) { _unpause(); } // 更新配置(需要多签) function setMinConfirmations(uint256 _minConfirmations) external onlyRole(DEFAULT_ADMIN_ROLE) { minConfirmations = _minConfirmations; } } 实战案例 案例:EVM链跨链桥 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 import { ethers } from 'ethers' import axios from 'axios' class EVMCrossChainBridge { private sourceChain: ethers.providers.Provider private destChain: ethers.providers.Provider private bridgeContract: ethers.Contract constructor( sourceRpc: string, destRpc: string, bridgeAddress: string, privateKey: string ) { this.sourceChain = new ethers.JsonRpcProvider(sourceRpc) this.destChain = new ethers.JsonRpcProvider(destRpc) const wallet = new ethers.Wallet(privateKey, this.destChain) this.bridgeContract = new ethers.Contract( bridgeAddress, [ 'function deposit(bytes32 destTxHash, address recipient, uint256 amount)', 'function withdraw(bytes32 srcTxHash, address recipient, uint256 amount, uint256 confirmations, bytes proof)', 'event Deposit(address indexed user, uint256 amount, bytes32 indexed destTxHash)', 'event Withdraw(address indexed user, uint256 amount, bytes32 indexed srcTxHash)' ], wallet ) } /** * 跨链转移资产 */ async transfer( fromAddress: string, toAddress: string, amount: bigint, tokenAddress: string ): Promise<string> { // 1. 在源链授权 const tokenContract = new ethers.Contract( tokenAddress, ['function approve(address spender, uint256 amount)'], new ethers.Wallet(process.env.PRIVATE_KEY, this.sourceChain) ) const approveTx = await tokenContract.approve( this.bridgeContract.address, amount ) await approveTx.wait() // 2. 存款到桥合约 const destTxHash = ethers.utils.keccak256( ethers.utils.defaultAbiCoder.encode( ['address', 'uint256', 'uint256'], [toAddress, amount, Date.now()] ) ) const depositTx = await this.bridgeContract.deposit( destTxHash, toAddress, amount ) const receipt = await depositTx.wait() // 3. 等待确认后,在目标链提取 const srcTxHash = receipt.transactionHash await this.waitForConfirmations(srcTxHash, 6) // 4. 提取资金 const withdrawTx = await this.bridgeContract.withdraw( srcTxHash, toAddress, amount, 6, // 确认数 '0x' // 证明(简化) ) await withdrawTx.wait() return withdrawTx.hash } /** * 等待足够的确认数 */ private async waitForConfirmations( txHash: string, confirmations: number ): Promise<void> { while (true) { const tx = await this.sourceChain.getTransaction(txHash) const currentBlock = await this.sourceChain.getBlockNumber() const confirmations = currentBlock - tx.blockNumber if (confirmations >= confirmations) { break } await new Promise(resolve => setTimeout(resolve, 10000)) // 等待10秒 } } } 案例:Cosmos IBC转账 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 package ibc import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) type IBCTransferKeeper struct { bankKeeper banktypes.Keeper channelKeeper ChannelKeeper portKeeper PortKeeper } // 跨链转账 func (k IBCTransferKeeper) Transfer( ctx sdk.Context, sourcePort string, sourceChannel string, token sdk.Coin, sender sdk.AccAddress, receiver string, timeoutHeight uint64, ) error { // 1. 验证参数 if token.Amount.IsZero() { return fmt.Errorf("amount must be positive") } // 2. 从发送者账户扣除代币 if err := k.bankKeeper.SendCoins( ctx, sender, accountAddr, sdk.NewCoins(token), ); err != nil { return err } // 3. 创建IBC数据包 packetData := TransferData{ Sender: sender.String(), Receiver: receiver, Amount: token, Memo: "", } packetBz := modulecdc.MustMarshalJSON(&packetData) packet := channeltypes.Packet{ Data: packetBz, TimeoutHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: timeoutHeight}, TimeoutTimestamp: 0, } // 4. 发送数据包 _, err := k.channelKeeper.SendPacket(ctx, packet) if err != nil { return err } ctx.EventManager().EmitEvents( sdk.Events{ sdk.NewEvent( "ibc_transfer", sdk.NewAttribute("sender", sender.String()), sdk.NewAttribute("receiver", receiver), sdk.NewAttribute("amount", token.String()), ), }, ) return nil } // 接收跨链代币 func (k IBCTransferKeeper) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { var data TransferData if err := modulecdc.UnmarshalJSON(packet.Data, &data); err != nil { return channeltypes.NewErrorAcknowledgement(err) } // 解析接收者地址 receiver, err := sdk.AccAddressFromBech32(data.Receiver) if err != nil { return channeltypes.NewErrorAcknowledgement(err) } // 铸造代币 coins := sdk.NewCoins(data.Amount) if err := k.bankKeeper.MintCoins(ctx, coins); err != nil { return channeltypes.NewErrorAcknowledgement(err) } // 发送给接收者 if err := k.bankKeeper.SendCoins( ctx, accountAddr, receiver, coins, ); err != nil { return channeltypes.NewErrorAcknowledgement(err) } // 记录事件 ctx.EventManager().EmitEvents( sdk.Events{ sdk.NewEvent( "ibc_receive", sdk.NewAttribute("receiver", receiver.String()), sdk.NewAttribute("amount", data.Amount.String()), ), }, ) return channeltypes.NewResultAcknowledgement([]byte{0x01}) } 总结 跨链技术是多链生态实现互操作性的核心。从简单的HTLC到复杂的轻客户端验证,不同的技术方案适用于不同的场景。 ...