Skip to content

Commit 9ae512f

Browse files
authored
Add terra sdk (#22)
1 parent 26af54b commit 9ae512f

File tree

8 files changed

+374
-0
lines changed

8 files changed

+374
-0
lines changed

.github/workflows/pyth-sdk-terra.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Terra SDK
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
defaults:
16+
run:
17+
working-directory: ./pyth-sdk-terra
18+
steps:
19+
- uses: actions/checkout@v2
20+
- name: Install dependencies
21+
run: sudo apt-get install libudev-dev
22+
- name: Build
23+
run: cargo build --verbose
24+
- name: Run tests
25+
run: cargo test --verbose

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ members = [
44
"pyth-sdk",
55
"pyth-sdk-solana",
66
"pyth-sdk-solana/test-contract",
7+
"pyth-sdk-terra",
78
]

pyth-sdk-terra/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "pyth-sdk-terra"
3+
version = "0.1.0"
4+
authors = ["Pyth Data Foundation"]
5+
edition = "2018"
6+
license = "Apache-2.0"
7+
homepage = "https://pyth.network"
8+
repository = "https://github.com/pyth-network/pyth-sdk-rs"
9+
description = "pyth price oracle data structures and example usage"
10+
keywords = [ "pyth", "terra", "oracle" ]
11+
readme = "README.md"
12+
13+
[dependencies]
14+
cosmwasm-std = { version = "0.16.0" }
15+
cosmwasm-storage = { version = "0.16.0" }
16+
serde = { version = "1.0.136", features = ["derive"] }
17+
pyth-sdk = { path = "../pyth-sdk", version = "0.2.0" }
18+
schemars = "0.8.1"
19+
20+
[dev-dependencies]
21+
cosmwasm-schema = { version = "0.16.0" }
22+
23+
[lib]
24+
crate-type = ["cdylib", "lib"]

pyth-sdk-terra/README.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Pyth SDK Terra
2+
3+
This crate provides utilities for reading price feeds from the [pyth.network](https://pyth.network/) oracle on the Terra network.
4+
The crate includes a library for reading and using Pyth data feeds in Terra.
5+
6+
## Usage
7+
8+
> :grey_exclamation: Please follow [consumer best practices](https://docs.pyth.network/consumers/best-practices) when consuming Pyth data.
9+
10+
### Read price
11+
12+
For reading the price you just need to call `query_price_feed` function within your contract with the id of the price feed.
13+
14+
You can find the contract address and price feed ids in the section [Contracts and Price Feeds](#contracts-and-price-feeds) below.
15+
16+
```rust
17+
let price_feed: PriceFeed = query_price_feed(deps.querier, contract_addr, id).unwrap().price_feed;
18+
```
19+
20+
The `PriceFeed` struct contains several useful functions for working with the price.
21+
Some of these functions are described below.
22+
For more detailed information, please see the crate documentation.
23+
24+
25+
### Get the current price
26+
27+
Read the current price from a `PriceFeed`:
28+
29+
```rust
30+
let current_price: Price = price_feed.get_current_price().unwrap();
31+
println!("price: ({} +- {}) x 10^{}", current_price.price, current_price.conf, current_price.expo);
32+
```
33+
34+
The price is returned along with a confidence interval that represents the degree of uncertainty in the price.
35+
Both values are represented as fixed-point numbers, `a * 10^e`.
36+
The method will return `None` if the price is not currently available.
37+
38+
### Non-USD prices
39+
40+
Most assets in Pyth are priced in USD.
41+
Applications can combine two USD prices to price an asset in a different quote currency:
42+
43+
```rust
44+
let btc_usd: Price = ...;
45+
let eth_usd: Price = ...;
46+
// -8 is the desired exponent for the result
47+
let btc_eth: Price = btc_usd.get_price_in_quote(&eth_usd, -8);
48+
println!("BTC/ETH price: ({} +- {}) x 10^{}", price.price, price.conf, price.expo);
49+
```
50+
51+
### Price a basket of assets
52+
53+
Applications can also compute the value of a basket of multiple assets:
54+
55+
```rust
56+
let btc_usd: Price = ...;
57+
let eth_usd: Price = ...;
58+
// Quantity of each asset in fixed-point a * 10^e.
59+
// This represents 0.1 BTC and .05 ETH.
60+
// -8 is desired exponent for result
61+
let basket_price: Price = Price::price_basket(&[
62+
(btc_usd, 10, -2),
63+
(eth_usd, 5, -2)
64+
], -8);
65+
println!("0.1 BTC and 0.05 ETH are worth: ({} +- {}) x 10^{} USD",
66+
basket_price.price, basket_price.conf, basket_price.expo);
67+
```
68+
69+
This function additionally propagates any uncertainty in the price into uncertainty in the value of the basket.
70+
71+
## Client-side Usage
72+
73+
You can use the provided schemas in the `schema` directory to query the terra contract client side.
74+
75+
The query looks like this:
76+
77+
```json
78+
{
79+
"price_feed": {
80+
"id": [249, 192, 23, ..., 163, 27] // id of the price feed as an array of bytes
81+
}
82+
}
83+
```
84+
85+
You can use
86+
87+
## Contracts and Price Feeds
88+
89+
Currently Pyth is only available in testnet network.
90+
91+
### Testnet
92+
93+
The contract address is [`terra1hdc8q4ejy82kd9w7wj389dlul9z5zz9a36jflh`](https://finder.terra.money/testnet/address/terra1wzs3rgzgjdde3kg7k3aaz6qx7sc5dcwxqe9fuc).
94+
95+
List of available Price Feeds and their ids:
96+
97+
| Symbol | id (hex) |
98+
|-----------------|----------------------------------------------------------------------|
99+
| Crypto.BTC/USD | `0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b` |
100+
| Crypto.ETH/USD | `0xca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6` |
101+
| Crypto.LUNA/USD | `0x6de025a4cf28124f8ea6cb8085f860096dbc36d9c40002e221fc449337e065b2` |
102+
| Crypto.UST/USD | `0x026d1f1cf9f1c0ee92eb55696d3bd2393075b611c4f468ae5b967175edc4c25c` |
103+
| Crypto.ALGO/USD | `0x08f781a893bc9340140c5f89c8a96f438bcfae4d1474cc0f688e3a52892c7318` |
104+
105+
#### Notes
106+
- :warning: `num_publishers` and `max_num_publishers` in `PriceFeed` are currrently unavailable and set to 0.

pyth-sdk-terra/examples/schema.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use cosmwasm_schema::{
2+
export_schema,
3+
remove_schemas,
4+
schema_for,
5+
};
6+
use std::env::current_dir;
7+
use std::fs::create_dir_all;
8+
9+
use pyth_sdk_terra::{
10+
PriceFeedResponse,
11+
QueryMsg,
12+
};
13+
14+
fn main() {
15+
let mut out_dir = current_dir().unwrap();
16+
out_dir.push("schema");
17+
create_dir_all(&out_dir).unwrap();
18+
remove_schemas(&out_dir).unwrap();
19+
20+
export_schema(&schema_for!(QueryMsg), &out_dir);
21+
export_schema(&schema_for!(PriceFeedResponse), &out_dir);
22+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "PriceFeedResponse",
4+
"type": "object",
5+
"required": [
6+
"price_feed"
7+
],
8+
"properties": {
9+
"price_feed": {
10+
"description": "Pyth Price Feed",
11+
"allOf": [
12+
{
13+
"$ref": "#/definitions/PriceFeed"
14+
}
15+
]
16+
}
17+
},
18+
"definitions": {
19+
"PriceFeed": {
20+
"description": "Represents a current aggregation price from pyth publisher feeds.",
21+
"type": "object",
22+
"required": [
23+
"conf",
24+
"ema_conf",
25+
"ema_price",
26+
"expo",
27+
"id",
28+
"max_num_publishers",
29+
"num_publishers",
30+
"price",
31+
"product_id",
32+
"status"
33+
],
34+
"properties": {
35+
"conf": {
36+
"description": "Confidence interval around the price.",
37+
"type": "integer",
38+
"format": "uint64",
39+
"minimum": 0.0
40+
},
41+
"ema_conf": {
42+
"description": "Exponentially moving average confidence interval.",
43+
"type": "integer",
44+
"format": "uint64",
45+
"minimum": 0.0
46+
},
47+
"ema_price": {
48+
"description": "Exponentially moving average price.",
49+
"type": "integer",
50+
"format": "int64"
51+
},
52+
"expo": {
53+
"description": "Price exponent.",
54+
"type": "integer",
55+
"format": "int32"
56+
},
57+
"id": {
58+
"description": "Unique identifier for this price.",
59+
"type": "array",
60+
"items": {
61+
"type": "integer",
62+
"format": "uint8",
63+
"minimum": 0.0
64+
},
65+
"maxItems": 32,
66+
"minItems": 32
67+
},
68+
"max_num_publishers": {
69+
"description": "Maximum number of allowed publishers that can contribute to a price.",
70+
"type": "integer",
71+
"format": "uint32",
72+
"minimum": 0.0
73+
},
74+
"num_publishers": {
75+
"description": "Number of publishers that made up current aggregate.",
76+
"type": "integer",
77+
"format": "uint32",
78+
"minimum": 0.0
79+
},
80+
"price": {
81+
"description": "The current price.",
82+
"type": "integer",
83+
"format": "int64"
84+
},
85+
"product_id": {
86+
"description": "Product account key.",
87+
"type": "array",
88+
"items": {
89+
"type": "integer",
90+
"format": "uint8",
91+
"minimum": 0.0
92+
},
93+
"maxItems": 32,
94+
"minItems": 32
95+
},
96+
"status": {
97+
"description": "Status of price (Trading is valid).",
98+
"allOf": [
99+
{
100+
"$ref": "#/definitions/PriceStatus"
101+
}
102+
]
103+
}
104+
}
105+
},
106+
"PriceStatus": {
107+
"description": "Represents availability status of a price feed.",
108+
"type": "string",
109+
"enum": [
110+
"Unknown",
111+
"Trading",
112+
"Halted",
113+
"Auction"
114+
]
115+
}
116+
}
117+
}

pyth-sdk-terra/schema/query_msg.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "QueryMsg",
4+
"oneOf": [
5+
{
6+
"type": "object",
7+
"required": [
8+
"price_feed"
9+
],
10+
"properties": {
11+
"price_feed": {
12+
"type": "object",
13+
"required": [
14+
"id"
15+
],
16+
"properties": {
17+
"id": {
18+
"type": "array",
19+
"items": {
20+
"type": "integer",
21+
"format": "uint8",
22+
"minimum": 0.0
23+
},
24+
"maxItems": 32,
25+
"minItems": 32
26+
}
27+
}
28+
}
29+
},
30+
"additionalProperties": false
31+
}
32+
]
33+
}

pyth-sdk-terra/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use cosmwasm_std::{
2+
to_binary,
3+
QuerierWrapper,
4+
QueryRequest,
5+
StdResult,
6+
WasmQuery,
7+
};
8+
use schemars::JsonSchema;
9+
use serde::{
10+
Deserialize,
11+
Serialize,
12+
};
13+
14+
pub use pyth_sdk::{
15+
Price,
16+
PriceFeed,
17+
PriceIdentifier,
18+
PriceStatus,
19+
ProductIdentifier,
20+
};
21+
22+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
23+
#[serde(rename_all = "snake_case")]
24+
pub enum QueryMsg {
25+
PriceFeed { id: PriceIdentifier },
26+
}
27+
28+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
29+
#[serde(rename_all = "snake_case")]
30+
pub struct PriceFeedResponse {
31+
/// Pyth Price Feed
32+
pub price_feed: PriceFeed,
33+
}
34+
35+
/// Queries the price on-chain
36+
pub fn query_price_feed(
37+
querier: &QuerierWrapper,
38+
contract_addr: String,
39+
id: PriceIdentifier,
40+
) -> StdResult<PriceFeedResponse> {
41+
let price_feed_response = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
42+
contract_addr,
43+
msg: to_binary(&QueryMsg::PriceFeed { id })?,
44+
}))?;
45+
Ok(price_feed_response)
46+
}

0 commit comments

Comments
 (0)