Skip to main content

bolt_cw_sdk/oracle/
get_price.rs

1use 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)); // 2h from now
79        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}