1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::models::ledger::objects::LedgerEntryType;
use crate::models::FlagCollection;
use crate::models::{amount::Amount, Model};
use alloc::borrow::Cow;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use strum_macros::{AsRefStr, Display, EnumIter};
use serde_with::skip_serializing_none;
use super::{CommonFields, LedgerObject};
#[derive(
Debug, Eq, PartialEq, Clone, Serialize_repr, Deserialize_repr, Display, AsRefStr, EnumIter,
)]
#[repr(u32)]
pub enum OfferFlag {
/// The object was placed as a passive Offer.
LsfPassive = 0x00010000,
/// The object was placed as a sell Offer.
LsfSell = 0x00020000,
}
/// The Offer ledger entry describes an Offer to exchange currencies in the XRP Ledger's
/// decentralized exchange. (In finance, this is more traditionally known as an order.)
/// An OfferCreate transaction only creates an Offer entry in the ledger when the Offer
/// cannot be fully executed immediately by consuming other Offers already in the ledger.
///
/// `<https://xrpl.org/offer.html#offer>`
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct Offer<'a> {
/// The base fields for all ledger object models.
///
/// See Ledger Object Common Fields:
/// `<https://xrpl.org/ledger-entry-common-fields.html>`
#[serde(flatten)]
pub common_fields: CommonFields<'a, OfferFlag>,
// The custom fields for the Offer model.
//
// See Offer fields:
// `<https://xrpl.org/offer.html#offer-fields>`
/// The address of the account that owns this `Offer`.
pub account: Cow<'a, str>,
/// The ID of the `Offer Directory` that links to this Offer.
pub book_directory: Cow<'a, str>,
/// A hint indicating which page of the offer directory links to this object, in case
/// the directory consists of multiple pages.
pub book_node: Cow<'a, str>,
/// A hint indicating which page of the owner directory links to this object, in case
/// the directory consists of multiple pages.
pub owner_node: Cow<'a, str>,
/// The identifying hash of the transaction that most recently modified this object.
#[serde(rename = "PreviousTxnID")]
pub previous_txn_id: Cow<'a, str>,
/// The index of the ledger that contains the transaction that most recently modified
/// this object.
pub previous_txn_lgr_seq: u32,
/// The `Sequence` value of the `OfferCreate` transaction that created this `Offer` object.
/// Used in combination with the `Account` to identify this `Offer`.
pub sequence: u32,
/// The remaining amount and type of currency being provided by the `Offer` creator.
pub taker_gets: Amount<'a>,
/// The remaining amount and type of currency requested by the `Offer` creator.
pub taker_pays: Amount<'a>,
/// Indicates the time after which this Offer is considered unfunded.
pub expiration: Option<u32>,
}
impl<'a> Model for Offer<'a> {}
impl<'a> LedgerObject<OfferFlag> for Offer<'a> {
fn get_ledger_entry_type(&self) -> LedgerEntryType {
self.common_fields.get_ledger_entry_type()
}
}
impl<'a> Offer<'a> {
pub fn new(
flags: FlagCollection<OfferFlag>,
index: Option<Cow<'a, str>>,
ledger_index: Option<Cow<'a, str>>,
account: Cow<'a, str>,
book_directory: Cow<'a, str>,
book_node: Cow<'a, str>,
owner_node: Cow<'a, str>,
previous_txn_id: Cow<'a, str>,
previous_txn_lgr_seq: u32,
sequence: u32,
taker_gets: Amount<'a>,
taker_pays: Amount<'a>,
expiration: Option<u32>,
) -> Self {
Self {
common_fields: CommonFields {
flags,
ledger_entry_type: LedgerEntryType::Offer,
index,
ledger_index,
},
account,
book_directory,
book_node,
owner_node,
previous_txn_id,
previous_txn_lgr_seq,
sequence,
taker_gets,
taker_pays,
expiration,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::amount::IssuedCurrencyAmount;
use alloc::borrow::Cow;
use alloc::vec;
#[test]
fn test_serde() {
let offer = Offer::new(
vec![OfferFlag::LsfSell].into(),
Some(Cow::from(
"96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797",
)),
None,
Cow::from("rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt"),
Cow::from("ACC27DE91DBA86FC509069EAF4BC511D73128B780F2E54BF5E07A369E2446000"),
Cow::from("0000000000000000"),
Cow::from("0000000000000000"),
Cow::from("F0AB71E777B2DA54B86231E19B82554EF1F8211F92ECA473121C655BFC5329BF"),
14524914,
866,
Amount::IssuedCurrencyAmount(IssuedCurrencyAmount::new(
"XAG".into(),
"r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH".into(),
"37".into(),
)),
Amount::XRPAmount("79550000000".into()),
None,
);
let serialized = serde_json::to_string(&offer).unwrap();
let deserialized: Offer = serde_json::from_str(&serialized).unwrap();
assert_eq!(offer, deserialized);
}
}