Skip to content

Commit e75ba41

Browse files
committed
Preliminary work on ripple_path_find
1 parent 9435cdb commit e75ba41

File tree

6 files changed

+141
-4
lines changed

6 files changed

+141
-4
lines changed

xrpl_api/src/api.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ pub use nft_buy_offers::*;
6666
pub mod nft_sell_offers;
6767
pub use nft_sell_offers::*;
6868

69+
pub mod path_find;
70+
pub use path_find::*;
71+
72+
pub mod ripple_path_find;
73+
pub use ripple_path_find::*;
74+
6975
// Server Info methods
7076

7177
pub mod fee;

xrpl_api/src/api/path_find.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//! WebSocket API only! The path_find method searches for a path along which a
2+
//! transaction can possibly be made, and periodically sends updates when the
3+
//! path changes over time. For a simpler version that is supported by
4+
//! JSON-RPC, see the ripple_path_find method. For payments occurring strictly
5+
//! in XRP, it is not necessary to find a path, because XRP can be sent
6+
//! directly to any account.
7+
//!
8+
//! There are three different modes, or sub-commands, of the path_find command.
9+
//! Specify which one you want with the subcommand parameter:
10+
//!
11+
//! create - Start sending pathfinding information
12+
//! close - Stop sending pathfinding information
13+
//! status - Get the information of the currently-open pathfinding request
14+
//!
15+
//! - https://xrpl.org/path_find.html
16+
17+
// #TODO

xrpl_api/src/api/ripple_path_find.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! The ripple_path_find method is a simplified version of the path_find method
2+
//! that provides a single response with a payment path you can use right away.
3+
//! It is available in both the WebSocket and JSON-RPC APIs. However, the
4+
//! results tend to become outdated as time passes. Instead of making multiple
5+
//! calls to stay updated, you should instead use the path_find method to
6+
//! subscribe to continued updates where possible.
7+
//!
8+
//! Although the rippled server tries to find the cheapest path or combination
9+
//! of paths for making a payment, it is not guaranteed that the paths
10+
//! returned by this method are, in fact, the best paths.
11+
//!
12+
//! - https://xrpl.org/ripple_path_find.html
13+
//! - https://xrpl.org/paths.html
14+
15+
use serde::{Deserialize, Serialize};
16+
use serde_json::Value;
17+
use xrpl_types::Amount;
18+
19+
use crate::Request;
20+
21+
// #TODO is Clone really needed?
22+
#[derive(Default, Clone, Serialize)]
23+
pub struct RipplePathFindRequest {
24+
/// Unique address of the account that would send funds in a transaction.
25+
source_account: String,
26+
/// Unique address of the account that would receive funds in a transaction.
27+
destination_account: String,
28+
/// Currency Amount that the destination account would receive in a
29+
/// transaction. Special case: New in: rippled 0.30.0 You can specify "-1"
30+
/// (for XRP) or provide -1 as the contents of the value field
31+
/// (for non-XRP currencies). This requests a path to deliver as much as
32+
/// possible, while spending no more than the amount specified in
33+
/// send_max (if provided).
34+
destination_amount: Amount,
35+
#[serde(skip_serializing_if = "Option::is_none")]
36+
send_max: Option<Amount>,
37+
/// A 20-byte hex string for the ledger version to use.
38+
#[serde(skip_serializing_if = "Option::is_none")]
39+
pub ledger_hash: Option<String>,
40+
/// The ledger index of the ledger to use, or a shortcut string to choose a
41+
/// ledger automatically.
42+
#[serde(skip_serializing_if = "Option::is_none")]
43+
pub ledger_index: Option<String>,
44+
}
45+
46+
impl Request for RipplePathFindRequest {
47+
type Response = RipplePathFindResponse;
48+
49+
fn method(&self) -> String {
50+
"ripple_path_find".to_owned()
51+
}
52+
}
53+
54+
impl RipplePathFindRequest {
55+
pub fn new(
56+
source_account: &str,
57+
destination_account: &str,
58+
destination_amount: Amount,
59+
) -> Self {
60+
Self {
61+
source_account: source_account.to_owned(),
62+
destination_account: destination_account.to_owned(),
63+
destination_amount,
64+
..Default::default()
65+
}
66+
}
67+
}
68+
69+
#[derive(Debug, Deserialize)]
70+
pub struct Path {
71+
// #TODO full types missing
72+
/// Array of arrays of objects defining payment paths.
73+
pub paths_computed: Vec<Vec<Value>>,
74+
/// Currency Amount that the source would have to send along this path for
75+
/// the destination to receive the desired amount.
76+
pub source_amount: Amount,
77+
}
78+
79+
#[derive(Debug, Deserialize)]
80+
pub struct RipplePathFindResponse {
81+
pub alternatives: Vec<Path>,
82+
pub destination_account: String,
83+
pub destination_currencies: Vec<String>,
84+
}

xrpl_sdk_jsonrpc/src/client.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ impl Client {
102102

103103
let body = serde_json::to_string(&request)?;
104104

105+
// dbg!(&body);
105106
debug!("POST {}", body);
106107

107108
let response = self
@@ -125,6 +126,7 @@ impl Client {
125126
let status = body["result"]["status"].as_str().unwrap_or("error");
126127

127128
if status == "error" {
129+
// dbg!(&body);
128130
debug!("{}", body);
129131

130132
return Err(Error::Api(

xrpl_sdk_jsonrpc/src/client_tests.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
#[cfg(test)]
22
mod tests {
3-
use crate::client::{Client, NFT_DEVNET_URL};
3+
use crate::{
4+
client::{Client, NFT_DEVNET_URL},
5+
error::Error,
6+
};
47
use xrpl_api::{
58
AccountChannelsRequest, AccountCurrenciesRequest, AccountInfoRequest, AccountLinesRequest,
69
AccountNftsRequest, AccountOffersRequest, AccountTxRequest, BookOffersRequest,
710
DepositAuthorizedRequest, FeeRequest, GatewayBalancesRequest, GetOfferObjectRequest,
811
LedgerClosedRequest, LedgerCurrentRequest, LedgerDataRequest, LedgerEntryRequest,
912
ManifestRequest, NftBuyOffersRequest, NftSellOffersRequest, PingRequest, RandomRequest,
10-
ServerInfoRequest, ServerStateRequest, TransactionEntryRequest, TxRequest,
13+
RipplePathFindRequest, ServerInfoRequest, ServerStateRequest, TransactionEntryRequest,
14+
TxRequest,
1115
};
12-
use xrpl_types::Currency;
16+
use xrpl_types::{Amount, Currency};
1317

1418
#[tokio::test]
1519
async fn client_can_fetch_account_currencies() {
@@ -220,6 +224,24 @@ mod tests {
220224
assert_eq!(resp.nft_id, nft_id);
221225
}
222226

227+
#[tokio::test]
228+
async fn client_can_find_a_payment_path() {
229+
let client = Client::default();
230+
231+
let resp = client
232+
.call(RipplePathFindRequest::new(
233+
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
234+
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
235+
Amount::issued("0.001", "USD", "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"),
236+
))
237+
.await;
238+
239+
let resp = resp;
240+
241+
// #TODO investigate why the server returns notSupported?
242+
assert!(matches!(resp, Err(Error::Api(s)) if s == "notSupported"));
243+
}
244+
223245
#[tokio::test]
224246
async fn client_can_fetch_transaction_entries() {
225247
let client = Client::default();

xrpl_types/src/amount.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::Currency;
22
use serde::{Deserialize, Serialize};
33

44
/// https://xrpl.org/serialization.html#amount-fields
5-
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
5+
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
66
#[serde(untagged)]
77
pub enum Amount {
88
Issued {
@@ -13,6 +13,12 @@ pub enum Amount {
1313
Drops(String),
1414
}
1515

16+
impl Default for Amount {
17+
fn default() -> Self {
18+
Amount::drops(0)
19+
}
20+
}
21+
1622
impl Amount {
1723
pub fn issued(value: &str, currency: &str, issuer: &str) -> Self {
1824
Self::Issued {

0 commit comments

Comments
 (0)