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::{ObjectId, TransactionKind};
25use iota_types::{
26 base_types::{IotaAddress, SequenceNumber, TransactionDigest},
27 dynamic_field::DynamicFieldName,
28 iota_serde::BigInt,
29 messages_checkpoint::CheckpointSequenceNumber,
30 transaction::TransactionData,
31};
32use jsonrpsee::core::client::Subscription;
33
34use crate::{
35 RpcClient,
36 error::{Error, IotaRpcResult},
37};
38
39/// Defines methods for retrieving data about objects and transactions.
40#[derive(Debug)]
41pub struct ReadApi {
42 api: Arc<RpcClient>,
43}
44
45impl ReadApi {
46 pub(crate) fn new(api: Arc<RpcClient>) -> Self {
47 Self { api }
48 }
49
50 /// Get the objects owned by the given address.
51 /// Results are paginated.
52 ///
53 /// Note that if the address owns more than
54 /// [`QUERY_MAX_RESULT_LIMIT`](iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT)
55 /// objects (default is 50), the pagination may not be accurate as the
56 /// previous page may have been updated before the next page is fetched.
57 ///
58 /// # Examples
59 ///
60 /// ```rust,no_run
61 /// use std::str::FromStr;
62 ///
63 /// use iota_sdk::{IotaClientBuilder, types::base_types::IotaAddress};
64 ///
65 /// #[tokio::main]
66 /// async fn main() -> Result<(), anyhow::Error> {
67 /// let iota = IotaClientBuilder::default().build_testnet().await?;
68 /// let address = IotaAddress::from_str("0x0000....0000")?;
69 /// let owned_objects = iota
70 /// .read_api()
71 /// .get_owned_objects(address, None, None, None)
72 /// .await?;
73 /// Ok(())
74 /// }
75 /// ```
76 pub async fn get_owned_objects(
77 &self,
78 address: IotaAddress,
79 query: impl Into<Option<IotaObjectResponseQuery>>,
80 cursor: impl Into<Option<ObjectId>>,
81 limit: impl Into<Option<usize>>,
82 ) -> IotaRpcResult<ObjectsPage> {
83 Ok(self
84 .api
85 .http
86 .get_owned_objects(address, query.into(), cursor.into(), limit.into())
87 .await?)
88 }
89
90 /// Get the dynamic fields owned by the given [ObjectId].
91 /// Results are paginated.
92 ///
93 /// If the field is a dynamic field, this method returns the ID of the Field
94 /// object, which contains both the name and the value.
95 ///
96 /// If the field is a dynamic object field, it returns the ID of the Object,
97 /// which is the value of the field.
98 ///
99 /// # Examples
100 ///
101 /// ```rust,no_run
102 /// use std::str::FromStr;
103 ///
104 /// use iota_sdk::{IotaClientBuilder, types::base_types::IotaAddress};
105 /// use iota_sdk_types::ObjectId;
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, rpc_types::IotaObjectDataOptions, types::base_types::IotaAddress,
188 /// };
189 /// use iota_sdk_types::ObjectId;
190 ///
191 /// #[tokio::main]
192 /// async fn main() -> Result<(), anyhow::Error> {
193 /// let iota = IotaClientBuilder::default().build_testnet().await?;
194 /// let address = IotaAddress::from_str("0x0000....0000")?;
195 /// let owned_objects = iota
196 /// .read_api()
197 /// .get_owned_objects(address, None, None, None)
198 /// .await?;
199 /// // this code example assumes that there are previous owned objects
200 /// let object = owned_objects
201 /// .data
202 /// .get(0)
203 /// .expect(&format!("No owned objects for this address {}", address));
204 /// let object_data = object.data.as_ref().expect(&format!(
205 /// "No object data for this IotaObjectResponse {:?}",
206 /// object
207 /// ));
208 /// let object_id = object_data.object_id;
209 /// let version = object_data.version;
210 /// let past_object = iota
211 /// .read_api()
212 /// .try_get_parsed_past_object(
213 /// object_id,
214 /// version,
215 /// IotaObjectDataOptions {
216 /// show_type: true,
217 /// show_owner: true,
218 /// show_previous_transaction: true,
219 /// show_display: true,
220 /// show_content: true,
221 /// show_bcs: true,
222 /// show_storage_rebate: true,
223 /// },
224 /// )
225 /// .await?;
226 /// Ok(())
227 /// }
228 /// ```
229 pub async fn try_get_parsed_past_object(
230 &self,
231 object_id: ObjectId,
232 version: SequenceNumber,
233 options: IotaObjectDataOptions,
234 ) -> IotaRpcResult<IotaPastObjectResponse> {
235 Ok(self
236 .api
237 .http
238 .try_get_past_object(object_id, version, Some(options))
239 .await?)
240 }
241
242 /// Get a list of parsed past objects.
243 ///
244 /// See [Self::try_get_parsed_past_object] for more details about past
245 /// objects.
246 ///
247 /// # Examples
248 ///
249 /// ```rust,no_run
250 /// use std::str::FromStr;
251 ///
252 /// use iota_sdk::{
253 /// IotaClientBuilder,
254 /// rpc_types::{IotaGetPastObjectRequest, IotaObjectDataOptions},
255 /// types::base_types::IotaAddress,
256 /// };
257 /// use iota_sdk_types::ObjectId;
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 let query_v2 = IotaTransactionBlockResponseQueryV2 {
516 filter: query.filter.as_ref().map(|f| f.as_v2()),
517 options: query.options,
518 };
519 self.query_transaction_blocks_v2(query_v2, cursor, limit, descending_order)
520 .await
521 }
522
523 /// Get filtered transaction blocks information.
524 /// Results are paginated.
525 pub async fn query_transaction_blocks_v2(
526 &self,
527 query: IotaTransactionBlockResponseQueryV2,
528 cursor: impl Into<Option<TransactionDigest>>,
529 limit: impl Into<Option<usize>>,
530 descending_order: bool,
531 ) -> IotaRpcResult<TransactionBlocksPage> {
532 Ok(self
533 .api
534 .http
535 .query_transaction_blocks_v2(query, cursor.into(), limit.into(), Some(descending_order))
536 .await?)
537 }
538
539 /// Get the first four bytes of the chain's genesis checkpoint digest in hex
540 /// format.
541 pub async fn get_chain_identifier(&self) -> IotaRpcResult<String> {
542 Ok(self.api.http.get_chain_identifier().await?)
543 }
544
545 /// Get a checkpoint by its ID.
546 pub async fn get_checkpoint(&self, id: CheckpointId) -> IotaRpcResult<Checkpoint> {
547 Ok(self.api.http.get_checkpoint(id).await?)
548 }
549
550 /// Return a list of checkpoints.
551 /// Results are paginated.
552 pub async fn get_checkpoints(
553 &self,
554 cursor: impl Into<Option<BigInt<u64>>>,
555 limit: impl Into<Option<usize>>,
556 descending_order: bool,
557 ) -> IotaRpcResult<CheckpointPage> {
558 Ok(self
559 .api
560 .http
561 .get_checkpoints(cursor.into(), limit.into(), descending_order)
562 .await?)
563 }
564
565 /// Get the sequence number of the latest checkpoint that has been executed.
566 pub async fn get_latest_checkpoint_sequence_number(
567 &self,
568 ) -> IotaRpcResult<CheckpointSequenceNumber> {
569 Ok(*self
570 .api
571 .http
572 .get_latest_checkpoint_sequence_number()
573 .await?)
574 }
575
576 /// Get a stream of transactions.
577 pub fn get_transactions_stream(
578 &self,
579 query: IotaTransactionBlockResponseQuery,
580 cursor: impl Into<Option<TransactionDigest>>,
581 descending_order: bool,
582 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
583 let query_v2 = IotaTransactionBlockResponseQueryV2 {
584 filter: query.filter.as_ref().map(|f| f.as_v2()),
585 options: query.options,
586 };
587
588 self.get_transactions_stream_v2(query_v2, cursor, descending_order)
589 }
590
591 /// Get a stream of transactions.
592 pub fn get_transactions_stream_v2(
593 &self,
594 query: IotaTransactionBlockResponseQueryV2,
595 cursor: impl Into<Option<TransactionDigest>>,
596 descending_order: bool,
597 ) -> impl Stream<Item = IotaTransactionBlockResponse> + '_ {
598 let cursor = cursor.into();
599
600 stream::unfold(
601 (vec![], cursor, true, query),
602 move |(mut data, cursor, first, query)| async move {
603 if let Some(item) = data.pop() {
604 Some((item, (data, cursor, false, query)))
605 } else if (cursor.is_none() && first) || cursor.is_some() {
606 let page = self
607 .query_transaction_blocks_v2(
608 query.clone(),
609 cursor,
610 Some(100),
611 descending_order,
612 )
613 .await
614 .ok()?;
615 let mut data = page.data;
616 data.reverse();
617 data.pop()
618 .map(|item| (item, (data, page.next_cursor, false, query)))
619 } else {
620 None
621 }
622 },
623 )
624 }
625
626 /// Subscribe to a stream of transactions.
627 ///
628 /// This is only available through WebSockets.
629 pub async fn subscribe_transaction(
630 &self,
631 filter: TransactionFilter,
632 ) -> IotaRpcResult<impl Stream<Item = IotaRpcResult<IotaTransactionBlockEffects>>> {
633 let Some(c) = &self.api.ws else {
634 return Err(Error::Subscription(
635 "Subscription only supported by WebSocket client.".to_string(),
636 ));
637 };
638 let subscription: Subscription<IotaTransactionBlockEffects> =
639 c.subscribe_transaction(filter).await?;
640 Ok(subscription.map(|item| Ok(item?)))
641 }
642
643 /// Get move modules by package ID, keyed by name.
644 pub async fn get_normalized_move_modules_by_package(
645 &self,
646 package: ObjectId,
647 ) -> IotaRpcResult<BTreeMap<String, IotaMoveNormalizedModule>> {
648 Ok(self
649 .api
650 .http
651 .get_normalized_move_modules_by_package(package)
652 .await?)
653 }
654
655 // TODO(devx): we can probably cache this given an epoch
656 /// Get the reference gas price.
657 pub async fn get_reference_gas_price(&self) -> IotaRpcResult<u64> {
658 Ok(*self.api.http.get_reference_gas_price().await?)
659 }
660
661 /// Dry run a transaction block given the provided transaction data.
662 ///
663 /// This simulates running the transaction, including all standard checks,
664 /// without actually running it. This is useful for estimating the gas fees
665 /// of a transaction before executing it. You can also use it to identify
666 /// any side-effects of a transaction before you execute it on the network.
667 pub async fn dry_run_transaction_block(
668 &self,
669 tx: TransactionData,
670 ) -> IotaRpcResult<DryRunTransactionBlockResponse> {
671 Ok(self
672 .api
673 .http
674 .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?))
675 .await?)
676 }
677
678 /// Use this function to inspect the current state of the network by running
679 /// a programmable transaction block without committing its effects on
680 /// chain.
681 ///
682 /// Unlike a dry run, this method will not validate whether the transaction
683 /// block would succeed or fail under normal circumstances, e.g.:
684 ///
685 /// - Transaction inputs are not checked for ownership (i.e. you can
686 /// construct calls involving objects you do not own)
687 /// - Calls are not checked for visibility (you can call private functions
688 /// on modules)
689 /// - Inputs of any type can be constructed and passed in, including coins
690 /// and other objects that would usually need to be constructed with a
691 /// move call
692 /// - Function returns do not need to be used, even if they do not have
693 /// `drop`
694 ///
695 /// This method's output includes a breakdown of results returned by every
696 /// transaction in the block, as well as the transaction's effects.
697 ///
698 /// To run an accurate simulation of a transaction and understand whether
699 /// it will successfully validate and run, use
700 /// [Self::dry_run_transaction_block] instead.
701 pub async fn dev_inspect_transaction_block(
702 &self,
703 sender_address: IotaAddress,
704 tx: TransactionKind,
705 gas_price: impl Into<Option<BigInt<u64>>>,
706 epoch: impl Into<Option<BigInt<u64>>>,
707 additional_args: impl Into<Option<DevInspectArgs>>,
708 ) -> IotaRpcResult<DevInspectResults> {
709 Ok(self
710 .api
711 .http
712 .dev_inspect_transaction_block(
713 sender_address,
714 Base64::from_bytes(&bcs::to_bytes(&tx)?),
715 gas_price.into(),
716 epoch.into(),
717 additional_args.into(),
718 )
719 .await?)
720 }
721
722 /// Get the protocol config by version.
723 ///
724 /// The version defaults to the current version.
725 pub async fn get_protocol_config(
726 &self,
727 version: impl Into<Option<BigInt<u64>>>,
728 ) -> IotaRpcResult<ProtocolConfigResponse> {
729 Ok(self.api.http.get_protocol_config(version.into()).await?)
730 }
731
732 /// Get an object by ID before the given version.
733 pub async fn try_get_object_before_version(
734 &self,
735 object_id: ObjectId,
736 version: SequenceNumber,
737 ) -> IotaRpcResult<IotaPastObjectResponse> {
738 Ok(self
739 .api
740 .http
741 .try_get_object_before_version(object_id, version)
742 .await?)
743 }
744
745 #[cfg(feature = "iota-names")]
746 /// Return the resolved record for the given name.
747 pub async fn iota_names_lookup(&self, name: &str) -> IotaRpcResult<Option<IotaNameRecord>> {
748 Ok(self.api.http.iota_names_lookup(name).await?)
749 }
750
751 #[cfg(feature = "iota-names")]
752 /// Return the resolved name for the given address.
753 pub async fn iota_names_reverse_lookup(
754 &self,
755 address: IotaAddress,
756 ) -> IotaRpcResult<Option<String>> {
757 Ok(self.api.http.iota_names_reverse_lookup(address).await?)
758 }
759
760 #[cfg(feature = "iota-names")]
761 /// Find all registration NFTs for the given address.
762 pub async fn iota_names_find_all_registration_nfts(
763 &self,
764 address: IotaAddress,
765 cursor: Option<ObjectId>,
766 limit: Option<usize>,
767 options: Option<IotaObjectDataOptions>,
768 ) -> IotaRpcResult<ObjectsPage> {
769 Ok(self
770 .api
771 .http
772 .iota_names_find_all_registration_nfts(address, cursor, limit, options)
773 .await?)
774 }
775}