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