xrpl/models/requests/path_find.rs
1use alloc::borrow::Cow;
2use alloc::vec::Vec;
3use serde::{Deserialize, Serialize};
4use serde_with::skip_serializing_none;
5
6use crate::models::currency::Currency;
7use crate::models::{requests::RequestMethod, Model, PathStep};
8
9use super::{CommonFields, Request};
10
11/// A path is an array. Each member of a path is an object that specifies a step on that path.
12pub type Path<'a> = Vec<PathStep<'a>>;
13
14/// There are three different modes, or sub-commands, of
15/// the path_find command. Specify which one you want with
16/// the subcommand parameter:
17/// * create - Start sending pathfinding information
18/// * close - Stop sending pathfinding information
19/// * status - Info on the currently-open pathfinding request
20///
21/// See Path Find:
22/// `<https://xrpl.org/path_find.html>`
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
24#[serde(rename_all = "snake_case")]
25pub enum PathFindSubcommand {
26 #[default]
27 Create,
28 Close,
29 Status,
30}
31
32/// WebSocket API only! The path_find method searches for
33/// a path along which a transaction can possibly be made,
34/// and periodically sends updates when the path changes
35/// over time. For a simpl<'a>er version that is supported by
36/// JSON-RPC, see the ripple_path_find method. For payments
37/// occurring strictly in XRP, it is not necessary to find
38/// a path, because XRP can be sent directly to any account.
39///
40/// Although the rippled server tries to find the cheapest
41/// path or combination of paths for making a payment, it is
42/// not guaranteed that the paths returned by this method
43/// are, in fact, the best paths. Due to server load,
44/// pathfinding may not find the best results. Additionally,
45/// you should be careful with the pathfinding results from
46/// untrusted servers. A server could be modified to return
47/// less-than-optimal paths to earn money for its operators.
48/// If you do not have your own server that you can trust
49/// with pathfinding, you should compare the results of
50/// pathfinding from multiple servers run by different
51/// parties, to minimize the risk of a single server
52/// returning poor results. (Note: A server returning
53/// less-than-optimal results is not necessarily proof of
54/// malicious behavior; it could also be a symptom of heavy
55/// server load.)
56///
57/// See Path Find:
58/// `<https://xrpl.org/path_find.html>`
59#[skip_serializing_none]
60#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
61pub struct PathFind<'a> {
62 /// The common fields shared by all requests.
63 #[serde(flatten)]
64 pub common_fields: CommonFields<'a>,
65 /// Unique address of the account to find a path to.
66 /// (In other words, the account that would receive a payment.)
67 pub destination_account: Cow<'a, str>,
68 /// Currency Amount that the destination account would
69 /// receive in a transaction. Special case: New in: rippled 0.30.0
70 /// You can specify "-1" (for XRP) or provide -1 as the contents of
71 /// the value field (for non-XRP currencies). This requests a path
72 /// to deliver as much as possible, while spending no more than
73 /// the amount specified in send_max (if provided).
74 pub destination_amount: Currency<'a>,
75 /// Unique address of the account to find a path
76 /// from. (In other words, the account that would
77 /// be sending a payment.)
78 pub source_account: Cow<'a, str>,
79 /// Use "create" to send the create sub-command.
80 pub subcommand: PathFindSubcommand,
81 /// Array of arrays of objects, representing payment paths to check.
82 /// You can use this to keep updated on changes to particular paths
83 /// you already know about, or to check the overall cost to make a
84 /// payment along a certain path.
85 pub paths: Option<Vec<Path<'a>>>,
86 /// Currency Amount that would be spent in the transaction.
87 /// Not compatible with source_currencies.
88 pub send_max: Option<Currency<'a>>,
89}
90
91impl<'a> Model for PathFind<'a> {}
92
93impl<'a> Request<'a> for PathFind<'a> {
94 fn get_common_fields(&self) -> &CommonFields<'a> {
95 &self.common_fields
96 }
97
98 fn get_common_fields_mut(&mut self) -> &mut CommonFields<'a> {
99 &mut self.common_fields
100 }
101}
102
103impl<'a> PathFind<'a> {
104 pub fn new(
105 id: Option<Cow<'a, str>>,
106 destination_account: Cow<'a, str>,
107 destination_amount: Currency<'a>,
108 source_account: Cow<'a, str>,
109 subcommand: PathFindSubcommand,
110 paths: Option<Vec<Vec<PathStep<'a>>>>,
111 send_max: Option<Currency<'a>>,
112 ) -> Self {
113 Self {
114 common_fields: CommonFields {
115 command: RequestMethod::PathFind,
116 id,
117 },
118 subcommand,
119 source_account,
120 destination_account,
121 destination_amount,
122 send_max,
123 paths,
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::models::currency::XRP;
132
133 #[test]
134 fn test_serde_round_trip() {
135 let req = PathFind::new(
136 Some("pf-1".into()),
137 "rDest11111111111111111111111111111".into(),
138 Currency::XRP(XRP::new()),
139 "rSrc111111111111111111111111111111".into(),
140 PathFindSubcommand::Create,
141 None,
142 Some(Currency::XRP(XRP::new())),
143 );
144 let serialized = serde_json::to_string(&req).unwrap();
145 let deserialized: PathFind = serde_json::from_str(&serialized).unwrap();
146 assert_eq!(req, deserialized);
147 assert!(serialized.contains("\"command\":\"path_find\""));
148 assert!(serialized.contains("\"subcommand\":\"create\""));
149 }
150
151 #[test]
152 fn test_subcommand_default() {
153 assert_eq!(PathFindSubcommand::default(), PathFindSubcommand::Create);
154 }
155}