diff --git a/stellar_rust_sdk/src/horizon_client.rs b/stellar_rust_sdk/src/horizon_client.rs index e0492e8..e07ac2b 100644 --- a/stellar_rust_sdk/src/horizon_client.rs +++ b/stellar_rust_sdk/src/horizon_client.rs @@ -36,6 +36,7 @@ use crate::{ trade_aggregations::prelude::*, transactions::prelude::*, trades::prelude::*, + payments::prelude::* }; use reqwest; use url::Url; @@ -1093,26 +1094,26 @@ impl HorizonClient { } /// Retrieves a list of order book details from the Horizon server. - /// + /// /// This asynchronous method fetches a list of order book details from the Horizon server. /// It requires a [`DetailsRequest`] to specify the parameters for the order book details request. - /// + /// /// # Arguments /// * `request` - A reference to a [`DetailsRequest`] instance, containing the parameters for the order book details request. - /// + /// /// # Returns - /// + /// /// On successful execution, returns a `Result` containing a [`DetailsResponse`], which includes the list of order book details obtained from the Horizon server. /// If the request fails, it returns an error within `Result`. - /// + /// /// # Usage /// To use this method, create an instance of [`DetailsRequest`] and set any desired filters or parameters. - /// + /// /// ``` /// # use stellar_rs::order_book::prelude::*; /// # use stellar_rs::models::Request; /// # use stellar_rs::horizon_client::HorizonClient; - /// + /// /// # async fn example() -> Result<(), Box> { /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); /// # let horizon_client = HorizonClient::new(base_url) @@ -1126,14 +1127,14 @@ impl HorizonClient { /// # .to_string(), /// # })) /// # .unwrap(); - /// + /// /// let response = horizon_client.get_order_book_details(&details_request).await; - /// + /// /// assert!(response.is_ok()); /// # Ok({}) /// # } /// ``` - /// + /// pub async fn get_order_book_details( &self, request: &DetailsRequest, @@ -1142,29 +1143,29 @@ impl HorizonClient { } /// Retrieves a list of trade aggregations from the Horizon server. - /// + /// /// This asynchronous method fetches a list of trade aggregations from the Horizon server. /// It requires a [`TradeAggregationsRequest`] to specify the parameters for the trade aggregations request. - /// + /// /// # Arguments /// * `request` - A reference to a [`TradeAggregationsRequest`] instance, containing the parameters for the order book details request. - /// + /// /// # Returns - /// + /// /// On successful execution, returns a `Result` containing a [`AllTradeAggregationsResponse`], which includes the list of order book details obtained from the Horizon server. /// If the request fails, it returns an error within `Result`. - /// + /// /// # Usage /// To use this method, create an instance of [`TradeAggregationsRequest`] and set any desired filters or parameters. - /// + /// /// ```rust /// use stellar_rs::horizon_client::HorizonClient; /// use stellar_rs::trade_aggregations::prelude::*; /// use stellar_rs::models::Request; - /// + /// /// # async fn example() -> Result<(), Box> { /// let horizon_client = HorizonClient::new("https://horizon-testnet.stellar.org".to_string())?; - /// + /// /// // Example: Fetching trade aggregations /// let request = TradeAggregationsRequest::new() /// .set_base_asset(AssetType::Native).unwrap() @@ -1174,12 +1175,12 @@ impl HorizonClient { /// })).unwrap() /// .set_resolution(Resolution(ResolutionData::Duration604800000)).unwrap(); /// let response = horizon_client.get_trade_aggregations(&request).await?; - /// + /// /// // Process the response... /// # Ok(()) /// # } /// ``` - /// + /// pub async fn get_trade_aggregations( &self, request: &TradeAggregationsRequest, @@ -1388,7 +1389,7 @@ impl HorizonClient { ) -> Result { self.get::(request).await } - + /// Retrieves a list of all operations for a specific liquidity pool from the Horizon server. /// /// This asynchronous method fetches a list of all operations for a specific liquidity pool from the Horizon server. @@ -1622,7 +1623,7 @@ impl HorizonClient { /// .unwrap(); /// /// let response = horizon_client.get_single_transaction(&request).await; - /// + /// /// // Access the details of the claimable balance /// if let Ok(transaction_response) = response { /// println!("Created at: {}", transaction_response.created_at()); @@ -1640,7 +1641,6 @@ impl HorizonClient { self.get::(request).await } - /// Retrieves a list of all transactions from the Horizon server. /// /// This asynchronous method fetches a list of all transactions from the Horizon server. @@ -1692,7 +1692,7 @@ impl HorizonClient { ) -> Result { self.get::(request).await } - + /// Retrieves a list of all transactions for a given account from the Horizon server. /// /// This asynchronous method fetches a list of all transactions for a given account from @@ -1745,7 +1745,7 @@ impl HorizonClient { ) -> Result { self.get::(request).await } - + /// Retrieves a list of all transactions in a given ledger from the Horizon server. /// /// This asynchronous method fetches a list of all transactions in a given ledger from @@ -1851,6 +1851,216 @@ impl HorizonClient { ) -> Result { self.get::(request).await } + + /// Retrieves a list of all payments from the Horizon server. + /// + /// This asynchronous method fetches a list of all payments from the Horizon server. + /// It requires an [`AllPaymentsRequest`] to specify the optional query parameters. + /// + /// # Arguments + /// * `request` - A reference to an [`AllPaymentsRequest`] instance, containing the + /// parameters for the payments request. + /// + /// # Returns + /// + /// On successful execution, returns a `Result` containing a [`PaymentsResponse`], which includes + /// the list of all payments obtained from the Horizon server. If the request fails, it returns an error within `Result`. + /// + /// # Usage + /// To use this method, create an instance of [`AllPaymentsRequest`] and set any desired + /// filters or parameters. + /// + /// ``` + /// # use stellar_rs::payments::prelude::*; + /// # use stellar_rs::models::Request; + /// # use stellar_rs::horizon_client::HorizonClient; + /// # use stellar_rust_sdk_derive::Pagination; + /// # use stellar_rs::Paginatable; + /// # + /// # async fn example() -> Result<(), Box> { + /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); + /// # let horizon_client = HorizonClient::new(base_url) + /// # .expect("Failed to create Horizon Client"); + /// let request = AllPaymentsRequest::new() + /// .set_limit(2).unwrap(); + /// + /// let response = horizon_client.get_all_payments(&request).await; + /// + /// // Access the payments + /// if let Ok(payments_response) = response { + /// for payment in payments_response.embedded().records() { + /// println!("Payment ID: {}", payment.id()); + /// // Further processing... + /// } + /// } + /// # Ok({}) + /// # } + /// ``` + /// + pub async fn get_all_payments( + &self, + request: &AllPaymentsRequest, + ) -> Result { + self.get::(request).await + } + + /// Retrieves a list of all payments for an account from the Horizon server. + /// + /// This asynchronous method fetches a list of all payments for an account from the Horizon server. + /// It requires an [`PaymentsForAccountRequest`] to specify the optional query parameters. + /// + /// # Arguments + /// * `request` - A reference to an [`PaymentsForAccountRequest`] instance, containing the + /// parameters for the payments for account request. + /// + /// # Returns + /// + /// On successful execution, returns a `Result` containing a [`PaymentsResponse`], which includes + /// the list of all payments obtained from the Horizon server. If the request fails, it returns an error within `Result`. + /// + /// # Usage + /// To use this method, create an instance of [`PaymentsForAccountRequest`] and set any desired + /// filters or parameters. + /// + /// ``` + /// # use stellar_rs::payments::prelude::*; + /// # use stellar_rs::models::Request; + /// # use stellar_rs::horizon_client::HorizonClient; + /// # use stellar_rust_sdk_derive::Pagination; + /// # use stellar_rs::Paginatable; + /// + /// # async fn example() -> Result<(), Box> { + /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); + /// # let horizon_client = HorizonClient::new(base_url) + /// # .expect("Failed to create Horizon Client"); + /// let request = PaymentsForAccountRequest::new() + /// .set_limit(2).unwrap(); + /// + /// let response = horizon_client.get_payments_for_account(&request).await; + /// + /// // Access the payments + /// if let Ok(payments_response) = response { + /// for payment in payments_response.embedded().records() { + /// println!("Payment ID: {}", payment.id()); + /// // Further processing... + /// } + /// } + /// # Ok({}) + /// # } + /// ``` + /// + pub async fn get_payments_for_account( + &self, + request: &PaymentsForAccountRequest, + ) -> Result { + self.get::(request).await + } + + /// Retrieves a list of all payments for a specific ledger from the Horizon server. + /// + /// This asynchronous method fetches a list of all payments for a specific ledger from the Horizon server. + /// It requires an [`PaymentsForLedgerRequest`] to specify the ledger sequence number and optional query parameters. + /// + /// # Arguments + /// * `request` - A reference to an [`PaymentsForLedgerRequest`] instance, containing the + /// parameters for the payments for ledger request. + /// + /// # Returns + /// + /// On successful execution, returns a `Result` containing a [`PaymentsResponse`], which includes + /// the list of all payments obtained from the Horizon server. If the request fails, it returns an error within `Result`. + /// + /// # Usage + /// To use this method, create an instance of [`PaymentsForLedgerRequest`] and set the ledger sequence number and any desired + /// filters or parameters. + /// + /// ``` + /// # use stellar_rs::payments::prelude::*; + /// # use stellar_rs::models::Request; + /// # use stellar_rs::horizon_client::HorizonClient; + /// # use stellar_rust_sdk_derive::Pagination; + /// # use stellar_rs::Paginatable; + /// + /// # async fn example() -> Result<(), Box> { + /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); + /// # let horizon_client = HorizonClient::new(base_url) + /// # .expect("Failed to create Horizon Client"); + /// let request = PaymentsForLedgerRequest::new() + /// .set_ledger_sequence("48483".to_string()); + /// + /// let response = horizon_client.get_payments_for_ledger(&request).await; + /// + /// // Access the payments + /// if let Ok(payments_response) = response { + /// for payment in payments_response.embedded().records() { + /// println!("Payment ID: {}", payment.id()); + /// + /// // Further processing... + /// } + /// } + /// # Ok({}) + /// # } + /// ``` + /// + pub async fn get_payments_for_ledger( + &self, + request: &PaymentsForLedgerRequest, + ) -> Result { + self.get::(request).await + } + + /// Retrieves a list of all payments for a specific transaction from the Horizon server. + /// + /// This asynchronous method fetches a list of all payments for a specific transaction from the Horizon server. + /// It requires an [`PaymentsForTransactionRequest`] to specify the transaction hash and optional query parameters. + /// + /// # Arguments + /// * `request` - A reference to an [`PaymentsForTransactionRequest`] instance, containing the + /// parameters for the payments for transaction request. + /// + /// # Returns + /// + /// On successful execution, returns a `Result` containing a [`PaymentsResponse`], which includes + /// the list of all payments obtained from the Horizon server. If the request fails, it returns an error within `Result`. + /// + /// # Usage + /// To use this method, create an instance of [`PaymentsForTransactionRequest`] and set the transaction hash and any desired + /// filters or parameters. + /// + /// ``` + /// # use stellar_rs::payments::prelude::*; + /// # use stellar_rs::models::Request; + /// # use stellar_rs::horizon_client::HorizonClient; + /// # use stellar_rust_sdk_derive::Pagination; + /// # use stellar_rs::Paginatable; + /// + /// # async fn example() -> Result<(), Box> { + /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); + /// # let horizon_client = HorizonClient::new(base_url) + /// # .expect("Failed to create Horizon Client"); + /// let request = PaymentsForTransactionRequest::new() + /// .set_transaction_hash("be0d59c8706e8fd525d2ab10910a55ec57323663858c65b330a3f93afb13ab0f".to_string()); + /// + /// let response = horizon_client.get_payments_for_transaction(&request).await; + /// + /// // Access the payments + /// if let Ok(payments_response) = response { + /// for payment in payments_response.embedded().records() { + /// println!("Payment ID: {}", payment.id()); + /// + /// // Further processing... + /// } + /// } + /// # Ok({}) + /// # } + /// ``` + /// + pub async fn get_payments_for_transaction( + &self, + request: &PaymentsForTransactionRequest, + ) -> Result { + self.get::(request).await + } } /// Handles the response received from an HTTP request made to the Horizon server. diff --git a/stellar_rust_sdk/src/lib.rs b/stellar_rust_sdk/src/lib.rs index fd0133b..76ae58e 100644 --- a/stellar_rust_sdk/src/lib.rs +++ b/stellar_rust_sdk/src/lib.rs @@ -15,7 +15,7 @@ //! stabilization. //! //! #### Supported endpoints: -//! ![80%](https://progress-bar.dev/80/?width=200) +//! ![86%](https://progress-bar.dev/86/?width=200) //! * Accounts //! * Assets //! * Claimable balance @@ -26,12 +26,12 @@ //! * Operations //! * Offers //! * Orderbook +//! * Payments //! * Trades //! * Trade aggregations //! //! #### Endpoints on the roadmap: //! * Paths -//! * Payments //! * Transactions //! @@ -205,7 +205,7 @@ pub mod claimable_balances; /// /// let base_url = "https://horizon-testnet.stellar.org".to_string(); /// let horizon_client = HorizonClient::new(base_url) -/// .expect("Failed to create Horizon Client");; +/// .expect("Failed to create Horizon Client"); /// ``` /// /// # Using the `HorizonClient` @@ -220,7 +220,7 @@ pub mod claimable_balances; /// # async fn example() -> Result<(), Box> { /// # let base_url = "https://horizon-testnet.stellar.org".to_string(); /// # let horizon_client = HorizonClient::new(base_url) -/// # .expect("Failed to create Horizon Client");; +/// # .expect("Failed to create Horizon Client"); /// let all_assets_request = AllAssetsRequest::new(); /// let accounts_response = horizon_client /// .get_all_assets(&all_assets_request) @@ -509,30 +509,30 @@ pub mod operations; pub mod order_book; /// Provides `Request` and `Response` structs for retrieving trade aggregation details. -/// +/// /// The `trade_aggregations` module in the Stellar Horizon SDK includes structures and methods that facilitate /// querying trade aggregations data from the Horizon server. -/// +/// /// # Usage -/// +/// /// This module is used to construct requests for trade aggregations related data and to parse the responses /// received from the Horizon server. It includes request and response structures for querying /// trade aggregations. -/// +/// /// # Example -/// +/// /// To use this module, you can create an instance of a request struct, such as `TradeAggregationsRequest`, /// set any desired query parameters, and pass the request to the `HorizonClient`. The client will /// then execute the request and return the corresponding response struct, like `AllTradeAggregationsResponse`. -/// +/// /// ```rust /// use stellar_rs::horizon_client::HorizonClient; /// use stellar_rs::trade_aggregations::prelude::*; /// use stellar_rs::models::Request; -/// +/// /// # async fn example() -> Result<(), Box> { /// let horizon_client = HorizonClient::new("https://horizon-testnet.stellar.org".to_string())?; -/// +/// /// // Example: Fetching trade aggregations /// let request = TradeAggregationsRequest::new() /// .set_base_asset(AssetType::Native).unwrap() @@ -542,7 +542,7 @@ pub mod order_book; /// })).unwrap() /// .set_resolution(Resolution(ResolutionData::Duration604800000)).unwrap(); /// let response = horizon_client.get_trade_aggregations(&request).await?; -/// +/// /// // Process the response... /// # Ok(()) /// # } @@ -632,6 +632,47 @@ pub mod transactions; /// pub mod trades; +/// Provides `Request` and `Response` structs for retrieving payments. +/// +/// This module provides a set of specialized request and response structures designed for +/// interacting with the payment-related endpoints of the Horizon server. These structures +/// facilitate the construction of requests to query trade data and the interpretation of +/// the corresponding responses. +/// +/// # Usage +/// +/// This module is intended to be used in conjunction with the [`HorizonClient`](crate::horizon_client::HorizonClient) +/// for making specific payment-related API calls to the Horizon server. The request +/// structures are designed to be passed to the client's methods, which handle the +/// communication with the server and return the corresponding response structures. +/// +/// /// # Example +/// +/// To use this module, you can create an instance of a request struct, such as +/// `AllPaymentsRequest`, set any desired query parameters, and pass the request to the +/// `HorizonClient`. The client will then execute the request and return the corresponding +/// response struct, like `AllPaymentsResponse`. +/// +/// ```rust +/// use stellar_rs::horizon_client::HorizonClient; +/// use stellar_rs::payments::prelude::*; +/// use stellar_rs::models::Request; +/// +/// # async fn example() -> Result<(), Box> { +/// let horizon_client = HorizonClient::new("https://horizon-testnet.stellar.org".to_string())?; +/// +/// // Example: Fetching all payments +/// let all_payments_request = AllPaymentsRequest::new(); +/// +/// let all_payments_response = horizon_client.get_all_payments(&all_payments_request).await?; +/// +/// // Process the responses... +/// # Ok(()) +/// # } +/// ``` +/// +pub mod payments; + /// Contains core data structures and traits. /// /// This module is used by the Stellar Rust SDK to interact with the Horizon API. diff --git a/stellar_rust_sdk/src/models/mod.rs b/stellar_rust_sdk/src/models/mod.rs index 9c8f18b..706b1f8 100644 --- a/stellar_rust_sdk/src/models/mod.rs +++ b/stellar_rust_sdk/src/models/mod.rs @@ -232,8 +232,10 @@ impl std::fmt::Display for Order { } } +#[derive(Default, Clone, PartialEq)] pub enum IncludeFailed { True, + #[default] False, } diff --git a/stellar_rust_sdk/src/payments/all_payments_request.rs b/stellar_rust_sdk/src/payments/all_payments_request.rs new file mode 100644 index 0000000..b8b6bcc --- /dev/null +++ b/stellar_rust_sdk/src/payments/all_payments_request.rs @@ -0,0 +1,42 @@ +use crate::models::{Order, Request}; +use crate::{BuildQueryParametersExt, Paginatable}; +use stellar_rust_sdk_derive::Pagination; + +#[derive(Default, Pagination)] +pub struct AllPaymentsRequest { + /// A pointer to a specific location in a collection of responses, derived from the + /// `paging_token` value of a record. Used for pagination control in the API response. + cursor: Option, + /// Specifies the maximum number of records to be returned in a single response. + /// The range for this parameter is from 1 to 200. The default value is set to 10. + limit: Option, + /// Determines the [`Order`] of the records in the response. Valid options are [`Order::Asc`] (ascending) + /// and [`Order::Desc`] (descending). If not specified, it defaults to ascending. + order: Option, +} + +impl AllPaymentsRequest { + /// Creates a new `AllPaymentsRequest` with default parameters. + pub fn new() -> AllPaymentsRequest { + AllPaymentsRequest { + cursor: None, + limit: None, + order: None, + } + } +} + +impl Request for AllPaymentsRequest { + fn get_query_parameters(&self) -> String { + vec![ + self.cursor.as_ref().map(|c| format!("cursor={}", c)), + self.limit.as_ref().map(|l| format!("limit={}", l)), + self.order.as_ref().map(|o| format!("order={}", o)), + ] + .build_query_parameters() + } + + fn build_url(&self, base_url: &str) -> String { + format!("{}/payments?{}", base_url, self.get_query_parameters()) + } +} diff --git a/stellar_rust_sdk/src/payments/mod.rs b/stellar_rust_sdk/src/payments/mod.rs new file mode 100644 index 0000000..b7c360c --- /dev/null +++ b/stellar_rust_sdk/src/payments/mod.rs @@ -0,0 +1,225 @@ +/// Provides the `AllPaymentsRequest` struct to build the request for the `/payments` endpoint +/// +/// # Usage +/// This module provides the `AllPaymentsRequest` struct, specifically for constructing requests to query information +/// about all payments made on the Stellar network. It is tailored for use in the `HorizonClient::get_all_payments` function. +pub mod all_payments_request; + +/// Provides the `PaymentsForAccountRequest` struct to build the request for the `/accounts/{account_id}/payments` endpoint +/// +/// # Usage +/// This module provides the `PaymentsForAccountRequest` struct, specifically for constructing requests to query information +/// about payments made to a specific account on the Stellar network. It is tailored for use in the `HorizonClient::get_payments_for_account` function. +/// +pub mod payments_for_account_request; + +/// Provides the `PaymentsForLedgerRequest` struct to build the request for the `/ledgers/{ledger_sequence}/payments` endpoint +/// +/// # Usage +/// This module provides the `PaymentsForLedgerRequest` struct, specifically for constructing requests to query information +/// about payments made in a specific ledger on the Stellar network. It is tailored for use in the `HorizonClient::get_payments_for_ledger` function. +/// +pub mod payments_for_ledger_request; + +/// Provides the `PaymentsForTransactionRequest` struct to build the request for the `/transactions/{transaction_hash}/payments` endpoint +/// +/// # Usage +/// This module provides the `PaymentsForTransactionRequest` struct, specifically for constructing requests to query information +/// about payments made in a specific transaction on the Stellar network. It is tailored for use in the `HorizonClient::get_payments_for_transaction` function. +/// +pub mod payments_for_transaction_request; + +/// Provides the `PaymentsResponse` struct to parse the response from the Horizon server when querying for payments +/// +/// This module defines structures representing the response from the Horizon API when querying +/// for payments. The structures are designed to deserialize the JSON response into Rust +/// objects, enabling straightforward access to various details of a single transaction. +/// Some fields are optional because not every payment response is exactly alike, but not different enough to warrent +/// different response structs for each type of payment. +/// +/// # Usage +/// This module provides the `PaymentsResponse` struct, which represents the response from the Horizon server when querying for payments. +/// It includes the links to the current, next, and previous pages of the response, as well as the embedded records of payments. +/// +pub mod response; + +static PAYMENTS_PATH: &str = "payments"; + +pub mod prelude { + pub use super::all_payments_request::*; + pub use super::payments_for_account_request::*; + pub use super::payments_for_ledger_request::*; + pub use super::payments_for_transaction_request::*; + pub use super::response::*; +} + +#[cfg(test)] +pub mod test { + use super::prelude::*; + use crate::{horizon_client::HorizonClient, models::IncludeFailed, Paginatable}; + + static ID: &str = "2314987376641"; + static PAGING_TOKEN: &str = "2314987376641"; + static TRANSACTION_SUCCESSFUL: &bool = &true; + static SOURCE_ACCOUNT: &str = "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"; + static TYPE: &str = "create_account"; + static TYPE_I: &i64 = &0; + static CREATED_AT: &str = "2024-06-11T21:36:12Z"; + static TRANSACTION_HASH: &str = + "b9d0b2292c4e09e8eb22d036171491e87b8d2086bf8b265874c8d182cb9c9020"; + static STARTING_BALANCE: &str = "10000000000.0000000"; + static FUNDER: &str = "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"; + static ACCOUNT: &str = "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR"; + static LEDGER_SEQUENCE: &str = "48483"; + + #[tokio::test] + async fn test_get_all_payments() { + // Initialize horizon client + let horizon_client = + HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); + + // construct request + let all_payments_request: AllPaymentsRequest = + AllPaymentsRequest::new().set_limit(1).unwrap(); + + let response: Result = + horizon_client.get_all_payments(&all_payments_request).await; + + assert!(response.is_ok()); + let binding = response.unwrap(); + let response = &binding.embedded().records()[0]; + assert_eq!(response.id(), ID); + assert_eq!(response.paging_token(), PAGING_TOKEN); + assert_eq!(response.transaction_successful(), TRANSACTION_SUCCESSFUL); + assert_eq!(response.source_account(), SOURCE_ACCOUNT); + assert_eq!(response.type_field(), TYPE); + assert_eq!(response.type_i(), TYPE_I); + assert_eq!(response.created_at(), CREATED_AT); + assert_eq!(response.transaction_hash(), TRANSACTION_HASH); + assert_eq!( + response.starting_balance().as_deref(), + Some(STARTING_BALANCE) + ); + assert_eq!(response.funder().as_deref(), Some(FUNDER)); + assert_eq!(response.account().as_deref(), Some(ACCOUNT)); + } + + #[tokio::test] + async fn test_get_payments_for_account() { + let horizon_client = + HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); + + let payments_for_account_request: PaymentsForAccountRequest = + PaymentsForAccountRequest::new().set_account_id( + "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H".to_string(), + ); + + let response: Result = horizon_client + .get_payments_for_account(&payments_for_account_request) + .await; + + assert!(response.is_ok()); + let binding = response.unwrap(); + let response = &binding.embedded().records()[0]; + assert_eq!(response.id(), ID); + assert_eq!(response.paging_token(), PAGING_TOKEN); + assert_eq!(response.transaction_successful(), TRANSACTION_SUCCESSFUL); + assert_eq!(response.source_account(), SOURCE_ACCOUNT); + assert_eq!(response.type_field(), TYPE); + assert_eq!(response.type_i(), TYPE_I); + assert_eq!(response.created_at(), CREATED_AT); + assert_eq!(response.transaction_hash(), TRANSACTION_HASH); + assert_eq!( + response.starting_balance().as_deref(), + Some(STARTING_BALANCE) + ); + assert_eq!(response.funder().as_deref(), Some(FUNDER)); + assert_eq!(response.account().as_deref(), Some(ACCOUNT)); + } + + #[tokio::test] + async fn test_get_payments_for_ledger() { + static ID: &str = "208232899428355"; + static PAGING_TOKEN: &str = "208232899428355"; + static TRANSACTION_SUCCESSFUL: &bool = &true; + static SOURCE_ACCOUNT: &str = "GAZPDM46VZKEYJR75AQ6SBASSFVBZXXOLLWBAI7FFTKJW3227LZGVRSY"; + static TYPE: &str = "payment"; + static TYPE_I: &i64 = &1; + static CREATED_AT: &str = "2024-06-14T19:37:16Z"; + static TRANSACTION_HASH: &str = + "14e250278575ca3979f26c048543d278192b1958a3777c59a5d87045a22e1db8"; + static ASSET_TYPE: &str = "credit_alphanum4"; + static ASSET_CODE: &str = "AUSD"; + static ASSET_ISSUER: &str = "GDIOZ6QL5L5SV5VQVEK2NYPTS7REOMWTG2FF62OQUBHNJD2FIPXJ234G"; + static FROM: &str = "GAZPDM46VZKEYJR75AQ6SBASSFVBZXXOLLWBAI7FFTKJW3227LZGVRSY"; + static TO: &str = "GACX6RVTLABDFH7JGQT2DQD5G54MA422UYLQZWYVIW6DSLRL2RJ2GTBJ"; + static AMOUNT: &str = "1.0000000"; + + let horizon_client = + HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); + + let payments_for_ledger_request: PaymentsForLedgerRequest = PaymentsForLedgerRequest::new() + .set_ledger_sequence(LEDGER_SEQUENCE.to_string()) + .set_include_failed(IncludeFailed::False) + .set_limit(1) + .unwrap(); + + let response: Result = horizon_client + .get_payments_for_ledger(&payments_for_ledger_request) + .await; + + assert!(response.is_ok()); + let binding = response.unwrap(); + let response = &binding.embedded().records()[0]; + assert_eq!(response.id(), ID); + assert_eq!(response.paging_token(), PAGING_TOKEN); + assert_eq!(response.transaction_successful(), TRANSACTION_SUCCESSFUL); + assert_eq!(response.source_account(), SOURCE_ACCOUNT); + assert_eq!(response.type_field(), TYPE); + assert_eq!(response.type_i(), TYPE_I); + assert_eq!(response.created_at(), CREATED_AT); + assert_eq!(response.transaction_hash(), TRANSACTION_HASH); + assert_eq!(response.asset_type().as_deref(), Some(ASSET_TYPE)); + assert_eq!(response.asset_code().as_deref(), Some(ASSET_CODE)); + assert_eq!(response.asset_issuer().as_deref(), Some(ASSET_ISSUER)); + assert_eq!(response.from().as_deref(), Some(FROM)); + assert_eq!(response.to().as_deref(), Some(TO)); + assert_eq!(response.amount().as_deref(), Some(AMOUNT)); + } + + #[tokio::test] + async fn test_get_payments_for_transaction() { + let horizon_client = + HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); + + let payments_for_transaction_request: PaymentsForTransactionRequest = + PaymentsForTransactionRequest::new() + .set_transaction_hash( + "b9d0b2292c4e09e8eb22d036171491e87b8d2086bf8b265874c8d182cb9c9020".to_string(), + ) + .set_limit(1) + .unwrap(); + + let response: Result = horizon_client + .get_payments_for_transaction(&payments_for_transaction_request) + .await; + + assert!(response.is_ok()); + let binding = response.unwrap(); + let response = &binding.embedded().records()[0]; + assert_eq!(response.id(), ID); + assert_eq!(response.paging_token(), PAGING_TOKEN); + assert_eq!(response.transaction_successful(), TRANSACTION_SUCCESSFUL); + assert_eq!(response.source_account(), SOURCE_ACCOUNT); + assert_eq!(response.type_field(), TYPE); + assert_eq!(response.type_i(), TYPE_I); + assert_eq!(response.created_at(), CREATED_AT); + assert_eq!(response.transaction_hash(), TRANSACTION_HASH); + assert_eq!( + response.starting_balance().as_deref(), + Some(STARTING_BALANCE) + ); + assert_eq!(response.funder().as_deref(), Some(FUNDER)); + assert_eq!(response.account().as_deref(), Some(ACCOUNT)); + } +} diff --git a/stellar_rust_sdk/src/payments/payments_for_account_request.rs b/stellar_rust_sdk/src/payments/payments_for_account_request.rs new file mode 100644 index 0000000..4d09c64 --- /dev/null +++ b/stellar_rust_sdk/src/payments/payments_for_account_request.rs @@ -0,0 +1,81 @@ +use crate::models::{IncludeFailed, Order, Request}; +use crate::payments::PAYMENTS_PATH; +use crate::{BuildQueryParametersExt, Paginatable}; +use stellar_rust_sdk_derive::Pagination; + +#[derive(Default, Pagination)] +pub struct PaymentsForAccountRequest { + /// The Stellar address of the account for which you want to retrieve payments. + account_id: Option, + /// A pointer to a specific location in a collection of responses, derived from the + /// `paging_token` value of a record. Used for pagination control in the API response. + cursor: Option, + /// Specifies the maximum number of records to be returned in a single response. + limit: Option, + /// Determines the [`Order`] of the records in the response. Valid options are [`Order::Asc`] (ascending) + /// and [`Order::Desc`] (descending). If not specified, it defaults to ascending. + order: Option, + /// A boolean value that determines whether failed transactions should be included in the response. + include_failed: Option, +} + +impl PaymentsForAccountRequest { + /// Creates a new `PaymentsForAccountRequest` with default parameters. + pub fn new() -> PaymentsForAccountRequest { + PaymentsForAccountRequest { + account_id: None, + cursor: None, + limit: None, + order: None, + include_failed: Option::from(IncludeFailed::False), + } + } + + /// Sets the Stellar address of the account for which you want to retrieve payments. + /// + /// # Arguments + /// * `account_id` - The Stellar address of the account for which you want to retrieve payments. + /// + pub fn set_account_id(mut self, account_id: String) -> PaymentsForAccountRequest { + self.account_id = Some(account_id); + self + } + + /// Sets a pointer to a specific location in a collection of responses, derived from the + /// + /// # Arguments + /// * `cursor` - A pointer to a specific location in a collection of responses, derived from the + /// `paging_token` value of a record. Used for pagination control in the API response. + /// + pub fn set_include_failed( + mut self, + include_failed: IncludeFailed, + ) -> PaymentsForAccountRequest { + self.include_failed = Option::from(include_failed); + self + } +} + +impl Request for PaymentsForAccountRequest { + fn get_query_parameters(&self) -> String { + vec![ + self.include_failed.as_ref().map(|s| format!("include_failed={}", s)), + self.cursor.as_ref().map(|c| format!("cursor={}", c)), + self.limit.as_ref().map(|l| format!("limit={}", l)), + self.order.as_ref().map(|o| format!("order={}", o)), + ] + .build_query_parameters() + } + + fn build_url(&self, base_url: &str) -> String { + let binding = "".to_string(); + let account_id = self.account_id.as_ref().unwrap_or(&binding); + format!( + "{}/accounts/{}/{}?{}", + base_url, + account_id, + PAYMENTS_PATH, + self.get_query_parameters() + ) + } +} diff --git a/stellar_rust_sdk/src/payments/payments_for_ledger_request.rs b/stellar_rust_sdk/src/payments/payments_for_ledger_request.rs new file mode 100644 index 0000000..5a8e838 --- /dev/null +++ b/stellar_rust_sdk/src/payments/payments_for_ledger_request.rs @@ -0,0 +1,76 @@ +use crate::models::{IncludeFailed, Order, Request}; +use crate::payments::PAYMENTS_PATH; +use crate::{BuildQueryParametersExt, Paginatable}; +use stellar_rust_sdk_derive::Pagination; + +#[derive(Default, Pagination)] +pub struct PaymentsForLedgerRequest { + /// The Stellar address of the account for which you want to retrieve payments. + ledger_sequence: Option, + /// A pointer to a specific location in a collection of responses, derived from the + /// `paging_token` value of a record. Used for pagination control in the API response. + cursor: Option, + /// Specifies the maximum number of records to be returned in a single response. + limit: Option, + /// Determines the [`Order`] of the records in the response. Valid options are [`Order::Asc`] (ascending) + /// and [`Order::Desc`] (descending). If not specified, it defaults to ascending. + order: Option, + /// A boolean value that determines whether failed transactions should be included in the response. + include_failed: Option, +} + +impl PaymentsForLedgerRequest { + /// Creates a new `PaymentsForAccountRequest` with default parameters. + pub fn new() -> PaymentsForLedgerRequest { + PaymentsForLedgerRequest { + ledger_sequence: None, + cursor: None, + limit: None, + order: None, + include_failed: Option::from(IncludeFailed::False), + } + } + + /// Sets the Stellar address of the account for which you want to retrieve payments. + /// + /// # Arguments + /// * `account_id` - The Stellar address of the account for which you want to retrieve payments. + /// + pub fn set_ledger_sequence(mut self, ledger_sequence: String) -> PaymentsForLedgerRequest { + self.ledger_sequence = Some(ledger_sequence); + self + } + + /// Sets whether to include failed operations in the response. + /// + /// # Arguments + /// * `include_failed` - A boolean value that determines whether to include failed operations in the response. + /// + pub fn set_include_failed(mut self, include_failed: IncludeFailed) -> PaymentsForLedgerRequest { + self.include_failed = Option::from(include_failed); + self + } +} + +impl Request for PaymentsForLedgerRequest { + fn get_query_parameters(&self) -> String { + vec![ + self.include_failed.as_ref().map(|s| format!("include_failed={}", s)), + self.cursor.as_ref().map(|c| format!("cursor={}", c)), + self.limit.as_ref().map(|l| format!("limit={}", l)), + self.order.as_ref().map(|o| format!("order={}", o)), + ].build_query_parameters() + } + + fn build_url(&self, base_url: &str) -> String { + let binding = "".to_string(); + let ledger_sequence = self.ledger_sequence.as_ref().unwrap_or(&binding); + format!( + "{}/ledgers/{}/{}?{}", + base_url, + ledger_sequence, + PAYMENTS_PATH, + self.get_query_parameters() + ) + } +} diff --git a/stellar_rust_sdk/src/payments/payments_for_transaction_request.rs b/stellar_rust_sdk/src/payments/payments_for_transaction_request.rs new file mode 100644 index 0000000..e5b4465 --- /dev/null +++ b/stellar_rust_sdk/src/payments/payments_for_transaction_request.rs @@ -0,0 +1,67 @@ +use crate::models::{Order, Request}; +use crate::payments::PAYMENTS_PATH; +use crate::{BuildQueryParametersExt, Paginatable}; +use stellar_rust_sdk_derive::Pagination; + +#[derive(Default, Pagination)] +pub struct PaymentsForTransactionRequest { + /// The transaction hash of the transaction for which you want to retrieve payments. + transaction_hash: Option, + /// A pointer to a specific location in a collection of responses, derived from the + /// `paging_token` value of a record. Used for pagination control in the API response. + cursor: Option, + /// Specifies the maximum number of records to be returned in a single response. + /// The range for this parameter is from 1 to 200. The default value is set to 10. + limit: Option, + /// Determines the [`Order`] of the records in the response. Valid options are [`Order::Asc`] (ascending) + /// and [`Order::Desc`] (descending). If not specified, it defaults to ascending. + order: Option, +} + +impl PaymentsForTransactionRequest { + /// Creates a new `PaymentsForTransactionRequest` with default parameters. + pub fn new() -> PaymentsForTransactionRequest { + PaymentsForTransactionRequest { + transaction_hash: None, + cursor: None, + limit: None, + order: None, + } + } + + /// Sets the transaction hash of the transaction for which you want to retrieve payments. + /// + /// # Arguments + /// * `transaction_hash` - The transaction hash of the transaction for which you want to retrieve payments. + /// + pub fn set_transaction_hash( + mut self, + transaction_hash: String, + ) -> PaymentsForTransactionRequest { + self.transaction_hash = Some(transaction_hash); + self + } +} + +impl Request for PaymentsForTransactionRequest { + fn get_query_parameters(&self) -> String { + vec![ + self.cursor.as_ref().map(|c| format!("cursor={}", c)), + self.limit.as_ref().map(|l| format!("limit={}", l)), + self.order.as_ref().map(|o| format!("order={}", o)), + ] + .build_query_parameters() + } + + fn build_url(&self, base_url: &str) -> String { + let binding = "".to_string(); + let transaction_hash = self.transaction_hash.as_ref().unwrap_or(&binding); + format!( + "{}/transactions/{}/{}?{}", + base_url, + transaction_hash, + PAYMENTS_PATH, + self.get_query_parameters() + ) + } +} diff --git a/stellar_rust_sdk/src/payments/response.rs b/stellar_rust_sdk/src/payments/response.rs new file mode 100644 index 0000000..ab599cc --- /dev/null +++ b/stellar_rust_sdk/src/payments/response.rs @@ -0,0 +1,52 @@ +use derive_getters::Getters; +use serde::{Deserialize, Serialize}; +use crate::models::prelude::{Embedded, ResponseLinks}; +use crate::models::Response; + +/// Represents the response from the Horizon server when querying for all payments. +/// +/// This struct represents the response from the Horizon server when querying for all payments. +/// It includes the links to the current, next, and previous pages of the response, as well as the +/// embedded records of payments. +#[derive(Default, Debug, Clone, Serialize, Deserialize, Getters)] +pub struct PaymentsResponse { + /// The links to the current, next, and previous pages of the response. + #[serde(rename = "_links")] + pub links: ResponseLinks, + /// The embedded records of liquidity pools. + #[serde(rename = "_embedded")] + pub embedded: Embedded, +} + +/// Represents the payment record in the Horizon API response. +/// +/// This struct encapsulates detailed information about a single payment, including its ID, paging token, +/// transaction success status, source account, type, creation date, transaction hash, starting balance, +/// funder, and account. +#[derive(Default, Debug, Clone, Serialize, Deserialize, Getters)] +pub struct Payment { + pub id: String, + pub paging_token: String, + pub transaction_successful: bool, + pub source_account: String, + #[serde(rename = "type")] + pub type_field: String, + pub type_i: i64, + pub created_at: String, + pub transaction_hash: String, + pub starting_balance: Option, + pub funder: Option, + pub account: Option, + pub asset_type: Option, + pub asset_code: Option, + pub asset_issuer: Option, + pub from: Option, + pub to: Option, + pub amount: Option, +} + +impl Response for PaymentsResponse { + fn from_json(json: String) -> Result { + serde_json::from_str(&json).map_err(|e| e.to_string()) + } +} \ No newline at end of file