使用 LayerZero V2 将任何代币桥接到 Berachain

本文介绍了如何使用 LayerZero 的 OFT (Omnichain Fungible Token) V2 版本,将 Sepolia 测试网上的 UNI 代币桥接到 Berachain。文章详细说明了在 Sepolia 上部署 OFT Adapter 合约,在 Berachain 上部署 OFT 合约,以及配置合约桥接代币的步骤,并提供了相关的 Foundry 脚本示例。

使用 LayerZero V2 部署 Omnichain Token

OFT 简介

Omnichain Fungible Tokens(OFTs) 是一种由LayerZero首创的用于跨链资产的新 token 标准。OFT 允许可互换的 token 在不同的区块链之间转移,而无需资产包装或流动性池,同时保持统一的供应。

除其他改进外,这些更改增强了 omnichain 应用程序开发人员可用的可扩展性和自定义性。 有关更深入的了解,请参见这篇文章。**

Foundry

本指南需要安装 Foundry。 在终端窗口中,运行:

curl -L https://foundry.paradigm.xyz | bash;

foundryup;
## foundryup 安装了 'forge' 和 'cast' 二进制文件,稍后会用到

有关更多安装说明,请参见 Foundry 的安装指南。 有关在 Berachain 上使用 Foundry 的更多详细信息,请参见此指南

创建我们的 LayerZero 项目

首先,我们将使用 Foundry 设置你的开发环境。

首先,创建一个新的项目文件夹并初始化 Foundry:

forge init layerzero-oft --no-git --no-commit;

cd layerzero-oft;
## 我们观察到以下基本布局
## .
## ├── foundry.toml
## ├── script
## │   └── Counter.s.sol
## ├── src
## │   └── Counter.sol
## └── test
##     └── Counter.t.sol

安装依赖

我们将利用与 LayerZeroOpenZeppelin 工具相关的许多依赖项,因此请在下面安装它们:

## 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 token 从 Sepolia 桥接到 Berachain 的过程中涉及的交互:

交互概述

  1. 在源链上,用户在 OFT Adapter 合约(由我们创建)上执行桥接交易
  2. $UNI 被锁定在 OFT Adapter
  3. LayerZero Endpoint 合约发送一条消息,其中包含在目标链上铸造 $UNI token 的指令
  4. 该消息由 DVN 验证
  5. 执行器在目标链上的 Endpoint 合约上调用 lzReceive(),接收消息
  6. $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合约,我们回顾一下,OFTAdapter 合约是源链上负责锁定 token 并将跨链功能扩展到现有 token 的合约。 在这里了解更多关于 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合约,我们将在目标链上定义token的详细信息(例如namesymbol)。 同样,定义了一个delegate

(你可以删除与项目一起生成的src/Counter.soltest/Counter.t.solscript/Counter.s.sol)。

部署和执行

步骤 1:将 OFT Adapter 部署到 Sepolia

在项目根目录创建一个/.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 --verify来验证合约):

## FROM: ./layerzero-oft

forge script script/MyAdapter.s.sol --rpc-url https://rpc.sepolia.org/ --broadcast

## [示例输出]:
## ##### sepolia
## ✅  [成功]哈希:0x16702f69752f1f7243793202435da6bd54d2ebec89294728c2bf0d55584ed732
## 合约地址:0xB66e0518570eA48286983322fc8F85301f955406
## 区块:5525968
## 已支付:0.007448778064556076 ETH(2482926 gas * 3.000000026 gwei)

使用MyAdapter部署的地址更新.env文件中的SEPOLIA_ADAPTER_ADDRESS

步骤 2:将 OFT 部署到 Berachain

接下来,创建./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 对等合约:

## FROM: ./layerzero-oft

forge script script/MyOFT.s.sol --rpc-url https://artio.rpc.berachain.com/ --broadcast

## [示例输出]
## ##### 80085
## ✅  [成功]哈希:0x16cf8daa6f335fb65dedee8e722c01adb45b87aeccad0d6dc751d6c04c466a5f
## 合约地址:0x42993d9A691636cbb23C201729b36B5C6e750733
## 区块:1147280
## 已支付:0.040444634965884468 ETH(2842719 gas * 14.227447372 gwei)

## ##### 80085
## ✅  [成功]哈希:0xd670e01e028fe50d9e8c323007a777590d202fada28d80d6a9f9973abcb8b607
## 区块:1147281
## 已支付:0.000682799744815656 ETH(47666 gas * 14.324670516 gwei)

使用MyOFT部署的地址更新.env文件中的BERACHAIN_OFT_ADDRESS

步骤 3:将 Token 从 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 = 40256;
    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以通知 Adapter 关于 Berachain 上的 OFT 合约
  • 定义选项以定义 Executor 为消息传递支付的 gas 金额(阅读更多加粗这里),准备消息负载,并为此交易请求fee报价

总结

恭喜,你已使用 LayerZero OFT 成功地将现有 token 桥接到 Berachain 🎉

要了解有关 OFT 以及所有跨链消息传递功能的更多信息,我们邀请你查看 加粗 LayerZero 文档

guides/apps/layerzero-oft at main · berachain/guides

  • 原文链接: medium.com/berachain-dev...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
bearythecucumber
bearythecucumber
江湖只有他的大名,没有他的介绍。