Skip to main content

xrpl/models/ledger/objects/
oracle.rs

1use crate::models::ledger::objects::LedgerEntryType;
2use crate::models::transactions::PriceData;
3use crate::models::{Model, NoFlags};
4use alloc::borrow::Cow;
5use alloc::vec::Vec;
6use serde::{Deserialize, Serialize};
7use serde_with::skip_serializing_none;
8
9use super::{CommonFields, LedgerObject};
10
11/// The Oracle ledger entry holds data associated with a single price oracle object.
12///
13/// See Oracle:
14/// `<https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/oracle>`
15#[skip_serializing_none]
16#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
17#[serde(rename_all = "PascalCase")]
18pub struct Oracle<'a> {
19    /// The base fields for all ledger object models.
20    ///
21    /// See Ledger Object Common Fields:
22    /// `<https://xrpl.org/ledger-entry-common-fields.html>`
23    #[serde(flatten)]
24    pub common_fields: CommonFields<'a, NoFlags>,
25    /// The XRPL account with update and delete privileges for the oracle.
26    pub owner: Cow<'a, str>,
27    /// An arbitrary value that identifies an oracle provider.
28    pub provider: Cow<'a, str>,
29    /// Describes the type of asset, such as "currency", "commodity", or "NFT".
30    pub asset_class: Cow<'a, str>,
31    /// An array of up to 10 PriceData objects, representing the price information.
32    pub price_data_series: Vec<PriceData>,
33    /// The time the data was last updated, represented in the ripple epoch.
34    pub last_update_time: u32,
35    /// An optional Universal Resource Identifier to reference price data off-chain.
36    #[serde(rename = "URI")]
37    pub uri: Option<Cow<'a, str>>,
38    /// A hint indicating which page of the owner directory links to this entry.
39    pub owner_node: Cow<'a, str>,
40    /// The identifying hash of the transaction that most recently modified this entry.
41    #[serde(rename = "PreviousTxnID")]
42    pub previous_txn_id: Cow<'a, str>,
43    /// The index of the ledger that contains the transaction that most recently
44    /// modified this entry.
45    pub previous_txn_lgr_seq: u32,
46    /// A unique identifier of the price oracle for the account, if present in
47    /// the ledger entry returned by the server.
48    #[serde(rename = "OracleDocumentID")]
49    pub oracle_document_id: Option<u32>,
50}
51
52impl Model for Oracle<'_> {}
53
54impl<'a> LedgerObject<NoFlags> for Oracle<'a> {
55    fn get_ledger_entry_type(&self) -> LedgerEntryType {
56        self.common_fields.get_ledger_entry_type()
57    }
58}
59
60#[cfg(test)]
61mod test_serde {
62    use super::*;
63    use crate::models::transactions::PriceData;
64    use crate::models::FlagCollection;
65    use alloc::borrow::Cow;
66    use alloc::string::ToString;
67    use alloc::vec;
68
69    #[test]
70    fn test_serialize() {
71        let oracle = Oracle {
72            common_fields: CommonFields {
73                flags: FlagCollection::default(),
74                ledger_entry_type: LedgerEntryType::Oracle,
75                index: Some(Cow::from("ForTest")),
76                ledger_index: None,
77            },
78            owner: Cow::from("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"),
79            provider: Cow::from("636861696E6C696E6B"),
80            asset_class: Cow::from("63757272656E6379"),
81            price_data_series: vec![PriceData {
82                base_asset: "XRP".to_string(),
83                quote_asset: "USD".to_string(),
84                asset_price: Some("2E4".to_string()),
85                scale: Some(1),
86            }],
87            last_update_time: 743609014,
88            uri: Some(Cow::from("68747470733A2F2F6578616D706C652E636F6D")),
89            owner_node: Cow::from("0000000000000000"),
90            previous_txn_id: Cow::from("ABC123DEF456"),
91            previous_txn_lgr_seq: 12345678,
92            oracle_document_id: Some(1),
93        };
94
95        let serialized = serde_json::to_string(&oracle).unwrap();
96        let deserialized: Oracle = serde_json::from_str(&serialized).unwrap();
97        assert_eq!(oracle, deserialized);
98    }
99
100    #[test]
101    fn test_deserialize() {
102        let json = r#"{
103            "LedgerEntryType": "Oracle",
104            "Flags": 0,
105            "Owner": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
106            "Provider": "636861696E6C696E6B",
107            "AssetClass": "63757272656E6379",
108            "PriceDataSeries": [
109                {
110                    "PriceData": {
111                        "BaseAsset": "XRP",
112                        "QuoteAsset": "USD",
113                        "AssetPrice": "2E4",
114                        "Scale": 1
115                    }
116                }
117            ],
118            "LastUpdateTime": 743609014,
119            "URI": "68747470733A2F2F6578616D706C652E636F6D",
120            "OwnerNode": "0000000000000000",
121            "PreviousTxnID": "ABC123DEF456",
122            "PreviousTxnLgrSeq": 12345678,
123            "OracleDocumentID": 1
124        }"#;
125
126        let oracle: Oracle = serde_json::from_str(json).unwrap();
127        assert_eq!(oracle.owner, "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW");
128        assert_eq!(oracle.provider, "636861696E6C696E6B");
129        assert_eq!(oracle.asset_class, "63757272656E6379");
130        assert_eq!(oracle.price_data_series.len(), 1);
131        assert_eq!(oracle.price_data_series[0].base_asset, "XRP");
132        assert_eq!(oracle.price_data_series[0].quote_asset, "USD");
133        assert_eq!(oracle.price_data_series[0].asset_price, Some("2E4".into()));
134        assert_eq!(oracle.price_data_series[0].scale, Some(1));
135        assert_eq!(oracle.last_update_time, 743609014);
136        assert_eq!(
137            oracle.uri,
138            Some("68747470733A2F2F6578616D706C652E636F6D".into())
139        );
140        assert_eq!(oracle.owner_node, "0000000000000000");
141        assert_eq!(oracle.previous_txn_id, "ABC123DEF456");
142        assert_eq!(oracle.previous_txn_lgr_seq, 12345678);
143        assert_eq!(oracle.oracle_document_id, Some(1));
144    }
145
146    #[test]
147    fn test_new_minimal() {
148        let oracle = Oracle {
149            common_fields: CommonFields {
150                flags: FlagCollection::default(),
151                ledger_entry_type: LedgerEntryType::Oracle,
152                index: None,
153                ledger_index: None,
154            },
155            owner: Cow::from("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"),
156            provider: Cow::from("70726F766964657231"),
157            asset_class: Cow::from("63757272656E6379"),
158            price_data_series: vec![PriceData {
159                base_asset: "XRP".to_string(),
160                quote_asset: "USD".to_string(),
161                asset_price: Some("2E4".to_string()),
162                scale: Some(1),
163            }],
164            last_update_time: 743609014,
165            uri: None,
166            owner_node: Cow::from("0000000000000000"),
167            previous_txn_id: Cow::from("ABC123"),
168            previous_txn_lgr_seq: 100,
169            oracle_document_id: None,
170        };
171
172        assert_eq!(oracle.owner, "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW");
173        assert_eq!(oracle.provider, "70726F766964657231");
174        assert_eq!(oracle.asset_class, "63757272656E6379");
175        assert_eq!(oracle.price_data_series.len(), 1);
176        assert_eq!(oracle.last_update_time, 743609014);
177        assert!(oracle.uri.is_none());
178        assert_eq!(oracle.owner_node, "0000000000000000");
179        assert_eq!(oracle.previous_txn_id, "ABC123");
180        assert_eq!(oracle.previous_txn_lgr_seq, 100);
181    }
182
183    #[test]
184    fn test_ledger_entry_type() {
185        let oracle = Oracle {
186            common_fields: CommonFields {
187                flags: FlagCollection::default(),
188                ledger_entry_type: LedgerEntryType::Oracle,
189                index: None,
190                ledger_index: None,
191            },
192            owner: Cow::from("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"),
193            provider: Cow::from("70726F766964657231"),
194            asset_class: Cow::from("63757272656E6379"),
195            price_data_series: vec![PriceData {
196                base_asset: "XRP".to_string(),
197                quote_asset: "USD".to_string(),
198                asset_price: Some("2E4".to_string()),
199                scale: Some(1),
200            }],
201            last_update_time: 0,
202            uri: None,
203            owner_node: Cow::from("0000000000000000"),
204            previous_txn_id: Cow::from("ABC123"),
205            previous_txn_lgr_seq: 0,
206            oracle_document_id: None,
207        };
208
209        assert_eq!(oracle.get_ledger_entry_type(), LedgerEntryType::Oracle);
210    }
211
212    #[test]
213    fn test_with_multiple_price_data() {
214        let oracle = Oracle {
215            common_fields: CommonFields {
216                flags: FlagCollection::default(),
217                ledger_entry_type: LedgerEntryType::Oracle,
218                index: Some(Cow::from("TestIndex")),
219                ledger_index: None,
220            },
221            owner: Cow::from("rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"),
222            provider: Cow::from("636861696E6C696E6B"),
223            asset_class: Cow::from("63757272656E6379"),
224            price_data_series: vec![
225                PriceData {
226                    base_asset: "XRP".to_string(),
227                    quote_asset: "USD".to_string(),
228                    asset_price: Some("2E4".to_string()),
229                    scale: Some(1),
230                },
231                PriceData {
232                    base_asset: "BTC".to_string(),
233                    quote_asset: "USD".to_string(),
234                    asset_price: Some("27AC40".to_string()),
235                    scale: Some(2),
236                },
237                PriceData {
238                    base_asset: "ETH".to_string(),
239                    quote_asset: "USD".to_string(),
240                    asset_price: Some("27100".to_string()),
241                    scale: Some(2),
242                },
243            ],
244            last_update_time: 743609014,
245            uri: Some(Cow::from("68747470733A2F2F6578616D706C652E636F6D")),
246            owner_node: Cow::from("0000000000000000"),
247            previous_txn_id: Cow::from("DEF789"),
248            previous_txn_lgr_seq: 99999,
249            oracle_document_id: None,
250        };
251
252        let series = oracle.price_data_series;
253        assert_eq!(series.len(), 3);
254        assert_eq!(series[0].base_asset, "XRP");
255        assert_eq!(series[1].base_asset, "BTC");
256        assert_eq!(series[2].base_asset, "ETH");
257    }
258}