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| Error::Data(format!("Can't get bcs of object {object_id:?}: {e:?}")))?;
452 // unwrap: requested bcs data
453 let move_object = resp.bcs.unwrap();
454 let raw_move_obj = move_object.try_into_move().ok_or(Error::Data(format!(
455 "Object {object_id:?} is not a MoveObject"
456 )))?;
457 Ok(raw_move_obj.bcs_bytes)
458 }
459
460 /// Get the total number of transaction blocks known to server.
461 ///
462 /// # Examples
463 ///
464 /// ```rust,no_run
465 /// use iota_sdk::IotaClientBuilder;
466 ///
467 /// #[tokio::main]
468 /// async fn main() -> Result<(), anyhow::Error> {
469 /// let iota = IotaClientBuilder::default().build_testnet().await?;
470 /// let total_transaction_blocks = iota.read_api().get_total_transaction_blocks().await?;
471 /// Ok(())
472 /// }
473 /// ```
474 pub async fn get_total_transaction_blocks(&self) -> IotaRpcResult<u64> {
475 Ok(*self.api.http.get_total_transaction_blocks().await?)
476 }
477
478 /// Get a transaction and its effects by its digest with optional fields
479 /// enabled by [IotaTransactionBlockResponseOptions].
480 pub async fn get_transaction_with_options(
481 &self,
482 digest: TransactionDigest,
483 options: IotaTransactionBlockResponseOptions,
484 ) -> IotaRpcResult<IotaTransactionBlockResponse> {
485 Ok(self
486 .api
487 .http
488 .get_transaction_block(digest, Some(options))
489 .await?)
490 }
491
492 /// Get a list of transactions and their effects by their digests with
493 /// optional fields enabled by [IotaTransactionBlockResponseOptions].
494 pub async fn multi_get_transactions_with_options(
495 &self,
496 digests: Vec<TransactionDigest>,
497 options: IotaTransactionBlockResponseOptions,
498 ) -> IotaRpcResult<Vec<IotaTransactionBlockResponse>> {
499 Ok(self
500 .api
501 .http
502 .multi_get_transaction_blocks(digests, Some(options))
503 .await?)
504 }
505
506 /// Get filtered transaction blocks information.
507 /// Results are paginated.
508 pub async fn query_transaction_blocks(
509 &self,
510 query: IotaTransactionBlockResponseQuery,
511 cursor: impl Into<Option<TransactionDigest>>,
512 limit: impl Into<Option<usize>>,
513 descending_order: bool,
514 ) -> IotaRpcResult<TransactionBlocksPage> {
515 Ok(self
516 .api
517 .http
518 .query_transaction_blocks(query, cursor.into(), limit.into(), Some(descending_order))
519 .await?)
520 }
521
522 /// Get the first four bytes of the chain's genesis checkpoint digest in hex
523 /// format.
524 pub async fn get_chain_identifier(&self) -> IotaRpcResult<String> {
525 Ok(self.api.http.get_chain_identifier().await?)
526 }
527
528 /// Get a checkpoint by its ID.
529 pub async fn get_checkpoint(&self, id: CheckpointId) -> IotaRpcResult<Checkpoint> {
530 Ok(self.api.http.get_checkpoint(id).await?)
531 }
532
533 /// Return a list of checkpoints.
534 /// Results are paginated.
535 pub async fn get_checkpoints(
536 &self,
537 cursor: impl Into<Option<BigInt<u64>>>,
538 limit: impl Into<Option<usize>>,
539 descending_order: bool,
540 ) -> IotaRpcResult<CheckpointPage> {
541 Ok(self
542 .api
543 .http
544 .get_checkpoints(cursor.into(), limit.into(), descending_order)
545 .await?)
546 }
547
548 /// Get the sequence number of the latest checkpoint that has been executed.
549 pub async fn get_latest_checkpoint_sequence_number(
550 &self,
551 ) -> IotaRpcResult<CheckpointSequenceNumber> {
552 Ok(*self
553 .api
554 .http
555 .get_latest_checkpoint_sequence_number()
556 .await?)
557 }
558
559 /// Get a stream of transactions.
560 pub fn get_transactions_stream(
561 &self,
562 query: IotaTransactionBlockResponseQuery,
563 cursor: impl Into<Option<TransactionDigest>>,
564 descending_order: bool,
565 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
566 let cursor = cursor.into();
567
568 stream::unfold(
569 (vec![], cursor, true, query),
570 move |(mut data, cursor, first, query)| async move {
571 if let Some(item) = data.pop() {
572 Some((item, (data, cursor, false, query)))
573 } else if (cursor.is_none() && first) || cursor.is_some() {
574 let page = self
575 .query_transaction_blocks(
576 query.clone(),
577 cursor,
578 Some(100),
579 descending_order,
580 )
581 .await
582 .ok()?;
583 let mut data = page.data;
584 data.reverse();
585 data.pop()
586 .map(|item| (item, (data, page.next_cursor, false, query)))
587 } else {
588 None
589 }
590 },
591 )
592 }
593
594 /// Subscribe to a stream of transactions.
595 ///
596 /// This is only available through WebSockets.
597 pub async fn subscribe_transaction(
598 &self,
599 filter: TransactionFilter,
600 ) -> IotaRpcResult<impl Stream<Item = IotaRpcResult<IotaTransactionBlockEffects>>> {
601 let Some(c) = &self.api.ws else {
602 return Err(Error::Subscription(
603 "Subscription only supported by WebSocket client.".to_string(),
604 ));
605 };
606 let subscription: Subscription<IotaTransactionBlockEffects> =
607 c.subscribe_transaction(filter).await?;
608 Ok(subscription.map(|item| Ok(item?)))
609 }
610
611 /// Get move modules by package ID, keyed by name.
612 pub async fn get_normalized_move_modules_by_package(
613 &self,
614 package: ObjectID,
615 ) -> IotaRpcResult<BTreeMap<String, IotaMoveNormalizedModule>> {
616 Ok(self
617 .api
618 .http
619 .get_normalized_move_modules_by_package(package)
620 .await?)
621 }
622
623 // TODO(devx): we can probably cache this given an epoch
624 /// Get the reference gas price.
625 pub async fn get_reference_gas_price(&self) -> IotaRpcResult<u64> {
626 Ok(*self.api.http.get_reference_gas_price().await?)
627 }
628
629 /// Dry run a transaction block given the provided transaction data.
630 ///
631 /// This simulates running the transaction, including all standard checks,
632 /// without actually running it. This is useful for estimating the gas fees
633 /// of a transaction before executing it. You can also use it to identify
634 /// any side-effects of a transaction before you execute it on the network.
635 pub async fn dry_run_transaction_block(
636 &self,
637 tx: TransactionData,
638 ) -> IotaRpcResult<DryRunTransactionBlockResponse> {
639 Ok(self
640 .api
641 .http
642 .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?))
643 .await?)
644 }
645
646 /// Use this function to inspect the current state of the network by running
647 /// a programmable transaction block without committing its effects on
648 /// chain.
649 ///
650 /// Unlike a dry run, this method will not validate whether the transaction
651 /// block would succeed or fail under normal circumstances, e.g.:
652 ///
653 /// - Transaction inputs are not checked for ownership (i.e. you can
654 /// construct calls involving objects you do not own)
655 /// - Calls are not checked for visibility (you can call private functions
656 /// on modules)
657 /// - Inputs of any type can be constructed and passed in, including coins
658 /// and other objects that would usually need to be constructed with a
659 /// move call
660 /// - Function returns do not need to be used, even if they do not have
661 /// `drop`
662 ///
663 /// This method's output includes a breakdown of results returned by every
664 /// transaction in the block, as well as the transaction's effects.
665 ///
666 /// To run an accurate simulation of a transaction and understand whether
667 /// it will successfully validate and run, use
668 /// [Self::dry_run_transaction_block] instead.
669 pub async fn dev_inspect_transaction_block(
670 &self,
671 sender_address: IotaAddress,
672 tx: TransactionKind,
673 gas_price: impl Into<Option<BigInt<u64>>>,
674 epoch: impl Into<Option<BigInt<u64>>>,
675 additional_args: impl Into<Option<DevInspectArgs>>,
676 ) -> IotaRpcResult<DevInspectResults> {
677 Ok(self
678 .api
679 .http
680 .dev_inspect_transaction_block(
681 sender_address,
682 Base64::from_bytes(&bcs::to_bytes(&tx)?),
683 gas_price.into(),
684 epoch.into(),
685 additional_args.into(),
686 )
687 .await?)
688 }
689
690 /// Get the protocol config by version.
691 ///
692 /// The version defaults to the current version.
693 pub async fn get_protocol_config(
694 &self,
695 version: impl Into<Option<BigInt<u64>>>,
696 ) -> IotaRpcResult<ProtocolConfigResponse> {
697 Ok(self.api.http.get_protocol_config(version.into()).await?)
698 }
699
700 /// Get an object by ID before the given version.
701 pub async fn try_get_object_before_version(
702 &self,
703 object_id: ObjectID,
704 version: SequenceNumber,
705 ) -> IotaRpcResult<IotaPastObjectResponse> {
706 Ok(self
707 .api
708 .http
709 .try_get_object_before_version(object_id, version)
710 .await?)
711 }
712
713 #[cfg(feature = "iota-names")]
714 /// Return the resolved record for the given name.
715 pub async fn iota_names_lookup(&self, name: &str) -> IotaRpcResult<Option<IotaNameRecord>> {
716 Ok(self.api.http.iota_names_lookup(name).await?)
717 }
718
719 #[cfg(feature = "iota-names")]
720 /// Return the resolved name for the given address.
721 pub async fn iota_names_reverse_lookup(
722 &self,
723 address: IotaAddress,
724 ) -> IotaRpcResult<Option<String>> {
725 Ok(self.api.http.iota_names_reverse_lookup(address).await?)
726 }
727
728 #[cfg(feature = "iota-names")]
729 /// Find all registration NFTs for the given address.
730 pub async fn iota_names_find_all_registration_nfts(
731 &self,
732 address: IotaAddress,
733 cursor: Option<ObjectID>,
734 limit: Option<usize>,
735 options: Option<IotaObjectDataOptions>,
736 ) -> IotaRpcResult<ObjectsPage> {
737 Ok(self
738 .api
739 .http
740 .iota_names_find_all_registration_nfts(address, cursor, limit, options)
741 .await?)
742 }
743}