Skip to content

chore: add post partially verified updates example #2177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { InstructionWithEphemeralSigners, PythSolanaReceiver } from "../";
import { Wallet } from "@coral-xyz/anchor";
import fs from "fs";
import os from "os";
import { HermesClient } from "@pythnetwork/hermes-client";

// Get price feed ids from https://pyth.network/developers/price-feed-ids#pyth-evm-stable
const SOL_PRICE_FEED_ID =
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d";

let keypairFile = "";
if (process.env["SOLANA_KEYPAIR"]) {
keypairFile = process.env["SOLANA_KEYPAIR"];
} else {
keypairFile = `${os.homedir()}/.config/solana/id.json`;
}

async function main() {
const connection = new Connection("https://api.devnet.solana.com");
const keypair = await loadKeypairFromFile(keypairFile);
console.log(
`Sending transactions from account: ${keypair.publicKey.toBase58()}`
);
const wallet = new Wallet(keypair);
const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet });

// Get the price update from hermes
const priceUpdateData = await getPriceUpdateData();
console.log(`Posting price update: ${priceUpdateData}`);

// If closeUpdateAccounts = true, the builder will automatically generate instructions to close the ephemeral price update accounts
// at the end of the transaction. Closing the accounts will reclaim their rent.
// The example is using closeUpdateAccounts = false so you can easily look up the price update account in an explorer.
const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({
closeUpdateAccounts: false,
});
// Post the price updates to ephemeral accounts, one per price feed.
// Using this method we can post the price update in a single transaction.
// With 5 signatures, the transaction size is 1197 bytes
// With 3 signatures, the transaction size is 1065 bytes
await transactionBuilder.addPostPartiallyVerifiedPriceUpdates(
priceUpdateData
);
console.log(
"The SOL/USD price update will get posted to:",
transactionBuilder.getPriceUpdateAccount(SOL_PRICE_FEED_ID).toBase58()
);

await transactionBuilder.addPriceConsumerInstructions(
async (
getPriceUpdateAccount: (priceFeedId: string) => PublicKey
): Promise<InstructionWithEphemeralSigners[]> => {
// You can generate instructions here that use the price updates posted above.
// getPriceUpdateAccount(<price feed id>) will give you the account you need.
// These accounts will be packed into transactions by the builder.
return [];
}
);

// Send the instructions in the builder in 1 or more transactions.
// The builder will pack the instructions into transactions automatically.
await pythSolanaReceiver.provider.sendAll(
await transactionBuilder.buildVersionedTransactions({
computeUnitPriceMicroLamports: 100000,
}),
{ preflightCommitment: "processed" }
);
}

// Fetch price update data from Hermes
async function getPriceUpdateData() {
const priceServiceConnection = new HermesClient(
"https://hermes.pyth.network/",
{}
);

const response = await priceServiceConnection.getLatestPriceUpdates(
[SOL_PRICE_FEED_ID],
{ encoding: "base64" }
);

return response.binary.data;
}

// Load a solana keypair from an id.json file
async function loadKeypairFromFile(filePath: string): Promise<Keypair> {
try {
const keypairData = JSON.parse(
await fs.promises.readFile(filePath, "utf8")
);
return Keypair.fromSecretKey(Uint8Array.from(keypairData));
} catch (error) {
throw new Error(`Error loading keypair from file: ${error}`);
}
}

main();
Loading