From 7d64d69b1126e7227a7491625247afbfad042e84 Mon Sep 17 00:00:00 2001 From: baraz <161754323+mubarizkyc@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:28:59 +0500 Subject: [PATCH] Add : Client example added example code to invoke the smart contract ,demonstrating how to construct account of type "PriceUpdateV2" --- .../solana/pyth_solana_receiver_sdk/README.md | 131 +++++++++++++++--- 1 file changed, 113 insertions(+), 18 deletions(-) diff --git a/target_chains/solana/pyth_solana_receiver_sdk/README.md b/target_chains/solana/pyth_solana_receiver_sdk/README.md index 219e489bce..a9a9837545 100644 --- a/target_chains/solana/pyth_solana_receiver_sdk/README.md +++ b/target_chains/solana/pyth_solana_receiver_sdk/README.md @@ -22,37 +22,132 @@ You should also check the `verification_level` of the account. Read more about t A Solana program can consume price update accounts created by the Pyth Solana Receiver using this SDK: ```rust + use anchor_lang::prelude::*; use pyth_solana_receiver_sdk::price_update::{get_feed_id_from_hex, PriceUpdateV2}; -declare_id!("2e5gZD3suxgJgkCg4pkoogxDKszy1SAwokz8mNeZUj4M"); +declare_id!("2UA3M6dSJQjrfTdzAiL2vMvubWoch1nTXK5TRaNGuiY4"); -pub const MAXIMUM_AGE: u64 = 60; // One minute -pub const FEED_ID: &str = "0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d"; // SOL/USD price feed id from https://pyth.network/developers/price-feed-ids +#[derive(Accounts)] +#[instruction(id:String)] +pub struct Sample<'info> { + #[account(mut)] + pub payer: Signer<'info>, + // Add this account to any instruction Context that needs price data. + pub price_update: Account<'info, PriceUpdateV2>, +} #[program] -pub mod my_first_pyth_app { +pub mod pyth_oracle_1 { + use super::*; - pub fn initialize(ctx: Context) -> Result<()> { + pub fn sample(ctx: Context, id: String) -> Result<()> { let price_update = &mut ctx.accounts.price_update; - let price = price_update.get_price_no_older_than( - &Clock::get()?, - MAXIMUM_AGE, - &get_feed_id_from_hex(FEED_ID)?, - )?; - /// Do something with the price + let maximum_age: u64 = 30; + let feed_id: [u8; 32] = get_feed_id_from_hex(&id)?; + let price = price_update.get_price_no_older_than(&Clock::get()?, maximum_age, &feed_id)?; + + msg!( + "The price is ({} ± {}) * 10^{}", + price.price, + price.conf, + price.exponent + ); Ok(()) } } -#[derive(Accounts)] -pub struct Initialize<'info> { - #[account(mut)] - pub payer: Signer<'info>, - pub price_update: Account<'info, PriceUpdateV2>, - // Add more accounts here -} +``` +## Test +To test this contract : + +```typescript + +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { PythOracle1 } from "../target/types/pyth_oracle_1"; +import { + PythSolanaReceiver, + InstructionWithEphemeralSigners, +} from "@pythnetwork/pyth-solana-receiver"; +import * as buffer from "buffer"; +import { AnchorProvider, BN, Wallet } from "@coral-xyz/anchor"; +import { PriceServiceConnection } from "@pythnetwork/price-service-client"; +import { Transaction } from "@solana/web3.js"; +const { SystemProgram, Keypair, Connection, PublicKey } = require('@solana/web3.js'); +const fs = require('fs'); +const path = require('path'); +const readline = require('readline'); +const SOL_PRICE_FEED_ID = "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; //BTC/USD +const HERMES_URL = "https://hermes.pyth.network/"; +const DEVNET_RPC_URL = "https://api.devnet.solana.com"; +const connection = new Connection(DEVNET_RPC_URL); +const provider = anchor.AnchorProvider.env() +const wallet = anchor.web3.Keypair.fromSecretKey(new Uint8Array(JSON.parse(fs.readFileSync("PATH_TO_WALLET", 'utf8')))); + +describe("pyth_oracle_1", () => { + + anchor.setProvider(provider); + + const program = anchor.workspace.PythOracle1 as Program; + + it("Is initialized!", async () => { + const priceServiceConnection = new PriceServiceConnection(HERMES_URL, { + priceFeedRequestConfig: { binary: true }, + }); + + const pythSolanaReceiver = new PythSolanaReceiver({ + connection: connection, + wallet: new Wallet(wallet), + }); + const priceUpdateData = await priceServiceConnection.getLatestVaas([SOL_PRICE_FEED_ID]); + + // Build transaction + const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ + closeUpdateAccounts: true, + }); + await transactionBuilder.addPostPriceUpdates([priceUpdateData[0]]); + + await transactionBuilder.addPriceConsumerInstructions( + async (getPriceUpdateAccount: (priceFeedId: string) => typeof PublicKey): Promise => { + return [{ + instruction: await program.methods + .sample(SOL_PRICE_FEED_ID) // Replace with your actual method and parameters + .accounts({ + payer: wallet.publicKey, + priceUpdate: getPriceUpdateAccount(SOL_PRICE_FEED_ID), + // Add other required accounts here + }) + .instruction(), + signers: [], + }]; + } + ); + + const txs = await pythSolanaReceiver.provider.sendAll( + await transactionBuilder.buildVersionedTransactions({ + computeUnitPriceMicroLamports: 50000, + }), + { skipPreflight: true } + ); + for (const signature of txs) { + try { + const tx = await connection.getTransaction(signature, { maxSupportedTransactionVersion: 0 }, { commitment: 'confirmed' }); + + if (tx && tx.meta && tx.meta.logMessages) { + console.log("Transaction logs:", tx.meta.logMessages); + } else { + console.log(" Solana Explorer:"); + console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`); + } + } catch (error) { + console.error("Error fetching transaction logs for signature:", signature, error); + } + } + + }); +}); ```