跳至主要内容
本页面使用机器翻译自英语,可能包含错误或不清楚的语言。如需最准确的信息,请参阅英文原文。由于更新频繁,部分内容可能与英文原文有出入。请加入我们在 Crowdin 上的努力,帮助我们改进本页面的翻译。 (Crowdin translation page, Contributing guide)

如何使用 Pyth 在 Kaia 上获取实时价格

介绍

Pyth 是一个去中心化的神谕网络,它在主要由推式神谕驱动的生态系统中采用了一种独特的方法。 Pyth 不需要以固定的时间间隔向合同推送数据,而是允许你按需提取真实世界的数据。 这种模式为开发人员提供了更多控制权,有助于避免不必要的链上更新。 通过这种集成,开发人员可以获取实时数据,并使用按使用付费的模式,即只有在请求更新时才收费。

在本指南中,您将学习如何使用 Pyth 的实时价格馈送来读取法定货币 IDR 的价值。 您的 Solidity 智能合约将使用 pyth-sdk-solidity 从 Pyth 获取美元/印尼盾价格,您将使用 hermes-client 更新并获取最新价格。

为了快速入门,您可以在 GitHub 上找到本教程的完整代码。 这为您提供了随时可用的参考资料,帮助您更快地设置项目和安装。

要求

在开始之前,请确保具备以下条件:

  • Node.js 和 npm

    需要安装依赖项和运行开发工具。

  • 由 KAIA 测试网络代币出资的钱包。

    您需要 KAIA 来支付 Kairos 测试网络的部署和交易气体费用。 您可以从 [Kaia 水龙头] (https://faucet.kaia.io/) 申请免费测试网络 KAIA。

设置开发环境

在本节中,您将设置开发环境,编译 Oracle 合同,并准备使用 Hardhat 进行部署。

1. 创建硬头巾项目

为项目创建一个新目录并初始化 Hardhat:


mkdir pyth-kaia-hardhat-example && cd pyth-kaia-hardhat-example
npm init -y
npx hardhat@next --init

根据提示接受默认回复。 在本指南中,我们将使用摩卡和以太模板。

通过检查 Hardhat 版本来验证您的安装:


npx hardhat --version

2. 设置加密机密

现在,您将使用 Hardhat 的加密密钥库存储 RPC URL 和私人密钥。

运行以下命令


npx hardhat keystore set KAIROS_RPC_URL
npx hardhat keystore set PRIVATE_KEY

确保为每个变量输入密码和值,以保持加密。

3. 配置文件中的参考秘诀

打开 hardhat.config.ts,更新网络部分以引用加密机密。 如果使用了不同的密钥名称,请相应更新密钥。


import { configVariable } from "hardhat/config";
module.exports = {
networks: {
kairos: {
url: configVariable("KAIROS_RPC_URL"),
accounts: [configVariable("PRIVATE_KEY")],
},
},
};

创建合约并从 Pyth Oracles 获取价格

在本节中,您将安装 Pyth Solidity SDK,创建一个 PriceConsumer 合约,并使用 Hardhat 进行部署。 该合约将读取 Pyth 价格源,稍后你将使用从 Hermes 获取的价格数据对其进行更新。

安装 Pyth SDK

Pyth 提供了一个 Solidity SDK,可让您与链上 Pyth 价格反馈合约进行交互。 SDK 公开了 IPyth 接口和相关结构。

使用 npm 安装 SDK:


npm install --save-dev @pythnetwork/pyth-sdk-solidity

创建 PriceConsumer 合同

contracts/PriceConsumer.sol 中创建一个新文件,并添加以下代码:


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
contract PriceConsumer {
IPyth public pyth;
constructor(address pythContract) {
pyth = IPyth(pythContract);
}
function updatePrice(bytes[] calldata priceUpdateData)
external
payable
{
// Pay the Pyth fee for receiving price updates
uint fee = pyth.getUpdateFee(priceUpdateData);
require(msg.value >= fee, "Not enough fee sent");
// Update the Pyth price state
pyth.updatePriceFeeds{value: fee}(priceUpdateData);
// Can fetch the price and use it as well
//PythStructs.Price memory currentBasePrice = pyth.getPriceNoOlderThan(priceFeedId, 60);
}
function getLatestPrice(bytes32 priceFeedId) public view returns (int64, int32) {
// Read the current price from a price feed if it is less than 60 seconds old.
// Each price feed (e.g., USD/IDR) is identified by a price feed ID.
// The complete list of feed IDs is available at https://docs.pyth.network/price-feeds/price-feeds
PythStructs.Price memory currentBasePrice = pyth.getPriceNoOlderThan(priceFeedId, 60);
// uint256 basePrice = PythUtils.convertToUint(
// currentBasePrice.price,
// currentBasePrice.expo,
// 18
// );
return (currentBasePrice.price, currentBasePrice.expo);
}
}

走过

价格消费者合同:

  • @pythnetwork/pyth-sdk-solidity 导入 Pyth 接口和结构体。
  • 商店
    • Pyth 合约实例 (pyth)。
    • 美元/印度卢比的价格输入 ID (usdIdrPriceId)。
  • Exposes updateAndGetUsdIdrPrice, which:
    • 使用 IPyth.getUpdateFee 计算更新费用。
    • 调用 IPyth.updatePriceFeeds,输入所需费用。
    • 调用 IPyth.getPriceNoOlderThan 读取新的美元/印度卢比价格。
    • 返回原始价格、指数和发布时间。

稍后,您的离链爱马仕客户端将建立 priceUpdate 字节数组,并在需要新价格时将其传入此函数。

编制合同

运行以下命令编译合同


npx hardhat compile

部署合同

要部署 PriceConsumer 合同,需要创建一个 Ignition 模块,然后运行部署命令。

创建点火模块

ignition/modules/PriceConsumer.ts 创建一个新文件:


import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
const pythContractAddress = "0x2880ab155794e7179c9ee2e38200202908c17b43";
export default buildModule("PriceConsumerModule", (m) => {
const priceConsumer = m.contract("PriceConsumer", [pythContractAddress]);
return { priceConsumer };
});

部署合同

使用 Ignition 模块将 PriceConsumer 合同部署到 Kairos 测试网络:


npx hardhat ignition deploy --network kairos ignition/modules/PriceConsumer.ts

出现提示时,输入先前为加密机密配置的密钥库密码。

完成上述操作后,您的 "PriceConsumer.sol "合约就会部署到 Kairos 测试网上,并准备好从 Pyth 消费实时美元/印尼盾价格。

从 TypeScript 互动

在最后一步,您将使用 TypeScript 与已部署的 PriceConsumer 合约交互。 该脚本将通过 Hermes 客户端请求 Pyth 价格更新数据,并在链上发送,从而获取最新的美元/印尼盾价格。

安装依赖项

安装所需的软件包:


npm install --save-dev tsx @pythnetwork/hermes-client @dotenv

** 设置 .env**

在项目根目录下创建 .env 文件,并添加私人密钥:


PRIVATE_KEY="0xDEAD....." // REPLACE WITH YOUR PRIVATE KEY

创建交互脚本

scripts/interact.ts创建一个新文件,并添加以下内容:


import { HermesClient } from "@pythnetwork/hermes-client";
import { ethers } from "ethers";
import 'dotenv/config'
// 1. Setup
const hermes = new HermesClient("https://hermes.pyth.network");
const provider = new ethers.JsonRpcProvider(
"https://public-en-kairos.node.kaia.io"
);
const PK = process.env.PRIVATE_KEY;
const wallet = new ethers.Wallet(PK, provider);
// 2. Your deployed contract
const priceConsumerAddress = "0x91e89aa32224dEd5dA483a83a4de45bF4bE57caA"; // REPLACE WITH DEPLOYED PRICE CONSUMER CONTRACT
const priceConsumerAbi = [
"function updatePrice(bytes[] priceUpdateData) external payable",
"function getLatestPrice(bytes32 priceId) public view returns(int64, int32)",
];
const priceConsumer = new ethers.Contract(
priceConsumerAddress,
priceConsumerAbi,
wallet
);
// 3. Price feed IDs
const priceId =
"0x6693afcd49878bbd622e46bd805e7177932cf6ab0b1c91b135d71151b9207433"; // FX.USD/IDR Beta Price Feed ID
async function run() {
// Fetch Hermes price update binary
const update = await hermes.getLatestPriceUpdates([priceId], {
encoding: "hex",
});
console.log(update);
const priceUpdateData = ["0x" + update.binary.data]; // must be array of bytes
console.log(priceUpdateData);
// Estimate fee required by Pyth contract
// EVM Network Price Feed Contract Addresses: https://docs.pyth.network/price-feeds/core/contract-addresses/evm
const pythContractAddress = "0x2880ab155794e7179c9ee2e38200202908c17b43";
const pythAbi = [
"function getUpdateFee(bytes[] calldata data) external view returns(uint)",
];
console.log("Pyth contract address:", pythContractAddress);
const pyth = new ethers.Contract(pythContractAddress, pythAbi, wallet);
const fee = await pyth.getUpdateFee(priceUpdateData);
console.log("Pyth fee:", fee.toString());
// Call your contract
const tx = await priceConsumer.updatePrice(priceUpdateData, {
value: fee, // pay the pyth update fee
gasLimit: 500000,
});
console.log("Tx sent:", tx.hash);
const receipt = await tx.wait();
console.log("Tx confirmed");
console.log(receipt);
// 4. Get latest price from contract
try {
console.log("=== Latest Price from Contract ===");
const [price, expo] = await priceConsumer.getLatestPrice(priceId);
console.log("Price Value : " + price.toString());
console.log("Exponent Value : " + expo.toString());
} catch (error) {
console.log(error);
// @ts-ignore
console.error("\nError calling getLatestPrice:", error.message);
console.log(
"This usually means the price is older than 60 seconds or hasn't been updated yet."
);
console.log("Make sure updatePrice() was called successfully first.");
}
}
run();

剧本

用以下命令执行脚本


npx tsx scripts/interact.ts

输出示例


Tx sent: 0x79c5dcb7abd9605b070bf9062ba2e2382272d23d58f7b50446c3107b7784fc8e
Tx confirmed
=== Latest Price from Contract ===
Price Value : 1669784988
Exponent Value : -5
======== —— =========

在搜索栏中粘贴交易哈希值,即可在 Kairos 浏览器上验证您的交易。 这证明更新和读取操作均已成功。

结论

在本教程中,你创建了一个从 Pyth 读取实时价格的 Solidity 合约,将其部署到 Kairos 测试网络,并使用 Hermes 客户端与之交互。 您还了解到 Pyth 基于拉动的设计如何让您控制价格更新的时间和方式。

欲了解更多信息,请浏览

让这个页面变得更好