Skip to content

Commit

Permalink
transaction request
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonardTibben committed Feb 26, 2024
1 parent 6880376 commit 04e541d
Show file tree
Hide file tree
Showing 3 changed files with 329 additions and 16 deletions.
166 changes: 166 additions & 0 deletions src/effects/effects_for_transaction_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use stellar_xdr::curr::SurveyRequestMessage;

Check warning on line 1 in src/effects/effects_for_transaction_request.rs

View workflow job for this annotation

GitHub Actions / Build and test Stellar SDK

unused import: `stellar_xdr::curr::SurveyRequestMessage`

Check warning on line 1 in src/effects/effects_for_transaction_request.rs

View workflow job for this annotation

GitHub Actions / Build and test Stellar SDK

unused import: `stellar_xdr::curr::SurveyRequestMessage`

use crate::{models::{Order, Request}, BuildQueryParametersExt};

/// Represents a request to fetch effect data from the Stellar Horizon API.
///
/// `EffectForTransactionRequest` is a struct used to construct queries for retrieving information about effects
/// from the Horizon server. It includes parameters that allow for pagination control and sorting
/// of the effect records.
///
/// # Usage
/// Instances of `EffectForTransactionRequest` are created and optionally configured using the builder pattern.
/// Once the desired parameters are set, the request can be passed to the Horizon client to fetch
/// effect data.
///
/// # Example
/// ```rust
/// use stellar_rs::effects::effects_for_transaction_request::EffectForTransactionRequest;
/// use stellar_rs::models::*;
///
/// let request = EffectForTransactionRequest::new()
/// .set_transaction_hash("transaction_hash".to_string())
/// .set_cursor(1234).unwrap()
/// .set_limit(20).unwrap()
/// .set_order(Order::Desc);
///
/// // The request can now be used with a Horizon client to fetch effects.
/// ```
#[derive(Default)]
pub struct EffectForTransactionRequest {
/// The transaction hash of the transaction of the effect
transaction_hash: Option<String>,

/// 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<u32>,

/// 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<u8>,

/// 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<Order>,
}

impl EffectForTransactionRequest {
/// Creates a new `EffectForTransactionRequest` with default parameters.
pub fn new() -> Self {
EffectForTransactionRequest::default()
}

/// Sets the liquidity pool id for the request.
///
/// # Arguments
/// * `liquidity_pool_id` - A `String` value representing the liquidity pool id.
///
pub fn set_transaction_hash(
self,
transaction_hash: String,
) -> EffectForTransactionRequest {
EffectForTransactionRequest {
transaction_hash: Some(transaction_hash),
..self
}
}

/// Sets the cursor for pagination.
///
/// # Arguments
/// * `cursor` - A `u32` value pointing to a specific location in a collection of responses.
///
pub fn set_cursor(self, cursor: u32) -> Result<EffectForTransactionRequest, String> {
if cursor < 1 {
return Err("cursor must be greater than or equal to 1".to_string());
}

Ok(EffectForTransactionRequest {
cursor: Some(cursor),
..self
})
}

/// Sets the maximum number of records to return.
///
/// # Arguments
/// * `limit` - A `u8` value specifying the maximum number of records. Range: 1 to 200. Defaults to 10.
///
pub fn set_limit(self, limit: u8) -> Result<EffectForTransactionRequest, String> {
if limit < 1 || limit > 200 {
return Err("limit must be between 1 and 200".to_string());
}

Ok(EffectForTransactionRequest {
limit: Some(limit),
..self
})
}

/// Sets the order of the returned records.
///
/// # Arguments
/// * `order` - An [`Order`] enum value specifying the order (ascending or descending).
///
pub fn set_order(self, order: Order) -> EffectForTransactionRequest {
EffectForTransactionRequest {
order: Some(order),
..self
}
}
}

impl Request for EffectForTransactionRequest {
fn get_query_parameters(&self) -> String {
vec![
self.transaction_hash
.as_ref()
.map(|l| format!("transaction_hash={}", l)),
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!(
"{}/{}{}",
base_url,
super::EFFECTS_PATH,
self.get_query_parameters()
)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::BuildQueryParametersExt;

#[test]
fn test_effects_for_liquidity_pools_request() {
let request = EffectForTransactionRequest::new()
.set_transaction_hash("transaction_hash".to_string())
.set_cursor(1)
.unwrap()
.set_limit(10)
.unwrap()
.set_order(Order::Asc);

let url = request.build_url("https://horizon-testnet.stellar.org");
let query_parameters = vec![
Some("transaction_hash=transaction_hash".to_string()),
Some("cursor=1".to_string()),
Some("limit=10".to_string()),
Some("order=asc".to_string()),
]
.build_query_parameters();

assert_eq!(
url,
"https://horizon-testnet.stellar.org/effects?transaction_hash=transaction_hash&cursor=1&limit=10&order=asc"
);
assert_eq!(query_parameters, "?transaction_hash=transaction_hash&cursor=1&limit=10&order=asc");
}
}
2 changes: 2 additions & 0 deletions src/effects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod effects_response;
pub mod effects_for_account_request;
pub mod effects_for_liquidity_pools_request;
pub mod effects_for_ledger_request;
pub mod effects_for_transaction_request;

static EFFECTS_PATH: &str = "effects";

Expand All @@ -12,6 +13,7 @@ pub mod prelude {
pub use super::effects_for_account_request::*;
pub use super::effects_for_liquidity_pools_request::*;
pub use super::effects_for_ledger_request::*;
pub use super::effects_for_transaction_request::*;
}

#[cfg(test)]
Expand Down
177 changes: 161 additions & 16 deletions src/horizon_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,57 @@ impl HorizonClient {
self.get::<EffectsResponse>(request).await
}

/// Retrieves a list of effects for a specific transaction from the Horizon server.
///
/// This asynchronous method fetches a list of effects for a specific transaction from the Horizon server.
/// It requires an [`EffectForTransactionRequest`] to specify the transaction hash and optional query parameters.
///
/// # Arguments
/// * `request` - A reference to an [`EffectForTransactionRequest`] instance, containing the transaction hash
/// and optional query parameters for the effects request.
///
/// # Returns
///
/// On successful execution, returns a `Result` containing an [`EffectsResponse`], which includes
/// the list of effects obtained from the Horizon server. If the request fails, it returns an error within `Result`.
///
/// # Example
/// To use this method, create an instance of [`EffectForTransactionRequest`] and set the transaction hash and any
/// desired query parameters.
///
/// ```
/// # use stellar_rs::effects::prelude::*;
/// # use stellar_rs::models::Request;
/// # use stellar_rs::horizon_client::HorizonClient;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # 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 = EffectForTransactionRequest::new()
/// .set_transaction_hash("000000006520216af66d20d63a58534d6cbdf28ba9f2a9c1e03f8d9a756bb7d988b29bca".to_string());
///
/// let response = horizon_client.get_effects_for_transaction(&request).await;
///
/// // Access the effects
/// if let Ok(effects_response) = response {
/// for effect in effects_response._embedded().records() {
/// println!("Effect ID: {}", effect.id());
/// // Further processing...
/// }
/// }
///
/// # Ok({})
/// # }
/// ```
///
pub async fn get_effects_for_transaction(
&self,
request: &EffectForTransactionRequest,
) -> Result<EffectsResponse, String> {
self.get::<EffectsResponse>(request).await
}

/// Retrieves a list of all ledgers.
///
/// This asynchronous method is designed to fetch list of ledgers
Expand Down Expand Up @@ -1911,41 +1962,135 @@ mod tests {
}

#[tokio::test]
async fn test_get_effects_for_ledger() {
// found by trial and error in the Stellar laboratory
let ledger_sequence = 125;
async fn get_effects_for_transactions() {
const ID: &str = "0000000459561504769-0000000001";
const PAGING_TOKEN: &str = "459561504769-1";
const ACCOUNT: &str = "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR";
const RECORD_TYPE: &str = "account_created";
const TYPE_I: u32 = 0;
const CREATED_AT: &str = "2024-02-06T17:42:48Z";
const STARTING_BALANCE: &str = "10000000000.0000000";

let horizon_client =
HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap();

let effects_for_ledger_request =
EffectsForLedgerRequest::new().set_sequence(ledger_sequence);
let _effects_for_ledger_response = horizon_client
.get_effects_for_ledger(&effects_for_ledger_request)
let effects_for_liquidity_pools_request =
EffectForTransactionRequest::new().set_limit(2).unwrap();

let effects_for_liquidity_pools_response = horizon_client
.get_effects_for_transaction(&effects_for_liquidity_pools_request)
.await;

println!("{:#?}", _effects_for_ledger_response);
assert!(effects_for_liquidity_pools_response.clone().is_ok());

assert_eq!(
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.id(),
ID
);

assert_eq!(
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.paging_token(),
PAGING_TOKEN
);

assert!(_effects_for_ledger_response.clone().is_ok());
assert_eq!(
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.account(),
ACCOUNT
);

assert_eq!(
_effects_for_ledger_response
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.id,
"0000000536870916097-0000000001"
.effect_type(),
RECORD_TYPE
);

assert_eq!(
_effects_for_ledger_response
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[1]
.effect_type,
"account_debited"
.records()[0]
.type_i(),
&TYPE_I
);

assert_eq!(
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.created_at(),
CREATED_AT
);

assert_eq!(
effects_for_liquidity_pools_response
.clone()
.unwrap()
._embedded()
.records()[0]
.starting_balance()
.as_ref()
.unwrap(),
&STARTING_BALANCE
);
}
}

#[tokio::test]
async fn test_get_effects_for_ledger() {
// found by trial and error in the Stellar laboratory
let ledger_sequence = 125;

let horizon_client =
HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap();

let effects_for_ledger_request = EffectsForLedgerRequest::new().set_sequence(ledger_sequence);
let _effects_for_ledger_response = horizon_client
.get_effects_for_ledger(&effects_for_ledger_request)
.await;

println!("{:#?}", _effects_for_ledger_response);

assert!(_effects_for_ledger_response.clone().is_ok());

assert_eq!(
_effects_for_ledger_response
.clone()
.unwrap()
._embedded()
.records()[0]
.id,
"0000000536870916097-0000000001"
);

assert_eq!(
_effects_for_ledger_response
.clone()
.unwrap()
._embedded()
.records()[1]
.effect_type,
"account_debited"
);
}

0 comments on commit 04e541d

Please sign in to comment.