本文介绍了如何使用 LayerZero 的 OFT (Omnichain Fungible Token) V2 版本,将 Sepolia 测试网上的 UNI 代币桥接到 Berachain。文章详细说明了在 Sepolia 上部署 OFT Adapter 合约,在 Berachain 上部署 OFT 合约,以及配置合约桥接代币的步骤,并提供了相关的 Foundry 脚本示例。
Omnichain Fungible Tokens(OFTs) 是一种由LayerZero首创的用于跨链资产的新 token 标准。OFT 允许可互换的 token 在不同的区块链之间转移,而无需资产包装或流动性池,同时保持统一的供应。
除其他改进外,这些更改增强了 omnichain 应用程序开发人员可用的可扩展性和自定义性。 有关更深入的了解,请参见这篇文章。**
$ETH
— 请参见 加粗 Sepolia 水龙头 (本指南中使用 0.0001)本指南需要安装 Foundry。 在终端窗口中,运行:
curl -L https://foundry.paradigm.xyz | bash;
foundryup;
## foundryup 安装了 'forge' 和 'cast' 二进制文件,稍后会用到
有关更多安装说明,请参见 Foundry 的安装指南。 有关在 Berachain 上使用 Foundry 的更多详细信息,请参见此指南。
首先,我们将使用 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
我们将利用与 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
token 从 Sepolia 桥接到 Berachain 的过程中涉及的交互:
交互概述
OFT Adapter
合约(由我们创建)上执行桥接交易$UNI
被锁定在 OFT Adapter
中$UNI
token 的指令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
合约,我们回顾一下,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的详细信息(例如name
,symbol
)。 同样,定义了一个delegate
。
(你可以删除与项目一起生成的src/Counter.sol
,test/Counter.t.sol
和script/Counter.s.sol
)。
在项目根目录创建一个/.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
。
接下来,创建./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
。
现在,我们将把所有组件绑在一起,并将 $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!");
}
}
让我们分解一下这个脚本的作用:
setPeer
以通知 Adapter 关于 Berachain 上的 OFT 合约fee
报价恭喜,你已使用 LayerZero OFT 成功地将现有 token 桥接到 Berachain 🎉
要了解有关 OFT 以及所有跨链消息传递功能的更多信息,我们邀请你查看 加粗 LayerZero 文档。
guides/apps/layerzero-oft at main · berachain/guides
- 原文链接: medium.com/berachain-dev...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!