Berachain上でPyth Entropyを使用した公平なランダムNFTミント [Berachain翻訳]


:::note info
本記事は下記の翻訳となります。
[『Fair Random NFT Mints with Pyth Entropy on Berachain』](https://blog.berachain.com/blog/fair-random-nft-mints-with-pyth-entropy-on-berachain)
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1926720/f9afbe57-d1b4-f221-50ee-85a5879d85aa.png)

### Pyth を使用したオンデマンド価格フィードの構築 🔮

オラクルは、ブロックチェーンを実世界と接続する役割を果たします。既存のオラクルパラダイムは、オラクル運営者が継続的に価格更新をオンチェーンにプッシュする（および関連する手数料を支払う）ことを中心に展開されています。これは、価格フィードとサポートされるチェーンの数が増加するにつれて、スケールが悪化する可能性があります。

[**_Pyth Network_**](https://pyth.network/?ref=berachain.ghost.io)は、**オンデマンド**の価格更新を使用してこのトレードオフを解消することを目指しています。ユーザーは*必要な時にのみ*オンチェーン価格を取得します - 詳細は[こちら](https://pyth.network/blog/pyth-a-new-model-to-the-price-oracle?ref=berachain.ghost.io)をご覧ください。

**この記事では、Pyth オラクルを活用して ETH/USD 価格フィードを利用するスマートコントラクトを作成するプロセスについて説明します。**

![](https://berachain.ghost.io/content/images/2024/05/1-hh7ij7r11xhj1kspitqmtq.png)

相互作用の概要

### 📋 要件

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

- NodeJS `v20.11.0` 以上
- [pnpm](https://pnpm.io/installation?ref=berachain.ghost.io)
- [jq](https://jqlang.github.io/jq/download/?ref=berachain.ghost.io) - JSON データの処理に使用
- [**Berachain Artio Network**](https://docs.berachain.com/developers/?ref=berachain.ghost.io)で設定されたウォレット
- そのウォレット内の`$BERA`または Berachain Testnet トークン - [**_Berachain Faucet_**](http://artio.faucet.berachain.com/?ref=berachain.ghost.io)を参照

#### Foundry

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

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

foundryup;
# foundryupは'forge'と'cast'バイナリをインストールします（後で使用）
```

インストールの詳細については、Foundry の[インストールガイド](https://book.getfoundry.sh/getting-started/installation?ref=berachain.ghost.io)を参照してください。Berachain で Foundry を使用する詳細については、この[ガイド](https://docs.berachain.com/developers/guides/create-erc20-contract-using-foundry?ref=berachain.ghost.io)を参照してください。

### Pyth Oracle プロジェクトの作成

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

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

```bash
forge init pyth-oracle --no-git --no-commit;

cd pyth-oracle;

# 以下の基本的なレイアウトが表示されます
# .
# ├── foundry.toml
# ├── script
# │   └── Counter.s.sol
# ├── src
# │   └── Counter.sol
# └── test
#     └── Counter.t.sol
```

#### Pyth の依存関係のインストール

Pyth のコントラクトを活用するため、まず Pyth のコントラクトインターフェースを node 依存関係としてインストールする必要があります：

```bash
# FROM: ./pyth-oracle

pnpm init;
pnpm add @pythnetwork/pyth-sdk-solidity;
```

Forge はインポートをより読みやすくするために依存関係を再マップできます。Pyth のインポートを再マップしましょう：

```bash
# FROM: ./pyth-oracle

echo "remappings = ['@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity']" >> ./foundry.toml
```

#### Oracle コンシューマーコントラクトの作成

これで Solidity スマートコントラクトで Pyth 価格フィードを利用するエキサイティングな部分に入ることができます。

新しいファイル`./src/ConsumerContract.sol`を作成し、以下を貼り付けます：

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";

contract ConsumerContract {
    IPyth pyth;

    /**
     * Network: Berachain Artio (testnet)
     * Address: 0x8D254a21b3C86D32F7179855531CE99164721933
     */
    constructor() {
        pyth = IPyth(0x8D254a21b3C86D32F7179855531CE99164721933);
    }

    function updatePrice(bytes[] calldata priceUpdateData) public payable {
        uint fee = pyth.getUpdateFee(priceUpdateData);
        pyth.updatePriceFeeds{value: fee}(priceUpdateData);
    }

    function getPrice() public view returns (PythStructs.Price memory) {
        // ETH/USD priceID
        bytes32 priceID = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
        return pyth.getPrice(priceID);
    }

    function getLatestPrice(
        bytes[] calldata priceUpdateData
    ) public payable returns (PythStructs.Price memory) {
        updatePrice(priceUpdateData);
        return getPrice();
    }
}
```

これを詳しく見ていきましょう：

まず、デプロイされた Pyth オラクルコントラクトと対話するためのインターフェースを提供する`IPyth`と`PythStructs`を**インポート**します。[Pyth SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity?ref=berachain.ghost.io)の使用に関する詳細情報をご覧ください。

**コンストラクタ**では、Berachain Artio Testnet にデプロイされた[`0x8D254a21b3C86D32F7179855531CE99164721933`](https://artio.beratrail.io/address/0x8D254a21b3C86D32F7179855531CE99164721933/contract/80085/code?ref=berachain.ghost.io)の Pyth オラクルに`pyth`インスタンスを接続します。

`**updatePrice**`関数は、Pyth がオフチェーンでストリーミングする署名付き価格更新である`priceUpdateData`を入力として受け取ります（後述）。

価格更新の後、`**getPrice()**`を呼び出すことができ、これは要求された`priceId`に対応する`Price`オブジェクトを返します。ここでは、Pyth の`ETH/USD`価格フィードに対応する`0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace`という`priceId`を使用しています。利用可能なフィードの完全なリストは[**こちら**](https://pyth.network/developers/price-feed-ids?ref=berachain.ghost.io)をご覧ください。

`getLatestPrice`は上記の 2 つの呼び出しを単に集約したものです。

（プロジェクトと共に生成された`src/Counter.sol`、`test/Counter.t.sol`、`script/Counter.s.sol`は削除してかまいません）

### スマートコントラクトのデプロイ

Berachain にコントラクトをデプロイする準備がほぼ整いました。まず、デプロイメント用のウォレットをセットアップする必要があります。

#### デプロイメントの準備

以下を実行して、ウォレットの秘密鍵を Foundry のキーストアに`deployer`エイリアスでインポートします：

```bash
cast wallet import deployer --interactive;

# [出力例]
# Enter private key:
# Enter password:
# `deployer` keystore was saved successfully. Address: <YOUR_WALLET_ADDRESS>
```

以下を実行して、ウォレットが正しくインポートされたことを確認します：

```bash
cast wallet list;

# [出力例]
# deployer (Local)
```

Berachain RPC をターミナルセッションにロードしましょう：

```bash
export BERACHAIN_ARTIO_RPC="https://rpc.ankr.com/berachain_testnet"
```

#### Berachain Testnet へのデプロイ

まず、スマートコントラクトをコンパイルします：

```bash
# FROM: ./pyth-oracle

forge build;
```

`./out`ディレクトリに多くのビルド出力が表示されることに気付くでしょう。

新しいコントラクトを Berachain Testnet にデプロイするために`forge create`コマンドを使用します（コマンドの詳細については[こちら](https://book.getfoundry.sh/reference/forge/forge-create?ref=berachain.ghost.io)を参照）：

```bash
# FROM: ./pyth-oracle

forge create ./src/ConsumerContract.sol:ConsumerContract --rpc-url $BERACHAIN_ARTIO_RPC --account deployer

# [期待される類似の出力]:
# Enter keystore password:
# Deployer: 0x529CA3A690E1bB4e9F04d132bd99D4398f626A44
# Deployed to: 0x9106b2041C896224Af2142ea9C7349aa283Df7C6
# Transaction hash: 0xc8efdd3132080491b42c469fb2219bc6f0432981a46cdd3f6ae73b9e834ff4e4
```

**デプロイされたコントラクトアドレスをメモしておいてください**、次のセクションで必要になります。

先ほど設定したキーストアのパスワードを入力するよう求められます。デプロイメント手数料を支払うために$BERA が必要です。フォーセットの資金は[https://artio.faucet.berachain.com/](https://artio.faucet.berachain.com/?ref=berachain.ghost.io)で入手可能です。

### スマートコントラクトとの対話

最後に、デプロイしたスマートコントラクト内から`ETH/USD`価格を取得します。

`updatePrice`を呼び出す前に`priceUpdateData`を取得する必要があったことを思い出してください。このペイロードは[Hermes](https://github.com/pyth-network/pyth-crosschain/tree/main/hermes?ref=berachain.ghost.io)を使用して取得します。これは、Pyth Network の価格更新をリッスンし、REST API を介して提供する Web サービスです。

`ETH/USD` priceId を使用して`priceUpdateData`を取得するリクエストを行います：

```bash
# FROM: ./pyth-oracle

curl -s "https://hermes.pyth.network/v2/updates/price/latest?&ids[]=0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace" | jq -r ".binary.data[0]" > price_update.txt
```

`jq`ユーティリティは出力を`price_update.txt`ファイルに書き込むために使用され、後で簡単に取得できるようになります。

このデータを入手したら、以下のコマンドで`updatePrice`を呼び出すことができます。Pyth から受け取ったペイロードを渡し、プレースホルダーをデプロイしたコントラクトに置き換えます：

```bash
# FROM: ./pyth-oracle

cast send <YOUR_DEPLOYED_CONTRACT> --rpc-url $BERACHAIN_ARTIO_RPC "updatePrice(bytes[])" "[0x`cat price_update.txt`]" --account deployer --value 0.0001ether

# [期待される類似の出力]:
# blockHash               0xf00e38ea8197d088973dc51502b9fb62d089ac31b6fe01002e83a969e9c05f93
# blockNumber             1037572
# contractAddress
# cumulativeGasUsed       208351
# effectiveGasPrice       3000000017
# from                    0x529CA3A690E1bB4e9F04d132bd99D4398f626A44
# ...
```

次に、`getPrice()`で価格を照会します：

```bash
cast call <YOUR_DEPLOYED_CONTRACT> --rpc-url $BERACHAIN_ARTIO_RPC "getPrice()"

# [期待される類似の出力]
# 0x0000000000000000000000000000000000000000000000000000005eb4cf6d2800000000000000000000000000000000000000000000000000000000130c6cd8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000065ef9853
```

これは、Solidity の`Price`構造体（`./pyth-oracle/lib/pyth-sdk-solidity/PythStructs.sol`から）の観点から`ETH/USD`価格を提供します：

```solidity
struct Price {
    // Price
    int64 price;
    // Confidence interval around the price
    uint64 conf;
    // Price exponent
    int32 expo;
    // Unix timestamp describing when the price was published
    uint publishTime;
}
```

16 進数の出力を人間が読める形式にデコードするには、以下の`abi-decode`コマンドを使用できます：

```bash
# FROM: ./pyth-oracle

cast abi-decode "getPrice()(int64,uint64,int32,uint)" <YOUR_GETPRICE_OUTPUT>

# [ETH/USDフィードのデコード出力例]
# 406760418600 [4.067e11]
# 319581400 [3.195e8]
# -8
# 1710200915 [1.71e9]
```

#### トラブルシューティング

- 十分に早く行動しないと、`StalePrice`エラーを表す`0x19abf40e`というエラーに遭遇する可能性があります。これは`price_update.txt`がコントラクトで使用するには古すぎたことを意味します。このサブセクションのコマンドのシーケンスを再実行して再試行してください。
- エラーコード`0x025dbdd4`は`InsufficientFee`エラーを表します。`updatePrice`呼び出しの$BERA 値を例えば`0.0005ether`に引き上げてみてください。

### まとめ

おめでとうございます！Berachain Testnet で Pyth オラクルから価格データを取得するスマートコントラクトの開発に成功しました 🎉

---

### 🐻 完全なコードリポジトリ

最終的なコードを確認し、他のガイドを見たい場合は、[**_Berachain Pyth Guide Code_**](https://github.com/berachain/guides/tree/main/apps/pyth-oracle?ref=berachain.ghost.io)をチェックしてください。

### 🛠️ さらに構築したい場合は？

Berachain でさらに構築し、より多くの例を見たい場合は、[**_Berachain GitHub Guides リポジトリ_**](https://github.com/berachain/guides?ref=berachain.ghost.io)をご覧ください。NextJS、Hardhat、Viem、Foundry などを含む、幅広い実装例があります。

より詳細な情報を探索したい場合は、[**_Berachain Docs_**](https://docs.berachain.com/?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)

:::

```

```