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

引言 跨链技术是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到复杂的轻客户端验证,不同的技术方案适用于不同的场景。 ...

WEB3去中心化身份(DID)技术深度解析

引言 去中心化身份(Decentralized Identity,简称DID)是WEB3的核心基础设施之一。它让用户完全掌控自己的身份数据,不再依赖中心化的身份提供商。本文将深入探讨DID的技术原理、W3C标准、可验证凭证(VC)以及如何构建生产级的去中心化身份系统。 DID基础概念 传统身份系统的问题 中心化身份平台 ├── Google账号 │ └── 谷歌掌握所有数据 ├── 微信账号 │ └── 腾讯掌握所有数据 └── 支付宝账号 └── 蚂蚁掌握所有数据 问题: - 数据孤岛:各平台数据不互通 - 隐私泄露:中心化服务器易被攻击 - 审查风险:平台可随时封禁账号 - 数据滥用:平台可擅自使用用户数据 去中心化身份的优势 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // DID架构 interface DIDArchitecture { user: { control: "complete", // 用户完全控制 portable: true, // 身份可跨平台使用 privacy: "enhanced" // 隐私保护 }, verifier: { trust: "decentralized", // 去中心化信任 cost: "low" // 验证成本低 }, issuer: { efficiency: "high", // 发行效率高 revocation: "easy" // 撤销机制简单 } } W3C DID标准 DID结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // DID URL格式 did:method:specific-idstring // 示例 did:ethr:0x5a2e... // Ethereum DID did:sol:1234... // Solana DID did:web:example.com // Web DID did:key:z6Mk... // Key DID // 解析DID interface DID { method: string // 方法名(ethr, sol, web, key等) id: string // 特定方法的标识符 } DID文档 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 { "@context": [ "https://www.w3.org/ns/did/v1" ], "id": "did:ethr:0x5a2e...", "verificationMethod": [ { "id": "did:ethr:0x5a2e...#controller", "type": "EcdsaSecp256k1RecoveryMethod2020", "controller": "did:ethr:0x5a2e...", "blockchainAccountId": "0x5a2e...@eip155:1" } ], "authentication": [ "did:ethr:0x5a2e...#controller" ], "assertionMethod": [ "did:ethr:0x5a2e...#controller" ], "capabilityDelegation": [ "did:ethr:0x5a2e...#controller" ], "capabilityInvocation": [ "did:ethr:0x5a2e...#controller" ], "keyAgreement": [ { "id": "did:ethr:0x5a2e...#keyAgreement", "type": "X25519KeyAgreementKey2019", "controller": "did:ethr:0x5a2e...", "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" } ], "service": [ { "id": "did:ethr:0x5a2e...#vcs", "type": "VerifiableCredentialService", "serviceEndpoint": "https://example.com/vcs/" } ] } DID方法实现 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 // Ethereum DID Registry import { ethers } from 'ethers' class EthrDID { private registry: ethers.Contract private provider: ethers.Provider constructor() { this.provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com') this.registry = new ethers.Contract( '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b', ['function owner(address) view returns (address)'], this.provider ) } async resolve(did: string): Promise<DIDDocument> { // 解析DID const [, , address] = did.split(':') // 从链上获取DID文档 const owner = await this.registry.owner(address) return { '@context': 'https://www.w3.org/ns/did/v1', id: did, verificationMethod: [{ id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `${address}@eip155:1` }], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`] } } async createDID(privateKey: string): Promise<string> { const wallet = new ethers.Wallet(privateKey) const address = await wallet.getAddress() return `did:ethr:${address}` } } // 使用 const ethrDid = new EthrDID() const did = await ethrDid.createDID(privateKey) // did:ethr:0x5a2e... const document = await ethrDid.resolve(did) 可验证凭证(Verifiable Credentials) VC数据模型 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 interface VerifiableCredential { '@context': string[] | string type: string[] id?: string issuer: string | Issuer issuanceDate: string expirationDate?: string credentialSubject: CredentialSubject credentialStatus?: CredentialStatus refreshService?: RefreshService termsOfUse?: TermsOfUse[] evidence?: Evidence[] proof?: Proof } // 示例:大学学历凭证 const universityDegree: VerifiableCredential = { '@context': [ 'https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1' ], type: ['VerifiableCredential', 'UniversityDegreeCredential'], id: 'urn:uuid:12345678-1234-5678-1234-567812345678', issuer: 'did:ethr:0x1234...', issuanceDate: '2024-01-06T12:00:00Z', expirationDate: '2034-01-06T12:00:00Z', credentialSubject: { id: 'did:ethr:0xabcd...', degree: { type: 'BachelorDegree', name: '计算机科学学士' }, university: '示例大学' }, proof: { type: 'EcdsaSecp256k1Signature2019', created: '2024-01-06T12:00:00Z', proofPurpose: 'assertionMethod', verificationMethod: 'did:ethr:0x1234...#controller', jws: 'eyJhbGciOiJFUzI1Nk...' // 签名 } } VC发行 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 import { ethers } from 'ethers' import { createVerifiableCredentialJwt } from 'did-jwt-vc' class CredentialIssuer { private issuerDid: string private issuerWallet: ethers.Wallet constructor(did: string, privateKey: string) { this.issuerDid = did this.issuerWallet = new ethers.Wallet(privateKey) } async issueCredential( subjectDid: string, claims: object, expiresIn: string = '1y' ): Promise<string> { const vc: VerifiableCredential = { '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiableCredential'], issuer: this.issuerDid, issuanceDate: new Date().toISOString(), expirationDate: new Date(Date.now() + this.parseExpiration(expiresIn)).toISOString(), credentialSubject: { id: subjectDid, ...claims } } // 创建签名 const signer = this.issuerWallet.signMessage.bind(this.issuerWallet) // 生成JWT格式的VC const vcJwt = await createVerifiableCredentialJwt( vc, { issuer: this.issuerDid, signer } ) return vcJwt } parseExpiration(expiresIn: string): number { const match = expiresIn.match(/^(\d+)([dhmy])$/) if (!match) throw new Error('Invalid expiration format') const value = parseInt(match[1]) const unit = match[2] const multipliers = { 'd': 86400000, 'h': 3600000, 'm': 60000, 'y': 31536000000 } return value * multipliers[unit] } } // 使用示例 const issuer = new CredentialIssuer( 'did:ethr:0x1234...', '0x私钥' ) const vcJwt = await issuer.issueCredential( 'did:ethr:0xabcd...', { degree: { type: 'BachelorDegree', name: '计算机科学学士' }, university: '示例大学' }, '1y' ) VC验证 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 import { verifyCredential, verifyPresentation } from 'did-jwt-vc' import { resolveDid } from '@identitybuilding/did-resolver' class CredentialVerifier { private didResolver: any constructor() { this.didResolver = resolveDid } async verifyCredential(vcJwt: string): Promise<VerificationResult> { try { // 验证签名 const verifiedVC = await verifyCredential(vcJwt, { resolver: this.didResolver }) // 检查过期 if (verifiedVC.expirationDate) { const expirationDate = new Date(verifiedVC.expirationDate) if (expirationDate < new Date()) { return { valid: false, reason: 'Credential has expired' } } } // 检查撤销状态 const status = await this.checkRevocation(verifiedVC) if (!status.valid) { return { valid: false, reason: 'Credential has been revoked' } } return { valid: true, credential: verifiedVC } } catch (error) { return { valid: false, reason: error.message } } } async checkRevocation(vc: VerifiableCredential): Promise<{ valid: boolean }> { if (!vc.credentialStatus) { return { valid: true } } const { id, type } = vc.credentialStatus if (type === 'RevocationList2021') { // 检查比特映射 const index = parseInt(id.split('#')[1]) const revoked = await this.checkBitMap(index) return { valid: !revoked } } return { valid: true } } async checkBitMap(index: number): Promise<boolean> { // 从链上或IPFS获取撤销列表 // ... return false } } // 使用示例 const verifier = new CredentialVerifier() const result = await verifier.verifyCredential(vcJwt) if (result.valid) { console.log('凭证有效', result.credential) } else { console.log('凭证无效:', result.reason) } VP(可验证表达) 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 // Verifiable Presentation interface VerifiablePresentation { '@context': string[] | string type: string[] id?: string verifiableCredential?: VerifiableCredential[] holder?: string proof?: Proof } // 创建VP import { createVerifiablePresentationJwt } from 'did-jwt-vc' class PresentationHolder { private holderDid: string private holderWallet: ethers.Wallet constructor(did: string, privateKey: string) { this.holderDid = did this.holderWallet = new ethers.Wallet(privateKey) } async createPresentation( vcs: string[], audience: string ): Promise<string> { const vp: VerifiablePresentation = { '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiablePresentation'], holder: this.holderDid, verifiableCredential: vcs.map(vcJwt => { // 简化版,实际应该解析JWT return { '@context': '...', type: ['VerifiableCredential'], ... } }) } const signer = this.holderWallet.signMessage.bind(this.holderWallet) const vpJwt = await createVerifiablePresentationJwt( vp, { audience, holder: this.holderDid, signer } ) return vpJwt } } // 使用 const holder = new PresentationHolder( 'did:ethr:0xabcd...', '0x用户私钥' ) const vpJwt = await holder.createPresentation( [vcJwt], 'did:ethr:0x9999...' // verifier的DID ) 链上身份协议 Lens Protocol 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 // Lens Profile NFT interface LensProfile { handle: string // @username imageURI: string // 头像 followModule: FollowModule followNFTURI: string dispatcher: Address } // 创建Lens Profile import { providers, Contract, utils } from 'ethers' class LensProfileManager { private lensHub: Contract private provider: providers.Provider constructor(rpcUrl: string) { this.provider = new providers.JsonRpcProvider(rpcUrl) this.lensHub = new Contract( '0xDb46d1Dc155634FfC7D94Fda11Bc2b0D29Ad869d', // LensHub on Polygon [ 'function createProfile(tuple(tuple(string handle,string imageURI) profile)) external', 'function getDefaultProfile(address) view returns (uint256)', 'function getProfile(uint256) view returns (tuple(...))' ], new ethers.Wallet(process.env.PRIVATE_KEY, this.provider) ) } async createProfile(handle: string, imageURI: string): Promise<string> { const tx = await this.lensHub.createProfile({ profile: { handle, imageURI } }) const receipt = await tx.wait() console.log('Profile created:', receipt.transactionHash) return receipt.transactionHash } async getProfile(profileId: number): Promise<LensProfile> { const profile = await this.lensHub.getProfile(profileId) return { handle: profile.handle, imageURI: profile.imageURI, followModule: profile.followModule, followNFTURI: profile.followNFTURI, dispatcher: profile.dispatcher } } } // 使用 const lens = new LensProfileManager('https://polygon-rpc.com') await lens.createProfile( 'myusername', 'ipfs://Qm...' ) ENS (Ethereum Name Service) 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 import { providers, Contract } from 'ethers' class ENSManager { private ensRegistry: Contract private resolverContract: Contract private provider: providers.Provider constructor(rpcUrl: string) { this.provider = new providers.JsonRpcProvider(rpcUrl) // ENS Registry this.ensRegistry = new Contract( '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', ['function owner(bytes32 node) view returns (address)'], this.provider ) // Public Resolver this.resolverContract = new Contract( '0x4976fb03C32e5B8cfe2b6cCCb85c41a121551E2F', [ 'function addr(bytes32 node) view returns (address)', 'function setText(bytes32 node, string key, string value)', 'function text(bytes32 node, string key) view returns (string)' ], this.provider ) } namehash(name: string): string { // ENS namehash算法 const node = '0x0000000000000000000000000000000000000000000000000000000000000000' if (name === '') { return node } const labels = name.split('.') let hash = node for (let i = labels.length - 1; i >= 0; i--) { const labelHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(labels[i])) hash = ethers.utils.keccak256( ethers.utils.concat([hash, labelHash]) ) } return hash } async getAddress(name: string): Promise<string> { const node = this.namehash(name) return await this.resolverContract.addr(node) } async setText(name: string, key: string, value: string, signer: ethers.Signer) { const node = this.namehash(name) const resolverWithSigner = this.resolverContract.connect(signer) const tx = await resolverWithSigner.setText(node, key, value) await tx.wait() } async getText(name: string, key: string): Promise<string> { const node = this.namehash(name) return await this.resolverContract.text(node, key) } } // 使用 const ens = new ENSManager('https://eth.llamarpc.com') // 解析ENS域名 const address = await ens.getAddress('vitalik.eth') // 0xab5801a7D398351b8bE11C439e05C5B3259aEbC4 // 设置和读取ENS记录 await ens.setText( 'mydomain.eth', 'com.twitter', '@myhandle', signer ) Soulbound Token (SBT) 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 // SBT(灵魂绑定代币)是不可转移的NFT import { ethers } from 'ethers' // SBT合约ABI const SBT_ABI = [ 'function issue(address to, uint256 tokenId, string uri) external', 'function revoke(address from, uint256 tokenId) external', 'function tokenURI(uint256 tokenId) view returns (string)', 'function balanceOf(address) view returns (uint256)', 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)' ] class SoulboundManager { private sbtContract: ethers.Contract constructor(contractAddress: string, privateKey: string) { const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com') const wallet = new ethers.Wallet(privateKey, provider) this.sbtContract = new ethers.Contract( contractAddress, SBT_ABI, wallet ) } async issueSBT( recipient: string, tokenId: number, metadataURI: string ): Promise<string> { const tx = await this.sbtContract.issue( recipient, tokenId, metadataURI ) const receipt = await tx.wait() return receipt.transactionHash } async getSBTsByAddress(address: string): Promise<number[]> { const balance = await this.sbtContract.balanceOf(address) const tokens = [] for (let i = 0; i < balance.toNumber(); i++) { const tokenId = await this.sbtContract.tokenOfOwnerByIndex(address, i) tokens.push(tokenId.toNumber()) } return tokens } async getSBTMetadata(tokenId: number): Promise<object> { const uri = await this.sbtContract.tokenURI(tokenId) // 从IPFS获取metadata const response = await fetch(uri) const metadata = await response.json() return metadata } } // 使用示例 const sbtManager = new SoulboundManager( '0x...', // SBT合约地址 process.env.PRIVATE_KEY ) // 发行SBT凭证 await sbtManager.issueSBT( '0x用户地址', 1, 'ipfs://Qm...' // metadata URI ) // 查询用户的SBT const tokens = await sbtManager.getSBTsByAddress('0x用户地址') for (const tokenId of tokens) { const metadata = await sbtManager.getSBTMetadata(tokenId) console.log('SBT:', metadata) // { // name: "大学学历凭证", // description: "计算机科学学士学位", // image: "ipfs://...", // attributes: [ // { trait_type: "大学", value: "示例大学" }, // { trait_type: "专业", value: "计算机科学" }, // { trait_type: "学位", value: "学士" } // ] // } } 链上声誉系统 信任分数算法 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 interface ReputationData { totalInteractions: number successfulInteractions: number averageRating: number stakingAmount: number accountAge: number } class ReputationCalculator { calculateScore(data: ReputationData): number { let score = 50 // 基础分 // 交互成功率(+30分) if (data.totalInteractions > 0) { const successRate = data.successfulInteractions / data.totalInteractions score += successRate * 30 } // 平均评分(+10分) score += (data.averageRating - 3) * 3.33 // 1-5分制 // 质押金额(+5分) const stakingBonus = Math.log10(data.stakingAmount + 1) * 2 score += Math.min(stakingBonus, 5) // 账号年龄(+5分) const ageInYears = data.accountAge / (365 * 24 * 60 * 60) score += Math.min(ageInYears * 2, 5) return Math.min(Math.max(score, 0), 100) } calculateTier(score: number): string { if (score >= 90) return '钻石级' if (score >= 75) return '黄金级' if (score >= 60) return '白银级' if (score >= 40) return '青铜级' return '新手级' } } // 链上声誉合约 import { ethers } from 'ethers' class OnChainReputation { private contract: ethers.Contract constructor() { const provider = new ethers.JsonRpcProvider('https://polygon-rpc.com') const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider) this.contract = new ethers.Contract( '0x...', // 声誉合约地址 [ 'function recordInteraction(address user, bool success, uint8 rating) external', 'function getReputationScore(address user) view returns (uint256)', 'function stakeTokens(uint256 amount) external', 'function unstakeTokens(uint256 amount) external', 'event ReputationUpdated(address indexed user, uint256 score)' ], wallet ) } async recordInteraction( user: string, success: boolean, rating: number ): Promise<void> { const tx = await this.contract.recordInteraction( user, success, rating ) await tx.wait() console.log('Interaction recorded') } async getReputationScore(user: string): Promise<number> { const score = await this.contract.getReputationScore(user) return score.toNumber() } async stakeTokens(amount: number): Promise<void> { const tx = await this.contract.stakeTokens( ethers.utils.parseEther(amount.toString()) ) await tx.wait() console.log('Tokens staked') } listenToReputationUpdates() { this.contract.on('ReputationUpdated', (user, score) => { console.log(`Reputation updated for ${user}: ${score}`) }) } } DID钱包实现 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 import { ethers } from 'ethers' import { hdkey } from 'ethereumjs-wallet' import * as bip39 from 'bip39' class DIDWallet { private mnemonic: string private hdNode: any private did: string private credentials: string[] = [] constructor() { this.generate() } private generate() { // 生成助记词 this.mnemonic = bip39.generateMnemonic() // 从助记词生成HD钱包 const seed = bip39.mnemonicToSeedSync(this.mnemonic) this.hdNode = hdkey.fromMasterSeed(seed) // 派生第一个账户作为DID const path = "m/44'/60'/0'/0/0" const wallet = this.hdNode.derivePath(path).getWallet() const address = wallet.getAddressString() this.did = `did:ethr:${address}` } getDID(): string { return this.did } getAddress(): string { return this.did.split(':')[2] } async sign(message: string): Promise<string> { const path = "m/44'/60'/0'/0/0" const wallet = this.hdNode.derivePath(path).getWallet() const signature = await wallet.signMessage(message) return signature } async verify(message: string, signature: string): Promise<boolean> { const address = ethers.utils.verifyMessage(message, signature) return address.toLowerCase() === this.getAddress().toLowerCase() } addCredential(vcJwt: string) { this.credentials.push(vcJwt) } getCredentials(): string[] { return this.credentials } exportWallet(): string { return JSON.stringify({ mnemonic: this.mnemonic, did: this.did, credentials: this.credentials }) } importWallet(data: string) { const wallet = JSON.parse(data) this.mnemonic = wallet.mnemonic this.did = wallet.did this.credentials = wallet.credentials || [] const seed = bip39.mnemonicToSeedSync(this.mnemonic) this.hdNode = hdkey.fromMasterSeed(seed) } } // React Hook import { useState, useEffect } from 'react' export function useDIDWallet() { const [wallet, setWallet] = useState<DIDWallet | null>(null) useEffect(() => { // 从localStorage加载钱包 const savedWallet = localStorage.getItem('did-wallet') if (savedWallet) { const newWallet = new DIDWallet() newWallet.importWallet(savedWallet) setWallet(newWallet) } else { // 创建新钱包 const newWallet = new DIDWallet() setWallet(newWallet) // 保存到localStorage localStorage.setItem('did-wallet', newWallet.exportWallet()) } }, []) const backupWallet = () => { if (wallet) { const data = wallet.exportWallet() const blob = new Blob([data], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `did-wallet-${Date.now()}.json` a.click() } } return { wallet, backupWallet } } 完整DID应用 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 import { useState } from 'react' import { DIDWallet } from './did-wallet' import { CredentialIssuer } from './credential-issuer' import { CredentialVerifier } from './credential-verifier' export default function DIDApp() { const [wallet] = useState(() => new DIDWallet()) const [credentials, setCredentials] = useState<string[]>([]) const [presentation, setPresentation] = useState<string>('') const issueCredential = async (claims: object) => { const issuer = new CredentialIssuer( wallet.getDID(), '0x...' // 发行方私钥 ) const vcJwt = await issuer.issueCredential( wallet.getDID(), claims ) setCredentials([...credentials, vcJwt]) } const createPresentation = async () => { const holder = new PresentationHolder( wallet.getDID(), '0x...' // 用户私钥 ) const vpJwt = await holder.createPresentation( credentials, 'did:ethr:0x9999...' // verifier DID ) setPresentation(vpJwt) } const verifyPresentation = async (vpJwt: string) => { const verifier = new CredentialVerifier() const result = await verifier.verifyPresentation(vpJwt) return result } return ( <div> <h1>DID身份钱包</h1> <div> <h2>我的DID</h2> <p>{wallet.getDID()}</p> </div> <div> <h2>凭证</h2> {credentials.map((vc, index) => ( <div key={index}> <pre>{vc}</pre> </div> ))} </div> <div> <h2>可验证表达</h2> <pre>{presentation}</pre> </div> <button onClick={() => issueCredential({ name: '张三' })}> 发行凭证 </button> <button onClick={createPresentation}> 创建表达 </button> </div> ) } 总结 去中心化身份(DID)是WEB3的重要基础设施,通过W3C标准化、区块链技术和密码学,为用户提供了真正自主可控的身份系统。 ...