本文详细介绍了如何使用Wormhole协议在Avalanche Fuji和Ethereum Sepolia测试网之间构建跨链消息传递应用,并提供了具体的代码实现和部署步骤。
更喜欢视频教程?跟随 Sahil 学习 Wormhole 协议的工作原理以及如何使用它来传输跨链消息。
Wormhole 是如何工作的?| @wormholecrypto - YouTube
QuickNode
131K 订阅者
Wormhole 是如何工作的?| @wormholecrypto
QuickNode
搜索
信息
购物
点击取消静音
如果播放没有立即开始,请尝试重新启动设备。
你已退出登录
你观看的视频可能会被添加到电视的观看历史记录中,并影响电视推荐。要避免这种情况,请取消并在电脑上登录 YouTube。
取消确认
分享
包含播放列表
检索分享信息时出错。请稍后再试。
稍后观看
分享
复制链接
观看
0:00
/ •直播
•
订阅我们的 YouTube 频道以获取更多视频!订阅
构建跨链基础设施可能既耗时又复杂。幸运的是,Wormhole 帮助开发者和企业创建跨链基础设施,以发送/接收消息和任意数据等信息。
在本指南中,我们将学习如何构建一个可以在 Avalanche Fuji 和 Ethereum Sepolia 测试网之间发送消息的跨链消息传递应用程序。我们将使用 QuickNode 访问区块链节点,使用 Foundry 进行智能合约开发,并使用 Wormhole 的消息传递协议来实现安全的跨链通信。
让我们开始吧!
依赖项 | 版本 |
---|---|
node.js | v22.12.0 |
forge | forge 0.3.0 |
Wormhole 是一种消息传递协议,支持不同区块链网络之间的通信。它充当跨链通信基础设施层,允许开发者构建跨多个链的互操作应用程序。
Wormhole 的关键特性包括:
通过 Wormhole 进行跨链消息传递遵循以下关键步骤:
消息发起:当源链(例如 Avalanche)上的用户或合约调用触发消息通过 Wormhole 发送的函数时,该过程开始。此消息包含有效载荷数据和目标链信息。
守护者网络:Wormhole 的去中心化守护者网络观察源链上的这些消息。当检测到消息时,守护者:
消息传递:一旦创建了 VAA:
消息处理:在目标链上:
IWormholeReceiver
接口此过程确保:
此过程的高级图示如下:
在我们的示例应用程序中,我们将从 Avalanche Fuji 向 Ethereum Sepolia 发送消息,但相同的原则适用于任何支持的链对。
在进入代码之前,让我们设置一些前提条件,例如获取我们需要的 RPC URL。你可以使用公共节点或部署和管理自己的基础设施;但是,如果你希望获得 8 倍的响应速度,可以将繁重的工作交给我们。在此注册一个免费账户。
登录 QuickNode 后,点击 创建端点 按钮,然后选择 Ethereum 链和 Sepolia 网络。
创建端点后,复制 HTTP Provider URL 链接并妥善保存,因为稍后你将需要它。现在,对 Avalanche 链和 Fuji 测试网网络执行相同的步骤,然后再进入下一部分。
要进行跨链消息传递,你将需要 Sepolia ETH 和 Fuji AVAX 来支付各自网络上的 gas 费用。你可以从 多链 QuickNode 水龙头免费获取这些测试代币。
导航到 多链 QuickNode 水龙头 并连接你的钱包(例如 MetaMask、Coinbase Wallet)或粘贴你的钱包地址以获取测试 ETH。请注意,使用 EVM 水龙头需要 Ethereum 主网上的 0.001 ETH 余额。你还可以通过推特或使用 QuickNode 账户登录以获得奖励!
在本指南中,我们将使用 Wormhole 创建的 demo-wormhole-messaging
示例应用程序。
我们的项目结构将如下所示:
script/ - 部署和交互脚本
deploy-config/ - 链配置和部署的合约地址
out/ - 编译的合约工件
lib/ - 外部依赖项(由 Foundry 自动管理)
test/ - 智能合约的单元测试
在进入代码的核心部分之前,让我们先了解一下我们将部署的智能合约如何将消息从一条链传递到另一条链的架构。
我们的跨链消息传递系统由三个主要合约组成:
现在,让我们深入了解每个合约的细节。发送者合约负责发起跨链消息。以下是合约代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol";
contract MessageSender {
IWormholeRelayer public wormholeRelayer;
uint256 constant GAS_LIMIT = 50000; // 根据需要调整 gas 限制
`constructor`(address _wormholeRelayer) {
wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
}
function quoteCrossChainCost(uint16 targetChain) public view returns (uint256 cost) {
(cost,) = wormholeRelayer.quoteEVMDeliveryPrice(targetChain, 0, GAS_LIMIT);
}
function sendMessage(uint16 targetChain, address targetAddress, string memory message) external payable {
uint256 cost = quoteCrossChainCost(targetChain); // 动态计算跨链成本
require(msg.value >= cost, "跨链传递资金不足");
wormholeRelayer.sendPayloadToEvm{value: cost}(
targetChain,
targetAddress,
abi.encode(message, msg.sender), // 有效载荷包含消息和发送者地址
0, // 不需要接收者值
GAS_LIMIT // 交易的 gas 限制
);
}
}
需要了解的重要事项:
IWormholeRelayer.sol
中继器接口。constructor
在部署时接受 _wormholeRelayer
地址。quoteCrossChainCost
函数根据 targetChain
返回我们的跨链消息传递的成本估算。sendMessage
函数是主要函数,接受 targetChain
、targetAddress
和 message
。请注意,你还可以发送数据资产(例如代币、NFT),但这是通过 实体 完成的,这是一个单独的工作流程。接收者合约处理目标链上的传入消息。以下是合约代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol";
import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol";
contract MessageReceiver is IWormholeReceiver {
IWormholeRelayer public wormholeRelayer;
address public registrationOwner;
// 映射以存储每条链的注册发送者
mapping(uint16 => bytes32) public registeredSenders;
event MessageReceived(string message);
event SourceChainLogged(uint16 sourceChain);
constructor(address _wormholeRelayer) {
wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
registrationOwner = msg.sender; // 将合约部署者设置为所有者
}
// 修饰符以检查发送者是否为源链的注册发送者
modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) {
require(registeredSenders[sourceChain] == sourceAddress, "未注册的发送者");
_;
}
// 函数以注册特定链的有效发送者地址
function setRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) public {
require(msg.sender == registrationOwner, "不允许设置注册发送者");
registeredSenders[sourceChain] = sourceAddress;
}
// 更新 receiveWormholeMessages 以包含源地址检查
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory, // 额外的 VAA(可选,此处不需要)
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 // 传递哈希
)
public
payable
override
isRegisteredSender(sourceChain, sourceAddress)
{
require(msg.sender == address(wormholeRelayer), "只有 Wormhole 中继器可以调用此函数");
// 解码有效载荷以提取消息
(string memory message) = abi.decode(payload, (string));
// 使用 sourceChain 进行日志记录的示例
if (sourceChain != 0) {
emit SourceChainLogged(sourceChain);
}
// 发出事件以记录接收到的消息
emit MessageReceived(message);
}
}
让我们回顾一下代码:
IWormholeRelayer.sol
中继器接口,此外还导入了 IWormholeReceiver
接口。constructor
使用 IWormholeRelayer
接口和地址初始化合约,并将 registrationOwner
设置为合约部署者。isRegisteredSender
修饰符确保消息来自注册的发送者。receiveWormholeMessages
函数从 MessageSender
合约接收消息。在高层次上,此流程如下所示:
sendMessage()
,并传入:Sender
合约:receiveWormholeMessages()
需要注意的是,只有注册的合约才能发送消息,跨链成本会自动处理,并且可以在两条链上验证消息传递。
现在,让我们进入指南的技术编码部分。
首先,让我们创建一个项目文件夹并克隆项目:
mkdir messaging-app && cd messaging-app
git clone git@github.com:wormhole-foundation/demo-wormhole-messaging.git # SSH
或
git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git # HTTPS
然后进入项目并安装所需的依赖项:
cd demo-wormhole-messaging
npm install
forge install
接下来,让我们在项目的根目录中创建一个包含你的私钥的 .env 文件:
echo > .env
记住 仅在本地使用
.env
文件,并在不使用时删除它们。
然后,打开文件并输入你的私钥:
PRIVATE_KEY=0x...
在继续之前,我们需要更新 deploy-config/chains.json
文件,打开文件并将其更新为以下内容:
{
"chains": [\
{\
"description": "Avalanche testnet fuji",\
"chainId": 6,\
"rpc": "YOUR_QUICKNODE_AVALANCHE-FUJI_ENDPOINT",\
"tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756",\
"wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB",\
"wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C"\
},\
{\
"description": "Sepolia Testnet",\
"chainId": 10002,\
"rpc": "YOUR_QUICKNODE_SEPOLIA_ENDPOINT",\
"tokenBridge": "0xDB5492265f6038831E89f495670FF909aDe94bd9",\
"wormholeRelayer": "0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470",\
"wormhole": "0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78"\
}\
]
}
记住 将占位符替换为实际的 RPC URL。还要确保在 Avalanche Fuji RPC URL 的末尾附加
/ext/bc/C/rpc/
路径(例如,https://amazing-grace.avalanche-testnet.quiknode.pro/TOKEN/ext/bc/C/rpc/)。
你会注意到,此文件中使用的链 ID 并不对应于公共链 ID。相反,此链 ID 是特定于 Wormhole 协议的。你可以在此处查看 Wormhole 的完整链 ID 列表:参考
在本节中,我们将在部署之前编译和测试跨链消息传递应用程序的智能合约。
该项目包括三个主要测试用例:
testDeployment()
:验证合约是否正确部署并正确初始化testReceiveMessage()
:确保接收者合约可以处理传入消息testSendMessage()
:验证发送者合约可以正确发送消息首先,让我们编译智能合约:
forge build
现在我们将运行测试以确保在部署智能合约之前一切正常:
forge test
你将看到类似于以下内容的输出:
[⠊] Compiling...
No files changed, compilation skipped
Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest
[PASS] testDeployment() (gas: 13008)
[PASS] testReceiveMessage() (gas: 19766)
[PASS] testSendMessage() (gas: 20922)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.98ms (1.93ms CPU time)
Ran 1 test suite in 109.55ms (2.98ms CPU time): 3 tests passed, 0 failed,
>- 原文链接: [quicknode.com/guides/cro...](https://www.quicknode.com/guides/cross-chain/wormhole/how-to-create-a-cross-chain-messaging-app)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!