Skip to content

Commit 4f4f8c7

Browse files
authored
Update price feed structure + cascade changes (pyth-network#77)
* Update price feed structure + cascade changes * Update the cw schema * Update the common schema * Fix clippy warnings * Update the example schema * Add link to the docs * Update schemas * Update docs according to reviews * Refactor the code according to reviews
1 parent 7df8baa commit 4f4f8c7

File tree

15 files changed

+449
-576
lines changed

15 files changed

+449
-576
lines changed

examples/cw-contract/schema/fetch_price_response.json

+9-3
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@
1616
},
1717
"definitions": {
1818
"Price": {
19-
"description": "A price with a degree of uncertainty, represented as a price +- a confidence interval.\n\nThe confidence interval roughly corresponds to the standard error of a normal distribution. Both the price and confidence are stored in a fixed-point numeric representation, `x * 10^expo`, where `expo` is the exponent. For example:\n\n``` use pyth_sdk::Price; Price { price: 12345, conf: 267, expo: -2 }; // represents 123.45 +- 2.67 Price { price: 123, conf: 1, expo: 2 }; // represents 12300 +- 100 ```\n\n`Price` supports a limited set of mathematical operations. All of these operations will propagate any uncertainty in the arguments into the result. However, the uncertainty in the result may overestimate the true uncertainty (by at most a factor of `sqrt(2)`) due to computational limitations. Furthermore, all of these operations may return `None` if their result cannot be represented within the numeric representation (e.g., the exponent is so small that the price does not fit into an i64). Users of these methods should (1) select their exponents to avoid this problem, and (2) handle the `None` case gracefully.",
19+
"description": "A price with a degree of uncertainty at a certain time, represented as a price +- a confidence interval.\n\nPlease refer to the documentation at https://docs.pyth.network/consumers/best-practices for using this price safely.\n\nThe confidence interval roughly corresponds to the standard error of a normal distribution. Both the price and confidence are stored in a fixed-point numeric representation, `x * 10^expo`, where `expo` is the exponent. For example:\n\n``` use pyth_sdk::Price; Price { price: 12345, conf: 267, expo: -2, publish_time: 100 }; // represents 123.45 +- 2.67 published at UnixTimestamp 100 Price { price: 123, conf: 1, expo: 2, publish_time: 100 }; // represents 12300 +- 100 published at UnixTimestamp 100 ```\n\n`Price` supports a limited set of mathematical operations. All of these operations will propagate any uncertainty in the arguments into the result. However, the uncertainty in the result may overestimate the true uncertainty (by at most a factor of `sqrt(2)`) due to computational limitations. Furthermore, all of these operations may return `None` if their result cannot be represented within the numeric representation (e.g., the exponent is so small that the price does not fit into an i64). Users of these methods should (1) select their exponents to avoid this problem, and (2) handle the `None` case gracefully.",
2020
"type": "object",
2121
"required": [
2222
"conf",
2323
"expo",
24-
"price"
24+
"price",
25+
"publish_time"
2526
],
2627
"properties": {
2728
"conf": {
28-
"description": "Confidence Interval.",
29+
"description": "Confidence interval.",
2930
"type": "string"
3031
},
3132
"expo": {
@@ -36,6 +37,11 @@
3637
"price": {
3738
"description": "Price.",
3839
"type": "string"
40+
},
41+
"publish_time": {
42+
"description": "Publish time.",
43+
"type": "integer",
44+
"format": "int64"
3945
}
4046
}
4147
}

examples/cw-contract/src/contract.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ pub fn execute(
6666

6767
/// Query the Pyth contract the current price of the configured price feed.
6868
#[cfg_attr(not(feature = "library"), entry_point)]
69-
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
69+
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
7070
match msg {
71-
QueryMsg::FetchPrice {} => to_binary(&query_fetch_price(deps)?),
71+
QueryMsg::FetchPrice {} => to_binary(&query_fetch_price(deps, env)?),
7272
}
7373
}
7474

75-
fn query_fetch_price(deps: Deps) -> StdResult<FetchPriceResponse> {
75+
fn query_fetch_price(deps: Deps, env: Env) -> StdResult<FetchPriceResponse> {
7676
let state = STATE.load(deps.storage)?;
7777

7878
// query_price_feed is the standard way to read the current price from a Pyth price feed.
@@ -92,13 +92,13 @@ fn query_fetch_price(deps: Deps) -> StdResult<FetchPriceResponse> {
9292
// you handle this scenario more carefully. Consult the [consumer best practices](https://docs.pyth.network/consumers/best-practices)
9393
// for recommendations.
9494
let current_price = price_feed
95-
.get_current_price()
95+
.get_price_no_older_than(env.block.time.seconds() as i64, 60)
9696
.ok_or_else(|| StdError::not_found("Current price is not available"))?;
9797

9898
// Get an exponentially-weighted moving average price and confidence interval.
9999
// The same notes about availability apply to this price.
100100
let ema_price = price_feed
101-
.get_ema_price()
101+
.get_ema_price_no_older_than(env.block.time.seconds() as i64, 60)
102102
.ok_or_else(|| StdError::not_found("EMA price is not available"))?;
103103

104104
Ok(FetchPriceResponse {

pyth-sdk-cw/schema/price_feed_response.json

+33-98
Original file line numberDiff line numberDiff line change
@@ -19,135 +19,70 @@
1919
"Identifier": {
2020
"type": "string"
2121
},
22-
"PriceFeed": {
23-
"description": "Represents a current aggregation price from pyth publisher feeds.",
22+
"Price": {
23+
"description": "A price with a degree of uncertainty at a certain time, represented as a price +- a confidence interval.\n\nPlease refer to the documentation at https://docs.pyth.network/consumers/best-practices for using this price safely.\n\nThe confidence interval roughly corresponds to the standard error of a normal distribution. Both the price and confidence are stored in a fixed-point numeric representation, `x * 10^expo`, where `expo` is the exponent. For example:\n\n``` use pyth_sdk::Price; Price { price: 12345, conf: 267, expo: -2, publish_time: 100 }; // represents 123.45 +- 2.67 published at UnixTimestamp 100 Price { price: 123, conf: 1, expo: 2, publish_time: 100 }; // represents 12300 +- 100 published at UnixTimestamp 100 ```\n\n`Price` supports a limited set of mathematical operations. All of these operations will propagate any uncertainty in the arguments into the result. However, the uncertainty in the result may overestimate the true uncertainty (by at most a factor of `sqrt(2)`) due to computational limitations. Furthermore, all of these operations may return `None` if their result cannot be represented within the numeric representation (e.g., the exponent is so small that the price does not fit into an i64). Users of these methods should (1) select their exponents to avoid this problem, and (2) handle the `None` case gracefully.",
2424
"type": "object",
2525
"required": [
2626
"conf",
27-
"ema_conf",
28-
"ema_price",
2927
"expo",
30-
"id",
31-
"max_num_publishers",
32-
"num_publishers",
33-
"prev_conf",
34-
"prev_price",
35-
"prev_publish_time",
3628
"price",
37-
"product_id",
38-
"publish_time",
39-
"status"
29+
"publish_time"
4030
],
4131
"properties": {
4232
"conf": {
43-
"description": "Confidence interval around the current aggregation price.",
44-
"type": "string"
45-
},
46-
"ema_conf": {
47-
"description": "Exponentially moving average confidence interval.",
48-
"type": "string"
49-
},
50-
"ema_price": {
51-
"description": "Exponentially moving average price.",
33+
"description": "Confidence interval.",
5234
"type": "string"
5335
},
5436
"expo": {
55-
"description": "Price exponent.",
37+
"description": "Exponent.",
5638
"type": "integer",
5739
"format": "int32"
5840
},
59-
"id": {
60-
"description": "Unique identifier for this price.",
61-
"allOf": [
62-
{
63-
"$ref": "#/definitions/Identifier"
64-
}
65-
]
66-
},
67-
"max_num_publishers": {
68-
"description": "Maximum number of allowed publishers that can contribute to a price.",
69-
"type": "integer",
70-
"format": "uint32",
71-
"minimum": 0.0
72-
},
73-
"num_publishers": {
74-
"description": "Number of publishers that made up current aggregate.",
75-
"type": "integer",
76-
"format": "uint32",
77-
"minimum": 0.0
78-
},
79-
"prev_conf": {
80-
"description": "Confidence interval of previous aggregate with Trading status.",
81-
"type": "string"
82-
},
83-
"prev_price": {
84-
"description": "Price of previous aggregate with Trading status.",
41+
"price": {
42+
"description": "Price.",
8543
"type": "string"
8644
},
87-
"prev_publish_time": {
88-
"description": "Publish time of previous aggregate with Trading status.",
45+
"publish_time": {
46+
"description": "Publish time.",
8947
"type": "integer",
9048
"format": "int64"
49+
}
50+
}
51+
},
52+
"PriceFeed": {
53+
"description": "Represents a current aggregation price from pyth publisher feeds.",
54+
"type": "object",
55+
"required": [
56+
"ema_price",
57+
"id",
58+
"price"
59+
],
60+
"properties": {
61+
"ema_price": {
62+
"description": "Exponentially-weighted moving average (EMA) price.",
63+
"allOf": [
64+
{
65+
"$ref": "#/definitions/Price"
66+
}
67+
]
9168
},
92-
"price": {
93-
"description": "The current aggregation price.",
94-
"type": "string"
95-
},
96-
"product_id": {
97-
"description": "Product account key.",
69+
"id": {
70+
"description": "Unique identifier for this price.",
9871
"allOf": [
9972
{
10073
"$ref": "#/definitions/Identifier"
10174
}
10275
]
10376
},
104-
"publish_time": {
105-
"description": "Current price aggregation publish time",
106-
"type": "integer",
107-
"format": "int64"
108-
},
109-
"status": {
110-
"description": "Status of price (Trading is valid).",
77+
"price": {
78+
"description": "Price.",
11179
"allOf": [
11280
{
113-
"$ref": "#/definitions/PriceStatus"
81+
"$ref": "#/definitions/Price"
11482
}
11583
]
11684
}
11785
}
118-
},
119-
"PriceStatus": {
120-
"description": "Represents availability status of a price feed.",
121-
"oneOf": [
122-
{
123-
"description": "The price feed is not currently updating for an unknown reason.",
124-
"type": "string",
125-
"enum": [
126-
"Unknown"
127-
]
128-
},
129-
{
130-
"description": "The price feed is updating as expected.",
131-
"type": "string",
132-
"enum": [
133-
"Trading"
134-
]
135-
},
136-
{
137-
"description": "The price feed is not currently updating because trading in the product has been halted.",
138-
"type": "string",
139-
"enum": [
140-
"Halted"
141-
]
142-
},
143-
{
144-
"description": "The price feed is not currently updating because an auction is setting the price.",
145-
"type": "string",
146-
"enum": [
147-
"Auction"
148-
]
149-
}
150-
]
15186
}
15287
}
15388
}

pyth-sdk-cw/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ pub use pyth_sdk::{
1616
Price,
1717
PriceFeed,
1818
PriceIdentifier,
19-
PriceStatus,
2019
ProductIdentifier,
2120
};
2221

pyth-sdk-solana/examples/eth_price.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use pyth_sdk_solana::load_price_feed_from_account;
44
use solana_client::rpc_client::RpcClient;
55
use solana_program::pubkey::Pubkey;
66
use std::str::FromStr;
7+
use std::time::{
8+
SystemTime,
9+
UNIX_EPOCH,
10+
};
711
use std::{
812
thread,
913
time,
@@ -24,10 +28,13 @@ fn main() {
2428
load_price_feed_from_account(&eth_price_key, &mut eth_price_account).unwrap();
2529

2630
println!(".....ETH/USD.....");
27-
println!("status .......... {:?}", eth_price_feed.status);
28-
println!("num_publishers .. {}", eth_price_feed.num_publishers);
2931

30-
let maybe_price = eth_price_feed.get_current_price();
32+
let current_time = SystemTime::now()
33+
.duration_since(UNIX_EPOCH)
34+
.unwrap()
35+
.as_secs() as i64;
36+
37+
let maybe_price = eth_price_feed.get_price_no_older_than(current_time, 60);
3138
match maybe_price {
3239
Some(p) => {
3340
println!("price ........... {} x 10^{}", p.price, p.expo);
@@ -40,7 +47,7 @@ fn main() {
4047
}
4148

4249

43-
let maybe_ema_price = eth_price_feed.get_ema_price();
50+
let maybe_ema_price = eth_price_feed.get_ema_price_no_older_than(current_time, 60);
4451
match maybe_ema_price {
4552
Some(ema_price) => {
4653
println!(

pyth-sdk-solana/examples/get_accounts.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ use pyth_sdk_solana::state::{
88
load_price_account,
99
load_product_account,
1010
CorpAction,
11-
PriceStatus,
1211
PriceType,
1312
};
1413
use solana_client::rpc_client::RpcClient;
1514
use solana_program::pubkey::Pubkey;
1615
use std::str::FromStr;
16+
use std::time::{
17+
SystemTime,
18+
UNIX_EPOCH,
19+
};
1720

1821
fn get_price_type(ptype: &PriceType) -> &'static str {
1922
match ptype {
@@ -22,15 +25,6 @@ fn get_price_type(ptype: &PriceType) -> &'static str {
2225
}
2326
}
2427

25-
fn get_status(st: &PriceStatus) -> &'static str {
26-
match st {
27-
PriceStatus::Unknown => "unknown",
28-
PriceStatus::Trading => "trading",
29-
PriceStatus::Halted => "halted",
30-
PriceStatus::Auction => "auction",
31-
}
32-
}
33-
3428
fn get_corp_act(cact: &CorpAction) -> &'static str {
3529
match cact {
3630
CorpAction::NoCorpAct => "nocorpact",
@@ -52,7 +46,7 @@ fn main() {
5246
// iget and print each Product in Mapping directory
5347
let mut i = 0;
5448
for prod_pkey in &map_acct.products {
55-
let prod_data = clnt.get_account_data(&prod_pkey).unwrap();
49+
let prod_data = clnt.get_account_data(prod_pkey).unwrap();
5650
let prod_acct = load_product_account(&prod_data).unwrap();
5751

5852
// print key and reference data for this Product
@@ -73,7 +67,12 @@ fn main() {
7367

7468
println!(" price_account .. {:?}", px_pkey);
7569

76-
let maybe_price = price_feed.get_current_price();
70+
let current_time = SystemTime::now()
71+
.duration_since(UNIX_EPOCH)
72+
.unwrap()
73+
.as_secs() as i64;
74+
75+
let maybe_price = price_feed.get_price_no_older_than(current_time, 60);
7776
match maybe_price {
7877
Some(p) => {
7978
println!(" price ........ {} x 10^{}", p.price, p.expo);
@@ -89,8 +88,6 @@ fn main() {
8988
" price_type ... {}",
9089
get_price_type(&price_account.ptype)
9190
);
92-
println!(" exponent ..... {}", price_feed.expo);
93-
println!(" status ....... {}", get_status(&price_feed.status));
9491
println!(
9592
" corp_act ..... {}",
9693
get_corp_act(&price_account.agg.corp_act)
@@ -100,7 +97,7 @@ fn main() {
10097
println!(" valid_slot ... {}", price_account.valid_slot);
10198
println!(" publish_slot . {}", price_account.agg.pub_slot);
10299

103-
let maybe_ema_price = price_feed.get_ema_price();
100+
let maybe_ema_price = price_feed.get_ema_price_no_older_than(current_time, 60);
104101
match maybe_ema_price {
105102
Some(ema_price) => {
106103
println!(

pyth-sdk-solana/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub use pyth_sdk::{
2020
Price,
2121
PriceFeed,
2222
PriceIdentifier,
23-
PriceStatus,
2423
ProductIdentifier,
2524
};
2625

0 commit comments

Comments
 (0)