bolt-cw-sdk 1.0.0

SDK for the BOLT protocol, providing utilities for interacting with the BOLT contracts.
Documentation
use cosmwasm_std::{Decimal256, Timestamp};
use serde::{Deserialize, Serialize};

use crate::oracle::client::OracleClient;
use crate::oracle::error::OracleError;

impl OracleClient {
    pub async fn get_prices(&self) -> Result<Vec<Price>, OracleError> {
        let query = Query {
            get_prices: GetPricesRequest {},
        };
        let response: GetPricesResponse = self
            .query_contract(self.oracle_contract_address.to_string(), &query, None)
            .await?
            .data;
        Ok(response.prices)
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct AssetPair(String);

impl PartialEq<String> for AssetPair {
    fn eq(&self, other: &String) -> bool {
        &self.0 == other
    }
}

impl From<AssetPair> for String {
    fn from(pair: AssetPair) -> Self {
        pair.0
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Price {
    pub asset_pair: AssetPair,
    pub price: Decimal256,
    pub expiry_time: Timestamp,
}

#[derive(Serialize)]
struct Query {
    pub get_prices: GetPricesRequest,
}

#[derive(Serialize)]
struct GetPricesRequest {}

#[derive(Deserialize)]
struct GetPricesResponse {
    pub prices: Vec<Price>,
}

#[cfg(test)]
mod tests {
    use std::ops::Add;
    use std::str::FromStr;
    use std::time::{Duration, SystemTime, UNIX_EPOCH};

    use serial_test::serial;

    use super::*;
    use crate::oracle::client::OracleAdminClient;
    use crate::test_utils::helpers::{
        TEST_ASSET_ARCH_ETH_PAIR, TEST_ASSET_ARCH_USDT_PAIR, TEST_ASSET_ETH_USDT_PAIR,
    };
    use crate::test_utils::test_scenario::TestScenario;

    #[test]
    fn eq_asset_pair() {
        let cmp = "DummyString".to_string();
        let pair = AssetPair(cmp.clone());

        assert_eq!(pair, cmp);
        assert_ne!(pair, "NotTheSame :(".to_string())
    }

    #[tokio::test]
    #[serial]
    async fn test_get_prices() {
        let test_scenario = TestScenario::new_from_config("config.json".to_string()).await;

        let price_threshold_ratio = Decimal256::from_str("0.5").unwrap();
        let price_expire_millis = Some(1000);
        let oracle_contract_address = test_scenario
            .instantiate_oracle_contract(price_threshold_ratio, price_expire_millis)
            .await;

        let client = OracleAdminClient::from_scenario(&test_scenario, &oracle_contract_address)
            .expect("Failed to create oracle admin client");

        let price_expiry_time = SystemTime::now().add(Duration::from_secs(7200)); // 2h from now
        let price_expiry_timestamp = price_expiry_time
            .duration_since(UNIX_EPOCH)
            .expect("Converting to timestamp failed");
        let price = Decimal256::from_str("50000").unwrap();

        let prices = client
            .public_oracle_client
            .get_prices()
            .await
            .expect("Failed to get prices");
        assert!(
            prices.is_empty(),
            "Prices should be empty before setting any"
        );

        test_scenario.set_default_assets(&client).await;
        test_scenario
            .set_default_prices(&client, price_expiry_timestamp, "50000")
            .await;

        let prices = client.public_oracle_client.get_prices().await.unwrap();
        let price_arch_usdt = Price {
            asset_pair: AssetPair(TEST_ASSET_ARCH_USDT_PAIR.to_owned()),
            price,
            expiry_time: Timestamp::from_seconds(price_expiry_timestamp.as_secs()),
        };
        let price_arch_eth = Price {
            asset_pair: AssetPair(TEST_ASSET_ARCH_ETH_PAIR.to_owned()),
            price,
            expiry_time: Timestamp::from_seconds(price_expiry_timestamp.as_secs()),
        };
        let price_eth_usdt = Price {
            asset_pair: AssetPair(TEST_ASSET_ETH_USDT_PAIR.to_owned()),
            price,
            expiry_time: Timestamp::from_seconds(price_expiry_timestamp.as_secs()),
        };
        assert_eq!(
            prices,
            vec![price_eth_usdt, price_arch_eth, price_arch_usdt]
        )
    }
}