本記事は下記の翻訳となります。
『Query Price Data on Berachain using Pyth Price Feeds』
Pyth を使用してオンデマンド価格フィードを構築する 🔮
オラクルは、ブロックチェーンと現実世界をつなぐ役割を果たします。既存のオラクルのパラダイムは、オラクルオペレータが連続して価格の更新をオンチェーンにプッシュし(関連する手数料を支払う)、価格フィードとサポートされるチェーンの数が増えるとスケーリングが悪化する可能性があります。
Pyth Networkは、ユーザーが必要な時にのみオンチェーンの価格を取得することで、このトレードオフを解消することを目指しています。詳細はこちらをご覧ください。
この記事では、Pyth オラクルを活用して ETH/USD 価格フィードを消費するスマートコントラクトの作成手順を案内します。
📋 要件
次に進む前に、コンピュータに以下のものがインストールされ、セットアップされていることを確認してください。
- NodeJS
v20.11.0
以上 - pnpm
- jq — JSON データの処理に使用します
- Berachain Artio Networkで構成されたウォレット
- そのウォレットに
$BERA
または Berachain テストネットトークンがあること — Berachain Faucetを参照してください
Foundry
このガイドでは Foundry のインストールが必要です。ターミナルウィンドウで次のコマンドを実行してください。
curl -L https://foundry.paradigm.xyz | bash;
foundryup;
# foundryup installs the 'forge' and 'cast' binaries, used later
インストール手順の詳細については、Foundry のインストールガイドを参照してください。Berachain で Foundry を使用する詳細については、このガイドを参照してください。
Pyth Oracle プロジェクトの作成
まず、Foundry を使用して開発環境をセットアップします。
新しいプロジェクトフォルダを作成し、Foundry を初期化します:
forge init pyth-oracle --no-git --no-commit;
cd pyth-oracle;
# We observe the following basic layout
# .
# ├── foundry.toml
# ├── script
# │ └── Counter.s.sol
# ├── src
# │ └── Counter.sol
# └── test
# └── Counter.t.sol
Pyth の依存関係のインストール
Pyth のコントラクトを利用するために、まず Pyth のコントラクトインターフェースをノードの依存関係としてインストールする必要があります。
# FROM: ./pyth-oracle
pnpm init;
pnpm add @pythnetwork/pyth-sdk-solidity;
Forge は依存関係を remap して、インポートをより読みやすくすることができます。したがって、Pyth のインポートを remap しましょう:
# FROM: ./pyth-oracle
echo "remappings = ['@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity']" >> ./foundry.toml
Oracle Consumer コントラクトの作成
さあ、Solidity スマートコントラクトで Pyth の価格フィードを消費するエキサイティングな部分に入っていきましょう。
新しいファイル ./src/ConsumerContract.sol
を作成し、以下のコードを貼り付けてください。
// 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();
}
}
さて、これを詳しく見ていきましょう。
まず、IPyth
とPythStructs
をimportしています。これにより、デプロイされた Pyth オラクルコントラクトとのやり取りのためのインターフェースが提供されます。Pyth SDKの使用方法についての詳細は、こちらをご覧ください。
constructorでは、Berachain Artio テストネット上に展開された Pyth オラクルにpyth
インスタンスを接続しています。アドレスは0x8D254a21b3C86D32F7179855531CE99164721933
です。
**updatePrice**
関数は、Pyth オフチェーンからストリーミングされる署名付き価格更新データであるpriceUpdateData
を入力として受け取ります(後述)。
価格の更新後には、**getPrice()**
を呼び出すことができます。これにより、要求されたpriceId
に対応するPrice
オブジェクトが返されます。ここでは、priceId
として0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace
を使用しています。使用可能なフィードの完全なリストについては、こちらをご覧ください。
getLatestPrice
は、上記の 2 つの呼び出しを単純に集約しています。
(プロジェクトで生成されたsrc/Counter.sol
、test/Counter.t.sol
、script/Counter.s.sol
を削除しても構いません)
スマートコントラクトのデプロイ
Berachain にコントラクトをデプロイする準備がほぼ整いました。まず、デプロイに使用するウォレットを設定する必要があります。
デプロイの準備
次のコマンドを実行して、ウォレットの秘密鍵を Foundry のキーストアに(deployer
エイリアスで)インポートします:
cast wallet import deployer --interactive;
# [Example Output]
# Enter private key:
# Enter password:
# `deployer` keystore was saved successfully. Address: <YOUR_WALLET_ADDRESS>
ウォレットがインポートされたことを確認するには、次のコマンドを実行してください:
cast wallet list;
# [Example Output]
# deployer (Local)
ターミナルセッションに Berachain RPC をロードしましょう:
export BERACHAIN_ARTIO_RPC="https://rpc.ankr.com/berachain_testnet"
Berachain テストネットへのデプロイ
まず、スマートコントラクトをコンパイルします:
# FROM: ./pyth-oracle
forge build;
./out
ディレクトリにいくつかのビルド出力が表示されることに気付くでしょう。
新しいコントラクトを Berachain Testnet に展開するために、forge create
コマンドを利用します(コマンドの詳細はこちらを参照してください):
# FROM: ./pyth-oracle
forge create ./src/ConsumerContract.sol:ConsumerContract --rpc-url $BERACHAIN_ARTIO_RPC --account deployer
# [Expected Similar Output]:
# Enter keystore password:
# Deployer: 0x529CA3A690E1bB4e9F04d132bd99D4398f626A44
# Deployed to: 0x9106b2041C896224Af2142ea9C7349aa283Df7C6
# Transaction hash: 0xc8efdd3132080491b42c469fb2219bc6f0432981a46cdd3f6ae73b9e834ff4e4
Take note of the deployed contract address, 次のセクションで必要になります。
先に設定したキーストアパスワードの入力を求められます。デプロイメント費用の支払いに$BERA が必要です。Faucet 資金はhttps://artio.faucet.berachain.com/で入手できます。
スマートコントラクトとのやり取り
最後に、デプロイされたスマートコントラクトからETH/USD
の価格を取得します。
updatePrice
を呼び出す前に、priceUpdateData
を取得する必要がありました。これは、Hermesを使用して取得します。Hermes は、Pyth Network から価格の更新を受信し、REST API を介して提供するウェブサービスです。
ETH/USD
の priceId を使用して、priceUpdateData
を取得するためのリクエストを行います:
# 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 から受け取ったペイロードを使用し、デプロイされたコントラクトでプレースホルダーを置き換えます。
# 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
# [Expected Similar Output]:
# blockHash 0xf00e38ea8197d088973dc51502b9fb62d089ac31b6fe01002e83a969e9c05f93
# blockNumber 1037572
# contractAddress
# cumulativeGasUsed 208351
# effectiveGasPrice 3000000017
# from 0x529CA3A690E1bB4e9F04d132bd99D4398f626A44
# ...
次に、getPrice()
で価格をクエリします:
cast call <YOUR_DEPLOYED_CONTRACT> --rpc-url $BERACHAIN_ARTIO_RPC "getPrice()"
# [Expected Similar Output]
# 0x0000000000000000000000000000000000000000000000000000005eb4cf6d2800000000000000000000000000000000000000000000000000000000130c6cd8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000065ef9853
これは、Solidity の Price
構造体 (./pyth-oracle/lib/pyth-sdk-solidity/PythStructs.sol
から) の ETH/USD
価格を提供します:
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
コマンドを使うことができます:
# FROM: ./pyth-oracle
cast abi-decode "getPrice()(int64,uint64,int32,uint)" <YOUR_GETPRICE_OUTPUT>
# [Example Decoded Output of ETH/USD Feed]
# 406760418600 [4.067e11]
# 319581400 [3.195e8]
# -8
# 1710200915 [1.71e9]
トラブルシューティング
-
素早く行動しないと、
0x19abf40e
というエラーコードに遭遇する可能性があります。これはStalePrice
(古い価格)エラーを表しており、price_update.txt
ファイルの内容が古すぎてコントラクトで使用できなかったことを意味します。このような場合は、このサブセクションのコマンド手順を再度実行してリトライしてください。 -
エラーコード
0x025dbdd4
はInsufficientFee
(手数料不足)エラーを表しています。この場合、updatePrice
呼び出し時の$BERA 値を増やしてみてください。例えば、0.0005ether
に上げてみるのがよいでしょう。
まとめ
おめでとうございます!あなたは、Berachain Testnet 上の Pyth オラクルから価格データを引き出すスマートコントラクトのデプロイに成功しました 🎉。
🐻 Full Code Repository
最終的なコードや他のガイドを見たい場合は、Berachain Pyth Guide Codeを参照してください。
🛠️ さらに開発を進めたいですか?
Berachain でさらに開発を進めたい、より多くの実装例を見たいとお考えですか?私たちのBerachain GitHub ガイドリポジトリをぜひご覧ください。このリポジトリには、NextJS、Hardhat、Viem、Foundry など、様々な技術を使用した幅広い実装例が用意されています。
より詳細な情報を探求したい場合は、Berachain ドキュメントをご覧ください。
開発者サポートをお探しですか?
質問をするために、Berachain Discordサーバーに参加し、開発者チャンネルをチェックしてください。
❤️ この記事に対して愛を示すのを忘れないでください 👏🏼
【Sunrise とは】
Sunrise は Proof of Liquidity(PoL)と Fee Abstraction(手数料抽象化)を備えたデータ可用性レイヤーです。 私たちは DA の体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。
【Social Links】
【お問合せ】
Sunrise へのお問い合わせはこちらから 👉 Google Form