bolt_cw_sdk/oracle/
get_price.rs1use crate::oracle::client::OracleClient;
2use crate::oracle::error::OracleError;
3use cosmwasm_std::{Decimal256, Timestamp};
4use serde::{Deserialize, Serialize};
5
6impl OracleClient {
7 pub async fn get_price(
8 &self,
9 base_token: String,
10 quote_token: String,
11 ) -> Result<Price, OracleError> {
12 let query = Query {
13 get_price: GetPriceRequest {
14 base_asset_symbol: base_token,
15 quote_asset_symbol: quote_token,
16 },
17 };
18 let response: GetPriceResponse = self
19 .query_contract(self.oracle_contract_address.to_string(), &query, None)
20 .await?
21 .data;
22 response.pair_data.ok_or_else(|| {
23 OracleError::PriceNotFound(
24 query.get_price.base_asset_symbol,
25 query.get_price.quote_asset_symbol,
26 )
27 })
28 }
29}
30
31#[derive(Serialize, Deserialize, Debug)]
32pub struct Price {
33 pub price: Decimal256,
34 pub expiry_time: Timestamp,
35}
36
37#[derive(Serialize)]
38struct Query {
39 pub get_price: GetPriceRequest,
40}
41
42#[derive(Serialize)]
43struct GetPriceRequest {
44 pub base_asset_symbol: String,
45 pub quote_asset_symbol: String,
46}
47
48#[derive(Deserialize)]
49struct GetPriceResponse {
50 pub pair_data: Option<Price>,
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use crate::oracle::client::OracleAdminClient;
57
58 use crate::test_utils::helpers::{TEST_ASSET_ARCH_SYMBOL, TEST_ASSET_USDT_SYMBOL};
59 use crate::test_utils::test_scenario::TestScenario;
60 use serial_test::serial;
61 use std::ops::Add;
62 use std::str::FromStr;
63 use std::time::{Duration, SystemTime, UNIX_EPOCH};
64
65 #[tokio::test]
66 #[serial]
67 async fn test_get_price() {
68 let test_scenario = TestScenario::new_from_config("config.json".to_string()).await;
69
70 let price_threshold_ratio = Decimal256::from_str("0.5").unwrap();
71 let price_expire_millis = Some(1000);
72 let oracle_contract_address = test_scenario
73 .instantiate_oracle_contract(price_threshold_ratio, price_expire_millis)
74 .await;
75
76 let client = OracleAdminClient::from_scenario(&test_scenario, &oracle_contract_address)
77 .expect("Failed to create oracle admin client");
78 let price_expiry_time = SystemTime::now().add(Duration::from_secs(7200)); let price_expiry_timestamp = price_expiry_time
80 .duration_since(UNIX_EPOCH)
81 .expect("Converting to timestamp failed");
82
83 let err = client
84 .public_oracle_client
85 .get_price(
86 TEST_ASSET_ARCH_SYMBOL.to_string(),
87 TEST_ASSET_USDT_SYMBOL.to_string(),
88 )
89 .await
90 .expect_err("Expected error as we haven't set any asset pairs yet");
91 assert_eq!(
92 err.to_string(),
93 OracleError::PriceNotFound(
94 TEST_ASSET_ARCH_SYMBOL.to_string(),
95 TEST_ASSET_USDT_SYMBOL.to_string()
96 )
97 .to_string()
98 );
99
100 test_scenario.set_default_assets(&client).await;
101
102 let err = client
103 .public_oracle_client
104 .get_price(
105 TEST_ASSET_ARCH_SYMBOL.to_string(),
106 TEST_ASSET_USDT_SYMBOL.to_string(),
107 )
108 .await
109 .expect_err("Expected error as we haven't set any prices yet");
110 assert!(matches!(err, OracleError::PriceNotFound(_, _)));
111
112 test_scenario
113 .set_default_prices(&client, price_expiry_timestamp, "50000")
114 .await;
115
116 let client = OracleClient::new(
117 test_scenario.cosmos_client,
118 oracle_contract_address
119 .parse()
120 .expect("Failed to parse account ID"),
121 )
122 .expect("Failed to create oracle client");
123 let result = client
124 .get_price(
125 TEST_ASSET_ARCH_SYMBOL.to_string(),
126 TEST_ASSET_USDT_SYMBOL.to_string(),
127 )
128 .await;
129 assert!(result.is_ok());
130 let price = result.unwrap();
131 assert_eq!(price.price, Decimal256::from_str("50000").unwrap());
132 }
133}