soroban_client/soroban_rpc.rs
1#![allow(non_snake_case)]
2use std::ops::Deref;
3
4use stellar_baselib::{
5 soroban_data_builder::{SorobanDataBuilder, SorobanDataBuilderBehavior},
6 xdr::{
7 ContractEvent, DiagnosticEvent, LedgerCloseMeta, LedgerEntry, LedgerEntryData,
8 LedgerEntryExt, LedgerHeaderHistoryEntry, LedgerKey, Limits, ReadXdr, ScVal,
9 SorobanAuthorizationEntry, SorobanTransactionData, TransactionEnvelope, TransactionEvent,
10 TransactionMeta, TransactionResult,
11 },
12};
13
14use serde::{Deserialize, Serialize};
15
16/// Response to [get_health](crate::Server::get_health) RPC method
17#[derive(Debug, Deserialize, PartialEq, Eq)]
18#[serde(rename_all = "camelCase")]
19pub struct GetHealthResponse {
20 /// Health status, typically 'healthy'
21 pub status: String,
22 /// Most recent known ledger sequence
23 pub latest_ledger: u32,
24 /// Oldest ledger sequence kept in history
25 pub oldest_ledger: u32,
26 /// Maximum retention window configured. A full window state can be determined via:
27 /// ledgerRetentionWindow = latestLedger - oldestLedger + 1
28 pub ledger_retention_window: u32,
29}
30
31/// A pair of LedgerKey and LedgerEntryData
32#[derive(Clone, Debug, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct LedgerEntryResult {
35 /// The ledger sequence number of the last time this entry was updated.
36 pub last_modified_ledger_seq: Option<u32>,
37 /// Sequence number of the ledger.
38 pub live_until_ledger_seq: Option<u32>,
39 key: String,
40 xdr: String,
41 ext_xdr: Option<String>,
42}
43
44impl LedgerEntryResult {
45 /// The key of the ledger entry
46 pub fn to_key(&self) -> LedgerKey {
47 LedgerKey::from_xdr_base64(&self.key, Limits::none()).expect("Invalid LedgerKey from RPC")
48 }
49 /// The current value of the given ledger entry
50 pub fn to_data(&self) -> LedgerEntryData {
51 LedgerEntryData::from_xdr_base64(&self.xdr, Limits::none())
52 .expect("Invalid LedgerEntryData from RPC")
53 }
54 /// The extension of the ledger entry
55 pub fn to_ext(&self) -> Option<LedgerEntryExt> {
56 self.ext_xdr.as_ref().map(|ext| {
57 LedgerEntryExt::from_xdr_base64(ext, Limits::none())
58 .expect("Invalid LedgerEntryData from RPC")
59 })
60 }
61}
62
63/// Response to [get_ledger_entries](crate::Server::get_ledger_entries)
64#[derive(Deserialize, Debug, Clone)]
65pub struct GetLedgerEntriesResponse {
66 /// Array of objects containing all found ledger entries
67 pub entries: Option<Vec<LedgerEntryResult>>,
68 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
69 pub latestLedger: u32,
70}
71
72/// Response to [get_network](crate::Server::get_network)
73#[derive(Deserialize, Debug, PartialEq, Eq)]
74#[serde(rename_all = "camelCase")]
75pub struct GetNetworkResponse {
76 /// Network passphrase configured for this Stellar RPC node.
77 pub passphrase: Option<String>,
78 /// Stellar Core protocol version associated with the latest ledger.
79 pub protocol_version: Option<i32>,
80 /// (optional) The URL of this network's "friendbot" faucet
81 pub friendbot_url: Option<String>,
82}
83
84/// Response to [get_latest_ledger](crate::Server::get_latest_ledger)
85#[derive(Deserialize, Debug, PartialEq, Eq)]
86#[serde(rename_all = "camelCase")]
87pub struct GetLatestLedgerResponse {
88 /// Hash identifier of the latest ledger (as a hex-encoded string) known to Stellar RPC at the time it handled the request.
89 pub id: String,
90 /// Stellar Core protocol version associated with the latest ledger.
91 pub protocol_version: u32,
92 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
93 pub sequence: u32,
94}
95
96/// Status of [GetTransactionResponse] or [GetTransactionsResponse] transactions
97#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
98#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
99pub enum TransactionStatus {
100 /// Transaction succeeded
101 Success,
102 /// NotFound, may not exist yet
103 NotFound,
104 /// Transaction failed
105 Failed,
106}
107
108/// Response to [get_transaction](crate::Server::get_transaction)
109///
110/// See [TransactionDetails] for additionnal fields
111#[derive(Debug, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct GetTransactionResponse {
114 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
115 pub latest_ledger: u32,
116 /// The unix timestamp of the close time of the latest ledger known to Stellar RPC at the time it handled the request.
117 pub latest_ledger_close_time: String,
118 /// The sequence number of the oldest ledger ingested by Stellar RPC at the time it handled the request.
119 pub oldest_ledger: u32,
120 /// The unix timestamp of the close time of the oldest ledger ingested by Stellar RPC at the time it handled the request.
121 pub oldest_ledger_close_time: String,
122 /// (optional) The unix timestamp of when the transaction was included in the ledger. This field is only present if status is [TransactionStatus::Success] or [TransactionStatus::Failed].
123 pub created_at: Option<String>,
124 /// Transaction details
125 #[serde(flatten)]
126 transaction: TransactionDetails,
127}
128// Flatten the transaction in the struct
129impl Deref for GetTransactionResponse {
130 type Target = TransactionDetails;
131
132 fn deref(&self) -> &Self::Target {
133 &self.transaction
134 }
135}
136
137/// Event types (system, contract, or diagnostic) used to filter events
138#[derive(PartialEq, Eq, Deserialize, Debug)]
139#[serde(rename_all = "lowercase")]
140pub enum EventType {
141 /// Only contract type events
142 Contract,
143 /// Only system type events
144 System,
145 /// Only diagnostic events
146 /// Since protocol 23: Diagnostic events are no longer returned by [get_events](crate::Server::get_events)
147 Diagnostic,
148 /// Any event type, contract, system and diagnostic
149 All,
150}
151
152/// Response to [get_events](crate::Server::get_events)
153#[derive(Debug, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct GetEventsResponse {
156 /// Events found for the filter
157 pub events: Vec<EventResponse>,
158 /// The last populated event ID if total events reach the limit or end of the search window.
159 pub cursor: Option<String>,
160 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
161 pub latest_ledger: u64,
162 /// The sequence number of the oldest ledger stored in Stellar-RPC
163 pub oldest_ledger: Option<u64>,
164 /// The unix timestamp of when the latest ledger was closed
165 pub latest_ledger_close_time: Option<String>,
166 /// The unix timestamp of when the oldest ledger was closed
167 pub oldest_ledger_close_time: Option<String>,
168}
169
170/// Event data
171#[derive(Debug, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct EventResponse {
174 /// The type of event emission.
175 #[serde(rename = "type")]
176 pub event_type: EventType,
177 /// Sequence number of the ledger in which this event was emitted.
178 pub ledger: u64,
179 /// ISO-8601 timestamp of the ledger closing time
180 pub ledger_closed_at: String,
181 /// `StrKey` representation of the contract address that emitted this event.
182 pub contract_id: String,
183 /// Unique identifier for this event.
184 ///
185 /// The event's unique id field is based on a toid from Horizon as used in
186 /// Horizon's [/effects endpoint](https://github.com/stellar/go/blob/master/services/horizon/internal/db2/history/effect.go#L58).
187 ///
188 /// Specifically, it is a string containing:
189 /// - bigint(32 bit ledger sequence + 20 bit txn number + 12 bit operation) + <hyphen> + number for the event within the operation.
190 /// For example: 1234-1
191 pub id: String,
192 /// The index of the operation in the transaction
193 pub operation_index: Option<u32>,
194 /// The index of the transaction in the ledger
195 pub transaction_index: Option<u32>,
196 /// The transaction which triggered this event.
197 pub tx_hash: String,
198 /// Duplicate of `id` field, but in the standard place for pagination tokens.
199 /// Since protocol 23: This field is no longer present
200 pub paging_token: Option<String>,
201 /// If true the event was emitted during a successful contract call.
202 ///
203 /// Deprecated: will be remove in protocol 24
204 pub in_successful_contract_call: bool,
205 topic: Vec<String>,
206 value: String,
207}
208
209impl EventResponse {
210 /// List containing the topic this event was emitted with.
211 pub fn topic(&self) -> Vec<ScVal> {
212 self.topic
213 .iter()
214 .map(|t| ScVal::from_xdr_base64(t, Limits::none()).expect("Invalid XDR from RPC"))
215 .collect()
216 }
217
218 /// The emitted body value of the event (serialized in a base64 string).
219 pub fn value(&self) -> ScVal {
220 ScVal::from_xdr_base64(&self.value, Limits::none()).expect("Invalid XDR from RPC")
221 }
222}
223
224/// Status of the transaction
225#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
226#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
227pub enum SendTransactionStatus {
228 /// Transaction submitted
229 Pending,
230 /// Transaction already submitted
231 Duplicate,
232 /// Transaction in error
233 Error,
234 /// Transaction cannot be submitted, try again
235 TryAgainLater,
236}
237
238/// Response to [send_transaction](crate::Server::send_transaction)
239#[derive(Debug, Serialize, Deserialize)]
240#[serde(rename_all = "camelCase")]
241pub struct SendTransactionResponse {
242 /// The current status of the transaction by hash.
243 pub status: SendTransactionStatus,
244 /// Transaction hash (as a hex-encoded string)
245 pub hash: String,
246 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
247 pub latest_ledger: u32,
248 /// The unix timestamp of the close time of the latest ledger known to Stellar RPC at the
249 /// time it handled the request.
250 pub latest_ledger_close_time: String,
251 error_result_xdr: Option<String>, // Base64 encoded TransactionResult
252 diagnostic_events_xdr: Option<Vec<String>>, // Base64 encoded DiagnosticEvent
253}
254
255impl SendTransactionResponse {
256 /// (optional) If the transaction status is [SendTransactionStatus::Error], this will be a
257 /// TransactionResult struct containing details on why stellar-core rejected the transaction.
258 pub fn to_error_result(&self) -> Option<TransactionResult> {
259 self.error_result_xdr.as_ref().map(|e| {
260 TransactionResult::from_xdr_base64(e, Limits::none()).expect("Invalid XDR from RPC")
261 })
262 }
263
264 /// (optional) If the transaction status is [SendTransactionStatus::Error], this field may
265 /// be present with [`Vec<DiagnosticEvent>`]. Each [DiagnosticEvent] is containing details on
266 /// why stellar-core rejected the transaction.
267 pub fn to_diagnostic_events(&self) -> Option<Vec<DiagnosticEvent>> {
268 if let Some(events) = self.diagnostic_events_xdr.as_ref() {
269 events
270 .iter()
271 .map(|e| DiagnosticEvent::from_xdr_base64(e, Limits::none()).ok())
272 .collect()
273 } else {
274 None
275 }
276 }
277}
278
279#[derive(Clone, Debug, Serialize, Deserialize)]
280#[serde(rename_all = "camelCase")]
281struct RestorePreamble {
282 min_resource_fee: String,
283 transaction_data: String,
284}
285
286#[derive(Clone, Debug, Serialize, Deserialize)]
287struct RawSimulateHostFunctionResult {
288 auth: Vec<String>,
289 xdr: String,
290}
291
292#[derive(Clone, Debug, Serialize, Deserialize)]
293struct RawStateChanges {
294 #[serde(rename = "type")]
295 kind: StateChangeKind,
296 key: String,
297 before: Option<String>,
298 after: Option<String>,
299}
300
301/// Indicates if the entry was created (1), updated (2), or deleted (3)
302#[derive(Clone, Debug, Serialize, Deserialize, Copy)]
303#[serde(rename_all = "lowercase")]
304pub enum StateChangeKind {
305 /// Entry has been created
306 Created = 1,
307 /// Entry has been updated
308 Updated = 2,
309 /// Entry has been deleted
310 Deleted = 3,
311}
312
313/// On successful simulation of InvokeHostFunction operations, this field will be an array of
314/// [LedgerEntry]s before and after simulation occurred. Note that at least one of before or after
315/// will be present: before and no after indicates a deletion event, the inverse is a creation
316/// event, and both present indicates an update event. Or just check the type.
317pub struct StateChange {
318 /// Type of change
319 pub kind: StateChangeKind,
320 /// The [LedgerKey] for this delta
321 pub key: LedgerKey,
322 /// If present, [LedgerEntry] state prior to simulation
323 pub before: Option<LedgerEntry>,
324 /// If present, [LedgerEntry] state after simulation
325 pub after: Option<LedgerEntry>,
326}
327
328/// Response to [simulate_transaction](crate::Server::simulate_transaction)
329#[derive(Clone, Debug, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct SimulateTransactionResponse {
332 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
333 pub latest_ledger: u32,
334 /// (optional) Stringified number - Recommended minimum resource fee to add when submitting
335 /// the transaction. This fee is to be added on top of the Stellar network fee.
336 /// Not present in case of error.
337 pub min_resource_fee: Option<String>,
338 /// (optional) - This field will include details about why the invoke host function call
339 /// failed. Only present if the transaction simulation failed.
340 pub error: Option<String>,
341 results: Option<Vec<RawSimulateHostFunctionResult>>,
342 transaction_data: Option<String>,
343 restore_preamble: Option<RestorePreamble>,
344 events: Option<Vec<String>>,
345 state_changes: Option<Vec<RawStateChanges>>,
346}
347
348impl SimulateTransactionResponse {
349 /// (optional) - This array will only have one element: the result for the Host Function
350 /// invocation.
351 /// Only present on successful simulation (i.e. no error) of InvokeHostFunction op
352 pub fn to_result(&self) -> Option<(ScVal, Vec<SorobanAuthorizationEntry>)> {
353 if let Some(r) = self.results.as_ref() {
354 let auth: Vec<SorobanAuthorizationEntry> = r[0]
355 .auth
356 .iter()
357 .map(|e| SorobanAuthorizationEntry::from_xdr_base64(e, Limits::none()).unwrap())
358 .collect();
359 let ret_val = ScVal::from_xdr_base64(&r[0].xdr, Limits::none())
360 .expect("Xdr from RPC should be valid");
361
362 Some((ret_val, auth))
363 } else {
364 None
365 }
366 }
367
368 /// (optional) - The recommended Soroban Transaction Data to use when
369 /// submitting the simulated transaction. This data contains the refundable fee and resource
370 /// usage information such as the ledger footprint and IO access data.
371 /// Not present in case of error.
372 pub fn to_transaction_data(&self) -> Option<SorobanTransactionData> {
373 self.transaction_data.as_ref().map(|data| {
374 SorobanDataBuilder::new(Some(stellar_baselib::soroban_data_builder::Either::Left(
375 data.to_owned(),
376 )))
377 .build()
378 })
379 }
380
381 /// (optional) - It can only be present on successful simulation (i.e. no error) of
382 /// InvokeHostFunction operations. If present, it indicates that the simulation detected
383 /// archived ledger entries which need to be restored before the submission of the
384 /// InvokeHostFunction operation.
385 /// The minResourceFee and transactionData fields should be used to submit a transaction
386 /// containing a RestoreFootprint operation.
387 ///```rust
388 /// # use soroban_client::*;
389 /// # use soroban_client::account::Account;
390 /// # use soroban_client::address::Address;
391 /// # use soroban_client::address::AddressTrait;
392 /// # use soroban_client::contract::Contracts;
393 /// # use soroban_client::contract::ContractBehavior;
394 /// # use soroban_client::network::Networks;
395 /// # use soroban_client::network::NetworkPassphrase;
396 /// # use soroban_client::xdr::Int128Parts;
397 /// # use soroban_client::xdr::ScVal;
398 /// # use soroban_client::xdr::int128_helpers::i128_from_pieces;
399 /// # use soroban_client::keypair::Keypair;
400 /// # use soroban_client::keypair::KeypairBehavior;
401 /// # use soroban_client::transaction::AccountBehavior;
402 /// # use soroban_client::transaction::TransactionBuilderBehavior;
403 /// # use soroban_client::transaction_builder::TransactionBuilder;
404 /// # #[tokio::main]
405 /// # async fn main() {
406 /// # let rpc = Server::new("https://soroban-testnet.stellar.org", Options::default()).unwrap();
407 /// # let native_id = "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC";
408 /// # let native_sac = Contracts::new(native_id).unwrap();
409 /// # let kp = Keypair::random().unwrap();
410 /// # let account = rpc.request_airdrop(&kp.public_key()).await.unwrap();
411 /// # let mut source_account = Account::new(&kp.public_key(), &account.sequence_number()).unwrap();
412 /// # let account_address = Address::new(&kp.public_key()).unwrap();
413 /// # let tx = TransactionBuilder::new(&mut source_account, Networks::testnet(), None)
414 /// # .fee(1000u32)
415 /// # .add_operation(
416 /// # native_sac.call(
417 /// # "balance",
418 /// # Some(vec![account_address.to_sc_val().unwrap()])))
419 /// # .build();
420 ///
421 /// let simulation = rpc.simulate_transaction(&tx, None).await.unwrap();
422 /// if let Some((min_resource_fee, transaction_data)) =
423 /// simulation.to_restore_transaction_data() {
424 /// // Build a RestoreFootprint transaction
425 /// }
426 /// # }
427 /// ```
428 pub fn to_restore_transaction_data(&self) -> Option<(i64, SorobanTransactionData)> {
429 if let Some(restore) = self.restore_preamble.clone() {
430 Some((
431 restore
432 .min_resource_fee
433 .parse()
434 .expect("Invalid i64 for min_resource_fee"),
435 SorobanDataBuilder::new(Some(stellar_baselib::soroban_data_builder::Either::Left(
436 restore.transaction_data,
437 )))
438 .build(),
439 ))
440 } else {
441 None
442 }
443 }
444
445 /// (optional) - Array of the events emitted during the
446 /// contract invocation. The events are ordered by their emission time.
447 /// Only present when simulating of InvokeHostFunction operations,
448 /// note that it can be present on error, providing extra context about what failed.
449 pub fn to_events(&self) -> Option<Vec<DiagnosticEvent>> {
450 if let Some(events) = self.events.as_ref() {
451 events
452 .iter()
453 .map(|e| DiagnosticEvent::from_xdr_base64(e, Limits::none()).ok())
454 .collect()
455 } else {
456 None
457 }
458 }
459
460 /// (optional) - On successful simulation of InvokeHostFunction operations, this field will be
461 /// an array of LedgerEntrys before and after simulation occurred. Note that at least one of
462 /// before or after will be present: before and no after indicates a deletion event, the
463 /// inverse is a creation event, and both present indicates an update event. Or just check the
464 /// type.
465 pub fn to_state_changes(&self) -> Vec<StateChange> {
466 if let Some(changes) = self.state_changes.as_ref() {
467 changes
468 .iter()
469 .map(|c| StateChange {
470 kind: c.kind,
471 key: LedgerKey::from_xdr_base64(&c.key, Limits::none())
472 .expect("Invalid LedgerKey"),
473 before: c.before.as_ref().map(|e| {
474 LedgerEntry::from_xdr_base64(e, Limits::none())
475 .expect("Invalid LedgerEntry")
476 }),
477 after: c.after.as_ref().map(|e| {
478 LedgerEntry::from_xdr_base64(e, Limits::none())
479 .expect("Invalid LedgerEntry")
480 }),
481 })
482 .collect()
483 } else {
484 Default::default()
485 }
486 }
487}
488
489/// Response to [get_fee_stats](crate::Server::get_fee_stats)
490#[derive(Debug, Deserialize)]
491#[serde(rename_all = "camelCase")]
492pub struct GetFeeStatsResponse {
493 /// Inclusion fee distribution statistics for Soroban transactions
494 pub soroban_inclusion_fee: FeeDistribution,
495 /// Fee distribution statistics for Stellar (i.e. non-Soroban) transactions.
496 /// Statistics are normalized per operation.
497 pub inclusion_fee: FeeDistribution,
498 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled
499 /// the request.
500 pub latest_ledger: u32,
501}
502
503/// Fee distribution
504#[derive(Debug, Deserialize)]
505#[serde(rename_all = "camelCase")]
506pub struct FeeDistribution {
507 /// Maximum fee
508 pub max: String,
509 /// Minimum fee
510 pub min: String,
511 /// Fee value which occurs the most often
512 pub mode: String,
513 /// 10th nearest-rank fee percentile
514 pub p10: String,
515 /// 20th nearest-rank fee percentile
516 pub p20: String,
517 /// 30th nearest-rank fee percentile
518 pub p30: String,
519 /// 40th nearest-rank fee percentile
520 pub p40: String,
521 /// 50th nearest-rank fee percentile
522 pub p50: String,
523 /// 60th nearest-rank fee percentile
524 pub p60: String,
525 /// 70th nearest-rank fee percentile
526 pub p70: String,
527 /// 80th nearest-rank fee percentile
528 pub p80: String,
529 /// 90th nearest-rank fee percentile
530 pub p90: String,
531 /// 95th nearest-rank fee percentile
532 pub p95: String,
533 /// 99th nearest-rank fee percentile
534 pub p99: String,
535 /// How many transactions are part of the distribution
536 pub transaction_count: String,
537 /// How many consecutive ledgers form the distribution
538 pub ledger_count: u32,
539}
540
541/// Response to [get_version_info](crate::Server::get_version_info)
542#[derive(Debug, Deserialize)]
543#[serde(rename_all = "camelCase")]
544pub struct GetVersionInfoResponse {
545 /// The version of the RPC server.
546 pub version: String,
547 /// The commit hash of the RPC server.
548 pub commit_hash: String,
549 /// The build timestamp of the RPC server.
550 pub build_timestamp: String,
551 /// The version of the Captive Core.
552 pub captive_core_version: String,
553 /// The protocol version.
554 pub protocol_version: u32,
555}
556
557/// Response to [get_transactions](crate::Server::get_transactions)
558#[derive(Debug, Deserialize)]
559#[serde(rename_all = "camelCase")]
560pub struct GetTransactionsResponse {
561 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
562 pub latest_ledger: u32,
563 /// The unix timestamp of the close time of the latest ledger known to Stellar RPC at the time it handled the request.
564 pub latest_ledger_close_timestamp: i64,
565 /// The sequence number of the oldest ledger ingested by Stellar RPC at the time it handled the request.
566 pub oldest_ledger: u32,
567 /// The unix timestamp of the close time of the oldest ledger ingested by Stellar RPC at the time it handled the request.
568 pub oldest_ledger_close_timestamp: i64,
569 /// Cursor reference
570 pub cursor: String,
571 /// The transactions found
572 pub transactions: Vec<TransactionInfo>,
573}
574
575/// Representation of a transaction returned by stellar RPC
576///
577/// Specific type for [GetTransactionsResponse]
578#[derive(Debug, Deserialize)]
579#[serde(rename_all = "camelCase")]
580pub struct TransactionInfo {
581 /// The unix timestamp of when the transaction was included in the ledger.
582 pub created_at: Option<i64>,
583 #[serde(flatten)]
584 transaction: TransactionDetails,
585}
586// Flatten the transaction in the struct
587impl Deref for TransactionInfo {
588 type Target = TransactionDetails;
589
590 fn deref(&self) -> &Self::Target {
591 &self.transaction
592 }
593}
594
595/// Representation of a transaction returned by stellar RPC
596#[derive(Debug, Deserialize)]
597#[serde(rename_all = "camelCase")]
598pub struct TransactionDetails {
599 /// The current status of the transaction by hash
600 pub status: TransactionStatus,
601 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
602 /// (optional) The sequence number of the ledger which included the transaction. This field is only present if status is [TransactionStatus::Success] or [TransactionStatus::Failed].
603 pub ledger: Option<u32>,
604 /// (optional) The index of the transaction among all transactions included in the ledger. This field is only present if status is [TransactionStatus::Success] or [TransactionStatus::Failed].
605 pub application_order: Option<i32>,
606 /// (optional) Indicates whether the transaction was fee bumped. This field is only present if status is [TransactionStatus::Success] or [TransactionStatus::Failed].
607 pub fee_bump: Option<bool>,
608 envelope_xdr: Option<String>,
609 result_xdr: Option<String>,
610 result_meta_xdr: Option<String>,
611 diagnostic_events_xdr: Option<Vec<String>>,
612 events: Option<Events>,
613}
614
615#[derive(Debug, Deserialize)]
616#[serde(rename_all = "camelCase")]
617struct Events {
618 transaction_events_xdr: Option<Vec<String>>,
619 contract_events_xdr: Option<Vec<Vec<String>>>,
620}
621
622impl TransactionDetails {
623 /// (optional) The [TransactionEnvelope] struct for this transaction.
624 pub fn to_envelope(&self) -> Option<TransactionEnvelope> {
625 if let Some(result) = &self.envelope_xdr {
626 let r = TransactionEnvelope::from_xdr_base64(result, Limits::none());
627 r.ok()
628 } else {
629 None
630 }
631 }
632
633 /// (optional) The [TransactionResult] struct for this transaction. This field is only present if status is [TransactionStatus::Success] or [TransactionStatus::Failed].
634 pub fn to_result(&self) -> Option<TransactionResult> {
635 if let Some(result) = &self.result_xdr {
636 let r = TransactionResult::from_xdr_base64(result, Limits::none());
637 r.ok()
638 } else {
639 None
640 }
641 }
642
643 /// (optional) The [TransactionMeta] struct of this transaction. Also return the optional
644 /// return value of the transaction.
645 pub fn to_result_meta(&self) -> Option<(TransactionMeta, Option<ScVal>)> {
646 if let Some(result) = &self.result_meta_xdr {
647 let r = TransactionMeta::from_xdr_base64(result, Limits::none());
648 if let Ok(e) = r {
649 let mut return_value = None;
650 match &e {
651 TransactionMeta::V3(v3) => {
652 if let Some(v) = &v3.soroban_meta {
653 return_value = Some(v.return_value.clone());
654 }
655 }
656 TransactionMeta::V4(v4) => {
657 if let Some(v) = &v4.soroban_meta {
658 return_value = v.return_value.clone();
659 }
660 }
661 _ => {}
662 };
663 Some((e, return_value))
664 } else {
665 None
666 }
667 } else {
668 None
669 }
670 }
671
672 /// (optional) A base64 encoded slice of xdr.DiagnosticEvent. This is only present if the
673 /// ENABLE_SOROBAN_DIAGNOSTIC_EVENTS has been enabled in the stellar-core config.
674 ///
675 /// Deprecated: will be removed in protocol 24
676 pub fn to_diagnostic_events(&self) -> Option<Vec<DiagnosticEvent>> {
677 if let Some(events) = &self.diagnostic_events_xdr {
678 events
679 .iter()
680 .map(|e| DiagnosticEvent::from_xdr_base64(e, Limits::none()).ok())
681 .collect()
682 } else {
683 None
684 }
685 }
686
687 /// Events contains all events related to the transaction: transaction and contract events.
688 pub fn to_events(&self) -> Option<(Vec<TransactionEvent>, Vec<Vec<ContractEvent>>)> {
689 if let Some(events) = &self.events {
690 let tx_events = match &events.transaction_events_xdr {
691 Some(te) => {
692 let v: Option<Vec<TransactionEvent>> = te
693 .iter()
694 .map(|e| TransactionEvent::from_xdr_base64(e, Limits::none()).ok())
695 .collect();
696 v.unwrap_or_default()
697 }
698 None => Vec::default(),
699 };
700 let cx_events = match &events.contract_events_xdr {
701 Some(te) => {
702 let v: Option<Vec<Vec<ContractEvent>>> = te
703 .iter()
704 .map(|row| {
705 row.iter()
706 .map(|e| ContractEvent::from_xdr_base64(e, Limits::none()).ok())
707 .collect()
708 })
709 .collect();
710 v.unwrap_or_default()
711 }
712 None => Vec::default(),
713 };
714 Some((tx_events, cx_events))
715 } else {
716 None
717 }
718 }
719}
720
721/// Response to [get_ledgers](crate::Server::get_ledgers)
722#[derive(Debug, Deserialize)]
723#[serde(rename_all = "camelCase")]
724pub struct GetLedgersResponse {
725 /// The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
726 pub latest_ledger: u32,
727 /// The unix timestamp of the close time of the latest ledger known to Stellar RPC at the time it handled the request.
728 pub latest_ledger_close_time: i64,
729 /// The sequence number of the oldest ledger ingested by Stellar RPC at the time it handled the request.
730 pub oldest_ledger: u32,
731 /// The unix timestamp of the close time of the oldest ledger ingested by Stellar RPC at the time it handled the request.
732 pub oldest_ledger_close_time: i64,
733 /// Cursor reference
734 pub cursor: String,
735 /// Ledgers returned
736 pub ledgers: Vec<LedgerInfo>,
737}
738
739/// Representation of the ledger
740#[derive(Debug, Clone, Deserialize)]
741#[serde(rename_all = "camelCase")]
742pub struct LedgerInfo {
743 /// The hash of the ledger header which was included in the chain
744 pub hash: String,
745 /// The sequence number of the ledger (sometimes called the 'block height').
746 pub sequence: u32,
747 /// The timestamp at which the ledger was closed.
748 pub ledger_close_time: String,
749 header_xdr: Option<String>,
750 metadataXdr: Option<String>,
751}
752
753impl LedgerInfo {
754 /// LedgerHeader for this ledger
755 pub fn to_header(&self) -> Option<LedgerHeaderHistoryEntry> {
756 self.header_xdr.as_ref().map(|header| {
757 LedgerHeaderHistoryEntry::from_xdr_base64(header, Limits::none())
758 .expect("Invalid XDR from RPC")
759 })
760 }
761 /// LedgerCloseMeta for this ledger
762 pub fn to_metadata(&self) -> Option<LedgerCloseMeta> {
763 self.metadataXdr.as_ref().map(|meta| {
764 LedgerCloseMeta::from_xdr_base64(meta, Limits::none()).expect("Invalid XDR from RPC")
765 })
766 }
767}