xrpl_rs/
lib.rs

1//! A client that exposes methods for interacting with the XRP Ledger.
2//!
3//! # Example Usage
4//! ```
5//! use std::convert::TryInto;
6//! use xrpl_rs::{XRPL, transports::HTTP, types::account::AccountInfoRequest, types::CurrencyAmount};
7//! use tokio_test::block_on;
8//!
9//! // Create a new XRPL client with the HTTP transport.
10//! let xrpl = XRPL::new(
11//!     HTTP::builder()
12//!         .with_endpoint("http://s1.ripple.com:51234/")
13//!         .unwrap()
14//!         .build()
15//!         .unwrap());
16//!
17//! // Create a request
18//! let mut req = AccountInfoRequest::default();
19//! req.account = "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn".to_owned();
20//!
21//! // Fetch the account info for an address.
22//! let account_info = block_on(async {
23//!     xrpl
24//!         .account_info(req)
25//!         .await
26//!         .unwrap()
27//! });
28//!
29//! assert_eq!(account_info.account_data.balance, CurrencyAmount::xrp(9977));
30//! ```
31
32use std::pin::Pin;
33
34use futures::stream::Stream;
35use serde::de::DeserializeOwned;
36use transports::{DuplexTransport, Transport, TransportError};
37use types::{
38    account::{
39        AccountChannelsRequest, AccountChannelsResponse, AccountCurrenciesRequest,
40        AccountCurrenciesResponse, AccountInfoRequest, AccountInfoResponse, AccountLinesRequest,
41        AccountLinesResponse, AccountOfferRequest, AccountOfferResponse,
42    },
43    channels::{ChannelVerifyRequest, ChannelVerifyResponse},
44    fee::{FeeRequest, FeeResponse},
45    ledger::{LedgerRequest, LedgerResponse},
46    submit::{SignAndSubmitRequest, SubmitRequest, SubmitResponse},
47    subscribe::{SubscribeRequest, SubscriptionEvent},
48    tx::{TxRequest, TxResponse},
49    TransactionEntryRequest, TransactionEntryResponse,
50};
51
52pub mod transaction;
53pub mod transports;
54pub mod types;
55pub mod utils;
56pub mod wallet;
57
58/// An enum providing error types that can be returned when calling XRPL methods.
59#[derive(Debug)]
60pub enum Error {
61    TransportError(TransportError),
62}
63
64impl From<TransportError> for Error {
65    fn from(e: TransportError) -> Self {
66        Self::TransportError(e)
67    }
68}
69
70/// A client that exposes methods for interacting with the XRP Ledger.
71///
72/// # Examples
73/// ```
74/// use std::convert::TryInto;
75/// use xrpl_rs::{XRPL, transports::HTTP, types::account::AccountInfoRequest, types::CurrencyAmount};
76/// use tokio_test::block_on;
77///
78/// // Create a new XRPL client with the HTTP transport.
79/// let xrpl = XRPL::new(
80///     HTTP::builder()
81///         .with_endpoint("http://s1.ripple.com:51234/")
82///         .unwrap()
83///         .build()
84///         .unwrap());
85///
86/// // Create a request
87/// let mut req = AccountInfoRequest::default();
88/// req.account = "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn".to_owned();
89///
90/// // Fetch the account info for an address.
91/// let account_info = block_on(async {
92///     xrpl
93///         .account_info(req)
94///         .await
95///         .unwrap()
96/// });
97///
98/// assert_eq!(account_info.account_data.balance, CurrencyAmount::xrp(9977));
99/// ```
100pub struct XRPL<T: Transport> {
101    transport: T,
102}
103
104macro_rules! impl_rpc_method {
105    ($(#[$attr:meta])* $name: ident, $method: expr, $request: ident, $response: ident) => {
106        $(#[$attr])*
107        pub async fn $name(&self, params: $request) -> Result<$response, Error> {
108            Ok(self
109                .transport
110                .send_request::<$request, $response>($method, params)
111                .await?)
112        }
113    };
114}
115
116impl<T: Transport> XRPL<T> {
117    pub fn new(transport: T) -> Self {
118        Self { transport }
119    }
120    impl_rpc_method!(
121        /// The account_channels method returns information about an account's Payment Channels. This includes only channels where the specified account is the channel's source, not the destination. (A channel's "source" and "owner" are the same.) All information retrieved is relative to a particular version of the ledger.
122        account_channels,
123        "account_channels",
124        AccountChannelsRequest,
125        AccountChannelsResponse
126    );
127    impl_rpc_method!(
128        /// The account_currencies command retrieves a list of currencies that an account can send or receive, based on its trust lines. (This is not a thoroughly confirmed list, but it can be used to populate user interfaces.)
129        account_currencies,
130        "account_currencies",
131        AccountCurrenciesRequest,
132        AccountCurrenciesResponse
133    );
134    impl_rpc_method!(
135        /// The account_info command retrieves information about an account, its activity, and its XRP balance. All information retrieved is relative to a particular version of the ledger.
136        account_info,
137        "account_info",
138        AccountInfoRequest,
139        AccountInfoResponse
140    );
141    impl_rpc_method!(
142        /// The account_lines method returns information about an account's trust lines, including balances in all non-XRP currencies and assets. All information retrieved is relative to a particular version of the ledger.
143        account_lines,
144        "account_lines",
145        AccountLinesRequest,
146        AccountLinesResponse
147    );
148    impl_rpc_method!(
149        /// The account_offers method retrieves a list of offers made by a given account that are outstanding as of a particular ledger version.
150        account_offers,
151        "account_offers",
152        AccountOfferRequest,
153        AccountOfferResponse
154    );
155    impl_rpc_method!(
156        /// The transaction_entry method retrieves information on a single transaction from a specific ledger version. (The tx method, by contrast, searches all ledgers for the specified transaction. We recommend using that method instead.)
157        transaction_entry,
158        "transaction_entry",
159        TransactionEntryRequest,
160        TransactionEntryResponse
161    );
162    impl_rpc_method!(
163        /// The submit method applies a transaction and sends it to the network to be confirmed and included in future ledgers.
164        submit,
165        "submit",
166        SubmitRequest,
167        SubmitResponse
168    );
169    impl_rpc_method!(
170        /// The sign_and_submit method applies a transaction and sends it to the network to be confirmed and included in future ledgers.
171        sign_and_submit,
172        "submit",
173        SignAndSubmitRequest,
174        SubmitResponse
175    );
176    impl_rpc_method!(
177        /// The fee command reports the current state of the open-ledger requirements for the transaction cost. This requires the FeeEscalation amendment to be enabled. New in: rippled 0.31.0.
178        fee,
179        "fee",
180        FeeRequest,
181        FeeResponse
182    );
183    impl_rpc_method!(
184        /// Retrieve information about the public ledger.
185        ledger,
186        "ledger",
187        LedgerRequest,
188        LedgerResponse
189    );
190    impl_rpc_method!(
191        /// The channel_verify method checks the validity of a signature that can be used to redeem a specific amount of XRP from a payment channel.
192        channel_verify,
193        "channel_verify",
194        ChannelVerifyRequest,
195        ChannelVerifyResponse
196    );
197    impl_rpc_method!(
198        /// The tx method retrieves information on a single transaction, by its identifying hash.
199        tx,
200        "tx",
201        TxRequest,
202        TxResponse
203    );
204}
205
206impl<T: DuplexTransport> XRPL<T> {
207    pub async fn subscribe(
208        &self,
209        request: SubscribeRequest,
210    ) -> Result<Pin<Box<dyn Stream<Item = Result<SubscriptionEvent, TransportError>>>>, TransportError> {
211        self.transport.subscribe(request).await
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use crate::types::{BigInt, CurrencyAmount};
218
219    use super::{transports::HTTPBuilder, types, XRPL};
220    #[test]
221    fn create_client() {
222        let _ = XRPL::new(
223            HTTPBuilder::default()
224                .with_endpoint("http://s1.ripple.com:51234/")
225                .unwrap()
226                .build()
227                .unwrap(),
228        );
229    }
230    #[tokio::test]
231    async fn account_info() {
232        let c = XRPL::new(
233            HTTPBuilder::default()
234                .with_endpoint("http://s1.ripple.com:51234/")
235                .unwrap()
236                .build()
237                .unwrap(),
238        );
239        let res = c
240            .account_info(types::account::AccountInfoRequest {
241                account: "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn".to_owned(),
242                strict: None,
243                queue: None,
244                ledger_info: types::LedgerInfo::default(),
245                signer_lists: None,
246            })
247            .await;
248        match res {
249            Err(e) => {
250                eprintln!("test failed: {:?}", e);
251            }
252            Ok(res) => {
253                assert_eq!(res.account_data.balance, CurrencyAmount::XRP(BigInt(9977)),);
254            }
255        }
256    }
257}