LayerZero V2であらゆるトークンをBerachainにブリッジする [Berachain翻訳]


:::note info
本記事は下記の翻訳となります。
[『Bridge any Token to Berachain with LayerZero V2』](https://blog.berachain.com/blog/bridge-any-token-to-berachain-with-layerzero-v2-2)
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1926720/73e4a7db-a77c-4cee-dab7-97829dfa4119.png)

### OFT の紹介

**_Omnichain Fungible Tokens_**（OFT）は、クロスチェーンアセットのために[**LayerZero**](https://layerzero.network/?ref=berachain.ghost.io)によって開拓された新しいトークン規格です。OFT を使用すると、アセットのラッピングや流動性プールの必要なく、異なるブロックチェーン間で代替可能なトークンを転送することができます。また、統一された供給を維持することも可能です。

LayerZero は汎用のクロスチェーンメッセージングプロトコルですが、この記事では、特に OFT のブリッジングアプリケーションに焦点を当てます。

#### LayerZero V2

LayerZero V2 は 2024 年 1 月に発表され、メッセージの検証と実行を分離することで重要なアップグレードをもたらしました（これらは LayerZero V1 では[リレーヤー](https://layerzero.gitbook.io/docs/ecosystem/relayer/layerzero-relayer?ref=berachain.ghost.io)を使用してバンドルされていました）：

- アプリケーション所有者は、メッセージペイロードを検証するための[分散型検証ネットワーク](https://docs.layerzero.network/v2/home/modular-security/security-stack-dvns?ref=berachain.ghost.io)（DVN）のセットを選択できます。
- 宛先チェーンでのメッセージの実行は[Executors](https://docs.layerzero.network/explore/executors?ref=berachain.ghost.io)によって処理されます。

その他の改善点に加えて、これらの変更により、オムニチェーンアプリの開発者に対してスケーラビリティとカスタマイズ性が向上しました。詳細は、この[**_記事_**](https://medium.com/layerzero-official/layerzero-v2-deep-dive-869f93e09850?ref=berachain.ghost.io)をご覧ください。

**_この記事では、LayerZero OFT を使用して、Sepolia Testnet から Berachain Testnet に`$UNI`トークンをブリッジする方法を紹介します。_**

### 📋 必要要件

次に進む前に、コンピュータに以下のものがインストールされ、設定されていることを確認してください。

- Node `v20.11.0`以上
- [pnpm](https://pnpm.io/installation?ref=berachain.ghost.io)
- [**Berachain bArtio Network**](https://docs.berachain.com/developers/network-configurations?ref=berachain.ghost.io)と[**Sepolia Testnet**](https://moralis.io/how-to-add-the-sepolia-network-to-metamask-full-guide/?ref=berachain.ghost.io#:~:text=Sepolia%20test-,network,-New%20RPC%20URL)が設定されたウォレット
- そのウォレットに`$BERA`または Berachain Testnet トークンがあること  — [**_Berachain Faucet_**](https://bartio.faucet.berachain.com/?ref=berachain.ghost.io)を参照してください
- そのウォレットに Sepolia Testnet の`$ETH`があること  — [**_Sepolia Faucet_**](https://faucet.quicknode.com/ethereum/sepolia?ref=berachain.ghost.io)を参照してください
- Sepolia の`$UNI`を取得すること  — [**_Uniswap_**](https://app.uniswap.org/swap?outputCurrency=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&inputCurrency=ETH&ref=berachain.ghost.io)を参照してください（このガイドでは 0.0001 を使用します）

### Foundry

このガイドでは Foundry のインストールが必要です。ターミナルウィンドウで次のコマンドを実行してください。

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

foundryup;
# foundryup installs the 'forge' and 'cast' binaries, used later
```

For more installation instructions, see Foundry’s [installation guide](https://book.getfoundry.sh/getting-started/installation?ref=berachain.ghost.io). For more details using Foundry on Berachain, see this [guide](https://docs.berachain.com/developers/guides/create-erc20-contract-using-foundry?ref=berachain.ghost.io).

### LayerZero プロジェクトの作成

まず、Foundry を使用して開発環境をセットアップします。

新しいプロジェクトフォルダを作成し、Foundry を初期化します：

```terminal
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](https://docs.layerzero.network/contracts/overview?ref=berachain.ghost.io)と[OpenZeppelin](https://docs.openzeppelin.com/contracts/5.x/?ref=berachain.ghost.io)のツールに関連するいくつかの依存関係を利用しますので、以下のコマンドでインストールしてください:

```terminal
# 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`の内容を以下のように置き換えて、依存関係を再マッピングします:

```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/',
]
```

### インタラクションの概要

コントラクトを書く前に、Sepolia から Berachain への`$UNI`トークンのブリッジングプロセスに関与するインタラクションについて簡単に説明しましょう：

![](https://super-translator.inaridiy.workers.dev/assets/image/5759b9c6-6c68-47f7-b8dc-e87780bab428)
_Overview of Interactions_

1. ユーザーはソースチェーン上で、私たちが作成した`OFT Adapter`コントラクトに対してブリッジのトランザクションを実行します。
2. `$UNI`トークンは`OFT Adapter`にロックされます。
3. LayerZero エンドポイント契約は、Destination Chain 上で`$UNI`トークンを作成するための指示を含むメッセージを送信します。
4. メッセージは DVN によって検証されます。
5. エグゼキューターは、Destination Chain 上のエンドポイント契約に対して`lzReceive()`を呼び出し、メッセージを受け取ります。
6. `$lzUNI`（私たちが作成した OFT）が作成され、ユーザーに送信されます。

### スマートコントラクトの作成

上記のプロセスを両方のソースチェーンとデスティネーションチェーンの両方で実行するために、いくつかのスマートコントラクトのデプロイが必要です。

新しいファイル `./src/MyAdapter.sol` を作成し、以下のコードを貼り付けてください:

```solidity
// 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 アダプターについての詳細は[**_こちら_**](https://docs.layerzero.network/contracts/oft-adapter?ref=berachain.ghost.io)をご覧ください。

さらに、`delegate` コントラクトが設定されており、このアドレスに設定の変更などの重要なタスクを処理する権限が与えられています。

次に、ファイル `./src/MyOFT.sol` を作成し、以下のコードを貼り付けてください:

```solidity
// 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` コントラクトを実装し、**デスティネーションチェーン**上でトークンの詳細（例: `name`、`symbol`）を定義する場所です。再度、`delegate` が定義されています。

（プロジェクトで生成された `src/Counter.sol`、`test/Counter.t.sol`、`script/Counter.s.sol` を削除しても構いません）。

### デプロイと実行

#### **ステップ 1: OFT アダプタを Sepolia にデプロイする**

以下の内容でプロジェクトのルートに`/.env`ファイルを作成し、`PRIVATE_KEY`を入力してください。

```text
PRIVATE_KEY=
SEPOLIA_ADAPTER_ADDRESS=
BERACHAIN_OFT_ADDRESS=
```

デプロイをサポートするために、いくつかの Foundry スクリプトを作成します。まず、`./script/MyAdapter.s.sol`を作成し、以下の内容で埋めてください。

```solidity
// 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();
    }
}
```

以下のコマンドを実行すると、`MyAdapter`コントラクトが Sepolia Testnet にデプロイされます。

（オプションでフラグ`— etherscan-api-key YOUR_ETHERSCAN_API_KEY — verify`を追加してコントラクトを検証することもできます）。

```terminal
# 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：OFT を Berachain にデプロイする

次に、`./script/MyOFT.s.sol` を作成し、その中に以下を入力します：

```solidity
// 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 ピアコントラクトを認識させます：

```terminal
# 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`を作成し、次のように入力してください：

```solidity
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!");
    }
}
```

1. まず、デプロイされた Sepolia アダプターのインスタンスに接続します。
2. 次に、`setPeer`を呼び出して、Berachain にある OFT コントラクトの情報をアダプターに伝えます。
3. オプションを定義して、Executor がメッセージ配信に支払うガス量を設定します（詳細は[**_こちら_**](https://docs.layerzero.network/contracts/options?ref=berachain.ghost.io)を参照）。また、メッセージペイロードを準備し、このトランザクションの`fee`（手数料）の見積もりを要求します。
4. アダプターコントラクトに対して、私たちの`$UNI`トークンを使用する権限を与えます。
5. 最後に、アダプターの`send`メソッドを、メッセージペイロードと`fee`を引数として呼び出します。

以下のコマンドでスクリプトを実行します：

```terminal
# FROM: ./layerzero-oft

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

しばらくすると、LayerZero の Executor がリクエストを処理し、ブリッジされた `$lzUNI` トークンが Berachain のウォレットに表示されます！

![](https://super-translator.inaridiy.workers.dev/assets/image/3df0fdec-b654-43e2-a6cc-20a0b87980a2)

### まとめ

おめでとうございます！LayerZero OFTs を使用して、既存のトークンを Berachain へ成功裏にブリッジしました 🎉

OFTs やクロスチェーンメッセージングが可能にするすべてについてさらに学びたい場合は、ぜひ[**_LayerZero のドキュメント_**](https://docs.layerzero.network/contracts/overview?ref=berachain.ghost.io)をご覧ください。

**_Disclaimer:_ OFT と OFT アダプターは、プロトコル開発者が自身のプロトコルのトークンを新しいチェーンに展開するためのソリューションです。既存トークンの非公認 OFT デプロイメントは、サポートを得られる可能性が低いでしょう。**

---

### 🐻 Full Code Repository

最終的なコードや他のガイドを見たい場合は、[**_Berachain LayerZero Guide Code_**](https://github.com/berachain/guides/tree/main/apps/layerzero-oft?ref=berachain.ghost.io)を参照してください。
[**_Berachain GitHub Guides Repo_**](https://github.com/berachain/guides?ref=berachain.ghost.io)
https://github.com/berachain/guides/tree/main/apps/pyth-oracle?ref=berachain.ghost.io

### 開発者サポートをお探しですか？

質問をするために、[**_Berachain Discord_**](https://discord.com/invite/berachain?ref=berachain.ghost.io)サーバーに参加し、開発者チャンネルをチェックしてください。

## ❤️ この記事に対して愛を示すのを忘れないでください 👏🏼

---

---

:::note info
【Sunrise とは】
Sunrise は Proof of Liquidity(PoL)と Fee Abstraction（手数料抽象化）を備えたデータ可用性レイヤーです。 私たちは DA の体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。

- [Sunrise - Specialized DA Layer for Proof of Liquidity](https://sunriselayer.io/)
- [Sunrise / Gluon Docs](https://docs.sunriselayer.io/)

【Social Links】

- [X(旧 Twitter)[英語])](https://twitter.com/SunriseLayer)
- [X(旧 Twitter)[日本語])](https://twitter.com/SunriseLayer)
- [Discord Community](https://discord.com/invite/sunrise)
- [Medium](https://sunriselayer.medium.com/)
- [Github](https://github.com/sunriselayer)
- [Linkedin](https://www.linkedin.com/company/sunriselayer)

【お問合せ】
Sunrise へのお問い合わせはこちらから 👉 [Google Form](https://forms.gle/h8RVahxRtXUvYwnv6)

![1080x360.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839047/8971d83b-3331-4757-dc72-320d28618735.jpeg)

:::