Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit 2bb9756

Browse files
jayantkJayant Krishnamurthy
andauthored
Docs and utilities (#12)
* uh oh * docs * fix error docs Co-authored-by: Jayant Krishnamurthy <[email protected]>
1 parent 2156320 commit 2bb9756

File tree

7 files changed

+318
-98
lines changed

7 files changed

+318
-98
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ no-entrypoint = []
1818
solana-program = "1.8.1"
1919
borsh = "0.9"
2020
borsh-derive = "0.9.0"
21+
bytemuck = "1.7.2"
22+
num-derive = "0.3"
23+
num-traits = "0.2"
24+
thiserror = "1.0"
2125

2226
[dev-dependencies]
2327
solana-program-test = "1.8.1"

README.md

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
1-
# pyth-client-rs
1+
# Pyth Client
22

3-
A rust API for describing on-chain pyth account structures. A primer on pyth accounts can be found at https://github.com/pyth-network/pyth-client/blob/main/doc/aggregate_price.md
3+
A Rust library for consuming price feeds from the [pyth.network](https://pyth.network/) oracle on the Solana network.
4+
This package includes a library for on-chain programs and an example program for printing product reference data.
45

5-
Contains a library for use in on-chain program development and an off-chain example program for loading and printing product reference data and aggregate prices from all devnet pyth accounts.
6+
Key features of this library include:
7+
8+
* Get the current price of over [50 products](https://pyth.network/markets/), including cryptocurrencies,
9+
US equities, forex and more.
10+
* Combine listed products to create new price feeds, e.g., for baskets of tokens or non-USD quote currencies.
11+
* Consume prices in on-chain Solana programs or off-chain applications.
12+
13+
Please see the [pyth.network documentation](https://docs.pyth.network/) for more information about pyth.network.
14+
15+
## Usage
16+
17+
Add a dependency to your Cargo.toml:
18+
19+
```toml
20+
[dependencies]
21+
pyth-client="<version>"
22+
```
23+
24+
See [pyth-client on crates.io](https://crates.io/crates/pyth-client/) to get the latest version of the library.
625

726
### Running the Example
827

@@ -38,9 +57,23 @@ product_account .. 6MEwdxe4g1NeAF9u6KDG14anJpFsVEa2cvr5H6iriFZ8
3857
twac ......... 2259870
3958
```
4059

60+
## Development
61+
62+
This library can be built for either your native platform or in BPF (used by Solana programs).
63+
Use `cargo build` / `cargo test` to build and test natively.
64+
Use `cargo build-bpf` / `cargo test-bpf` to build in BPF for Solana; these commands require you to have installed the [Solana CLI tools](https://docs.solana.com/cli/install-solana-cli-tools).
65+
66+
The BPF tests will also run an instruction count program that logs the resource consumption
67+
of various library functions.
68+
This program can also be run on its own using `cargo test-bpf --test instruction_count`.
69+
70+
### Releases
4171

42-
### Development
72+
To release a new version of this package, perform the following steps:
4373

44-
Run `cargo test-bpf` to build in BPF and run the unit tests.
45-
This command will also build an instruction count program that logs the resource consumption
46-
of various functions.
74+
1. Increment the version number in `Cargo.toml`.
75+
You may use a version number with a `-beta.x` suffix such as `0.0.1-beta.0` to create opt-in test versions.
76+
2. Merge your change into `main` on github.
77+
3. Create and publish a new github release.
78+
The name of the release should be the version number, and the tag should be the version number prefixed with `v`.
79+
Publishing the release will trigger a github action that will automatically publish the [pyth-client](https://crates.io/crates/pyth-client) rust crate to `crates.io`.

examples/get_accounts.rs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22
// bootstrap all product and pricing accounts from root mapping account
33

44
use pyth_client::{
5-
AccountType,
6-
Mapping,
7-
Product,
8-
Price,
95
PriceType,
106
PriceStatus,
117
CorpAction,
12-
cast,
13-
MAGIC,
14-
VERSION_2,
8+
load_mapping,
9+
load_product,
10+
load_price,
1511
PROD_HDR_SIZE
1612
};
1713
use solana_client::{
@@ -71,24 +67,14 @@ fn main() {
7167
loop {
7268
// get Mapping account from key
7369
let map_data = clnt.get_account_data( &akey ).unwrap();
74-
let map_acct = cast::<Mapping>( &map_data );
75-
assert_eq!( map_acct.magic, MAGIC, "not a valid pyth account" );
76-
assert_eq!( map_acct.atype, AccountType::Mapping as u32,
77-
"not a valid pyth mapping account" );
78-
assert_eq!( map_acct.ver, VERSION_2,
79-
"unexpected pyth mapping account version" );
70+
let map_acct = load_mapping( &map_data ).unwrap();
8071

8172
// iget and print each Product in Mapping directory
8273
let mut i = 0;
8374
for prod_akey in &map_acct.products {
8475
let prod_pkey = Pubkey::new( &prod_akey.val );
8576
let prod_data = clnt.get_account_data( &prod_pkey ).unwrap();
86-
let prod_acct = cast::<Product>( &prod_data );
87-
assert_eq!( prod_acct.magic, MAGIC, "not a valid pyth account" );
88-
assert_eq!( prod_acct.atype, AccountType::Product as u32,
89-
"not a valid pyth product account" );
90-
assert_eq!( prod_acct.ver, VERSION_2,
91-
"unexpected pyth product account version" );
77+
let prod_acct = load_product( &prod_data ).unwrap();
9278

9379
// print key and reference data for this Product
9480
println!( "product_account .. {:?}", prod_pkey );
@@ -106,13 +92,8 @@ fn main() {
10692
let mut px_pkey = Pubkey::new( &prod_acct.px_acc.val );
10793
loop {
10894
let pd = clnt.get_account_data( &px_pkey ).unwrap();
109-
let pa = cast::<Price>( &pd );
95+
let pa = load_price( &pd ).unwrap();
11096

111-
assert_eq!( pa.magic, MAGIC, "not a valid pyth account" );
112-
assert_eq!( pa.atype, AccountType::Price as u32,
113-
"not a valid pyth price account" );
114-
assert_eq!( pa.ver, VERSION_2,
115-
"unexpected pyth price account version" );
11697
println!( " price_account .. {:?}", px_pkey );
11798

11899
let maybe_price = pa.get_current_price();

src/error.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use num_derive::FromPrimitive;
2+
use solana_program::program_error::ProgramError;
3+
use thiserror::Error;
4+
5+
/// Errors that may be returned by Pyth.
6+
#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
7+
pub enum PythError {
8+
// 0
9+
/// Invalid account data -- either insufficient data, or incorrect magic number
10+
#[error("Failed to convert account into a Pyth account")]
11+
InvalidAccountData,
12+
/// Wrong version number
13+
#[error("Incorrect version number for Pyth account")]
14+
BadVersionNumber,
15+
/// Tried reading an account with the wrong type, e.g., tried to read
16+
/// a price account as a product account.
17+
#[error("Incorrect account type")]
18+
WrongAccountType,
19+
}
20+
21+
impl From<PythError> for ProgramError {
22+
fn from(e: PythError) -> Self {
23+
ProgramError::Custom(e as u32)
24+
}
25+
}

src/instruction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Program instructions, used for end-to-end testing and instruction counts
1+
//! Program instructions for end-to-end testing and instruction counts
22
33
use {
44
crate::id,

0 commit comments

Comments
 (0)