iota_sdk/apis/read.rs
1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{collections::BTreeMap, sync::Arc};
6
7use fastcrypto::encoding::Base64;
8use futures::{StreamExt, stream};
9use futures_core::Stream;
10use iota_json_rpc_api::{
11 GovernanceReadApiClient, IndexerApiClient, MoveUtilsClient, ReadApiClient, WriteApiClient,
12};
13#[cfg(feature = "iota-names")]
14use iota_json_rpc_types::IotaNameRecord;
15use iota_json_rpc_types::{
16 Checkpoint, CheckpointId, CheckpointPage, DevInspectArgs, DevInspectResults,
17 DryRunTransactionBlockResponse, DynamicFieldPage, IotaData, IotaGetPastObjectRequest,
18 IotaMoveNormalizedModule, IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery,
19 IotaPastObjectResponse, IotaTransactionBlockEffects, IotaTransactionBlockResponse,
20 IotaTransactionBlockResponseOptions, IotaTransactionBlockResponseQuery, ObjectsPage,
21 ProtocolConfigResponse, TransactionBlocksPage, TransactionFilter,
22};
23use iota_types::{
24 base_types::{IotaAddress, ObjectID, SequenceNumber, TransactionDigest},
25 dynamic_field::DynamicFieldName,
26 iota_serde::BigInt,
27 messages_checkpoint::CheckpointSequenceNumber,
28 transaction::{TransactionData, TransactionKind},
29};
30use jsonrpsee::core::client::Subscription;
31
32use crate::{
33 RpcClient,
34 error::{Error, IotaRpcResult},
35};
36
37/// Defines methods for retrieving data about objects and transactions.
38#[derive(Debug)]
39pub struct ReadApi {
40 api: Arc<RpcClient>,
41}
42
43impl ReadApi {
44 pub(crate) fn new(api: Arc<RpcClient>) -> Self {
45 Self { api }
46 }
47
48 /// Get the objects owned by the given address.
49 /// Results are paginated.
50 ///
51 /// Note that if the address owns more than
52 /// [`QUERY_MAX_RESULT_LIMIT`](iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT)
53 /// objects (default is 50), the pagination may not be accurate as the
54 /// previous page may have been updated before the next page is fetched.
55 ///
56 /// # Examples
57 ///
58 /// ```rust,no_run
59 /// use std::str::FromStr;
60 ///
61 /// use iota_sdk::{IotaClientBuilder, types::base_types::IotaAddress};
62 ///
63 /// #[tokio::main]
64 /// async fn main() -> Result<(), anyhow::Error> {
65 /// let iota = IotaClientBuilder::default().build_testnet().await?;
66 /// let address = IotaAddress::from_str("0x0000....0000")?;
67 /// let owned_objects = iota
68 /// .read_api()
69 /// .get_owned_objects(address, None, None, None)
70 /// .await?;
71 /// Ok(())
72 /// }
73 /// ```
74 pub async fn get_owned_objects(
75 &self,
76 address: IotaAddress,
77 query: impl Into<Option<IotaObjectResponseQuery>>,
78 cursor: impl Into<Option<ObjectID>>,
79 limit: impl Into<Option<usize>>,
80 ) -> IotaRpcResult<ObjectsPage> {
81 Ok(self
82 .api
83 .http
84 .get_owned_objects(address, query.into(), cursor.into(), limit.into())
85 .await?)
86 }
87
88 /// Get the dynamic fields owned by the given [ObjectID].
89 /// Results are paginated.
90 ///
91 /// If the field is a dynamic field, this method returns the ID of the Field
92 /// object, which contains both the name and the value.
93 ///
94 /// If the field is a dynamic object field, it returns the ID of the Object,
95 /// which is the value of the field.
96 ///
97 /// # Examples
98 ///
99 /// ```rust,no_run
100 /// use std::str::FromStr;
101 ///
102 /// use iota_sdk::{
103 /// IotaClientBuilder,
104 /// types::base_types::{IotaAddress, ObjectID},
105 /// };
106 ///
107 /// #[tokio::main]
108 /// async fn main() -> Result<(), anyhow::Error> {
109 /// let iota = IotaClientBuilder::default().build_testnet().await?;
110 /// let address = IotaAddress::from_str("0x0000....0000")?;
111 /// let owned_objects = iota
112 /// .read_api()
113 /// .get_owned_objects(address, None, None, None)
114 /// .await?;
115 /// // this code example assumes that there are previous owned objects
116 /// let object = owned_objects
117 /// .data
118 /// .get(0)
119 /// .expect(&format!("No owned objects for this address {}", address));
120 /// let object_data = object.data.as_ref().expect(&format!(
121 /// "No object data for this IotaObjectResponse {:?}",
122 /// object
123 /// ));
124 /// let object_id = object_data.object_id;
125 /// let dynamic_fields = iota
126 /// .read_api()
127 /// .get_dynamic_fields(object_id, None, None)
128 /// .await?;
129 /// Ok(())
130 /// }
131 /// ```
132 pub async fn get_dynamic_fields(
133 &self,
134 object_id: ObjectID,
135 cursor: impl Into<Option<ObjectID>>,
136 limit: impl Into<Option<usize>>,
137 ) -> IotaRpcResult<DynamicFieldPage> {
138 Ok(self
139 .api
140 .http
141 .get_dynamic_fields(object_id, cursor.into(), limit.into())
142 .await?)
143 }
144
145 /// Get information for a specified dynamic field object by its parent
146 /// object ID and field name.
147 pub async fn get_dynamic_field_object(
148 &self,
149 parent_object_id: ObjectID,
150 name: DynamicFieldName,
151 ) -> IotaRpcResult<IotaObjectResponse> {
152 Ok(self
153 .api
154 .http
155 .get_dynamic_field_object(parent_object_id, name)
156 .await?)
157 }
158
159 /// Get information for a specified dynamic field object by its parent
160 /// object ID and field name with options.
161 pub async fn get_dynamic_field_object_v2(
162 &self,
163 parent_object_id: ObjectID,
164 name: DynamicFieldName,
165 options: impl Into<Option<IotaObjectDataOptions>>,
166 ) -> IotaRpcResult<IotaObjectResponse> {
167 Ok(self
168 .api
169 .http
170 .get_dynamic_field_object_v2(parent_object_id, name, options.into())
171 .await?)
172 }
173
174 /// Get a parsed past object and version for the provided object ID.
175 ///
176 /// An object's version increases when the object is mutated, though it is
177 /// not guaranteed that it increases always by 1. A past object can be used
178 /// to understand how the object changed over time, i.e. what was the total
179 /// balance at a specific version.
180 ///
181 /// # Examples
182 ///
183 /// ```rust,no_run
184 /// use std::str::FromStr;
185 ///
186 /// use iota_sdk::{
187 /// IotaClientBuilder,
188 /// rpc_types::IotaObjectDataOptions,
189 /// types::base_types::{IotaAddress, ObjectID},
190 /// };
191 ///
192 /// #[tokio::main]
193 /// async fn main() -> Result<(), anyhow::Error> {
194 /// let iota = IotaClientBuilder::default().build_testnet().await?;
195 /// let address = IotaAddress::from_str("0x0000....0000")?;
196 /// let owned_objects = iota
197 /// .read_api()
198 /// .get_owned_objects(address, None, None, None)
199 /// .await?;
200 /// // this code example assumes that there are previous owned objects
201 /// let object = owned_objects
202 /// .data
203 /// .get(0)
204 /// .expect(&format!("No owned objects for this address {}", address));
205 /// let object_data = object.data.as_ref().expect(&format!(
206 /// "No object data for this IotaObjectResponse {:?}",
207 /// object
208 /// ));
209 /// let object_id = object_data.object_id;
210 /// let version = object_data.version;
211 /// let past_object = iota
212 /// .read_api()
213 /// .try_get_parsed_past_object(
214 /// object_id,
215 /// version,
216 /// IotaObjectDataOptions {
217 /// show_type: true,
218 /// show_owner: true,
219 /// show_previous_transaction: true,
220 /// show_display: true,
221 /// show_content: true,
222 /// show_bcs: true,
223 /// show_storage_rebate: true,
224 /// },
225 /// )
226 /// .await?;
227 /// Ok(())
228 /// }
229 /// ```
230 pub async fn try_get_parsed_past_object(
231 &self,
232 object_id: ObjectID,
233 version: SequenceNumber,
234 options: IotaObjectDataOptions,
235 ) -> IotaRpcResult<IotaPastObjectResponse> {
236 Ok(self
237 .api
238 .http
239 .try_get_past_object(object_id, version, Some(options))
240 .await?)
241 }
242
243 /// Get a list of parsed past objects.
244 ///
245 /// See [Self::try_get_parsed_past_object] for more details about past
246 /// objects.
247 ///
248 /// # Examples
249 ///
250 /// ```rust,no_run
251 /// use std::str::FromStr;
252 ///
253 /// use iota_sdk::{
254 /// IotaClientBuilder,
255 /// rpc_types::{IotaGetPastObjectRequest, IotaObjectDataOptions},
256 /// types::base_types::{IotaAddress, ObjectID},
257 /// };
258 ///
259 /// #[tokio::main]
260 /// async fn main() -> Result<(), anyhow::Error> {
261 /// let iota = IotaClientBuilder::default().build_testnet().await?;
262 /// let address = IotaAddress::from_str("0x0000....0000")?;
263 /// let owned_objects = iota
264 /// .read_api()
265 /// .get_owned_objects(address, None, None, None)
266 /// .await?;
267 /// // this code example assumes that there are previous owned objects
268 /// let object = owned_objects
269 /// .data
270 /// .get(0)
271 /// .expect(&format!("No owned objects for this address {}", address));
272 /// let object_data = object.data.as_ref().expect(&format!(
273 /// "No object data for this IotaObjectResponse {:?}",
274 /// object
275 /// ));
276 /// let object_id = object_data.object_id;
277 /// let version = object_data.version;
278 /// let past_object = iota
279 /// .read_api()
280 /// .try_get_parsed_past_object(
281 /// object_id,
282 /// version,
283 /// IotaObjectDataOptions {
284 /// show_type: true,
285 /// show_owner: true,
286 /// show_previous_transaction: true,
287 /// show_display: true,
288 /// show_content: true,
289 /// show_bcs: true,
290 /// show_storage_rebate: true,
291 /// },
292 /// )
293 /// .await?;
294 /// let past_object = past_object.into_object()?;
295 /// let multi_past_object = iota
296 /// .read_api()
297 /// .try_multi_get_parsed_past_object(
298 /// vec![IotaGetPastObjectRequest {
299 /// object_id: past_object.object_id,
300 /// version: past_object.version,
301 /// }],
302 /// IotaObjectDataOptions {
303 /// show_type: true,
304 /// show_owner: true,
305 /// show_previous_transaction: true,
306 /// show_display: true,
307 /// show_content: true,
308 /// show_bcs: true,
309 /// show_storage_rebate: true,
310 /// },
311 /// )
312 /// .await?;
313 /// Ok(())
314 /// }
315 /// ```
316 pub async fn try_multi_get_parsed_past_object(
317 &self,
318 past_objects: Vec<IotaGetPastObjectRequest>,
319 options: IotaObjectDataOptions,
320 ) -> IotaRpcResult<Vec<IotaPastObjectResponse>> {
321 Ok(self
322 .api
323 .http
324 .try_multi_get_past_objects(past_objects, Some(options))
325 .await?)
326 }
327
328 /// Get an object by object ID with optional fields enabled by
329 /// [IotaObjectDataOptions].
330 ///
331 /// # Examples
332 ///
333 /// ```rust,no_run
334 /// use std::str::FromStr;
335 ///
336 /// use iota_sdk::{
337 /// IotaClientBuilder, rpc_types::IotaObjectDataOptions, types::base_types::IotaAddress,
338 /// };
339 ///
340 /// #[tokio::main]
341 /// async fn main() -> Result<(), anyhow::Error> {
342 /// let iota = IotaClientBuilder::default().build_testnet().await?;
343 /// let address = IotaAddress::from_str("0x0000....0000")?;
344 /// let owned_objects = iota
345 /// .read_api()
346 /// .get_owned_objects(address, None, None, None)
347 /// .await?;
348 /// // this code example assumes that there are previous owned objects
349 /// let object = owned_objects
350 /// .data
351 /// .get(0)
352 /// .expect(&format!("No owned objects for this address {}", address));
353 /// let object_data = object.data.as_ref().expect(&format!(
354 /// "No object data for this IotaObjectResponse {:?}",
355 /// object
356 /// ));
357 /// let object_id = object_data.object_id;
358 /// let object = iota
359 /// .read_api()
360 /// .get_object_with_options(
361 /// object_id,
362 /// IotaObjectDataOptions {
363 /// show_type: true,
364 /// show_owner: true,
365 /// show_previous_transaction: true,
366 /// show_display: true,
367 /// show_content: true,
368 /// show_bcs: true,
369 /// show_storage_rebate: true,
370 /// },
371 /// )
372 /// .await?;
373 /// Ok(())
374 /// }
375 /// ```
376 pub async fn get_object_with_options(
377 &self,
378 object_id: ObjectID,
379 options: IotaObjectDataOptions,
380 ) -> IotaRpcResult<IotaObjectResponse> {
381 Ok(self.api.http.get_object(object_id, Some(options)).await?)
382 }
383
384 /// Get a list of objects by their object IDs with optional fields enabled
385 /// by [IotaObjectDataOptions].
386 ///
387 /// # Examples
388 ///
389 /// ```rust,no_run
390 /// use std::str::FromStr;
391 ///
392 /// use iota_sdk::{
393 /// IotaClientBuilder, rpc_types::IotaObjectDataOptions, types::base_types::IotaAddress,
394 /// };
395 ///
396 /// #[tokio::main]
397 /// async fn main() -> Result<(), anyhow::Error> {
398 /// let iota = IotaClientBuilder::default().build_testnet().await?;
399 /// let address = IotaAddress::from_str("0x0000....0000")?;
400 /// let owned_objects = iota
401 /// .read_api()
402 /// .get_owned_objects(address, None, None, None)
403 /// .await?;
404 /// // this code example assumes that there are previous owned objects
405 /// let object = owned_objects
406 /// .data
407 /// .get(0)
408 /// .expect(&format!("No owned objects for this address {}", address));
409 /// let object_data = object.data.as_ref().expect(&format!(
410 /// "No object data for this IotaObjectResponse {:?}",
411 /// object
412 /// ));
413 /// let object_id = object_data.object_id;
414 /// let object_ids = vec![object_id]; // and other object ids
415 /// let object = iota
416 /// .read_api()
417 /// .multi_get_object_with_options(
418 /// object_ids,
419 /// IotaObjectDataOptions {
420 /// show_type: true,
421 /// show_owner: true,
422 /// show_previous_transaction: true,
423 /// show_display: true,
424 /// show_content: true,
425 /// show_bcs: true,
426 /// show_storage_rebate: true,
427 /// },
428 /// )
429 /// .await?;
430 /// Ok(())
431 /// }
432 /// ```
433 pub async fn multi_get_object_with_options(
434 &self,
435 object_ids: Vec<ObjectID>,
436 options: IotaObjectDataOptions,
437 ) -> IotaRpcResult<Vec<IotaObjectResponse>> {
438 Ok(self
439 .api
440 .http
441 .multi_get_objects(object_ids, Some(options))
442 .await?)
443 }
444
445 /// Get a [bcs] serialized object's bytes by object ID.
446 pub async fn get_move_object_bcs(&self, object_id: ObjectID) -> IotaRpcResult<Vec<u8>> {
447 let resp = self
448 .get_object_with_options(object_id, IotaObjectDataOptions::default().with_bcs())
449 .await?
450 .into_object()
451 .map_err(|e| {
452 Error::Data(format!("Can't get bcs of object {:?}: {:?}", object_id, e))
453 })?;
454 // unwrap: requested bcs data
455 let move_object = resp.bcs.unwrap();
456 let raw_move_obj = move_object.try_into_move().ok_or(Error::Data(format!(
457 "Object {:?} is not a MoveObject",
458 object_id
459 )))?;
460 Ok(raw_move_obj.bcs_bytes)
461 }
462
463 /// Get the total number of transaction blocks known to server.
464 ///
465 /// # Examples
466 ///
467 /// ```rust,no_run
468 /// use iota_sdk::IotaClientBuilder;
469 ///
470 /// #[tokio::main]
471 /// async fn main() -> Result<(), anyhow::Error> {
472 /// let iota = IotaClientBuilder::default().build_testnet().await?;
473 /// let total_transaction_blocks = iota.read_api().get_total_transaction_blocks().await?;
474 /// Ok(())
475 /// }
476 /// ```
477 pub async fn get_total_transaction_blocks(&self) -> IotaRpcResult<u64> {
478 Ok(*self.api.http.get_total_transaction_blocks().await?)
479 }
480
481 /// Get a transaction and its effects by its digest with optional fields
482 /// enabled by [IotaTransactionBlockResponseOptions].
483 pub async fn get_transaction_with_options(
484 &self,
485 digest: TransactionDigest,
486 options: IotaTransactionBlockResponseOptions,
487 ) -> IotaRpcResult<IotaTransactionBlockResponse> {
488 Ok(self
489 .api
490 .http
491 .get_transaction_block(digest, Some(options))
492 .await?)
493 }
494
495 /// Get a list of transactions and their effects by their digests with
496 /// optional fields enabled by [IotaTransactionBlockResponseOptions].
497 pub async fn multi_get_transactions_with_options(
498 &self,
499 digests: Vec<TransactionDigest>,
500 options: IotaTransactionBlockResponseOptions,
501 ) -> IotaRpcResult<Vec<IotaTransactionBlockResponse>> {
502 Ok(self
503 .api
504 .http
505 .multi_get_transaction_blocks(digests, Some(options))
506 .await?)
507 }
508
509 /// Get filtered transaction blocks information.
510 /// Results are paginated.
511 pub async fn query_transaction_blocks(
512 &self,
513 query: IotaTransactionBlockResponseQuery,
514 cursor: impl Into<Option<TransactionDigest>>,
515 limit: impl Into<Option<usize>>,
516 descending_order: bool,
517 ) -> IotaRpcResult<TransactionBlocksPage> {
518 Ok(self
519 .api
520 .http
521 .query_transaction_blocks(query, cursor.into(), limit.into(), Some(descending_order))
522 .await?)
523 }
524
525 /// Get the first four bytes of the chain's genesis checkpoint digest in hex
526 /// format.
527 pub async fn get_chain_identifier(&self) -> IotaRpcResult<String> {
528 Ok(self.api.http.get_chain_identifier().await?)
529 }
530
531 /// Get a checkpoint by its ID.
532 pub async fn get_checkpoint(&self, id: CheckpointId) -> IotaRpcResult<Checkpoint> {
533 Ok(self.api.http.get_checkpoint(id).await?)
534 }
535
536 /// Return a list of checkpoints.
537 /// Results are paginated.
538 pub async fn get_checkpoints(
539 &self,
540 cursor: impl Into<Option<BigInt<u64>>>,
541 limit: impl Into<Option<usize>>,
542 descending_order: bool,
543 ) -> IotaRpcResult<CheckpointPage> {
544 Ok(self
545 .api
546 .http
547 .get_checkpoints(cursor.into(), limit.into(), descending_order)
548 .await?)
549 }
550
551 /// Get the sequence number of the latest checkpoint that has been executed.
552 pub async fn get_latest_checkpoint_sequence_number(
553 &self,
554 ) -> IotaRpcResult<CheckpointSequenceNumber> {
555 Ok(*self
556 .api
557 .http
558 .get_latest_checkpoint_sequence_number()
559 .await?)
560 }
561
562 /// Get a stream of transactions.
563 pub fn get_transactions_stream(
564 &self,
565 query: IotaTransactionBlockResponseQuery,
566 cursor: impl Into<Option<TransactionDigest>>,
567 descending_order: bool,
568 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
569 let cursor = cursor.into();
570
571 stream::unfold(
572 (vec![], cursor, true, query),
573 move |(mut data, cursor, first, query)| async move {
574 if let Some(item) = data.pop() {
575 Some((item, (data, cursor, false, query)))
576 } else if (cursor.is_none() && first) || cursor.is_some() {
577 let page = self
578 .query_transaction_blocks(
579 query.clone(),
580 cursor,
581 Some(100),
582 descending_order,
583 )
584 .await
585 .ok()?;
586 let mut data = page.data;
587 data.reverse();
588 data.pop()
589 .map(|item| (item, (data, page.next_cursor, false, query)))
590 } else {
591 None
592 }
593 },
594 )
595 }
596
597 /// Subscribe to a stream of transactions.
598 ///
599 /// This is only available through WebSockets.
600 pub async fn subscribe_transaction(
601 &self,
602 filter: TransactionFilter,
603 ) -> IotaRpcResult<impl Stream<Item = IotaRpcResult<IotaTransactionBlockEffects>>> {
604 let Some(c) = &self.api.ws else {
605 return Err(Error::Subscription(
606 "Subscription only supported by WebSocket client.".to_string(),
607 ));
608 };
609 let subscription: Subscription<IotaTransactionBlockEffects> =
610 c.subscribe_transaction(filter).await?;
611 Ok(subscription.map(|item| Ok(item?)))
612 }
613
614 /// Get move modules by package ID, keyed by name.
615 pub async fn get_normalized_move_modules_by_package(
616 &self,
617 package: ObjectID,
618 ) -> IotaRpcResult<BTreeMap<String, IotaMoveNormalizedModule>> {
619 Ok(self
620 .api
621 .http
622 .get_normalized_move_modules_by_package(package)
623 .await?)
624 }
625
626 // TODO(devx): we can probably cache this given an epoch
627 /// Get the reference gas price.
628 pub async fn get_reference_gas_price(&self) -> IotaRpcResult<u64> {
629 Ok(*self.api.http.get_reference_gas_price().await?)
630 }
631
632 /// Dry run a transaction block given the provided transaction data.
633 ///
634 /// This simulates running the transaction, including all standard checks,
635 /// without actually running it. This is useful for estimating the gas fees
636 /// of a transaction before executing it. You can also use it to identify
637 /// any side-effects of a transaction before you execute it on the network.
638 pub async fn dry_run_transaction_block(
639 &self,
640 tx: TransactionData,
641 ) -> IotaRpcResult<DryRunTransactionBlockResponse> {
642 Ok(self
643 .api
644 .http
645 .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?))
646 .await?)
647 }
648
649 /// Use this function to inspect the current state of the network by running
650 /// a programmable transaction block without committing its effects on
651 /// chain.
652 ///
653 /// Unlike a dry run, this method will not validate whether the transaction
654 /// block would succeed or fail under normal circumstances, e.g.:
655 ///
656 /// - Transaction inputs are not checked for ownership (i.e. you can
657 /// construct calls involving objects you do not own)
658 /// - Calls are not checked for visibility (you can call private functions
659 /// on modules)
660 /// - Inputs of any type can be constructed and passed in, including coins
661 /// and other objects that would usually need to be constructed with a
662 /// move call
663 /// - Function returns do not need to be used, even if they do not have
664 /// `drop`
665 ///
666 /// This method's output includes a breakdown of results returned by every
667 /// transaction in the block, as well as the transaction's effects.
668 ///
669 /// To run an accurate simulation of a transaction and understand whether
670 /// it will successfully validate and run, use
671 /// [Self::dry_run_transaction_block] instead.
672 pub async fn dev_inspect_transaction_block(
673 &self,
674 sender_address: IotaAddress,
675 tx: TransactionKind,
676 gas_price: impl Into<Option<BigInt<u64>>>,
677 epoch: impl Into<Option<BigInt<u64>>>,
678 additional_args: impl Into<Option<DevInspectArgs>>,
679 ) -> IotaRpcResult<DevInspectResults> {
680 Ok(self
681 .api
682 .http
683 .dev_inspect_transaction_block(
684 sender_address,
685 Base64::from_bytes(&bcs::to_bytes(&tx)?),
686 gas_price.into(),
687 epoch.into(),
688 additional_args.into(),
689 )
690 .await?)
691 }
692
693 /// Get the protocol config by version.
694 ///
695 /// The version defaults to the current version.
696 pub async fn get_protocol_config(
697 &self,
698 version: impl Into<Option<BigInt<u64>>>,
699 ) -> IotaRpcResult<ProtocolConfigResponse> {
700 Ok(self.api.http.get_protocol_config(version.into()).await?)
701 }
702
703 /// Get an object by ID before the given version.
704 pub async fn try_get_object_before_version(
705 &self,
706 object_id: ObjectID,
707 version: SequenceNumber,
708 ) -> IotaRpcResult<IotaPastObjectResponse> {
709 Ok(self
710 .api
711 .http
712 .try_get_object_before_version(object_id, version)
713 .await?)
714 }
715
716 #[cfg(feature = "iota-names")]
717 /// Return the resolved record for the given name.
718 pub async fn iota_names_lookup(&self, name: &str) -> IotaRpcResult<Option<IotaNameRecord>> {
719 Ok(self.api.http.iota_names_lookup(name).await?)
720 }
721
722 #[cfg(feature = "iota-names")]
723 /// Return the resolved name for the given address.
724 pub async fn iota_names_reverse_lookup(
725 &self,
726 address: IotaAddress,
727 ) -> IotaRpcResult<Option<String>> {
728 Ok(self.api.http.iota_names_reverse_lookup(address).await?)
729 }
730
731 #[cfg(feature = "iota-names")]
732 /// Find all registration NFTs for the given address.
733 pub async fn iota_names_find_all_registration_nfts(
734 &self,
735 address: IotaAddress,
736 cursor: Option<ObjectID>,
737 limit: Option<usize>,
738 options: Option<IotaObjectDataOptions>,
739 ) -> IotaRpcResult<ObjectsPage> {
740 Ok(self
741 .api
742 .http
743 .iota_names_find_all_registration_nfts(address, cursor, limit, options)
744 .await?)
745 }
746}