Skip to content

Commit 103c60e

Browse files
Add Pyth examples
1 parent 729dd9c commit 103c60e

File tree

13 files changed

+241
-0
lines changed

13 files changed

+241
-0
lines changed

oracles/pyth/anchor/.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
.anchor
3+
.DS_Store
4+
target
5+
**/*.rs.bk
6+
node_modules
7+
test-ledger

oracles/pyth/anchor/.prettierignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
.anchor
3+
.DS_Store
4+
target
5+
node_modules
6+
dist
7+
build
8+
test-ledger

oracles/pyth/anchor/Anchor.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[features]
2+
seeds = false
3+
skip-lint = false
4+
[programs.localnet]
5+
pythexample = "F6mNuN1xoPdRaZcUX3Xviq7x1EFtoBXygpFggCLd62eU"
6+
7+
[registry]
8+
url = "https://api.apr.dev"
9+
10+
[provider]
11+
cluster = "Localnet"
12+
wallet = "~/.config/solana/id.json"
13+
14+
[scripts]
15+
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
16+
17+
[test.validator]
18+
url = "https://api.mainnet-beta.solana.com"
19+
20+
[[test.validator.clone]]
21+
address = "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG"

oracles/pyth/anchor/Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[workspace]
2+
members = [
3+
"programs/*"
4+
]
5+
6+
[profile.release]
7+
overflow-checks = true
8+
lto = "fat"
9+
codegen-units = 1
10+
[profile.release.build-override]
11+
opt-level = 3
12+
incremental = false
13+
codegen-units = 1
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Migrations are an early feature. Currently, they're nothing more than this
2+
// single deploy script that's invoked from the CLI, injecting a provider
3+
// configured from the workspace's Anchor.toml.
4+
5+
const anchor = require("@coral-xyz/anchor");
6+
7+
module.exports = async function (provider) {
8+
// Configure client to use the provider.
9+
anchor.setProvider(provider);
10+
11+
// Add your deploy script here.
12+
};

oracles/pyth/anchor/package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"scripts": {
3+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5+
},
6+
"dependencies": {
7+
"@coral-xyz/anchor": "^0.27.0"
8+
},
9+
"devDependencies": {
10+
"chai": "^4.3.4",
11+
"mocha": "^9.0.3",
12+
"ts-mocha": "^10.0.0",
13+
"@types/bn.js": "^5.1.0",
14+
"@types/chai": "^4.3.0",
15+
"@types/mocha": "^9.0.0",
16+
"typescript": "^4.3.5",
17+
"prettier": "^2.6.2"
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "pythexample"
3+
version = "0.1.0"
4+
description = "Created with Anchor"
5+
edition = "2021"
6+
7+
[lib]
8+
crate-type = ["cdylib", "lib"]
9+
name = "pythexample"
10+
11+
[features]
12+
no-entrypoint = []
13+
no-idl = []
14+
no-log-ix-name = []
15+
cpi = ["no-entrypoint"]
16+
default = []
17+
18+
[dependencies]
19+
anchor-lang = "0.27.0"
20+
pyth-sdk-solana = "0.7.1"
21+
pyth-sdk = "0.7.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.bpfel-unknown-unknown.dependencies.std]
2+
features = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use anchor_lang::prelude::*;
2+
3+
#[error_code]
4+
pub enum ErrorCode {
5+
#[msg("PythError")]
6+
PythError,
7+
#[msg("TryToSerializePriceAccount")]
8+
TryToSerializePriceAccount,
9+
#[msg("InvalidArgument")]
10+
InvalidArgument,
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use anchor_lang::prelude::*;
2+
pub mod state;
3+
use state::PriceFeed;
4+
5+
pub mod error;
6+
use error::ErrorCode;
7+
8+
declare_id!("F6mNuN1xoPdRaZcUX3Xviq7x1EFtoBXygpFggCLd62eU");
9+
10+
#[program]
11+
pub mod pythexample {
12+
use super::*;
13+
pub fn read_price(ctx: Context<Pyth>) -> Result<()> {
14+
let price_feed = &ctx.accounts.price_feed;
15+
let clock = &ctx.accounts.clock;
16+
// Get the current timestamp
17+
let timestamp: i64 = clock.unix_timestamp;
18+
// Load the price from the price feed. Here, the price can be no older than 500 seconds.
19+
let price: pyth_sdk::Price = price_feed
20+
.get_price_no_older_than(timestamp, 30)
21+
.ok_or(ErrorCode::PythError)?;
22+
23+
let confidence_interval: u64 = price.conf;
24+
25+
let asset_price_full: i64 = price.price;
26+
27+
let asset_exponent: i32 = price.expo;
28+
29+
let asset_price = asset_price_full as f64 * 10f64.powi(asset_exponent);
30+
31+
msg!("Price: {}", asset_price);
32+
msg!("Confidence interval: {}", confidence_interval);
33+
34+
Ok(())
35+
}
36+
}
37+
38+
#[derive(Accounts)]
39+
pub struct Pyth<'info> {
40+
pub price_feed: Account<'info, PriceFeed>,
41+
pub system_program: Program<'info, System>,
42+
pub clock: Sysvar<'info, Clock>,
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// This file is the pyth default implementation for using PriceAccount in your Anchor context.
2+
use anchor_lang::prelude::*;
3+
use pyth_sdk_solana::state::load_price_account;
4+
use std::ops::Deref;
5+
use std::str::FromStr;
6+
7+
// import the error code from the error.rs file
8+
use crate::error::ErrorCode;
9+
10+
#[derive(Clone)]
11+
pub struct PriceFeed(pyth_sdk::PriceFeed);
12+
13+
impl anchor_lang::Owner for PriceFeed {
14+
fn owner() -> Pubkey {
15+
// The mainnet Pyth program ID
16+
let oracle_addr = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH";
17+
return Pubkey::from_str(&oracle_addr).unwrap();
18+
}
19+
}
20+
21+
impl anchor_lang::AccountDeserialize for PriceFeed {
22+
fn try_deserialize_unchecked(data: &mut &[u8]) -> Result<Self> {
23+
let account = load_price_account(data).map_err(|_x| error!(ErrorCode::PythError))?;
24+
let zeros: [u8; 32] = [0; 32];
25+
let dummy_key = Pubkey::new_from_array(zeros);
26+
let feed = account.to_price_feed(&dummy_key);
27+
return Ok(PriceFeed(feed));
28+
}
29+
}
30+
31+
impl anchor_lang::AccountSerialize for PriceFeed {
32+
fn try_serialize<W: std::io::Write>(&self, _writer: &mut W) -> std::result::Result<(), Error> {
33+
Err(error!(ErrorCode::TryToSerializePriceAccount))
34+
}
35+
}
36+
37+
impl Deref for PriceFeed {
38+
type Target = pyth_sdk::PriceFeed;
39+
40+
fn deref(&self) -> &Self::Target {
41+
&self.0
42+
}
43+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as anchor from "@coral-xyz/anchor";
2+
import { Program } from "@coral-xyz/anchor";
3+
import { Pythexample } from "../target/types/pythexample";
4+
5+
describe("pythexample", () => {
6+
// Configure the client to use the local cluster.
7+
anchor.setProvider(anchor.AnchorProvider.env());
8+
9+
const program = anchor.workspace.Pythexample as Program<Pythexample>;
10+
11+
const PYTH_FEED_ID = new anchor.web3.PublicKey(
12+
"H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG"
13+
);
14+
15+
it("Check SOL_USD Price", async () => {
16+
const tx = await program.methods
17+
.readPrice()
18+
.accounts({
19+
priceFeed: PYTH_FEED_ID,
20+
systemProgram: anchor.web3.SystemProgram.programId,
21+
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
22+
})
23+
.rpc();
24+
25+
console.log(
26+
"Your transaction signature, find the price in the program logs",
27+
tx
28+
);
29+
});
30+
});

oracles/pyth/anchor/tsconfig.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"types": ["mocha", "chai"],
4+
"typeRoots": ["./node_modules/@types"],
5+
"lib": ["es2015"],
6+
"module": "commonjs",
7+
"target": "es6",
8+
"esModuleInterop": true
9+
}
10+
}
11+

0 commit comments

Comments
 (0)