Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/_serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ macro_rules! serde_with_tag {
)*
}

let hash_map: $crate::_serde::HashMap<&$lt str, Helper<$lt>> = $crate::_serde::HashMap::deserialize(deserializer)?;
let hash_map: $crate::_serde::HashMap<alloc::string::String, Helper<$lt>> = $crate::_serde::HashMap::deserialize(deserializer)?;
let helper_result = hash_map.get(stringify!($name));

match helper_result {
Expand Down Expand Up @@ -269,7 +269,7 @@ macro_rules! serde_with_tag {
)*
}

let hash_map: $crate::_serde::HashMap<&'de str, Helper> = $crate::_serde::HashMap::deserialize(deserializer)?;
let hash_map: $crate::_serde::HashMap<alloc::string::String, Helper> = $crate::_serde::HashMap::deserialize(deserializer)?;
let helper_result = hash_map.get(stringify!($name));

match helper_result {
Expand Down
1 change: 1 addition & 0 deletions src/models/requests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub enum RequestMethod {
#[serde(rename = "amm_info")]
AMMInfo,
GatewayBalances,
#[serde(rename = "noripple_check")]
NoRippleCheck,

// Transaction methods
Expand Down
1 change: 0 additions & 1 deletion src/models/requests/no_ripple_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use super::{CommonFields, LedgerIndex, LookupByLedgerRequest, Request};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Display)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
#[serde(tag = "role")]
#[derive(Default)]
pub enum NoRippleCheckRole {
#[default]
Expand Down
6 changes: 3 additions & 3 deletions src/models/requests/ripple_path_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;

use crate::models::{currency::Currency, requests::RequestMethod, Model};
use crate::models::{amount::Amount, currency::Currency, requests::RequestMethod, Model};

use super::{CommonFields, LedgerIndex, LookupByLedgerRequest, Request};

Expand Down Expand Up @@ -38,7 +38,7 @@ pub struct RipplePathFind<'a> {
/// of the value field (for non-XRP currencies). This requests a
/// path to deliver as much as possible, while spending no more
/// than the amount specified in send_max (if provided).
pub destination_amount: Currency<'a>,
pub destination_amount: Amount<'a>,
/// Unique address of the account that would send funds
/// in a transaction.
pub source_account: Cow<'a, str>,
Expand Down Expand Up @@ -74,7 +74,7 @@ impl<'a> RipplePathFind<'a> {
pub fn new(
id: Option<Cow<'a, str>>,
destination_account: Cow<'a, str>,
destination_amount: Currency<'a>,
destination_amount: Amount<'a>,
source_account: Cow<'a, str>,
ledger_hash: Option<Cow<'a, str>>,
ledger_index: Option<LedgerIndex<'a>>,
Expand Down
15 changes: 11 additions & 4 deletions src/models/results/account_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ pub struct AccountTxV1<'a> {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct TransactionBase<'a> {
/// The ledger index of the ledger version that included this transaction.
pub ledger_index: u32,
/// In API v1 this field is inside the `tx` object rather than at the
/// transaction-entry level, so it may be absent here.
pub ledger_index: Option<u32>,
/// Whether or not the transaction is included in a validated ledger. Any
/// transaction not yet in a validated ledger is subject to change.
pub validated: bool,
pub validated: Option<bool>,
/// (Binary mode) A unique hex string defining the transaction.
pub tx_blob: Option<Cow<'a, str>>,
}
Expand All @@ -103,8 +105,10 @@ pub struct AccountTxTransaction<'a> {
pub struct AccountTxTransactionV1<'a> {
#[serde(flatten)]
pub base: TransactionBase<'a>,
/// (Binary mode) A hex string of the transaction in binary format.
pub tx: Cow<'a, str>,
/// (JSON mode) JSON object defining the transaction (API v1).
pub tx: Option<Value>,
/// (JSON mode) The transaction results metadata in JSON.
pub meta: Option<TransactionMetadata<'a>>,
}

impl<'a> TryFrom<XRPLResult<'a>> for AccountTxVersionMap<'a> {
Expand All @@ -113,6 +117,9 @@ impl<'a> TryFrom<XRPLResult<'a>> for AccountTxVersionMap<'a> {
fn try_from(result: XRPLResult<'a>) -> XRPLModelResult<Self> {
match result {
XRPLResult::AccountTx(account_tx) => Ok(account_tx),
XRPLResult::Other(super::XRPLOtherResult(ref value)) => {
serde_json::from_value(value.clone()).map_err(Into::into)
}
res => Err(XRPLResultException::UnexpectedResultType(
"AccountTx".to_string(),
res.get_name(),
Expand Down
189 changes: 106 additions & 83 deletions src/models/results/ledger_entry.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,105 @@
use alloc::borrow::Cow;

use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Represents an AccountRoot ledger object in the XRP Ledger.
/// This object type represents a single account, its settings, and XRP balance.
use crate::models::ledger::objects::{
account_root::AccountRoot, amendments::Amendments, amm::AMM, bridge::Bridge, check::Check,
deposit_preauth::DepositPreauth, directory_node::DirectoryNode, escrow::Escrow,
fee_settings::FeeSettings, ledger_hashes::LedgerHashes, negative_unl::NegativeUNL,
nftoken_offer::NFTokenOffer, nftoken_page::NFTokenPage, offer::Offer, pay_channel::PayChannel,
ripple_state::RippleState, signer_list::SignerList, ticket::Ticket,
xchain_owned_claim_id::XChainOwnedClaimID,
xchain_owned_create_account_claim_id::XChainOwnedCreateAccountClaimID,
};

/// A discriminated union representing any ledger object type that can be
/// returned by the `ledger_entry` method. Dispatches on the `LedgerEntryType`
/// field, mirroring the `LedgerEntry` union type in xrpl.js.
///
/// See AccountRoot:
/// `<https://xrpl.org/accountroot.html>`
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "PascalCase")]
pub struct Node<'a> {
/// The identifying address of this account
pub account: Cow<'a, str>,
/// The identifying hash of the transaction that most recently modified
/// this object
#[serde(rename = "AccountTxnID")]
pub account_txn_id: Cow<'a, str>,
/// The account's current XRP balance in drops
pub balance: Cow<'a, str>,
/// The domain associated with this account. The raw domain value is a
/// hex string representing the ASCII for the domain
pub domain: Option<Cow<'a, str>>,
/// Hash of an email address to be used for generating an avatar image
pub email_hash: Option<Cow<'a, str>>,
/// Various boolean flags enabled for this account
pub flags: u32,
/// The type of ledger object. For AccountRoot objects, this is always
/// "AccountRoot"
pub ledger_entry_type: Cow<'a, str>,
/// Public key for sending encrypted messages to this account
pub message_key: Option<Cow<'a, str>>,
/// Number of objects this account owns in the ledger, which contributes
/// to its owner reserve
pub owner_count: u32,
/// Identifying hash of the previous transaction that modified this object
#[serde(rename = "PreviousTxnID")]
pub previous_txn_id: Cow<'a, str>,
/// Ledger index of the ledger containing the previous transaction that
/// modified this object
pub previous_txn_lgr_seq: u32,
/// The identifying address of a key pair that can be used to authorize
/// transactions for this account instead of the master key
pub regular_key: Option<Cow<'a, str>>,
/// The sequence number of the next valid transaction for this account
pub sequence: u32,
/// The rate to charge when users transfer this account's issued currencies,
/// represented as billionths of a unit. A value of 0 means no fee
pub transfer_rate: Option<u32>,
/// The unique ID of this ledger entry
#[serde(rename = "index")]
pub index: Cow<'a, str>,
/// Each variant wraps the corresponding ledger object struct from
/// `crate::models::ledger::objects`. The `Unknown` variant handles any
/// ledger entry types not yet modeled in the library.
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum LedgerEntryNode<'a> {
AccountRoot(AccountRoot<'a>),
Amendments(Amendments<'a>),
AMM(AMM<'a>),
Bridge(Bridge<'a>),
Check(Check<'a>),
DepositPreauth(DepositPreauth<'a>),
DirectoryNode(DirectoryNode<'a>),
Escrow(Escrow<'a>),
FeeSettings(FeeSettings<'a>),
LedgerHashes(LedgerHashes<'a>),
NegativeUNL(NegativeUNL<'a>),
NFTokenOffer(NFTokenOffer<'a>),
NFTokenPage(NFTokenPage<'a>),
Offer(Offer<'a>),
PayChannel(PayChannel<'a>),
RippleState(RippleState<'a>),
SignerList(SignerList<'a>),
Ticket(Ticket<'a>),
XChainOwnedClaimID(XChainOwnedClaimID<'a>),
XChainOwnedCreateAccountClaimID(XChainOwnedCreateAccountClaimID<'a>),
/// Fallback for unknown or new ledger entry types not yet modeled.
Unknown(Value),
}

/// Custom deserializer that reads `LedgerEntryType` to dispatch to the
/// correct variant, avoiding the serde limitation where internally tagged
/// enums strip the tag from flattened content.
impl<'de, 'a> Deserialize<'de> for LedgerEntryNode<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = Value::deserialize(deserializer)?;
let entry_type = value
.get("LedgerEntryType")
.and_then(|v| v.as_str())
.unwrap_or("");

let result = match entry_type {
"AccountRoot" => serde_json::from_value(value.clone()).map(Self::AccountRoot),
"Amendments" => serde_json::from_value(value.clone()).map(Self::Amendments),
"AMM" => serde_json::from_value(value.clone()).map(Self::AMM),
"Bridge" => serde_json::from_value(value.clone()).map(Self::Bridge),
"Check" => serde_json::from_value(value.clone()).map(Self::Check),
"DepositPreauth" => serde_json::from_value(value.clone()).map(Self::DepositPreauth),
"DirectoryNode" => serde_json::from_value(value.clone()).map(Self::DirectoryNode),
"Escrow" => serde_json::from_value(value.clone()).map(Self::Escrow),
"FeeSettings" => serde_json::from_value(value.clone()).map(Self::FeeSettings),
"LedgerHashes" => serde_json::from_value(value.clone()).map(Self::LedgerHashes),
"NegativeUNL" => serde_json::from_value(value.clone()).map(Self::NegativeUNL),
"NFTokenOffer" => serde_json::from_value(value.clone()).map(Self::NFTokenOffer),
"NFTokenPage" => serde_json::from_value(value.clone()).map(Self::NFTokenPage),
"Offer" => serde_json::from_value(value.clone()).map(Self::Offer),
"PayChannel" => serde_json::from_value(value.clone()).map(Self::PayChannel),
"RippleState" => serde_json::from_value(value.clone()).map(Self::RippleState),
"SignerList" => serde_json::from_value(value.clone()).map(Self::SignerList),
"Ticket" => serde_json::from_value(value.clone()).map(Self::Ticket),
"XChainOwnedClaimID" => {
serde_json::from_value(value.clone()).map(Self::XChainOwnedClaimID)
}
"XChainOwnedCreateAccountClaimID" => {
serde_json::from_value(value.clone()).map(Self::XChainOwnedCreateAccountClaimID)
}
_ => return Ok(Self::Unknown(value)),
};

result.map_err(serde::de::Error::custom)
}
}

/// Response format for the ledger_entry method, which returns a single ledger
/// object from the XRP Ledger in its raw format.
///
/// The `node` field is a typed enum (`LedgerEntryNode`) that can represent any
/// ledger object type (AccountRoot, DirectoryNode, Offer, RippleState, etc.),
/// mirroring the `LedgerEntry` union type in xrpl.js.
///
/// See Ledger Entry:
/// `<https://xrpl.org/ledger_entry.html>`
#[serde_with::skip_serializing_none]
Expand All @@ -68,8 +112,9 @@ pub struct LedgerEntry<'a> {
/// The identifying hash of the ledger version used to retrieve this data
pub ledger_hash: Option<Cow<'a, str>>,
/// Object containing the data of this ledger entry, according to the
/// ledger format. Omitted if "binary": true specified.
pub node: Option<Node<'a>>,
/// ledger format. Can be any ledger object type (AccountRoot,
/// DirectoryNode, Offer, etc.). Omitted if "binary": true specified.
pub node: Option<LedgerEntryNode<'a>>,
/// The binary representation of the ledger object, as hexadecimal.
/// Only present if "binary": true specified.
pub node_binary: Option<Cow<'a, str>>,
Expand Down Expand Up @@ -124,38 +169,16 @@ mod tests {
assert_eq!(result.validated, Some(true));

let node = result.node.unwrap();
assert_eq!(node.account, "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn");
assert_eq!(
node.account_txn_id,
"4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB"
);
assert_eq!(node.balance, "424021949");
assert_eq!(node.domain, Some("6D64756F31332E636F6D".into()));
assert_eq!(
node.email_hash,
Some("98B4375E1D753E5B91627516F6D70977".into())
);
assert_eq!(node.flags, 9568256);
assert_eq!(node.ledger_entry_type, "AccountRoot");
assert_eq!(
node.message_key,
Some("0000000000000000000000070000000300".into())
);
assert_eq!(node.owner_count, 12);
assert_eq!(
node.previous_txn_id,
"4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB"
);
assert_eq!(node.previous_txn_lgr_seq, 61965653);
assert_eq!(
node.regular_key,
Some("rD9iJmieYHn8jTtPjwwkW2Wm9sVDvPXLoJ".into())
);
assert_eq!(node.sequence, 385);
assert_eq!(node.transfer_rate, Some(4294967295));
assert_eq!(
node.index,
"13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"
);
match node {
LedgerEntryNode::AccountRoot(account_root) => {
assert_eq!(account_root.account, "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn");
assert_eq!(
account_root.account_txn_id,
Some("4E0AA11CBDD1760DE95B68DF2ABBE75C9698CEB548BEA9789053FCB3EBD444FB".into())
);
assert_eq!(account_root.sequence, 385);
}
_ => panic!("Expected AccountRoot variant"),
}
}
}
Loading
Loading