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