Skip to content

Commit cb9afdb

Browse files
kevin-peaseLeonardTibben
authored andcommitted
Copy code from original offer branch
1 parent b9daa81 commit cb9afdb

File tree

5 files changed

+402
-0
lines changed

5 files changed

+402
-0
lines changed

stellar_rust_sdk/src/horizon_client.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::{
1919
},
2020
},
2121
models::{Request, Response},
22+
offers::prelude::*,
2223
operations::{
2324
operations_for_account_request::OperationsForAccountRequest,
2425
prelude::{
@@ -789,6 +790,60 @@ impl HorizonClient {
789790
self.get::<FeeStatsResponse>(request).await
790791
}
791792

793+
/// Retrieves detailed information for a specific offer from the Horizon server.
794+
///
795+
/// This asynchronous method fetches details of a single offer from the Horizon server.
796+
/// It requires a [`SingleOfferRequest`] parameterized with `OfferId`, which includes the ID
797+
/// of the offer to be retrieved.
798+
///
799+
/// Adheres to the <a href="https://developers.stellar.org/network/horizon/resources/get-offer-by-offer-id">Retrieve An Offer endpoint</a>
800+
/// endpoint.
801+
///
802+
/// # Arguments
803+
///
804+
/// * `request` - A reference to a [`SingleOfferRequest<OfferId>`] instance, containing the
805+
/// id of the offer for which details are to be fetched.
806+
///
807+
/// # Returns
808+
///
809+
/// Returns a `Result` containing an [`Offer`], which includes detailed
810+
/// information about the requested offer. If the request fails, it returns an error
811+
/// encapsulated within `Result`.
812+
///
813+
/// # Usage
814+
/// To use this method, create an instance of [`SingleOfferRequest`] and set the
815+
/// id of the offer to be queried.
816+
///
817+
/// ```
818+
/// # use stellar_rs::offers::prelude::*;
819+
/// # use stellar_rs::models::Request;
820+
/// # use stellar_rs::horizon_client::HorizonClient;
821+
/// #
822+
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
823+
/// # let base_url = "https://horizon-testnet.stellar.org".to_string();
824+
/// # let horizon_client = HorizonClient::new(base_url)
825+
/// # .expect("Failed to create Horizon Client");
826+
/// let request = SingleOfferRequest::new()
827+
/// .set_offer_id("1".to_string()) // example offer ID
828+
/// .unwrap();
829+
///
830+
/// let response = horizon_client.get_single_offer(&request).await;
831+
///
832+
/// if let Ok(offer) = response {
833+
/// println!("Offer ID: {}", offer.id());
834+
/// // Additional processing...
835+
/// }
836+
/// # Ok({})
837+
/// # }
838+
/// ```
839+
///
840+
pub async fn get_single_offer(
841+
&self,
842+
request: &SingleOfferRequest<OfferId>,
843+
) -> Result<SingleOfferResponse, String> {
844+
self.get::<SingleOfferResponse>(request).await
845+
}
846+
792847
/// Retrieves a list of all operations from the Horizon server.
793848
///
794849
/// This asynchronous method fetches a list of all operations from the Horizon server.

stellar_rust_sdk/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,48 @@ pub mod fee_stats;
346346

347347
pub mod liquidity_pools;
348348

349+
/// Provides `Request` and `Response` structs for retrieving offers.
350+
///
351+
/// This module provides a set of specialized request and response structures designed for
352+
/// interacting with the offer-related endpoints of the Horizon server. These structures
353+
/// facilitate the construction of requests to query offer data and the interpretation of
354+
/// the corresponding responses.
355+
///
356+
/// # Usage
357+
///
358+
/// This module is intended to be used in conjunction with the [`HorizonClient`](crate::horizon_client::HorizonClient)
359+
/// for making specific offer-related API calls to the Horizon server. The request
360+
/// structures are designed to be passed to the client's methods, which handle the
361+
/// communication with the server and return the corresponding response structures.
362+
///
363+
/// # Example
364+
///
365+
/// /// To use this module, you can create an instance of a request struct, such as
366+
/// `SingleOfferRequest`, set any desired query parameters, and pass the request to the
367+
/// `HorizonClient`. The client will then execute the request and return the corresponding
368+
/// response struct, like `SingleOfferResponse`.
369+
///
370+
/// ```rust
371+
/// use stellar_rs::horizon_client::HorizonClient;
372+
/// use stellar_rs::offers::prelude::*;
373+
/// use stellar_rs::models::Request;
374+
///
375+
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
376+
/// let horizon_client = HorizonClient::new("https://horizon-testnet.stellar.org".to_string())?;
377+
///
378+
/// // Example: Fetching all effects
379+
/// let single_offer_request = SingleOfferRequest::new()
380+
/// .set_offer_id("1".to_string())
381+
/// .unwrap();
382+
/// let single_offer_response = horizon_client.get_single_offer(&single_offer_request).await?;
383+
///
384+
/// // Process the responses...
385+
/// # Ok(())
386+
/// # }
387+
/// ```
388+
///
389+
pub mod offers;
390+
349391
/// Provides `Request` and `Response` structs for retrieving operations.
350392
///
351393
/// The `operations` module in the Stellar Horizon SDK includes structures and methods that facilitate

stellar_rust_sdk/src/offers/mod.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/// Provides the `SingleOfferRequest`.
2+
///
3+
/// This module provides the `SingleOfferRequest` struct, specifically designed for
4+
/// constructing requests to query information about a single offer from the Horizon
5+
/// server. It is tailored for use with the [`HorizonClient::get_single_offer`](crate::horizon_client::HorizonClient::get_single_offer)
6+
/// method.
7+
///
8+
pub mod single_offer_request;
9+
10+
/// Provides the responses.
11+
///
12+
/// This module defines structures representing the response from the Horizon API when querying
13+
/// for offers. The structures are designed to deserialize the JSON response into Rust
14+
/// objects, enabling straightforward access to various details of a single Stellar account.
15+
///
16+
/// These structures are equipped with serialization capabilities to handle the JSON data from the
17+
/// Horizon server and with getter methods for easy field access.
18+
///
19+
pub mod response;
20+
21+
/// The base path for offer-related endpoints in the Horizon API.
22+
///
23+
/// # Usage
24+
/// This variable is intended to be used internally by the request-building logic
25+
/// to ensure consistent and accurate path construction for offer-related API calls.
26+
///
27+
static OFFERS_PATH: &str = "offers";
28+
29+
/// The `prelude` module of the `offers` module.
30+
///
31+
/// This module serves as a convenience for users of the Horizon Rust SDK, allowing for easy and
32+
/// ergonomic import of the most commonly used items across various modules. It re-exports
33+
/// key structs and traits from the sibling modules, simplifying access to these components
34+
/// when using the library.
35+
///
36+
/// By importing the contents of `prelude`, users can conveniently access the primary
37+
/// functionalities of the offer-related modules without needing to import each item
38+
/// individually.
39+
///
40+
/// # Contents
41+
///
42+
/// The `prelude` includes the following re-exports:
43+
///
44+
/// * From `single_offer_request`: All items (e.g. `SingleOfferRequest`).
45+
/// * From `response`: All items (e.g. `SingleOfferResponse`, `PriceR`, etc.).
46+
///
47+
/// # Example
48+
/// ```
49+
/// # use crate::stellar_rs::models::*;
50+
/// // Import the contents of the offers prelude
51+
/// use stellar_rs::offers::prelude::*;
52+
///
53+
/// // Now you can directly use SingleOfferRequest, SingleOfferResponse, etc.
54+
/// let single_offer_request = SingleOfferRequest::new();
55+
/// ```
56+
///
57+
pub mod prelude {
58+
pub use super::single_offer_request::*;
59+
pub use super::response::*;
60+
}
61+
62+
#[cfg(test)]
63+
pub mod test {
64+
use super::prelude::*;
65+
use crate::horizon_client::HorizonClient;
66+
67+
#[tokio::test]
68+
async fn test_get_single_offer() {
69+
const LINK_SELF: &str = "https://horizon-testnet.stellar.org/offers/1";
70+
const LINK_OFFER_MAKER: &str = "https://horizon-testnet.stellar.org/accounts/GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
71+
const OFFER_ID: &str = "1";
72+
const PAGING_TOKEN: &str = "1";
73+
const SELLER: &str = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
74+
const SELLING_ASSET_TYPE: &str = "credit_alphanum4";
75+
const SELLING_ASSET_CODE: &str = "USDC";
76+
const SELLING_ASSET_ISSUER: &str = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
77+
const BUYING_ASSET_TYPE: &str = "credit_alphanum12";
78+
const BUYING_ASSET_CODE: &str = "USDCAllow";
79+
const BUYING_ASSET_ISSUER: &str = "GAWZGWFOURKXZ4XYXBGFADZM4QIG6BJNM74XIZCEIU3BHM62RN2MDEZN";
80+
const AMOUNT: &str = "909086990804.0875807";
81+
const PRICE_R_N: &u32 = &1;
82+
const PRICE_R_D: &u32 = &1;
83+
const PRICE: &str = "1.0000000";
84+
const LAST_MODIFIED_LEDGER: &u32 = &747543;
85+
const LAST_MODIFIED_TIME: &str = "2024-03-23T04:51:18Z";
86+
87+
let horizon_client =
88+
HorizonClient::new("https://horizon-testnet.stellar.org"
89+
.to_string())
90+
.unwrap();
91+
92+
let single_offer_request =
93+
SingleOfferRequest::new()
94+
.set_offer_id(OFFER_ID.to_string())
95+
.unwrap();
96+
97+
let single_offer_response = horizon_client
98+
.get_single_offer(&single_offer_request)
99+
.await;
100+
101+
assert!(single_offer_response.clone().is_ok());
102+
let response = single_offer_response.unwrap();
103+
assert_eq!(response.links().self_link().href().as_ref().unwrap(), LINK_SELF);
104+
assert_eq!(response.links().offer_maker().href().as_ref().unwrap(), LINK_OFFER_MAKER);
105+
assert_eq!(response.id(), OFFER_ID);
106+
assert_eq!(response.paging_token(), PAGING_TOKEN);
107+
assert_eq!(response.seller(), SELLER);
108+
assert_eq!(response.selling().asset_type(), SELLING_ASSET_TYPE);
109+
assert_eq!(response.selling().asset_code().as_ref().unwrap(), SELLING_ASSET_CODE);
110+
assert_eq!(response.selling().asset_issuer().as_ref().unwrap(), SELLING_ASSET_ISSUER);
111+
assert_eq!(response.buying().asset_type(), BUYING_ASSET_TYPE);
112+
assert_eq!(response.buying().asset_code().as_ref().unwrap(), BUYING_ASSET_CODE);
113+
assert_eq!(response.buying().asset_issuer().as_ref().unwrap(), BUYING_ASSET_ISSUER);
114+
assert_eq!(response.amount(), AMOUNT);
115+
assert_eq!(response.price_ratio().numenator(), PRICE_R_N);
116+
assert_eq!(response.price_ratio().denominator(), PRICE_R_D);
117+
assert_eq!(response.price_decimal(), PRICE);
118+
assert_eq!(response.last_modified_ledger(), LAST_MODIFIED_LEDGER);
119+
assert_eq!(response.last_modified_time(), LAST_MODIFIED_TIME);
120+
}
121+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use crate::models::prelude::*;
2+
use derive_getters::Getters;
3+
use serde::{Deserialize, Serialize};
4+
5+
/// Represents the asset to buy or to sell.
6+
///
7+
/// This struct details information about the asset to buy or to sell, including its type,
8+
/// code (optional) and issuer (optional).
9+
///
10+
#[derive(Debug, Deserialize, Clone, Getters)]
11+
pub struct Transaction {
12+
/// The type of asset (e.g. "credit_alphanum4", "credit_alphanum12").
13+
asset_type: String,
14+
/// Optional. The code of the asset.
15+
asset_code: Option<String>,
16+
/// Optional. The public key of the issuer.
17+
asset_issuer: Option<String>,
18+
}
19+
20+
/// Represents the precise buy and sell price of the assets on offer.
21+
///
22+
/// This struct contains a numenator and a denominator, so that the price ratio can be determined
23+
/// in a precise manner.
24+
///
25+
#[derive(Debug, Deserialize, Clone, Getters)]
26+
pub struct PriceR {
27+
/// The numenator.
28+
#[serde(rename = "n")]
29+
numenator: u32,
30+
/// The denominator.
31+
#[serde(rename = "d")]
32+
denominator: u32,
33+
}
34+
35+
/// Represents the navigational links in a single offer response from the Horizon API.
36+
///
37+
/// This struct includes various hyperlinks such as links to the offer itself
38+
/// and the offer maker.
39+
///
40+
#[derive(Debug, Deserialize, Serialize, Clone, Getters)]
41+
pub struct OfferResponseLinks {
42+
/// The link to the offer itself.
43+
#[serde(rename = "self")]
44+
self_link: Link,
45+
/// Link to the offer's maker.
46+
offer_maker: Link,
47+
}
48+
49+
/// Represents the response for a single offer query in the Horizon API.
50+
///
51+
/// This struct defines the overall structure of the response for a single offer query.
52+
/// It includes navigational links, offer identifiers, the seller, the assets to buy and sell,
53+
/// the amount, the price and additional data.
54+
///
55+
#[derive(Debug, Deserialize, Clone, Getters)]
56+
pub struct SingleOfferResponse {
57+
/// Navigational links related to the offer.
58+
#[serde(rename = "_links")]
59+
links: OfferResponseLinks,
60+
/// The unique identifier for the offer.
61+
id: String,
62+
/// A token used for paging through results.
63+
paging_token: String,
64+
/// The ID of the seller making the offer.
65+
seller: String,
66+
/// The asset the offer wants to sell.
67+
selling: Transaction,
68+
/// The asset the offer wants to buy.
69+
buying: Transaction,
70+
/// The amount of `selling` that the account making this offer is willing to sell.
71+
amount: String,
72+
/// A precise representation of the buy and sell price of the assets on offer.
73+
#[serde(rename = "price_r")]
74+
price_ratio: PriceR,
75+
/// A number representing the decimal form of `price_r`.
76+
#[serde(rename = "price")]
77+
price_decimal: String,
78+
/// The sequence number of the last ledger in which the offer was modified.
79+
last_modified_ledger: u32,
80+
/// The time at which the offer was last modified.
81+
last_modified_time: String,
82+
/// The account ID of the sponsor who is paying the reserves for this offer.
83+
sponsor: Option<String>,
84+
}
85+
86+
impl Response for SingleOfferResponse {
87+
fn from_json(json: String) -> Result<Self, String> {
88+
serde_json::from_str(&json).map_err(|e| e.to_string())
89+
}
90+
}

0 commit comments

Comments
 (0)