Skip to content

Commit caf75c0

Browse files
tompntnali-behjati
andauthored
Add unique identifier for Price (#23)
* Add unique identifier for Price * Update solana sdk to support new id - Also makes a major version bump because it's breaking. Co-authored-by: Ali Behjati <[email protected]>
1 parent adf60e2 commit caf75c0

File tree

10 files changed

+63
-25
lines changed

10 files changed

+63
-25
lines changed

pyth-sdk-solana/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-sdk-solana"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
authors = ["Pyth Data Foundation"]
55
edition = "2018"
66
license = "Apache-2.0"
@@ -19,7 +19,7 @@ num-derive = "0.3"
1919
num-traits = "0.2"
2020
thiserror = "1.0"
2121
serde = { version = "1.0.136", features = ["derive"] }
22-
pyth-sdk = { path = "../pyth-sdk", version = "0.1.0" }
22+
pyth-sdk = { path = "../pyth-sdk", version = "0.2.0" }
2323

2424
[dev-dependencies]
2525
solana-client = "1.8.1"
@@ -30,4 +30,3 @@ crate-type = ["cdylib", "lib"]
3030

3131
[package.metadata.docs.rs]
3232
targets = ["x86_64-unknown-linux-gnu"]
33-

pyth-sdk-solana/README.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,31 @@ The examples below assume that the user has already obtained this account data.
4747
Each price feed (e.g: `Crypto.BTC/USD`) is stored in a Solana price account.
4848
You can find price accounts in the pyth.network website (e.g.: [Crypto.BTC/USD accounts](https://pyth.network/markets/#Crypto.BTC/USD)).
4949

50-
To read the price from a price account, this library provides a `load_price` method that translates the binary account data into a `Price` struct:
50+
The `Price` struct contains several useful functions for working with the price.
51+
Some of these functions are described below.
52+
For more detailed information, please see the crate documentation.
53+
54+
#### On-chain
55+
56+
To read the price from a price account on-chain, this library provides a `load_price_from_account_info` method that constructs `Price` struct from AccountInfo:
5157

5258
```rust
53-
use pyth_sdk_solana::{load_price, Price};
59+
use pyth_sdk_solana::{load_price_from_account_info, Price};
5460

55-
let price_account_data: Vec<u8> = ...;
56-
let price: Price = load_price( &price_account_data ).unwrap();
61+
let price_account_info: AccountInfo = ...;
62+
let price: Price = load_price( &price_account_info ).unwrap();
5763
```
5864

59-
The `Price` struct contains several useful functions for working with the price.
60-
Some of these functions are described below.
61-
For more detailed information, please see the crate documentation.
65+
#### Off-chain
66+
To read the price from a price account off-chain in clients, this library provides a `load_price_from_account` method that constructs `Price` struct from Account:
67+
68+
```rust
69+
use pyth_sdk_solana::{load_price_from_account, Price};
70+
71+
let price_key: Pubkey = ...;
72+
let mut price_account: Account = ...;
73+
let price: Price = load_price_from_account( &price_key, &mut price_account ).unwrap();
74+
```
6275

6376
### Get the current price
6477

pyth-sdk-solana/examples/eth_price.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// example usage of reading pyth price from solana price account
22

3-
use pyth_sdk_solana::load_price;
3+
use pyth_sdk_solana::load_price_from_account;
44
use solana_client::rpc_client::RpcClient;
55
use solana_program::pubkey::Pubkey;
66
use std::str::FromStr;
@@ -19,8 +19,8 @@ fn main() {
1919

2020
loop {
2121
// get price data from key
22-
let eth_price_data = clnt.get_account_data(&eth_price_key).unwrap();
23-
let eth_price = load_price(&eth_price_data).unwrap();
22+
let mut eth_price_account = clnt.get_account(&eth_price_key).unwrap();
23+
let eth_price = load_price_from_account(&eth_price_key, &mut eth_price_account).unwrap();
2424

2525
println!(".....ETH/USD.....");
2626
println!("status .......... {:?}", eth_price.status);

pyth-sdk-solana/examples/get_accounts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fn main() {
7070
loop {
7171
let price_data = clnt.get_account_data(&px_pkey).unwrap();
7272
let price_account = load_price_account(&price_data).unwrap();
73-
let price = price_account.to_price();
73+
let price = price_account.to_price(&px_pkey);
7474

7575
println!(" price_account .. {:?}", px_pkey);
7676

pyth-sdk-solana/src/lib.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ pub use self::error::PythError;
77
mod error;
88
pub mod state;
99

10+
use solana_program::{
11+
account_info::{
12+
Account,
13+
AccountInfo,
14+
IntoAccountInfo,
15+
}, pubkey::Pubkey,
16+
};
17+
1018
use state::load_price_account;
1119

1220
pub use pyth_sdk::{
@@ -19,9 +27,18 @@ pub use pyth_sdk::{
1927
/// Maximum valid slot period before price is considered to be stale.
2028
pub const VALID_SLOT_PERIOD: u64 = 25;
2129

22-
/// Loads Pyth Price from the raw byte value of a Solana account.
23-
pub fn load_price(data: &[u8]) -> Result<Price, PythError> {
24-
let price_account = load_price_account(data)?;
30+
/// Loads Pyth Price from Price Account Info.
31+
pub fn load_price_from_account_info(price_account_info: &AccountInfo) -> Result<Price, PythError> {
32+
let data = price_account_info.try_borrow_data().map_err(|_| PythError::InvalidAccountData)?;
33+
let price_account = load_price_account(*data)?;
34+
35+
Ok(price_account.to_price(&price_account_info.key))
36+
}
2537

26-
Ok(price_account.to_price())
38+
/// Loads Pyth Price from Account when using Solana Client.
39+
///
40+
/// It is a helper function which constructs Account Info when reading Account in clients.
41+
pub fn load_price_from_account(price_key: &Pubkey, price_account: &mut impl Account) -> Result<Price, PythError> {
42+
let price_account_info = (price_key, price_account).into_account_info();
43+
load_price_from_account_info(&price_account_info)
2744
}

pyth-sdk-solana/src/state.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use bytemuck::{
1212
PodCastError,
1313
Zeroable,
1414
};
15+
use solana_program::pubkey::Pubkey;
1516
use std::mem::size_of;
1617

1718
pub use pyth_sdk::{
@@ -333,7 +334,7 @@ unsafe impl Pod for PriceAccount {
333334
}
334335

335336
impl PriceAccount {
336-
pub fn to_price(&self) -> Price {
337+
pub fn to_price(&self, price_key: &Pubkey) -> Price {
337338
#[allow(unused_mut)]
338339
let mut status = self.agg.status;
339340

@@ -345,6 +346,7 @@ impl PriceAccount {
345346
}
346347

347348
Price {
349+
id: price_key.to_bytes(),
348350
price: self.agg.price,
349351
conf: self.agg.conf,
350352
status,

pyth-sdk-solana/test-contract/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
[package]
22
name = "test-contract"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2018"
55

66
[features]
77
test-bpf = []
88
no-entrypoint = []
99

1010
[dependencies]
11-
pyth-sdk-solana = { path = "../", version = "0.1.0" }
11+
pyth-sdk-solana = { path = "../", version = "0.2.0" }
1212
solana-program = "1.8.1"
1313
bytemuck = "1.7.2"
1414
borsh = "0.9"

pyth-sdk-solana/test-contract/src/processor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use solana_program::program_error::ProgramError;
77
use solana_program::pubkey::Pubkey;
88

99
use crate::instruction::PythClientInstruction;
10-
use pyth_sdk_solana::load_price;
10+
use pyth_sdk_solana::state::load_price_account;
1111

1212
pub fn process_instruction(
1313
_program_id: &Pubkey,
@@ -44,7 +44,8 @@ pub fn process_instruction(
4444
price_account_data,
4545
expected_price_status,
4646
} => {
47-
let price = load_price(&price_account_data[..])?;
47+
let price_account = load_price_account(price_account_data.as_ref())?;
48+
let price = price_account.to_price(&Pubkey::default());
4849

4950
if price.status == expected_price_status {
5051
Ok(())

pyth-sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-sdk"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
authors = ["Pyth Data Foundation"]
55
edition = "2018"
66
license = "Apache-2.0"

pyth-sdk/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ use schemars::JsonSchema;
88
mod price_conf;
99
pub use price_conf::PriceConf;
1010

11-
/// Consists of 32 bytes and it is currently based on largest Public Key size on various blockchains.
11+
/// Unique identifier for a price.
12+
pub type PriceIdentifier = [u8; 32];
13+
14+
/// Consists of 32 bytes and it is currently based on largest Public Key size on various
15+
/// blockchains.
1216
pub type ProductIdentifier = [u8; 32];
1317

1418
/// Represents availability status of a price feed.
@@ -58,6 +62,8 @@ impl Default for PriceStatus {
5862
)]
5963
#[repr(C)]
6064
pub struct Price {
65+
/// Unique identifier for this price.
66+
pub id: PriceIdentifier,
6167
/// The current price.
6268
pub price: i64,
6369
/// Confidence interval around the price.

0 commit comments

Comments
 (0)