koios-sdk 0.1.1

A Rust SDK for the Koios Cardano API
Documentation
use crate::{
    error::Result,
    models::{
        address::{AddressAsset, AddressInfo, AddressTransaction},
        requests::{
            AddressTransactionsRequest, CredentialTransactionsRequest, CredentialUtxosRequest,
            PaymentAddressesRequest, PaymentAddressesWithExtendedRequest,
        },
        UtxoInfo,
    },
    Client,
};
use urlencoding::encode;

impl Client {
    /// Get address info - balance, associated stake address (if any) and UTxO set for given addresses
    ///
    /// # Arguments
    ///
    /// * `addresses` - List of addresses to query
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let addresses = vec![
    ///         "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz".to_string()
    ///     ];
    ///     let address_info = client.get_address_info(&addresses).await?;
    ///     println!("Address info: {:?}", address_info);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_address_info(&self, addresses: &[String]) -> Result<Vec<AddressInfo>> {
        let encoded_addresses: Vec<String> = addresses
            .iter()
            .map(|addr| encode(addr).into_owned())
            .collect();
        let request = PaymentAddressesRequest::new(encoded_addresses);
        self.post("/address_info", &request).await
    }

    /// Get UTxO set for given addresses
    ///
    /// # Arguments
    ///
    /// * `addresses` - List of addresses to query
    /// * `extended` - Optional flag to include extended information
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let addresses = vec![
    ///         "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz".to_string()
    ///     ];
    ///     let utxos = client.get_address_utxos(&addresses, Some(true)).await?;
    ///     println!("Address UTXOs: {:?}", utxos);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_address_utxos(
        &self,
        addresses: &[String],
        extended: Option<bool>,
    ) -> Result<Vec<UtxoInfo>> {
        let encoded_addresses: Vec<String> = addresses
            .iter()
            .map(|addr| encode(addr).into_owned())
            .collect();
        let request = PaymentAddressesWithExtendedRequest::new(encoded_addresses, extended);
        self.post("/address_utxos", &request).await
    }

    /// Get UTxO details for requested payment credentials
    ///
    /// # Arguments
    ///
    /// * `payment_credentials` - List of payment credentials to query
    /// * `extended` - Optional flag to include extended information
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let credentials = vec![
    ///         "025b0a8f85cb8a46e1dda3fae5d22f07e2d56abb4019a2129c5d6c52".to_string()
    ///     ];
    ///     let utxos = client.get_credential_utxos(&credentials, Some(true)).await?;
    ///     println!("Credential UTXOs: {:?}", utxos);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_credential_utxos(
        &self,
        payment_credentials: &[String],
        extended: Option<bool>,
    ) -> Result<Vec<UtxoInfo>> {
        let encoded_credentials: Vec<String> = payment_credentials
            .iter()
            .map(|cred| encode(cred).into_owned())
            .collect();
        let request = CredentialUtxosRequest::new(encoded_credentials, extended);
        self.post("/credential_utxos", &request).await
    }

    /// Get the transaction hash list of input address array, optionally filtering after specified block height
    ///
    /// # Arguments
    ///
    /// * `addresses` - List of addresses to query
    /// * `after_block_height` - Optional block height to filter from
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let addresses = vec![
    ///         "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz".to_string()
    ///     ];
    ///     let txs = client.get_address_transactions(&addresses, Some(42000000)).await?;
    ///     println!("Address transactions: {:?}", txs);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_address_transactions(
        &self,
        addresses: &[String],
        after_block_height: Option<u64>,
    ) -> Result<Vec<AddressTransaction>> {
        let encoded_addresses: Vec<String> = addresses
            .iter()
            .map(|addr| encode(addr).into_owned())
            .collect();
        let request = AddressTransactionsRequest::new(encoded_addresses, after_block_height);
        self.post("/address_txs", &request).await
    }

    /// Get the transaction hash list of input payment credential array, optionally filtering after specified block height
    ///
    /// # Arguments
    ///
    /// * `payment_credentials` - List of payment credentials to query
    /// * `after_block_height` - Optional block height to filter from
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let credentials = vec![
    ///         "025b0a8f85cb8a46e1dda3fae5d22f07e2d56abb4019a2129c5d6c52".to_string()
    ///     ];
    ///     let txs = client.get_credential_transactions(&credentials, Some(42000000)).await?;
    ///     println!("Credential transactions: {:?}", txs);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_credential_transactions(
        &self,
        payment_credentials: &[String],
        after_block_height: Option<u64>,
    ) -> Result<Vec<AddressTransaction>> {
        let encoded_credentials: Vec<String> = payment_credentials
            .iter()
            .map(|cred| encode(cred).into_owned())
            .collect();
        let request = CredentialTransactionsRequest::new(encoded_credentials, after_block_height);
        self.post("/credential_txs", &request).await
    }

    /// Get the list of all the assets (policy, name and quantity) for given addresses
    ///
    /// # Arguments
    ///
    /// * `addresses` - List of addresses to query
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use koios_sdk::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new()?;
    ///     let addresses = vec![
    ///         "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz".to_string()
    ///     ];
    ///     let assets = client.get_address_assets(&addresses).await?;
    ///     println!("Address assets: {:?}", assets);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_address_assets(&self, addresses: &[String]) -> Result<Vec<AddressAsset>> {
        let encoded_addresses: Vec<String> = addresses
            .iter()
            .map(|addr| encode(addr).into_owned())
            .collect();
        let request = PaymentAddressesRequest::new(encoded_addresses);
        self.post("/address_assets", &request).await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;
    use wiremock::matchers::{method, path};
    use wiremock::{Mock, MockServer, ResponseTemplate};

    #[tokio::test]
    async fn test_get_address_info() {
        let mock_server = MockServer::start().await;
        let client = Client::builder()
            .base_url(mock_server.uri())
            .build()
            .unwrap();

        let address = "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz";
        let mock_response = json!([{
            "address": address,
            "balance": "42000000",
            "stake_address": "stake1u9ylzsgxaa6xctf4juup682ar3juj85n8tx3hthnljg47zctvm3rc",
            "script_address": false,
            "utxo_set": []
        }]);

        Mock::given(method("POST"))
            .and(path("/address_info"))
            .respond_with(ResponseTemplate::new(200).set_body_json(&mock_response))
            .mount(&mock_server)
            .await;

        let response = client
            .get_address_info(&[address.to_string()])
            .await
            .unwrap();
        assert_eq!(response.len(), 1);
        assert_eq!(response[0].address, address);
    }

    // Add more tests for other endpoints...
}