本文介绍了如何使用LayerZero V2部署全链可替代代币(OFTs),并展示了将$UNI代币从Sepolia测试网桥接到Berachain测试网的过程。通过详细的步骤说明,包括智能合约的编写与部署,开发者可以快速掌握如何通过LayerZero实现跨链通信和代币桥接。
导言
随着区块链技术的不断发展,跨链通信已经成为了加密世界中的重要需求。
LayerZero V2 推出的全链可替代代币(OFTs)标准,为跨链资产提供了一种创新解决方案。OFTs 不仅允许代币在不同区块链之间自由流通,还能够保持代币的统一供应,解决了传统跨链桥接中的流动性和资产包装问题。本
文将详细介绍如何通过 LayerZero V2 和 Foundry 工具,跨链桥接 $UNI 代币,从 Sepolia 测试网到 Berachain 测试网的完整过程。
通过对智能合约的编写与部署,开发者可以进一步了解 LayerZero 的跨链通信能力,并掌握其在多链环境下的实际应用。
如你在开发过程中遇到任何问题,可以按照文末的方式和官方团队进行沟通,也可以联系 DAppChaser,和我们的开发者一起讨论。
Erica
使用LayerZero V2部署跨链代币
OFTs 简介
全链可替代代币(Omnichain Fungible Tokens, OFTs)是由 LayerZero 推出的一种新代币标准,用于跨链资产。OFTs 允许可替代代币在不同区块链间传输,无需使用资产包装或流动性池,且能够保持统一的供应。
LayerZero是一个通用的跨链消息传递协议,但在本文中,我们将重点讨论它的跨链桥接应用,尤其是OFTs。
LayerZero V2
LayerZero V2于2024年1月发布,带来了重要升级,它将消息验证与执行分离(在LayerZero V1中,这两者是通过 Relayers 绑定在一起的):
除了其他改进之外,这些变化增强了全链应用开发者的可扩展性和定制性。有关更深入的探讨,请参阅这篇文章。
本文将展示如何利用 LayerZero OFTs,将 $UNI 代币从 Sepolia 测试网桥接到Berachain 测试网。
📋需求
在开始之前,确保你的电脑上已安装并设置好以下内容:
- Node v20.11.0或更高版本
- pnpm
- 配置了 Berachain bArtio 网络和 Sepolia测试网 的钱包
- 该钱包中有 $BERA 或 Berachain 测试网代币 — 参见 Berachain Faucet
- 该钱包中有Sepolia测试网的$ETH — 参见 Sepolia Faucet
- 获取Sepolia $UNI — 参见 Uniswap(本指南中使用0.0001)
Foundry
本指南需要安装Foundry。在终端窗口中运行以下命令:
curl -L https://foundry.paradigm.xyz | bash;
foundryup;
# foundryup installs the 'forge' and 'cast' binaries, used later
Foundry 的更多安装说明,请参见 Foundry 的安装指南。有关在 Berachain 上使用Foundry 的更多详细信息,请参见此指南。
创建LayerZero项目
首先,我们将使用Foundry设置开发环境。
新建一个项目文件夹并初始化 Foundry:
forge init layerzero-oft --no-git --no-commit;
cd layerzero-oft;
# We observe the following basic layout
# .
# ├── foundry.toml
# ├── script
# │ └── Counter.s.sol
# ├── src
# │ └── Counter.sol
# └── test
# └── Counter.t.sol
安装依赖
我们将使用与 LayerZero 和 OpenZeppelin 工具相关的多个依赖项,安装它们:
# FROM: ./layerzero-oft
pnpm init;
pnpm add -D @layerzerolabs/lz-evm-oapp-v2 @layerzerolabs/toolbox-foundry @layerzerolabs/lz-evm-protocol-v2 @layerzerolabs/lz-evm-messagelib-v2 @layerzerolabs/lz-definitions @openzeppelin/contracts --ignore-workspace;
将 foundry.toml
内容替换为以下内容以重新映射依赖项:
[profile.default]
src = "src"
out = "out"
libs = [
'node_modules/@layerzerolabs/toolbox-foundry/lib',
'node_modules',
]
remappings = [
'forge-std/=node_modules/@layerzerolabs/toolbox-foundry/lib/forge-std',
'@layerzerolabs/=node_modules/@layerzerolabs/',
'@openzeppelin/=node_modules/@openzeppelin/',
]
交互概览
在编写合约之前,让我们简要介绍一下将$UNI代币从Sepolia桥接到Berachain过程中涉及的交互:
- 在源链上,用户在
OFT Adapter
合约上执行桥接交易(我们创建的合约); -
$UNI
在OFT Adapter
中被锁定; - LayerZero 终端合约发送一条包含在目标链上铸造
$UNI
代币的指令的消息; - 消息由 DVN 验证;
- 执行者在目标链的终端合约上调用
lzReceive()
,接收消息; -
$lzUNI
(我们创建的OFT)被铸造并发送给用户。
编写智能合约
编写智能合约
我们将需要在源链和目标链上部署多个智能合约,以推进上述过程。
新建一个文件 ./src/MyAdapter.sol
并粘贴以下内容:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import {OFTAdapter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTAdapter.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract MyAdapter is OFTAdapter {
constructor(
address _token, // a deployed, already existing ERC20 token address
address _layerZeroEndpoint, // local endpoint address
address _delegate // token owner used as a delegate in LayerZero Endpoint
) OFTAdapter(_token, _layerZeroEndpoint, _delegate) Ownable(_delegate) {}
}
该合约简单地实现了 OFTAdapter 合约,正如我们所提到的,这是源链上的合约,负责锁定代币并为现有代币扩展跨链功能。你可以在这里了解更多关于OFT适配器的信息。
此外,设置了一个合约委托,该地址被授予执行关键任务的能力,比如设置配置。
接下来,创建一个文件 ./src/MyOFT.sol
,并粘贴以下内容:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {OFT} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";
contract MyOFT is OFT {
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
}
该合约实现了OFT合约,在这里我们定义了目标链上的代币详细信息(例如名称、符号)。同样,也定义了一个委托地址。
(你可以删除项目中生成的 src/Counter.sol
、test/Counter.t.sol
和 script/Counter.s.sol
文件。)
部署与执行
步骤1:在 Sepolia 上部署 OFT 适配器
在项目根目录下创建一个 .env
文件,填入以下内容,并填写你的 PRIVATE_KEY
开始:
PRIVATE_KEY=
SEPOLIA_ADAPTER_ADDRESS=
BERACHAIN_OFT_ADDRESS=
我们将创建几个Foundry脚本来帮助部署。首先,创建 ./script/MyAdapter.s.sol
文件,并填入以下内容:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;
import {Script} from "forge-std/Script.sol";
import "../src/MyAdapter.sol";
contract MyAdapterScript is Script {
address constant UNI_TOKEN = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984;
address constant LAYERZERO_ENDPOINT =
0x6EDCE65403992e310A62460808c4b910D972f10f;
function run() public {
// Setup
uint256 privateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(privateKey);
// Deploy
MyAdapter myAdapter = new MyAdapter(
UNI_TOKEN,
LAYERZERO_ENDPOINT,
vm.addr(privateKey) // Address of private key
);
vm.stopBroadcast();
}
}
运行以下命令将在 Sepolia 测试网上部署 MyAdapter 合约。
(可选地添加标志 — etherscan-api-key YOUR_ETHERSCAN_API_KEY
— 用于验证合约):
# FROM: ./layerzero-oft
forge script script/MyAdapter.s.sol --rpc-url https://rpc.sepolia.org/ --broadcast
# [Example Output]:
# ##### sepolia
# ✅ [Success]Hash: 0x16702f69752f1f7243793202435da6bd54d2ebec89294728c2bf0d55584ed732
# Contract Address: 0xB66e0518570eA48286983322fc8F85301f955406
# Block: 5525968
# Paid: 0.007448778064556076 ETH (2482926 gas * 3.000000026 gwei)
在你的 .env
文件中将 SEPOLIA_ADAPTER_ADDRESS
更新为你部署的 MyAdapter 合约地址。
步骤2:在 Berachain 上部署 OFT
接下来,创建 ./script/MyOFT.s.sol
文件,并填入以下内容:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;
import {Script} from "forge-std/Script.sol";
import "../src/MyOFT.sol";
contract MyOFTScript is Script {
address constant LAYERZERO_ENDPOINT =
0x6EDCE65403992e310A62460808c4b910D972f10f;
uint32 constant SEPOLIA_ENDPOINT_ID = 40161;
function run() public {
// Setup
address SEPOLIA_ADAPTER_ADDRESS = vm.envAddress(
"SEPOLIA_ADAPTER_ADDRESS"
);
uint256 privateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(privateKey);
// Deploy
MyOFT myOFT = new MyOFT(
"Layer Zero UNI",
"lzUNI",
LAYERZERO_ENDPOINT,
vm.addr(privateKey) // Wallet address of signer
);
// Hook up Berachain OFT to Sepolia's adapter
myOFT.setPeer(
SEPOLIA_ENDPOINT_ID,
bytes32(uint256(uint160(SEPOLIA_ADAPTER_ADDRESS)))
);
vm.stopBroadcast();
}
}
接下来,执行你的脚本,以 1) 部署你的 OFT 合约到 Berachain,2) 使其识别 Sepolia 对应的合约:4o
# FROM: ./layerzero-oft
forge script script/MyOFT.s.sol --rpc-url https://bartio.rpc.berachain.com/ --broadcast
# [Example Output]
# ##### 80085
# ✅ [Success]Hash: 0x16cf8daa6f335fb65dedee8e722c01adb45b87aeccad0d6dc751d6c04c466a5f
# Contract Address: 0x42993d9A691636cbb23C201729b36B5C6e750733
# Block: 1147280
# Paid: 0.040444634965884468 ETH (2842719 gas * 14.227447372 gwei)
#
# ##### 80085
# ✅ [Success]Hash: 0xd670e01e028fe50d9e8c323007a777590d202fada28d80d6a9f9973abcb8b607
# Block: 1147281
# Paid: 0.000682799744815656 ETH (47666 gas * 14.324670516 gwei)
在你的 .env
文件中将 BERACHAIN_OFT_ADDRESS
更新为你部署的 MyOFT 合约地址。
步骤3:将代币从 Sepolia 桥接到 Berachain
现在,我们将把所有组件连接起来,并将 $UNI 从 Sepolia 桥接到 Berachain。
创建 ./script/Bridge.s.sol
文件,并填入以下内容:
pragma solidity ^0.8.22;
import "forge-std/Script.sol";
import {IOFT, SendParam} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol";
import {IOAppCore} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppCore.sol";
import {MessagingFee} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTCore.sol";
import {OptionsBuilder} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OptionsBuilder.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IAdapter is IOAppCore, IOFT {}
contract SendOFTScript is Script {
using OptionsBuilder for bytes;
uint32 constant BERACHAIN_ENPOINT_ID = 40291;
address constant SEPOLIA_UNI_ADDRESS =
0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984;
function run() external {
address SEPOLIA_ADAPTER_ADDRESS = vm.envAddress(
"SEPOLIA_ADAPTER_ADDRESS"
);
address BERACHAIN_OFT_ADDRESS = vm.envAddress("BERACHAIN_OFT_ADDRESS");
uint256 privateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(privateKey);
address signer = vm.addr(privateKey);
// Get the Adapter contract instance
IAdapter sepoliaAdapter = IAdapter(SEPOLIA_ADAPTER_ADDRESS);
// Hook up Sepolia Adapter to Berachain's OFT
sepoliaAdapter.setPeer(
BERACHAIN_ENPOINT_ID,
bytes32(uint256(uint160(BERACHAIN_OFT_ADDRESS)))
);
// Define the send parameters
uint256 tokensToSend = 0.0001 ether; // 0.0001 $UNI tokens
bytes memory options = OptionsBuilder
.newOptions()
.addExecutorLzReceiveOption(200000, 0);
SendParam memory sendParam = SendParam(
BERACHAIN_ENPOINT_ID,
bytes32(uint256(uint160(signer))),
tokensToSend,
tokensToSend,
options,
"",
""
);
// Quote the send fee
MessagingFee memory fee = sepoliaAdapter.quoteSend(sendParam, false);
console.log("Native fee: %d", fee.nativeFee);
// Approve the OFT contract to spend UNI tokens
IERC20(SEPOLIA_UNI_ADDRESS).approve(
SEPOLIA_ADAPTER_ADDRESS,
tokensToSend
);
// Send the tokens
sepoliaAdapter.send{value: fee.nativeFee}(sendParam, fee, signer);
console.log("Tokens bridged successfully!");
}
}
让我们分解一下这个脚本的作用:
- 首先,我们连接到已部署的 Sepolia Adapter 实例。
- 然后,我们调用
setPeer
方法,将 Berachain 上的 OFT 合约告知 Adapter。 - 定义选项,指定执行者为消息传递支付的 gas 数量(更多内容请阅读此处),准备消息负载,并为该交易请求费用报价。
- 我们批准 Adapter 合约支出我们的 $UNI 代币。
- 最后,调用 Adapter 的
send
方法,使用消息负载和费用发送交易。
使用以下命令运行脚本:
# FROM: ./layerzero-oft
forge script script/Bridge.s.sol --rpc-url https://rpc.sepolia.org/ --broadcast
等待片刻,LayerZero 执行者处理请求后,我们将在 Berachain 钱包中看到桥接的 $lzUNI 代币!
总结
恭喜你,已成功使用 LayerZero OFTs 将现有代币桥接到 Berachain 🎉
若想了解更多有关 OFTs 及跨链消息传递的功能,欢迎查阅 LayerZero 文档。
免责声明:OFT 和 OFT 适配器是为协议开发者提供的解决方案,用于将其协议的代币引入新链。未经授权的现有代币的 OFT 部署不太可能获得支持。
🐻 完整代码库
如果你想查看最终代码并浏览其他指南,请查看 Berachain LayerZero 指南代码。
https://github.com/berachain/guides/tree/main/apps/layerzero-oft
🛠️ 想构建更多项目吗?
如果你想在 Berachain 上构建更多项目并查看更多示例,请访问我们的 Berachain GitHub 指南库,其中包含各种实现方式,包括 NextJS、Hardhat、Viem、Foundry 等。
https://github.com/berachain/guides/tree/main
如果你想深入了解细节,请查看我们的 Berachain 文档。
寻求开发支持?
请务必加入我们的 Berachain Discord 服务器,并查看我们的开发者频道以提出问题。
❤️ 别忘了为这篇文章点赞呀~~ 👏🏼
原创文章,作者:Erica,如若转载,请注明出处:https://www.dappchaser.com/bridge-any-token-to-berachain-with-layerzero-v2-2/