跨链桥
跨链
跨链技术指的是在不同的区块链之间传输数据和Token的能力。
Web3 的格局正日益变成多链,dApp 生态系统存在于数百个区块链、layer-2 网络和应用链中。然而,区块链本身不具备与外部系统或 API 通信的能力。这种限制不仅阻止了区块链与现有的 Web 基础设施通信,也阻止了它们与其他区块链通信。
鉴于区块链生态系统的多样性,这些不同的链上环境能够互操作和相互通信至关重要。跨链互操作性协议是用于在不同区块链之间交换数据和Token的关键基础设施。跨链互操作性对于一个更集成的 Web3 生态系统以及在现有 Web2 基础设施和 Web3 服务之间建立桥梁至关重要。通过启用跨链智能合约,跨链互操作性解决方案减少了生态系统中的碎片化,并释放了更高的资本效率和更好的流动性条件。
DeFi 的无需许可的组合性催生了日益复杂的应用程序,允许开发者将不同的 dApp 组合成一个结构,从而实现大于各个部分之和的效果。然而,由于智能合约只能与同一网络上的其他合约进行本地组合,因此在数百个不同的网络中,组合性受到了极大的阻碍。如果一个应用程序想要跟随用户并在快速变化的多链环境中保持竞争力,它必须部署在多个平台上,从而导致流动性分散和用户体验下降。此外,单个 dApp 的部署占用了宝贵的开发资源,而这些资源本可以用于改进应用程序的业务逻辑。
在多链环境中,每个 dApp 实例都是一组孤立的智能合约,与其他区块链没有连接。
跨链互操作性使开发者能够构建一个原生的跨链应用程序,其中一个统一的 dApp 可以在多个不同的智能合约中运行,而这些合约部署在多个不同的区块链上,而无需在不同的网络上部署多个独立的版本
跨链智能合约由部署在多个网络上的多个智能合约组成,从而创建一个统一的 dApp。
跨链解决方案通常涉及验证源区块链的状态,并将后续交易中继到目标区块链。完成大多数跨链交互都需要这两个功能。
区块链本身就不能相互通信——它们通常不具备监视或理解其他网络上发生的事情的能力。每个链在协议设计、货币、编程语言、治理结构、文化和其他要素方面都有自己的一套规则,这使得链之间的通信变得困难。
一个关键的基础设施是跨链桥,它使Token能够从源区块链转移到目标区块链。跨链桥通常涉及通过智能合约锁定或销毁源链上的Token,并通过目标链上的另一个智能合约解锁或铸造它们。实际上,跨链桥是一种应用于非常狭窄用例的跨链消息传递协议——在不同的区块链之间转移Token。因此,跨链桥通常是两个区块链之间的特定于应用程序的服务。
跨链桥只是服务于跨链功能的一个简单应用。可编程Token桥实现了更复杂的跨链交互,例如在执行桥接功能的同一交易中,在智能合约中交换、借贷、质押或存入Token,而任意数据消息传递协议提供了更通用的跨链功能,可以支持创建更复杂的 dApp,例如跨链去中心化交易所 (DEXs),跨链货币市场、跨链 NFT、跨链游戏等等。
跨链解决方案的挑战
跨链互操作性提出了一些在多链设计范例中不存在的挑战。但是,如果以安全第一的思维方式来处理,跨链解决方案可以开启一个全新的功能领域。
在没有受信任的第三方的情况下,区块链之间的安全通信是具有挑战性的。跨链通信本质上需要安全、信任或灵活性方面的权衡,而这些权衡对于在单个区块链上发生的交互是不需要的。这也意味着,只有在安全、信任假设或灵活性方面做出权衡,才能实现不同区块链上智能合约之间的组合性。
如果跨链消息传递存在局限性,为什么不将所有应用活动都部署在单个区块链上呢?答案是双重的。首先,如果去中心化和可信中立是网络的核心价值,那么由于计算能力、带宽和存储能力的限制,单个区块链可以处理的活动量存在理论上的限制。其次,各个区块链和扩展解决方案针对不同的质量进行了优化,例如速度、安全性和去中心化,并且很可能对于这些价值的最佳组合总是存在分歧,从而导致对多个链和解决方案的需求。
与跨链桥相关的一个重要问题是包装资产与原生资产的使用。包装或桥接资产是源区块链上另一种资产的表示,因此,由于需要一个或多个实体托管底层代币,因此引入了不同形式的安全和信任假设。这些局限性可以通过 Chainlink 储备证明支持的去中心化验证来缓解。如果使用原生资产,那么在桥接功能执行后,实际上在目标链上使用相同的资产,但需要考虑如何验证一条链上的代币销毁以触发另一条链上的发行。
密码经济系统的弹性仅取决于其最薄弱的攻击载体。安全性较弱的跨链消息传递协议,即使底层网络或 layer-2 网络是安全的,也可能使资金容易受到攻击。在保护桥梁方面,关键的考虑因素是攻击成本和成功攻击所需要妥协的参与者数量。从这个意义上讲,最大化跨链桥的安全性意味着最大化实体的多样性和/或在状态验证和将后续交易中继到目标区块链期间保护桥梁的密码学保证的强度。
跨链Token桥的另一个考虑因素是最终性,这意味着保证一旦在源链上成功提交资金,目标链上的资金就可用。如果没有保证的最终性,源链上的反向交易(例如区块重组)可能会对目标链产生不利后果,例如创建无支持的桥接代币。
跨链互操作性协议(CCIP)
跨链互操作性协议(CCIP)是一种区块链无关的、用于跨链通信的开源标准,涉及任意消息传递和Token转移。CCIP旨在通过单个接口在数百个区块链网络之间建立通用连接,从而满足对复杂跨链交互不断增长的需求。CCIP 的构建具有高度的可组合性,因此它可以与可编程Token桥框架中的各种其他预言机服务集成,以支持高度复杂的跨链交互和跨链应用程序。
CCIP 引入的一些安全增强功能包括:风险管理网络,用于监控恶意活动和异常事件;来自范围广泛的高质量节点运营商的去中心化预言机计算,具有可验证的链上性能历史;以及离链报告(OCR)协议的使用,该协议已经帮助保护了各种 Chainlink 服务中数千亿美元的资金。
CCIP 启用的跨链基础设施堆栈旨在帮助解锁各种跨链应用程序。跨链互操作性是下一代 Web3 的一个重要组成部分,它将帮助解锁全新的用例和用户体验,以满足 Web2 世界所设定的期望。跨链解决方案将成为加速 Web3 采用率的关键,它允许开发者创建可以通过更传统的用户体验访问的复杂 dApp,并帮助企业、机构和政府安全地访问任何链上环境。
跨链桥
跨链桥是一种区块链协议,它连接独立的区块链,并实现资产和信息在它们之间的转移,允许用户轻松访问其他协议。例如,一个在以太坊主网上运行的ERC20代币,可以通过跨链桥转移到其他兼容以太坊的侧链或独立链。
同时,跨链桥不是区块链原生支持的,跨链操作需要可信第三方来执行,这也带来了风险。
跨链桥的类型
跨链桥由三种主要机制类型驱动:
- 销毁和铸造——用户销毁源链上的代币,然后在目标链上重新发行(铸造)相同的原生代币。
- 锁定和铸造——用户将代币锁定在源链上的智能合约中,然后将这些锁定的代币的包装版本在目标链上铸造为 IOU 的一种形式。在相反的方向上,目标链上的包装代币被销毁以解锁源链上的原始代币。
- 锁定和解锁——用户将代币锁定在源链上,然后从目标链上的流动性池中解锁相同的原生代币。这些类型的跨链桥通常通过经济激励(例如收入分成)来吸引桥两侧的流动性。
此外,跨链桥还可以与任意数据消息传递功能相结合——不仅能够在区块链之间移动代币,还能够移动任何类型的数据。这些可编程代币桥涉及代币桥和任意消息传递的组合,一旦代币被传递到目标链,就会在目标链上执行智能合约调用。
对跨链桥进行分类的另一种方法是,考察它们在验证源区块链状态并将后续交易中继到目标区块链方面,在信任最小化的频谱中所处的位置。通常,跨链解决方案在频谱上越靠近信任最小化,其计算成本就越高,灵活性就越差,通用性也就越低。做出这些权衡是为了支持需要最强信任最小化保证的用例。
跨链桥主要有以下三种类型:
Burn/Mint:在源链上销毁(burn)代币,然后在目标链上创建(mint)同等数量的代币。此方法好处是代币的总供应量保持不变,但是需要跨链桥拥有代币的铸造权限,适合项目方搭建自己的跨链桥。
Stake/Mint:在源链上锁定(stake)代币,然后在目标链上创建(mint)同等数量的代币(凭证)。源链上的代币被锁定,当代币从目标链移回源链时再解锁。这是一般跨链桥使用的方案,不需要任何权限,但是风险也较大,当源链的资产被黑客攻击时,目标链上的凭证将变为空气。
Stake/Unstake:在源链上锁定(stake)代币,然后在目标链上释放(unstake)同等数量的代币,在目标链上的代币可以随时兑换回源链的代币。这个方法需要跨链桥在两条链都有锁定的代币,门槛较高,一般需要激励用户在跨链桥锁仓。
跨链桥的七大关键漏洞
1 私钥管理漏洞
跨链桥通常会使用一个或一组私钥来管理。一个或多个跨链桥运行节点各自会持有一把独特的私钥。他们的任务是对用户发送的跨链消息或传输的价值达成共识,并准确地将消息或价值进行跨链传输。他们会使用私钥来进行数字签名,或使用多个私钥组成门限签名,以批准跨链消息。
因此,私钥被盗是跨链桥最常见的漏洞之一。Web3行业中最臭名昭著的跨链桥被盗事件都是因为私钥被盗导致的。而私钥被盗通常是因为私钥管理或跨链桥运行安全出现漏洞。
一个大致的原则就是,跨链桥及其私钥如果在服务器、基础设施提供方、部署地点和节点运营商这几个方面越去中心化,那么就越有能力防范单点失效和中心化风险。
中心化的网络不仅容易被攻击,还会出现某一方全权控制所有用户资金的情况去中心化的模式可以有效防范中心化风险。在去中心化模式下,任何攻击者(或甚至运行跨链桥的节点)都必须同时对多个独立实体的私钥进行攻击,才有可能成功,因此极大降低了内外部攻击发生的概率。这是一种非常稳健的安全模式。不过,要保障私钥安全还需要考虑到其他因素。另外一个同样重要的因素就是,各个跨链桥运行节点需要独立地采用不同的安全机制来保障私钥安全。
最佳实践
虽然去中心化可以很好地避免单点失效,但要保障私钥安全还需要同时采取多种措施。安全性最高的跨链协议通常既会采用去中心化的模式来保障安全,也会采用成熟的解决方案来保存私钥,比如硬件安全模块(HSM)、加密(传输中的数据和静止数据)、网络诈骗防范教育、权限控制以及密钥管理服务等。
由于私钥被盗导致跨链桥遭受攻击的真实案例
- Ronin跨链桥(2022年3月)—— 在Ronin跨链桥上开展、审批和执行交易所需的九把私钥中有五把被盗。
- Harmony跨链桥(2022年6月)—— 在Harmony跨链桥上开展、审批和执行交易所需的五把私钥中有两把被盗。
- Multichain跨链桥(2023年7月)—— 跨链桥私钥被盗,导致资金未经审批就被取出。而这些私钥都由Multichain的CEO一人持有。
- Orbit Chain(2024年1月)—— Orbit Chain跨链桥的十把私钥中有七把被盗,导致资金池被抽干。
2 智能合约审计漏洞
由于跨链桥的主要功能是将价值从一条链转移到另一条链,因此所有跨链协议都必须涉及到智能合约。
在大多数的跨链用例中,都需要使用多条链上的智能合约来铸造、销毁、锁定或解锁跨链Token。这些智能合约通过跨链桥连接,通常会与Token发行方建立合作。
可以说,智能合约是防止跨链桥被盗的额外安全层,但如果智能合约本身出现漏洞,也有可能导致技术风险。一方面,智能合约为跨链桥提供了宝贵的平台,可以开展各类常规安全检查,比如确保用户取出的金额不超过存入的金额以及设置跨链桥的速率限制(rate limit)。另一方面,如果智能合约代码质量很差或没有经过严格审计,那么就会适得其反。黑客利用智能合约代码漏洞已经从多个跨链桥盗走了数额庞大的资金。
任何项目,无论它对安全多么看重,都无法完全保障它的智能合约代码中没有技术漏洞。不过有一个非常成熟的方案可以保障代码的稳健性,那就是与经验丰富的第三方审计合作,对项目代码库进行测试,测试通过后再发布。这并非一劳永逸的事情,因为一旦代码库在审计后做了更改,或未审计的智能合约添加到了已审计的代码库中,那么即使是最完备的代码库都会立即回到未审计的状态。
最佳实践
在使用跨链协议时,智能合约的风险是真实存在的。安全性最高的跨链桥往往会对其代码库持续展开多次内部审计和竞争性的外部审计。另外,这些跨链桥还会开展一系列内部安全测试,比如模糊测试、静态分析、形式验证以及符号执行等。
如果要了解跨链桥潜在的技术风险,就需要查看其代码库的审计次数以及审计人员等相关信息。另外,还需要建立紧急关停和紧急更新等多层安全模式,并设置速率限制,这些都可以有效降低智能合约漏洞的风险。
由于智能合约漏洞导致的跨链桥被盗真实案例
- Wormhole跨链桥(2022年2月)—— 黑客找到了跨链桥智能合约中验证步骤的漏洞,在抵押资产不足的情况下在Solana链上铸造了12万枚wETH。
- Nomad跨链桥(2022年8月)—— 跨链桥智能合约代码中默认接受的根账户(0x00)实现方式出现了错误,导致任何人都可以从跨链桥中盗走资金。
- 币安跨链桥(2022年10月)—— 跨链桥智能合约中IAVL默克尔证明验证系统存在漏洞,导致跨链桥被攻击。此次攻击导致200万个BNB从跨链桥转到了攻击者账户。
- Socket互操作性协议(2024年1月)—— 协议智能合约存在漏洞,导致钱包对Socket智能合约出现无限批准。
3 升级流程漏洞
可升级性指智能合约代码的升级能力,或更改智能合约代码中部分参数配置的能力。
开发者通常会采用可升级的智能合约来进行升级,以添加新功能、解决智能合约逻辑错误并修改关键的风险参数。跨链桥可以通过升级来添加新的Token和区块链,采用新技术来验证跨链消息,调整资金提取限额和节点构成等关键风险参数,并迅速解决底层智能合约中新发现的任何逻辑错误。
可升级的智能合约需要在终端用户、前端实现和底层智能合约之间开发代理合约可升级性对于安全来说至关重要,因为如果升级流程出现漏洞,就可能造成潜在的攻击向量。跨链桥要具备安全的可升级性,就需要采取深度防御机制,其中包括建立稳健的私钥管理机制,密钥由多个独立实体分别持有;采用时间锁延迟机制,让用户可以在链上更改生效前提前查看;建立稳健的审批流程,比如跨链桥运行节点可以一票否决在时间锁有效期内的决议。在特殊情况下,如果需要快速实现升级,跨链桥运行节点在评估更改决议后可以直接审批通过。
最佳实践
要不断适应发展需要并应对未知状况,就必须实现可升级性。然而,升级流程如果存在漏洞,可能会为跨链协议带来潜在风险。时间锁智能合约和节点一票否决机制是重要的工具,可以加固升级流程。然而,要保障跨链桥安全还必须制定应急预案,并同时保障最高水平的安全性。
4 依赖单一网络
一些跨链桥依赖单一验证节点网络进行所有跨链操作。如果跨链桥专门用于连接两条指定的区块链,那么单一网络这个方案也许可行。但如果要用通用型跨链桥连接多链世界,那这个方案既不安全也不可扩展。
避免使用这类跨链桥有一个最重要的原因,那就是一旦跨链桥被攻击,用户受到的打击最为严重。由于所有跨链交易及其价值都由一个网络支撑,所以一旦网络成功被攻陷,所有区块链的跨链桥都会全军覆没,风险几乎无法隔离。
利用多个独立的去中心化网络可以有效隔离风险,防止因一次跨链桥攻击导致所有区块链和用户的资金全部被盗采用独立的多网络设计结构是更加安全且可扩展的解决方案,具体如下:
- 跨链通道由独立的去中心化网络运行。 这意味着,每条跨链通道都有一个独立的去中心化网络,每两条区块链之间都有一条单独的跨链通道。这样做可以将一次攻击的影响限制在某一条跨链通道内。
- 每条跨链通道都由多个网络保障安全。 安全性最高的跨链桥和协议都会为每条跨链通道创建多个网络,以增强安全性。这样一来,攻击者必须要同时攻陷一条安全通道的多个网络,才能成功。因此,这也为安全通道提供了额外的安全层。
Chainlink CCIP为单一跨链通道建立多个网络,是唯一一个达到第五层(也是最高层)跨链安全性的跨链协议最佳实践
为每条跨链通道都创建多个独立的去中心化网络,可以大幅降低攻击面以及攻击者的回报率。这个方案的最佳实践还包括采用多种编程语言开发客户端,以实现客户端的多样性;创建单独的节点集合,保障这些节点与网络节点无重叠;以及添加主动风控功能。
5 验证节点集合质量差
验证节点是所有跨链桥的灵魂。节点包括各类人员和组织,他们负责维护基础设施,运行跨链桥功能。
用户、机构和dApp开发者应该警惕验证节点由于缺乏经验和知识而导致无法安全运行跨链桥的风险。安全性最高的跨链桥通常会要求其验证节点拥有世界一流的水平和丰富的经验,保障运行安全(OPSEC), 妥善保管私钥并可靠处理和执行跨链交易 。
其中第二点经常被用户、开发者和机构所忽略。对于任何一个跨链桥用户来说,节点网络最大的风险就是无法可靠地执行交易。比如,用户在一条链上锁定资金,然后准备在另一条链上铸造相应的资金。但如果由于节点网络下线而无法批准铸造,那么用户资金实际上就会被冻结。
最佳实践
跨链桥应该只采用优质的节点,并且这些节点要具备丰富的运行安全经验、卓越的性能和强大的稳健性。运行安全并非Web3独有的能力,因此许多Web2和Web3的验证节点都可以加入。不过在招募跨链桥节点时很有必要核实节点的过往记录。另外,还可以要求验证节点进行质押,一旦出现违规行为或操作,质押的保证金就会被没收。这样做可以激励验证节点诚实可靠地展开工作,并创建新的经济安全层。
6 缺乏主动交易监控
主动监控交易的目的是实时监控跨链桥的异常行为,并作出响应。如果主动交易监控机制实施得当,就可以很好地监测到可疑行为并立刻采取必要的防御措施,以防范攻击。
主动交易监控的一个典型用例就是在执行可疑交易前或通过恶意交易后紧急关停跨链系统。恶意交易包括在抵押资产不足的情况下成功取走跨链桥的全部资产。
最佳实践
主动交易监控通常由一组与跨链桥主节点完全不相关的独立实体或节点网络组成。这样做可以清晰划分责任,并实现相互制衡的机制,降低一个或一组节点操纵实时响应的可能性。
7 缺乏速率限制
速率限制(rate limit)并不是一个新的概念。在传统软件行业中,速率限制是网站采用的一种安全机制,目的是防范DoS攻击。数据提供方也会采用这种机制来防范过多API请求导致的服务器宕机。
这个概念非常简单,即:在时间和数量的维度上限制请求数量。那么是什么样的请求呢?在跨链世界中,速率限制指限制 某一段时间内两条链之间可以传输的最大资金价值 。
这个安全机制看上去虽然简单,但却是跨链桥最后一道坚实的防线。即使黑客成功穿透了其他所有防线,速率限制仍可以限制他们能够从跨链桥盗取的金额。
速率限制就像是在水桶上穿一个小洞,在单位时间内只有定量的水可以流出来由于缺乏速率限制而导致的跨链桥被盗真实案例
- 如果设置了速率限制和紧急关停功能,并且在实现过程中没有任何逻辑错误,那么所有跨链桥攻击中短时间内被盗的资金都可以被限制在一定金额内。
最佳实践
每条跨链通道的速率限制都应该定制化,以在最大程度上实现安全性和模块化。另外,每条跨链通道还应该限制所有资产加在一起的跨链传输总额。设置合理的吞吐量速率(即:每十分钟最多传输X枚Token)可以有效防范攻击者在一次交易中抽干资产池中的所有资产。另外,还可以针对各个跨链资产和跨链通道设置“充值速率”(refill rate),以避免攻击者等到速率限制归零后再盗走上限资产。
实例:
代币合约:
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// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
//Hoodi_addr: 0xe938d6C5eE95a1063cA119424F9fc45EEf385E25
//Sepolia_addr: 0x4f6edC2F49D36EE8758916fCdDddA1d65da8133F
contract CrossChainToken is ERC20, Ownable {
// Bridge event
event Bridge(address indexed user, uint256 amount);
// Mint event
event Mint(address indexed to, uint256 amount);
/**
* @param name Token Name
* @param symbol Token Symbol
* @param totalSupply Token Supply
*/
constructor(
string memory name,
string memory symbol,
uint256 totalSupply
) payable ERC20(name, symbol) Ownable(msg.sender) {
_mint(msg.sender, totalSupply);
}
/**
* Bridge function
* @param amount: burn amount of token on the current chain and mint on the other chain
*/
function bridge(uint256 amount) public {
_burn(msg.sender, amount);
emit Bridge(msg.sender, amount);
}
/**
* Mint function
*/
function mint(address to, uint amount) external onlyOwner {
_mint(to, amount);
emit Mint(to, amount);
}
}constructor(): 构造函数,在部署合约时会被调用一次,用于初始化代币的名字、符号和总供应量。bridge(): 用户调用此函数进行跨链转移,它会销毁用户指定数量的代币,并释放Bridge事件。mint(): 只有合约的所有者才能调用此函数,用于处理跨链事件,并释放Mint事件。当用户在另一条链调用bridge()函数销毁代币,脚本会监听Bridge事件,并给用户在目标链铸造代币。
有了代币合约之后,我们需要一个服务器来处理跨链事件。我们可以编写一个ethers.js脚本(v6版本)监听
Bridge事件,当事件被触发时,在目标链上创建同样数量的代币。ethers.js脚本:
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
58import { ethers } from "ethers";
// 初始化两条链的provider
const providerHoodi = new ethers.JsonRpcProvider("https://eth-hoodi.g.alchemy.com/v2/kHk6kuGZy4sMQ-7UtWOBUYMPG5il_0I3");
const providerSepolia = new ethers.JsonRpcProvider("https://eth-sepolia.g.alchemy.com/v2/kHk6kuGZy4sMQ-7UtWOBUYMPG5il_0I3");
// 初始化两条链的signer
// privateKey填管理者钱包的私钥
const privateKey = process.env.SEPOLIA_PRIVATE_KEY;
const walletHoodi = new ethers.Wallet(privateKey, providerHoodi);
const walletSepolia = new ethers.Wallet(privateKey, providerSepolia);
// 合约地址和ABI
const contractAddressHoodi = "0xe938d6C5eE95a1063cA119424F9fc45EEf385E25";
const contractAddressSepolia = "0x4f6edC2F49D36EE8758916fCdDddA1d65da8133F";
const abi = [
"event Bridge(address indexed user, uint256 amount)",
"function bridge(uint256 amount) public",
"function mint(address to, uint amount) external",
];
// 初始化合约实例
const contractHoodi = new ethers.Contract(contractAddressHoodi, abi, walletHoodi);
const contractSepolia = new ethers.Contract(contractAddressSepolia, abi, walletSepolia);
const main = async () => {
try {
console.log(`开始监听跨链事件`)
// 监听chain Sepolia的Bridge事件,然后在Hoodi上执行mint操作,完成跨链
contractSepolia.on("Bridge", async (user, amount) => {
console.log(`Bridge event on Chain Sepolia: User ${user} burned ${amount} tokens`);
// 在Hoodi上执行mint操作
let tx = await contractHoodi.mint(user, amount);
await tx.wait();
console.log(`Minted ${amount} tokens to ${user} on Chain Hoodi`);
});
// 监听chain Hoodi的Bridge事件,然后在Sepolia上执行mint操作,完成跨链
contractHoodi.on("Bridge", async (user, amount) => {
console.log(`Bridge event on Chain Hoodi: User ${user} burned ${amount} tokens`);
// 在Sepolia上执行mint操作
let tx = await contractSepolia.mint(user, amount);
await tx.wait();
console.log(`Minted ${amount} tokens to ${user} on Chain Sepolia`);
});
} catch (e) {
console.log(e);
}
}
main();
在Hoodi测试链部署
CrossChainToken合约, 铸造 10000 枚代币forge create CrossChainToken --rpc-url $SEPOLIA_RPC_URL --private-key $SEPOLIA_PRIVATE_KEY --broadcast --constructor-args Hoodi Hoodi 10000在Sepolia测试链部署
CrossChainToken合约, 铸造 10000 枚代币forge create CrossChainToken --rpc-url $SEPOLIA_RPC_URL --private-key $SEPOLIA_PRIVATE_KEY --broadcast --constructor-args Hoodi Hoodi 10000运行脚本
node ethers.js调用hoodi链上代币合约的
bridge()函数,跨链100枚代币。cast send 0xe938d6C5eE95a1063cA119424F9fc45EEf385E25 "bridge(uint256)" 100 --rpc-url $SEPOLIA_RPC_URL --private-key $SEPOLIA_PRIVATE_KEY脚本监听到跨链事件,并在Sepolia链上铸造100枚代币。
检查余额
cast call 0xe938d6C5eE95a1063cA119424F9fc45EEf385E25 "balanceOf(address)(uint256)" 0x949AC2C16Ea7B0B003927Db532908Fc97090d 9E5 --rpc-url $SEPOLIA_RPC_URLcast call 0x4f6edC2F49D36EE8758916fCdDddA1d65da8133F "balanceOf(address)(uint256)" 0x949AC2C16Ea7B0B003927Db532908Fc97090d 9E5 --rpc-url $SEPOLIA_RPC_URL








